OSDN Git Service

fix #36370
[jnethack/source.git] / src / detect.c
1 /* NetHack 3.6  detect.c        $NHDT-Date: 1446369464 2015/11/01 09:17:44 $  $NHDT-Branch: master $:$NHDT-Revision: 1.61 $ */
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 /* JNetHack Copyright */
11 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
12 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016            */
13 /* JNetHack may be freely redistributed.  See license for details. */
14
15 #include "hack.h"
16 #include "artifact.h"
17
18 extern boolean known; /* from read.c */
19
20 STATIC_DCL void FDECL(do_dknown_of, (struct obj *));
21 STATIC_DCL boolean FDECL(check_map_spot, (int, int, CHAR_P, unsigned));
22 STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P, unsigned));
23 STATIC_DCL void FDECL(sense_trap, (struct trap *, XCHAR_P, XCHAR_P, int));
24 STATIC_DCL int FDECL(detect_obj_traps, (struct obj *, BOOLEAN_P, int));
25 STATIC_DCL void FDECL(show_map_spot, (int, int));
26 STATIC_PTR void FDECL(findone, (int, int, genericptr_t));
27 STATIC_PTR void FDECL(openone, (int, int, genericptr_t));
28
29 /* Recursively search obj for an object in class oclass and return 1st found
30  */
31 struct obj *
32 o_in(obj, oclass)
33 struct obj *obj;
34 char oclass;
35 {
36     register struct obj *otmp;
37     struct obj *temp;
38
39     if (obj->oclass == oclass)
40         return obj;
41
42     if (Has_contents(obj)) {
43         for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
44             if (otmp->oclass == oclass)
45                 return otmp;
46             else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)))
47                 return temp;
48     }
49     return (struct obj *) 0;
50 }
51
52 /* Recursively search obj for an object made of specified material.
53  * Return first found.
54  */
55 struct obj *
56 o_material(obj, material)
57 struct obj *obj;
58 unsigned material;
59 {
60     register struct obj *otmp;
61     struct obj *temp;
62
63     if (objects[obj->otyp].oc_material == material)
64         return obj;
65
66     if (Has_contents(obj)) {
67         for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
68             if (objects[otmp->otyp].oc_material == material)
69                 return otmp;
70             else if (Has_contents(otmp)
71                      && (temp = o_material(otmp, material)))
72                 return temp;
73     }
74     return (struct obj *) 0;
75 }
76
77 STATIC_OVL void
78 do_dknown_of(obj)
79 struct obj *obj;
80 {
81     struct obj *otmp;
82
83     obj->dknown = 1;
84     if (Has_contents(obj)) {
85         for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
86             do_dknown_of(otmp);
87     }
88 }
89
90 /* Check whether the location has an outdated object displayed on it. */
91 STATIC_OVL boolean
92 check_map_spot(x, y, oclass, material)
93 int x, y;
94 char oclass;
95 unsigned material;
96 {
97     int glyph;
98     register struct obj *otmp;
99     register struct monst *mtmp;
100
101     glyph = glyph_at(x, y);
102     if (glyph_is_object(glyph)) {
103         /* there's some object shown here */
104         if (oclass == ALL_CLASSES) {
105             return (boolean) !(level.objects[x][y] /* stale if nothing here */
106                                || ((mtmp = m_at(x, y)) != 0 && mtmp->minvent));
107         } else {
108             if (material
109                 && objects[glyph_to_obj(glyph)].oc_material == material) {
110                 /* object shown here is of interest because material matches */
111                 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
112                     if (o_material(otmp, GOLD))
113                         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, GOLD))
118                             return FALSE;
119                 }
120                 /* detection indicates removal of this object from the map */
121                 return TRUE;
122             }
123             if (oclass && objects[glyph_to_obj(glyph)].oc_class == oclass) {
124                 /* obj shown here is of interest because its class matches */
125                 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
126                     if (o_in(otmp, oclass))
127                         return FALSE;
128                 /* didn't find it; perhaps a monster is carrying it */
129                 if ((mtmp = m_at(x, y)) != 0) {
130                     for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
131                         if (o_in(otmp, oclass))
132                             return FALSE;
133                 }
134                 /* detection indicates removal of this object from the map */
135                 return TRUE;
136             }
137         }
138     }
139     return FALSE;
140 }
141
142 /*
143  * When doing detection, remove stale data from the map display (corpses
144  * rotted away, objects carried away by monsters, etc) so that it won't
145  * reappear after the detection has completed.  Return true if noticeable
146  * change occurs.
147  */
148 STATIC_OVL boolean
149 clear_stale_map(oclass, material)
150 char oclass;
151 unsigned material;
152 {
153     register int zx, zy;
154     boolean change_made = FALSE;
155
156     for (zx = 1; zx < COLNO; zx++)
157         for (zy = 0; zy < ROWNO; zy++)
158             if (check_map_spot(zx, zy, oclass, material)) {
159                 unmap_object(zx, zy);
160                 change_made = TRUE;
161             }
162
163     return change_made;
164 }
165
166 /* look for gold, on the floor or in monsters' possession */
167 int
168 gold_detect(sobj)
169 register struct obj *sobj;
170 {
171     register struct obj *obj;
172     register struct monst *mtmp;
173     struct obj *temp;
174     boolean stale;
175
176     known = stale =
177         clear_stale_map(COIN_CLASS, (unsigned) (sobj->blessed ? GOLD : 0));
178
179     /* look for gold carried by monsters (might be in a container) */
180     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
181         if (DEADMONSTER(mtmp))
182             continue; /* probably not needed in this case but... */
183         if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
184             known = TRUE;
185             goto outgoldmap; /* skip further searching */
186         } else
187             for (obj = mtmp->minvent; obj; obj = obj->nobj)
188                 if (sobj->blessed && o_material(obj, GOLD)) {
189                     known = TRUE;
190                     goto outgoldmap;
191                 } else if (o_in(obj, COIN_CLASS)) {
192                     known = TRUE;
193                     goto outgoldmap; /* skip further searching */
194                 }
195     }
196
197     /* look for gold objects */
198     for (obj = fobj; obj; obj = obj->nobj) {
199         if (sobj->blessed && o_material(obj, GOLD)) {
200             known = TRUE;
201             if (obj->ox != u.ux || obj->oy != u.uy)
202                 goto outgoldmap;
203         } else if (o_in(obj, COIN_CLASS)) {
204             known = TRUE;
205             if (obj->ox != u.ux || obj->oy != u.uy)
206                 goto outgoldmap;
207         }
208     }
209
210     if (!known) {
211         /* no gold found on floor or monster's inventory.
212            adjust message if you have gold in your inventory */
213         if (sobj) {
214             char buf[BUFSZ];
215             if (youmonst.data == &mons[PM_GOLD_GOLEM]) {
216 /*JP
217                 Sprintf(buf, "You feel like a million %s!", currency(2L));
218 */
219                 Strcpy(buf, "\82 \82È\82½\82Í\8bà\8e\9d\82¿\82É\82È\82Á\82½\82æ\82¤\82É\8a´\82\82½\81I");
220             } else if (hidden_gold() || money_cnt(invent))
221                 Strcpy(buf,
222 /*JP
223                    "You feel worried about your future financial situation.");
224 */
225                    "\82 \82È\82½\82Í\8f«\97\88\82Ì\8co\8dÏ\8fó\8bµ\82ª\90S\94z\82É\82È\82Á\82½\81D");
226             else
227 /*JP
228                 Strcpy(buf, "You feel materially poor.");
229 */
230                 Strcpy(buf, "\82 \82È\82½\82Í\82Ð\82à\82\82³\82ð\8a´\82\82½\81D");
231             strange_feeling(sobj, buf);
232         }
233         return 1;
234     }
235     /* only under me - no separate display required */
236     if (stale)
237         docrt();
238 /*JP
239     You("notice some gold between your %s.", makeplural(body_part(FOOT)));
240 */
241     You("%s\82Ì\8aÔ\82É\8bà\89Ý\82ª\97\8e\82¿\82Ä\82¢\82é\82±\82Æ\82É\8bC\82ª\82Â\82¢\82½\81D", body_part(FOOT));
242     return 0;
243
244 outgoldmap:
245     cls();
246
247     iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
248     u.uinwater = u.uburied = 0;
249     /* Discover gold locations. */
250     for (obj = fobj; obj; obj = obj->nobj) {
251         if (sobj->blessed && (temp = o_material(obj, GOLD))) {
252             if (temp != obj) {
253                 temp->ox = obj->ox;
254                 temp->oy = obj->oy;
255             }
256             map_object(temp, 1);
257         } else if ((temp = o_in(obj, COIN_CLASS))) {
258             if (temp != obj) {
259                 temp->ox = obj->ox;
260                 temp->oy = obj->oy;
261             }
262             map_object(temp, 1);
263         }
264     }
265     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
266         if (DEADMONSTER(mtmp))
267             continue; /* probably overkill here */
268         if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
269             struct obj gold;
270             gold = zeroobj; /* ensure oextra is cleared too */
271             gold.otyp = GOLD_PIECE;
272             gold.ox = mtmp->mx;
273             gold.oy = mtmp->my;
274             map_object(&gold, 1);
275         } else
276             for (obj = mtmp->minvent; obj; obj = obj->nobj)
277                 if (sobj->blessed && (temp = o_material(obj, GOLD))) {
278                     temp->ox = mtmp->mx;
279                     temp->oy = mtmp->my;
280                     map_object(temp, 1);
281                     break;
282                 } else if ((temp = o_in(obj, COIN_CLASS))) {
283                     temp->ox = mtmp->mx;
284                     temp->oy = mtmp->my;
285                     map_object(temp, 1);
286                     break;
287                 }
288     }
289     newsym(u.ux, u.uy);
290     u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
291 /*JP
292     You_feel("very greedy, and sense gold!");
293 */
294     You("\82Ç\82ñ\97~\82É\82È\82Á\82½\82æ\82¤\82È\8bC\82ª\82µ\82½\81C\82»\82µ\82Ä\8bà\89Ý\82Ì\88Ê\92u\82ð\8a´\92m\82µ\82½\81I");
295     exercise(A_WIS, TRUE);
296     display_nhwindow(WIN_MAP, TRUE);
297     docrt();
298     if (Underwater)
299         under_water(2);
300     if (u.uburied)
301         under_ground(2);
302     return 0;
303 }
304
305 /* returns 1 if nothing was detected   */
306 /* returns 0 if something was detected */
307 int
308 food_detect(sobj)
309 register struct obj *sobj;
310 {
311     register struct obj *obj;
312     register struct monst *mtmp;
313     register int ct = 0, ctu = 0;
314     boolean confused = (Confusion || (sobj && sobj->cursed)), stale;
315     char oclass = confused ? POTION_CLASS : FOOD_CLASS;
316 /*JP
317     const char *what = confused ? something : "food";
318 */
319     const char *what = confused ? "\83n\83\89\83w\83\8a" : "\90H\82×\95¨";
320
321     stale = clear_stale_map(oclass, 0);
322
323     for (obj = fobj; obj; obj = obj->nobj)
324         if (o_in(obj, oclass)) {
325             if (obj->ox == u.ux && obj->oy == u.uy)
326                 ctu++;
327             else
328                 ct++;
329         }
330     for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) {
331         /* no DEADMONSTER(mtmp) check needed since dmons never have inventory
332          */
333         for (obj = mtmp->minvent; obj; obj = obj->nobj)
334             if (o_in(obj, oclass)) {
335                 ct++;
336                 break;
337             }
338     }
339
340     if (!ct && !ctu) {
341         known = stale && !confused;
342         if (stale) {
343             docrt();
344 /*JP
345             You("sense a lack of %s nearby.", what);
346 */
347             You("%s\82ª\8c¸\82Á\82Ä\82¢\82é\82Ì\82É\8bC\82ª\82Â\82¢\82½\81D",what);
348             if (sobj && sobj->blessed) {
349                 if (!u.uedibility)
350 /*JP
351                     Your("%s starts to tingle.", body_part(NOSE));
352 */
353                     Your("%s\82ª\82Ò\82­\82Á\82Æ\93®\82¢\82½\81D", body_part(NOSE));
354                 u.uedibility = 1;
355             }
356         } else if (sobj) {
357             char buf[BUFSZ];
358 #if 0 /*JP*/
359             Sprintf(buf, "Your %s twitches%s.", body_part(NOSE),
360                     (sobj->blessed && !u.uedibility)
361                         ? " then starts to tingle"
362                         : "");
363 #else
364             Sprintf(buf, "\82 \82È\82½\82Ì%s\82ª\82Ð\82­\82Ð\82­\82Æ\93®\82¢%s\81D", body_part(NOSE),
365                     (sobj->blessed && !u.uedibility)
366                         ? "\82Ä\81C\82¤\82¸\82¤\82¸\82µ\82¾\82µ\82½"
367                         : "\82½");
368 #endif
369             if (sobj->blessed && !u.uedibility) {
370                 boolean savebeginner = flags.beginner;
371
372                 flags.beginner = FALSE; /* prevent non-delivery of message */
373                 strange_feeling(sobj, buf);
374                 flags.beginner = savebeginner;
375                 u.uedibility = 1;
376             } else
377                 strange_feeling(sobj, buf);
378         }
379         return !stale;
380     } else if (!ct) {
381         known = TRUE;
382 /*JP
383         You("%s %s nearby.", sobj ? "smell" : "sense", what);
384 */
385         You("\8bß\82­\82Å%s%s\81D", what, sobj ? "\82Ì\82É\82¨\82¢\82ð\82©\82¢\82¾" : "\82ð\8a´\92m\82µ\82½");
386         if (sobj && sobj->blessed) {
387             if (!u.uedibility)
388 /*JP
389                 pline("Your %s starts to tingle.", body_part(NOSE));
390 */
391                 pline("\82 \82È\82½\82Ì%s\82ª\82¤\82¸\82¤\82¸\82µ\82¾\82µ\82½\81D", body_part(NOSE));
392             u.uedibility = 1;
393         }
394     } else {
395         struct obj *temp;
396         known = TRUE;
397         cls();
398         iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
399         u.uinwater = u.uburied = 0;
400         for (obj = fobj; obj; obj = obj->nobj)
401             if ((temp = o_in(obj, oclass)) != 0) {
402                 if (temp != obj) {
403                     temp->ox = obj->ox;
404                     temp->oy = obj->oy;
405                 }
406                 map_object(temp, 1);
407             }
408         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
409             /* no DEADMONSTER(mtmp) check needed since dmons never have
410              * inventory */
411             for (obj = mtmp->minvent; obj; obj = obj->nobj)
412                 if ((temp = o_in(obj, oclass)) != 0) {
413                     temp->ox = mtmp->mx;
414                     temp->oy = mtmp->my;
415                     map_object(temp, 1);
416                     break; /* skip rest of this monster's inventory */
417                 }
418         newsym(u.ux, u.uy);
419         u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
420         if (sobj) {
421             if (sobj->blessed) {
422 #if 0 /*JP*/
423                 Your("%s %s to tingle and you smell %s.", body_part(NOSE),
424                      u.uedibility ? "continues" : "starts", what);
425 #else
426                 Your("%s\82Í\82¤\82¸\82¤\82¸\82µ%s\81C%s\82Ì\93õ\82¢\82ð\9ak\82¬\82Æ\82Á\82½\81D", body_part(NOSE),
427                      u.uedibility ? "\91±\82¯" : "\8en\82ß", what);
428 #endif
429                 u.uedibility = 1;
430             } else
431 /*JP
432                 Your("%s tingles and you smell %s.", body_part(NOSE), what);
433 */
434                 Your("%s\82Í\82¤\82¸\82¤\82¸\82µ\81C%s\82Ì\93õ\82¢\82ð\9ak\82¬\82Æ\82Á\82½\81D", body_part(NOSE), what);
435         } else
436 /*JP
437             You("sense %s.", what);
438 */
439             You("%s\82ð\8a´\92m\82µ\82½\81D", what);
440         display_nhwindow(WIN_MAP, TRUE);
441         exercise(A_WIS, TRUE);
442         docrt();
443         if (Underwater)
444             under_water(2);
445         if (u.uburied)
446             under_ground(2);
447     }
448     return 0;
449 }
450
451 /*
452  * Used for scrolls, potions, spells, and crystal balls.  Returns:
453  *
454  *      1 - nothing was detected
455  *      0 - something was detected
456  */
457 int
458 object_detect(detector, class)
459 struct obj *detector; /* object doing the detecting */
460 int class;            /* an object class, 0 for all */
461 {
462     register int x, y;
463     char stuff[BUFSZ];
464     int is_cursed = (detector && detector->cursed);
465     int do_dknown = (detector && (detector->oclass == POTION_CLASS
466                                   || detector->oclass == SPBOOK_CLASS)
467                      && detector->blessed);
468     int ct = 0, ctu = 0;
469     register struct obj *obj, *otmp = (struct obj *) 0;
470     register struct monst *mtmp;
471     int sym, boulder = 0;
472
473     if (class < 0 || class >= MAXOCLASSES) {
474         impossible("object_detect:  illegal class %d", class);
475         class = 0;
476     }
477
478     /* Special boulder symbol check - does the class symbol happen
479      * to match iflags.bouldersym which is a user-defined?
480      * If so, that means we aren't sure what they really wanted to
481      * detect. Rather than trump anything, show both possibilities.
482      * We can exclude checking the buried obj chain for boulders below.
483      */
484     sym = class ? def_oc_syms[class].sym : 0;
485     if (sym && iflags.bouldersym && sym == iflags.bouldersym)
486         boulder = ROCK_CLASS;
487
488     if (Hallucination || (Confusion && class == SCROLL_CLASS))
489         Strcpy(stuff, something);
490     else
491 /*JP
492         Strcpy(stuff, class ? def_oc_syms[class].name : "objects");
493 */
494         Strcpy(stuff, class ? def_oc_syms[class].name : "\95¨\91Ì");
495     if (boulder && class != ROCK_CLASS)
496 /*JP
497         Strcat(stuff, " and/or large stones");
498 */
499         Strcat(stuff, "\82Æ\8b\90\8aâ");
500
501     if (do_dknown)
502         for (obj = invent; obj; obj = obj->nobj)
503             do_dknown_of(obj);
504
505     for (obj = fobj; obj; obj = obj->nobj) {
506         if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) {
507             if (obj->ox == u.ux && obj->oy == u.uy)
508                 ctu++;
509             else
510                 ct++;
511         }
512         if (do_dknown)
513             do_dknown_of(obj);
514     }
515
516     for (obj = level.buriedobjlist; obj; obj = obj->nobj) {
517         if (!class || o_in(obj, class)) {
518             if (obj->ox == u.ux && obj->oy == u.uy)
519                 ctu++;
520             else
521                 ct++;
522         }
523         if (do_dknown)
524             do_dknown_of(obj);
525     }
526
527     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
528         if (DEADMONSTER(mtmp))
529             continue;
530         for (obj = mtmp->minvent; obj; obj = obj->nobj) {
531             if ((!class && !boulder) || o_in(obj, class)
532                 || o_in(obj, boulder))
533                 ct++;
534             if (do_dknown)
535                 do_dknown_of(obj);
536         }
537         if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT
538              && (!class || class == objects[mtmp->mappearance].oc_class))
539             || (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) {
540             ct++;
541             break;
542         }
543     }
544
545     if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) {
546         if (!ctu) {
547             if (detector)
548 /*JP
549                 strange_feeling(detector, "You feel a lack of something.");
550 */
551                 strange_feeling(detector, "\82 \82È\82½\82Í\89½\82©\82ª\8c\87\96R\82µ\82Ä\82¢\82é\82æ\82¤\82È\8bC\82ª\82µ\82½\81D");
552             return 1;
553         }
554
555 /*JP
556         You("sense %s nearby.", stuff);
557 */
558         You("\8bß\82­\82Ì%s\82ð\8a´\92m\82µ\82½\81D", stuff);
559         return 0;
560     }
561
562     cls();
563
564     iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
565     u.uinwater = u.uburied = 0;
566     /*
567      *  Map all buried objects first.
568      */
569     for (obj = level.buriedobjlist; obj; obj = obj->nobj)
570         if (!class || (otmp = o_in(obj, class))) {
571             if (class) {
572                 if (otmp != obj) {
573                     otmp->ox = obj->ox;
574                     otmp->oy = obj->oy;
575                 }
576                 map_object(otmp, 1);
577             } else
578                 map_object(obj, 1);
579         }
580     /*
581      * If we are mapping all objects, map only the top object of a pile or
582      * the first object in a monster's inventory.  Otherwise, go looking
583      * for a matching object class and display the first one encountered
584      * at each location.
585      *
586      * Objects on the floor override buried objects.
587      */
588     for (x = 1; x < COLNO; x++)
589         for (y = 0; y < ROWNO; y++)
590             for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
591                 if ((!class && !boulder) || (otmp = o_in(obj, class))
592                     || (otmp = o_in(obj, boulder))) {
593                     if (class || boulder) {
594                         if (otmp != obj) {
595                             otmp->ox = obj->ox;
596                             otmp->oy = obj->oy;
597                         }
598                         map_object(otmp, 1);
599                     } else
600                         map_object(obj, 1);
601                     break;
602                 }
603
604     /* Objects in the monster's inventory override floor objects. */
605     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
606         if (DEADMONSTER(mtmp))
607             continue;
608         for (obj = mtmp->minvent; obj; obj = obj->nobj)
609             if ((!class && !boulder) || (otmp = o_in(obj, class))
610                 || (otmp = o_in(obj, boulder))) {
611                 if (!class && !boulder)
612                     otmp = obj;
613                 otmp->ox = mtmp->mx; /* at monster location */
614                 otmp->oy = mtmp->my;
615                 map_object(otmp, 1);
616                 break;
617             }
618         /* Allow a mimic to override the detected objects it is carrying. */
619         if (is_cursed && mtmp->m_ap_type == M_AP_OBJECT
620             && (!class || class == objects[mtmp->mappearance].oc_class)) {
621             struct obj temp;
622
623             temp.oextra = (struct oextra *) 0;
624             temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */
625             temp.ox = mtmp->mx;
626             temp.oy = mtmp->my;
627             temp.corpsenm = PM_TENGU; /* if mimicing a corpse */
628             map_object(&temp, 1);
629         } else if (findgold(mtmp->minvent)
630                    && (!class || class == COIN_CLASS)) {
631             struct obj gold;
632             gold = zeroobj; /* ensure oextra is cleared too */
633             gold.otyp = GOLD_PIECE;
634             gold.ox = mtmp->mx;
635             gold.oy = mtmp->my;
636             map_object(&gold, 1);
637         }
638     }
639
640     newsym(u.ux, u.uy);
641     u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
642 /*JP
643     You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
644 */
645     You("%s%s\81D", stuff, ct ? "\82ð\94­\8c©\82µ\82½" : "\82Í\89½\82à\82È\82¢\82±\82Æ\82ª\82í\82©\82Á\82½" );
646     display_nhwindow(WIN_MAP, TRUE);
647     /*
648      * What are we going to do when the hero does an object detect while blind
649      * and the detected object covers a known pool?
650      */
651     docrt(); /* this will correctly reset vision */
652
653     if (Underwater)
654         under_water(2);
655     if (u.uburied)
656         under_ground(2);
657     return 0;
658 }
659
660 /*
661  * Used by: crystal balls, potions, fountains
662  *
663  * Returns 1 if nothing was detected.
664  * Returns 0 if something was detected.
665  */
666 int
667 monster_detect(otmp, mclass)
668 register struct obj *otmp; /* detecting object (if any) */
669 int mclass;                /* monster class, 0 for all */
670 {
671     register struct monst *mtmp;
672     int mcnt = 0;
673
674     /* Note: This used to just check fmon for a non-zero value
675      * but in versions since 3.3.0 fmon can test TRUE due to the
676      * presence of dmons, so we have to find at least one
677      * with positive hit-points to know for sure.
678      */
679     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
680         if (!DEADMONSTER(mtmp)) {
681             mcnt++;
682             break;
683         }
684
685     if (!mcnt) {
686         if (otmp)
687             strange_feeling(otmp, Hallucination
688 /*JP
689                                       ? "You get the heebie jeebies."
690 */
691                                       ? "\82 \82È\82½\82Í\8bà\92¹\82Ì\89Ä\82Å\83L\83\93\83`\83\87\81[\82µ\82½\81D"
692 /*JP
693                                       : "You feel threatened.");
694 */
695                                       : "\82 \82È\82½\82Í\8b°\95|\82Å\82¼\82­\82Á\82Æ\82µ\82½\81D");
696         return 1;
697     } else {
698         boolean woken = FALSE;
699
700         cls();
701         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
702             if (DEADMONSTER(mtmp))
703                 continue;
704             if (!mclass || mtmp->data->mlet == mclass
705                 || (mtmp->data == &mons[PM_LONG_WORM]
706                     && mclass == S_WORM_TAIL))
707                 if (mtmp->mx > 0) {
708                     if (mclass && def_monsyms[mclass].sym == ' ')
709                         show_glyph(mtmp->mx, mtmp->my,
710                                    detected_mon_to_glyph(mtmp));
711                     else
712                         show_glyph(mtmp->mx, mtmp->my,
713                                    mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp));
714                     /* don't be stingy - display entire worm */
715                     if (mtmp->data == &mons[PM_LONG_WORM])
716                         detect_wsegs(mtmp, 0);
717                 }
718             if (otmp && otmp->cursed
719                 && (mtmp->msleeping || !mtmp->mcanmove)) {
720                 mtmp->msleeping = mtmp->mfrozen = 0;
721                 mtmp->mcanmove = 1;
722                 woken = TRUE;
723             }
724         }
725         display_self();
726 /*JP
727         You("sense the presence of monsters.");
728 */
729         You("\89ö\95¨\82Ì\91\8dÝ\82ð\9ak\82¬\82Â\82¯\82½\81D");
730         if (woken)
731 /*JP
732             pline("Monsters sense the presence of you.");
733 */
734             pline("\89ö\95¨\82Í\82 \82È\82½\82Ì\91\8dÝ\82ð\9ak\82¬\82Â\82¯\82½\81D");
735         display_nhwindow(WIN_MAP, TRUE);
736         docrt();
737         if (Underwater)
738             under_water(2);
739         if (u.uburied)
740             under_ground(2);
741     }
742     return 0;
743 }
744
745 STATIC_OVL void
746 sense_trap(trap, x, y, src_cursed)
747 struct trap *trap;
748 xchar x, y;
749 int src_cursed;
750 {
751     if (Hallucination || src_cursed) {
752         struct obj obj; /* fake object */
753
754         obj.oextra = (struct oextra *) 0;
755         if (trap) {
756             obj.ox = trap->tx;
757             obj.oy = trap->ty;
758         } else {
759             obj.ox = x;
760             obj.oy = y;
761         }
762         obj.otyp = (src_cursed) ? GOLD_PIECE : random_object();
763         obj.corpsenm = random_monster(); /* if otyp == CORPSE */
764         map_object(&obj, 1);
765     } else if (trap) {
766         map_trap(trap, 1);
767         trap->tseen = 1;
768     } else {
769         struct trap temp_trap; /* fake trap */
770         temp_trap.tx = x;
771         temp_trap.ty = y;
772         temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */
773         map_trap(&temp_trap, 1);
774     }
775 }
776
777 #define OTRAP_NONE 0  /* nothing found */
778 #define OTRAP_HERE 1  /* found at hero's location */
779 #define OTRAP_THERE 2 /* found at any other location */
780
781 /* check a list of objects for chest traps; return 1 if found at <ux,uy>,
782    2 if found at some other spot, 3 if both, 0 otherwise; optionally
783    update the map to show where such traps were found */
784 STATIC_OVL int
785 detect_obj_traps(objlist, show_them, how)
786 struct obj *objlist;
787 boolean show_them;
788 int how; /* 1 for misleading map feedback */
789 {
790     struct obj *otmp;
791     xchar x, y;
792     int result = OTRAP_NONE;
793
794     for (otmp = objlist; otmp; otmp = otmp->nobj) {
795         if (Is_box(otmp) && otmp->otrapped
796             && get_obj_location(otmp, &x, &y, BURIED_TOO | CONTAINED_TOO)) {
797             result |= (x == u.ux && y == u.uy) ? OTRAP_HERE : OTRAP_THERE;
798             if (show_them)
799                 sense_trap((struct trap *) 0, x, y, how);
800         }
801         if (Has_contents(otmp))
802             result |= detect_obj_traps(otmp->cobj, show_them, how);
803     }
804     return result;
805 }
806
807 /* the detections are pulled out so they can
808  * also be used in the crystal ball routine
809  * returns 1 if nothing was detected
810  * returns 0 if something was detected
811  */
812 int
813 trap_detect(sobj)
814 register struct obj *sobj;
815 /* sobj is null if crystal ball, *scroll if gold detection scroll */
816 {
817     register struct trap *ttmp;
818     struct monst *mon;
819     int door, glyph, tr;
820     int cursed_src = sobj && sobj->cursed;
821     boolean found = FALSE;
822     coord cc;
823
824     /* floor/ceiling traps */
825     for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
826         if (ttmp->tx != u.ux || ttmp->ty != u.uy)
827             goto outtrapmap;
828         else
829             found = TRUE;
830     }
831     /* chest traps (might be buried or carried) */
832     if ((tr = detect_obj_traps(fobj, FALSE, 0)) != OTRAP_NONE) {
833         if (tr & OTRAP_THERE)
834             goto outtrapmap;
835         else
836             found = TRUE;
837     }
838     if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0))
839         != OTRAP_NONE) {
840         if (tr & OTRAP_THERE)
841             goto outtrapmap;
842         else
843             found = TRUE;
844     }
845     for (mon = fmon; mon; mon = mon->nmon) {
846         if (DEADMONSTER(mon))
847             continue;
848         if ((tr = detect_obj_traps(mon->minvent, FALSE, 0)) != OTRAP_NONE) {
849             if (tr & OTRAP_THERE)
850                 goto outtrapmap;
851             else
852                 found = TRUE;
853         }
854     }
855     if (detect_obj_traps(invent, FALSE, 0) != OTRAP_NONE)
856         found = TRUE;
857     /* door traps */
858     for (door = 0; door < doorindex; door++) {
859         cc = doors[door];
860         if (levl[cc.x][cc.y].doormask & D_TRAPPED) {
861             if (cc.x != u.ux || cc.y != u.uy)
862                 goto outtrapmap;
863             else
864                 found = TRUE;
865         }
866     }
867     if (!found) {
868         char buf[BUFSZ];
869
870 /*JP
871         Sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE)));
872 */
873         Sprintf(buf, "\82 \82È\82½\82Ì%s\82Ì\82Þ\82¸\82Þ\82¸\82Í\82¨\82³\82Ü\82Á\82½\81D", makeplural(body_part(TOE)));
874         strange_feeling(sobj, buf);
875         return 1;
876     }
877     /* traps exist, but only under me - no separate display required */
878 /*JP
879     Your("%s itch.", makeplural(body_part(TOE)));
880 */
881     Your("%s\82Í\82Þ\82¸\82Þ\82¸\82µ\82½\81D", makeplural(body_part(TOE)));
882     return 0;
883 outtrapmap:
884     cls();
885
886     iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
887     u.uinwater = u.uburied = 0;
888
889     /* show chest traps first, so that subsequent floor trap display
890        will override if both types are present at the same location */
891     (void) detect_obj_traps(fobj, TRUE, cursed_src);
892     (void) detect_obj_traps(level.buriedobjlist, TRUE, cursed_src);
893     for (mon = fmon; mon; mon = mon->nmon) {
894         if (DEADMONSTER(mon))
895             continue;
896         (void) detect_obj_traps(mon->minvent, TRUE, cursed_src);
897     }
898     (void) detect_obj_traps(invent, TRUE, cursed_src);
899
900     for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
901         sense_trap(ttmp, 0, 0, cursed_src);
902
903     for (door = 0; door < doorindex; door++) {
904         cc = doors[door];
905         if (levl[cc.x][cc.y].doormask & D_TRAPPED)
906             sense_trap((struct trap *) 0, cc.x, cc.y, cursed_src);
907     }
908
909     /* redisplay hero unless sense_trap() revealed something at <ux,uy> */
910     glyph = glyph_at(u.ux, u.uy);
911     if (!(glyph_is_trap(glyph) || glyph_is_object(glyph)))
912         newsym(u.ux, u.uy);
913     u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
914
915 /*JP
916     You_feel("%s.", cursed_src ? "very greedy" : "entrapped");
917 */
918     You("%s\8bC\8e\9d\82É\82È\82Á\82½\81D", cursed_src ? "\82Æ\82Ä\82à\82Ç\82ñ\97~\82È" : "\82¾\82Ü\82³\82ê\82Ä\82¢\82é\82æ\82¤\82È");
919     /* wait for user to respond, then reset map display to normal */
920     display_nhwindow(WIN_MAP, TRUE);
921     docrt();
922     if (Underwater)
923         under_water(2);
924     if (u.uburied)
925         under_ground(2);
926     return 0;
927 }
928
929 const char *
930 level_distance(where)
931 d_level *where;
932 {
933     register schar ll = depth(&u.uz) - depth(where);
934     register boolean indun = (u.uz.dnum == where->dnum);
935
936     if (ll < 0) {
937         if (ll < (-8 - rn2(3)))
938             if (!indun)
939 /*JP
940                 return "far away";
941 */
942               return "\82Í\82é\82©\94Þ\95û\82É";
943             else
944 /*JP
945                 return "far below";
946 */
947         return "\82Í\82é\82©\89º\95û\82É";
948         else if (ll < -1)
949             if (!indun)
950 /*JP
951                 return "away below you";
952 */
953               return "\82¸\82Á\82Æ\89º\95û\82É";
954             else
955 /*JP
956                 return "below you";
957 */
958               return "\89º\95û\82É";
959         else if (!indun)
960 /*JP
961             return "in the distance";
962 */
963           return "\89\93\82­\82É";
964         else
965 /*JP
966             return "just below";
967 */
968           return "\90^\89º\82É";
969     } else if (ll > 0) {
970         if (ll > (8 + rn2(3)))
971             if (!indun)
972 /*JP
973                 return "far away";
974 */
975               return "\82Í\82é\82©\94Þ\95û\82É";
976             else
977 /*JP
978                 return "far above";
979 */
980               return "\82Í\82é\82©\8fã\95û\82É";
981         else if (ll > 1)
982             if (!indun)
983 /*JP
984                 return "away above you";
985 */
986               return "\82¸\82Á\82Æ\8fã\95û\82É";
987             else
988 /*JP
989                 return "above you";
990 */
991               return "\8fã\95û\82É";
992         else if (!indun)
993 /*JP
994             return "in the distance";
995 */
996           return "\89\93\82­\82É";
997         else
998 /*JP
999             return "just above";
1000 */
1001           return "\90^\8fã\82É";
1002     } else if (!indun)
1003 /*JP
1004         return "in the distance";
1005 */
1006       return "\89\93\82­\82É";
1007     else
1008 /*JP
1009         return "near you";
1010 */
1011       return "\8bß\82­\82É";
1012 }
1013
1014 static const struct {
1015     const char *what;
1016     d_level *where;
1017 } level_detects[] = {
1018 /*JP
1019     { "Delphi", &oracle_level },
1020 */
1021     { "\83f\83\8b\83t\83@\83C", &oracle_level },
1022 /*JP
1023     { "Medusa's lair", &medusa_level },
1024 */
1025     { "\83\81\83f\83\85\81[\83T\82Ì\8fZ\82Ý\82©", &medusa_level },
1026 /*JP
1027     { "a castle", &stronghold_level },
1028 */
1029     { "\8fé", &stronghold_level },
1030 /*JP
1031     { "the Wizard of Yendor's tower", &wiz1_level },
1032 */
1033     { "\83C\83F\83\93\83_\81[\82Ì\96\82\96@\8eg\82¢\82Ì\93\83", &wiz1_level },
1034 };
1035
1036 void
1037 use_crystal_ball(optr)
1038 struct obj **optr;
1039 {
1040     char ch;
1041     int oops;
1042     struct obj *obj = *optr;
1043
1044     if (Blind) {
1045 /*JP
1046         pline("Too bad you can't see %s.", the(xname(obj)));
1047 */
1048         pline("\82È\82ñ\82Ä\82±\82Æ\82¾\81D%s\82ð\8c©\82é\82±\82Æ\82ª\82Å\82«\82È\82¢\81D", the(xname(obj)));
1049         return;
1050     }
1051     oops = (rnd(20) > ACURR(A_INT) || obj->cursed);
1052     if (oops && (obj->spe > 0)) {
1053         switch (rnd(obj->oartifact ? 4 : 5)) {
1054         case 1:
1055 /*JP
1056             pline("%s too much to comprehend!", Tobjnam(obj, "are"));
1057 */
1058             pline("%s\82ð\94`\82¢\82½\82ª\89½\82Ì\82±\82Æ\82¾\82©\82³\82Á\82Ï\82è\82í\82©\82ç\82È\82©\82Á\82½\81I", xname(obj));
1059             break;
1060         case 2:
1061 /*JP
1062             pline("%s you!", Tobjnam(obj, "confuse"));
1063 */
1064             pline("%s\82ð\94`\82¢\82Ä\82é\82Æ\82Ó\82ç\82Â\82¢\82Ä\82«\82½\81I", xname(obj));
1065             make_confused((HConfusion & TIMEOUT) + (long) rnd(100), FALSE);
1066             break;
1067         case 3:
1068             if (!resists_blnd(&youmonst)) {
1069 /*JP
1070                 pline("%s your vision!", Tobjnam(obj, "damage"));
1071 */
1072                 pline("%s\82ð\94`\82¢\82Ä\82¢\82é\82Æ\8e\8b\8ao\82ª\82¨\82©\82µ\82­\82È\82Á\82Ä\82«\82½\81I", xname(obj));
1073                 make_blinded((Blinded & TIMEOUT) + (long) rnd(100), FALSE);
1074                 if (!Blind)
1075                     Your1(vision_clears);
1076             } else {
1077 /*JP
1078                 pline("%s your vision.", Tobjnam(obj, "assault"));
1079 */
1080                 pline("%s\82ª\82 \82È\82½\82Ì\8e\8b\8aE\82É\94\97\82Á\82Ä\82«\82½\81D", xname(obj));
1081 /*JP
1082                 You("are unaffected!");
1083 */
1084                 pline("\82µ\82©\82µ\81C\82 \82È\82½\82Í\89e\8b¿\82ð\8eó\82¯\82È\82©\82Á\82½\81I");
1085             }
1086             break;
1087         case 4:
1088 /*JP
1089             pline("%s your mind!", Tobjnam(obj, "zap"));
1090 */
1091             pline("%s\82ð\94`\82¢\82Ä\82¢\82é\82Æ\8cÜ\8a´\82ª\82¨\82©\82µ\82­\82È\82Á\82Ä\82«\82½\81I", xname(obj));
1092             (void) make_hallucinated(
1093                 (HHallucination & TIMEOUT) + (long) rnd(100), FALSE, 0L);
1094             break;
1095         case 5:
1096 /*JP
1097             pline("%s!", Tobjnam(obj, "explode"));
1098 */
1099             pline("%s\82Í\94\9a\94­\82µ\82½\81I", xname(obj));
1100             useup(obj);
1101             *optr = obj = 0; /* it's gone */
1102             /* physical damage cause by the shards and force */
1103 /*JP
1104             losehp(Maybe_Half_Phys(rnd(30)), "exploding crystal ball",
1105 */
1106             losehp(Maybe_Half_Phys(rnd(30)), "\90\85\8f»\8bÊ\82Ì\94\9a\94­\82Å",
1107                    KILLED_BY_AN);
1108             break;
1109         }
1110         if (obj)
1111             consume_obj_charge(obj, TRUE);
1112         return;
1113     }
1114
1115     if (Hallucination) {
1116         if (!obj->spe) {
1117 /*JP
1118             pline("All you see is funky %s haze.", hcolor((char *) 0));
1119 */
1120             pline("\82¨\82¨\81I\83t\83@\83\93\83L\81[\83\82\83\93\83L\81[\82È%s\82à\82â\82ª\8c©\82¦\82é\81D", hcolor((char *)0));
1121         } else {
1122             switch (rnd(6)) {
1123             case 1:
1124 /*JP
1125                 You("grok some groovy globs of incandescent lava.");
1126 */
1127                 You("\90\85\96å\82Ì\8c®\82ð\82à\82Á\82½\90\85\8cË\89©\96å\82ª\95Ç\82Ì\89e\82É\89B\82ê\82Ä\82¢\82é\82Ì\82ª\8c©\82¦\82½\81D");
1128                 break;
1129             case 2:
1130 #if 0 /*JP:T*/
1131                 pline("Whoa!  Psychedelic colors, %s!",
1132                       poly_gender() == 1 ? "babe" : "dude");
1133 #else
1134                 pline("\83\8f\81[\83I\81I\83\89\83\8a\82Á\82Ä\82é\82©\82¢\81H%s\81I",
1135                       poly_gender() == 1 ? "\83x\83C\83r\81[" : "\83\86\81[");
1136 #endif
1137                 break;
1138             case 3:
1139 /*JP
1140                 pline_The("crystal pulses with sinister %s light!",
1141 */
1142                 pline("\90\85\8f»\82Í\95s\8bg\82È%s\83p\83\8b\83X\82ð\94­\82µ\82½\81I", 
1143                           hcolor((char *) 0));
1144                 break;
1145             case 4:
1146 /*JP
1147                 You_see("goldfish swimming above fluorescent rocks.");
1148 */
1149                 You("\8cu\8cõ\8aâ\82Ì\8fã\82ð\8bà\8b\9b\82ª\89j\82¢\82Å\82¢\82é\82Ì\82ð\8c©\82½\81D");
1150                 break;
1151             case 5:
1152 #if 0 /*JP*/
1153                 You_see(
1154                     "tiny snowflakes spinning around a miniature farmhouse.");
1155 #else
1156                     You("\8f¬\82³\82¢\90á\95Ð\82ª\83~\83j\83`\83\85\83A\82Ì\94_\89Æ\82Ì\89Æ\82Ì\82Ü\82í\82è\82ð\95\91\82Á\82Ä\82é\82Ì\82ð\8c©\82½\81D");
1157 #endif
1158                 break;
1159             default:
1160 /*JP
1161                 pline("Oh wow... like a kaleidoscope!");
1162 */
1163                 pline("\83\8f\81[\83I\81D\96\9c\89Ø\8b¾\82Ì\82æ\82¤\82¾\81I");
1164                  break;
1165             }
1166             consume_obj_charge(obj, TRUE);
1167         }
1168         return;
1169     }
1170
1171     /* read a single character */
1172     if (flags.verbose)
1173 /*JP
1174         You("may look for an object or monster symbol.");
1175 */
1176         You("\95¨\91Ì\82â\89ö\95¨\82Ì\8bL\8d\86\82ð\92T\82¹\82é\81D");
1177 /*JP
1178     ch = yn_function("What do you look for?", (char *) 0, '\0');
1179 */
1180     ch = yn_function("\89½\82ð\92T\82µ\82Ü\82·\82©\81H", (char *)0, '\0');
1181     /* Don't filter out ' ' here; it has a use */
1182     if ((ch != def_monsyms[S_GHOST].sym) && index(quitchars, ch)) {
1183         if (flags.verbose)
1184             pline1(Never_mind);
1185         return;
1186     }
1187 /*JP
1188     You("peer into %s...", the(xname(obj)));
1189 */
1190     You("%s\82ð\94`\82«\82±\82ñ\82¾\81D\81D\81D", the(xname(obj)));
1191     nomul(-rnd(10));
1192 /*JP
1193     multi_reason = "gazing into a crystal ball";
1194 */
1195     multi_reason = "\90\85\8f»\8b\85\82ð\94`\82«\8d\9e\82ñ\82Å\82¢\82é\8e\9e\82É";
1196     nomovemsg = "";
1197     if (obj->spe <= 0)
1198 /*JP
1199         pline_The("vision is unclear.");
1200 */
1201         pline("\89f\91\9c\82Í\95s\91N\96¾\82¾\82Á\82½\81D");
1202     else {
1203         int class;
1204         int ret = 0;
1205
1206         makeknown(CRYSTAL_BALL);
1207         consume_obj_charge(obj, TRUE);
1208
1209         /* special case: accept ']' as synonym for mimic
1210          * we have to do this before the def_char_to_objclass check
1211          */
1212         if (ch == DEF_MIMIC_DEF)
1213             ch = DEF_MIMIC;
1214
1215         if ((class = def_char_to_objclass(ch)) != MAXOCLASSES)
1216             ret = object_detect((struct obj *) 0, class);
1217         else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES)
1218             ret = monster_detect((struct obj *) 0, class);
1219         else if (iflags.bouldersym && (ch == iflags.bouldersym))
1220             ret = object_detect((struct obj *) 0, ROCK_CLASS);
1221         else
1222             switch (ch) {
1223             case '^':
1224                 ret = trap_detect((struct obj *) 0);
1225                 break;
1226             default: {
1227                 int i = rn2(SIZE(level_detects));
1228 #if 0 /*JP*/
1229                 You_see("%s, %s.", level_detects[i].what,
1230                         level_distance(level_detects[i].where));
1231 #else
1232                 You_see("%s\82ð%s\8c©\82½\81D", level_detects[i].what,
1233                         level_distance(level_detects[i].where));
1234 #endif
1235             }
1236                 ret = 0;
1237                 break;
1238             }
1239
1240         if (ret) {
1241             if (!rn2(100)) /* make them nervous */
1242 /*JP
1243                 You_see("the Wizard of Yendor gazing out at you.");
1244 */
1245                 You("\83C\83F\83\93\83_\81[\82Ì\96\82\96@\8eg\82¢\82ª\82 \82È\82½\82ð\82É\82ç\82ñ\82Å\82¢\82é\82Ì\82ð\8c©\82½\81D");
1246             else
1247 /*JP
1248                 pline_The("vision is unclear.");
1249 */
1250                 pline("\89f\91\9c\82Í\95s\91N\96¾\82É\82È\82Á\82½\81D");
1251         }
1252     }
1253     return;
1254 }
1255
1256 STATIC_OVL void
1257 show_map_spot(x, y)
1258 register int x, y;
1259 {
1260     struct rm *lev;
1261     struct trap *t;
1262     int oldglyph;
1263
1264     if (Confusion && rn2(7))
1265         return;
1266     lev = &levl[x][y];
1267
1268     lev->seenv = SVALL;
1269
1270     /* Secret corridors are found, but not secret doors. */
1271     if (lev->typ == SCORR) {
1272         lev->typ = CORR;
1273         unblock_point(x, y);
1274     }
1275
1276     /*
1277      * Force the real background, then if it's not furniture and there's
1278      * a known trap there, display the trap, else if there was an object
1279      * shown there, redisplay the object.  So during mapping, furniture
1280      * takes precedence over traps, which take precedence over objects,
1281      * opposite to how normal vision behaves.
1282      */
1283     oldglyph = glyph_at(x, y);
1284     if (level.flags.hero_memory) {
1285         magic_map_background(x, y, 0);
1286         newsym(x, y); /* show it, if not blocked */
1287     } else {
1288         magic_map_background(x, y, 1); /* display it */
1289     }
1290     if (!IS_FURNITURE(lev->typ)) {
1291         if ((t = t_at(x, y)) != 0 && t->tseen) {
1292             map_trap(t, 1);
1293         } else if (glyph_is_trap(oldglyph) || glyph_is_object(oldglyph)) {
1294             show_glyph(x, y, oldglyph);
1295             if (level.flags.hero_memory)
1296                 lev->glyph = oldglyph;
1297         }
1298     }
1299 }
1300
1301 void
1302 do_mapping()
1303 {
1304     register int zx, zy;
1305
1306     iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
1307     u.uinwater = u.uburied = 0;
1308     for (zx = 1; zx < COLNO; zx++)
1309         for (zy = 0; zy < ROWNO; zy++)
1310             show_map_spot(zx, zy);
1311     u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
1312     if (!level.flags.hero_memory || Underwater) {
1313         flush_screen(1);                 /* flush temp screen */
1314         display_nhwindow(WIN_MAP, TRUE); /* wait */
1315         docrt();
1316     }
1317     exercise(A_WIS, TRUE);
1318 }
1319
1320 void
1321 do_vicinity_map()
1322 {
1323     register int zx, zy;
1324     int lo_y = (u.uy - 5 < 0 ? 0 : u.uy - 5),
1325         hi_y = (u.uy + 6 > ROWNO ? ROWNO : u.uy + 6),
1326         lo_x = (u.ux - 9 < 1 ? 1 : u.ux - 9), /* avoid column 0 */
1327         hi_x = (u.ux + 10 > COLNO ? COLNO : u.ux + 10);
1328
1329     for (zx = lo_x; zx < hi_x; zx++)
1330         for (zy = lo_y; zy < hi_y; zy++)
1331             show_map_spot(zx, zy);
1332
1333     if (!level.flags.hero_memory || Underwater) {
1334         flush_screen(1);                 /* flush temp screen */
1335         display_nhwindow(WIN_MAP, TRUE); /* wait */
1336         docrt();
1337     }
1338 }
1339
1340 /* convert a secret door into a normal door */
1341 void
1342 cvt_sdoor_to_door(lev)
1343 struct rm *lev;
1344 {
1345     int newmask = lev->doormask & ~WM_MASK;
1346
1347     if (Is_rogue_level(&u.uz))
1348         /* rogue didn't have doors, only doorways */
1349         newmask = D_NODOOR;
1350     else
1351         /* newly exposed door is closed */
1352         if (!(newmask & D_LOCKED))
1353         newmask |= D_CLOSED;
1354
1355     lev->typ = DOOR;
1356     lev->doormask = newmask;
1357 }
1358
1359 STATIC_PTR void
1360 findone(zx, zy, num)
1361 int zx, zy;
1362 genericptr_t num;
1363 {
1364     register struct trap *ttmp;
1365     register struct monst *mtmp;
1366
1367     if (levl[zx][zy].typ == SDOOR) {
1368         cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */
1369         magic_map_background(zx, zy, 0);
1370         newsym(zx, zy);
1371         (*(int *) num)++;
1372     } else if (levl[zx][zy].typ == SCORR) {
1373         levl[zx][zy].typ = CORR;
1374         unblock_point(zx, zy);
1375         magic_map_background(zx, zy, 0);
1376         newsym(zx, zy);
1377         (*(int *) num)++;
1378     } else if ((ttmp = t_at(zx, zy)) != 0) {
1379         if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
1380             ttmp->tseen = 1;
1381             newsym(zx, zy);
1382             (*(int *) num)++;
1383         }
1384     } else if ((mtmp = m_at(zx, zy)) != 0) {
1385         if (mtmp->m_ap_type) {
1386             seemimic(mtmp);
1387             (*(int *) num)++;
1388         }
1389         if (mtmp->mundetected
1390             && (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) {
1391             mtmp->mundetected = 0;
1392             newsym(zx, zy);
1393             (*(int *) num)++;
1394         }
1395         if (!canspotmon(mtmp) && !glyph_is_invisible(levl[zx][zy].glyph))
1396             map_invisible(zx, zy);
1397     } else if (glyph_is_invisible(levl[zx][zy].glyph)) {
1398         unmap_object(zx, zy);
1399         newsym(zx, zy);
1400         (*(int *) num)++;
1401     }
1402 }
1403
1404 STATIC_PTR void
1405 openone(zx, zy, num)
1406 int zx, zy;
1407 genericptr_t num;
1408 {
1409     register struct trap *ttmp;
1410     register struct obj *otmp;
1411     int *num_p = (int *) num;
1412
1413     if (OBJ_AT(zx, zy)) {
1414         for (otmp = level.objects[zx][zy]; otmp; otmp = otmp->nexthere) {
1415             if (Is_box(otmp) && otmp->olocked) {
1416                 otmp->olocked = 0;
1417                 (*num_p)++;
1418             }
1419         }
1420         /* let it fall to the next cases. could be on trap. */
1421     }
1422     if (levl[zx][zy].typ == SDOOR
1423         || (levl[zx][zy].typ == DOOR
1424             && (levl[zx][zy].doormask & (D_CLOSED | D_LOCKED)))) {
1425         if (levl[zx][zy].typ == SDOOR)
1426             cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */
1427         if (levl[zx][zy].doormask & D_TRAPPED) {
1428             if (distu(zx, zy) < 3)
1429 /*JP
1430                 b_trapped("door", 0);
1431 */
1432                 b_trapped("\94à", 0);
1433             else
1434 #if 0 /*JP*/
1435                 Norep("You %s an explosion!",
1436                       cansee(zx, zy) ? "see" : (!Deaf ? "hear"
1437                                                       : "feel the shock of"));
1438 #else
1439                 Norep("\82 \82È\82½\82Í\94\9a\94­%s\81I",
1440                       cansee(zx, zy) ? "\82ð\8c©\82½" : (!Deaf ? "\89¹\82ð\95·\82¢\82½"
1441                                                          : "\82Ì\8fÕ\8c\82\82ð\8a´\82\82½"));
1442 #endif
1443             wake_nearto(zx, zy, 11 * 11);
1444             levl[zx][zy].doormask = D_NODOOR;
1445         } else
1446             levl[zx][zy].doormask = D_ISOPEN;
1447         unblock_point(zx, zy);
1448         newsym(zx, zy);
1449         (*num_p)++;
1450     } else if (levl[zx][zy].typ == SCORR) {
1451         levl[zx][zy].typ = CORR;
1452         unblock_point(zx, zy);
1453         newsym(zx, zy);
1454         (*num_p)++;
1455     } else if ((ttmp = t_at(zx, zy)) != 0) {
1456         struct monst *mon;
1457         boolean dummy; /* unneeded "you notice it arg" */
1458
1459         if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
1460             ttmp->tseen = 1;
1461             newsym(zx, zy);
1462             (*num_p)++;
1463         }
1464         mon = (zx == u.ux && zy == u.uy) ? &youmonst : m_at(zx, zy);
1465         if (openholdingtrap(mon, &dummy)
1466             || openfallingtrap(mon, TRUE, &dummy))
1467             (*num_p)++;
1468     } else if (find_drawbridge(&zx, &zy)) {
1469         /* make sure it isn't an open drawbridge */
1470         open_drawbridge(zx, zy);
1471         (*num_p)++;
1472     }
1473 }
1474
1475 /* returns number of things found */
1476 int
1477 findit()
1478 {
1479     int num = 0;
1480
1481     if (u.uswallow)
1482         return 0;
1483     do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (genericptr_t) &num);
1484     return num;
1485 }
1486
1487 /* returns number of things found and opened */
1488 int
1489 openit()
1490 {
1491     int num = 0;
1492
1493     if (u.uswallow) {
1494         if (is_animal(u.ustuck->data)) {
1495             if (Blind)
1496 /*JP
1497                 pline("Its mouth opens!");
1498 */
1499                 pline("\89½\8eÒ\82©\82Ì\8cû\82ª\8aJ\82¢\82½\81I");
1500             else
1501 /*JP
1502                 pline("%s opens its mouth!", Monnam(u.ustuck));
1503 */
1504                 pline("%s\82Í\8cû\82ð\8aJ\82¢\82½\81I", Monnam(u.ustuck));
1505         }
1506         expels(u.ustuck, u.ustuck->data, TRUE);
1507         return -1;
1508     }
1509
1510     do_clear_area(u.ux, u.uy, BOLT_LIM, openone, (genericptr_t) &num);
1511     return num;
1512 }
1513
1514 /* callback hack for overriding vision in do_clear_area() */
1515 boolean
1516 detecting(func)
1517 void FDECL((*func), (int, int, genericptr_t));
1518 {
1519     return (func == findone || func == openone);
1520 }
1521
1522 void
1523 find_trap(trap)
1524 struct trap *trap;
1525 {
1526     int tt = what_trap(trap->ttyp);
1527     boolean cleared = FALSE;
1528
1529     trap->tseen = 1;
1530     exercise(A_WIS, TRUE);
1531     feel_newsym(trap->tx, trap->ty);
1532
1533     if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) {
1534         /* There's too much clutter to see your find otherwise */
1535         cls();
1536         map_trap(trap, 1);
1537         display_self();
1538         cleared = TRUE;
1539     }
1540
1541 /*JP
1542     You("find %s.", an(defsyms[trap_to_defsym(tt)].explanation));
1543 */
1544     You("%s\82ð\8c©\82Â\82¯\82½\81D", defsyms[trap_to_defsym(tt)].explanation);
1545
1546     if (cleared) {
1547         display_nhwindow(WIN_MAP, TRUE); /* wait */
1548         docrt();
1549     }
1550 }
1551
1552 int
1553 dosearch0(aflag)
1554 register int aflag; /* intrinsic autosearch vs explicit searching */
1555 {
1556 #ifdef GCC_BUG
1557     /* some versions of gcc seriously muck up nested loops. if you get strange
1558        crashes while searching in a version compiled with gcc, try putting
1559        #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the
1560        makefile).
1561      */
1562     volatile xchar x, y;
1563 #else
1564     register xchar x, y;
1565 #endif
1566     register struct trap *trap;
1567     register struct monst *mtmp;
1568
1569     if (u.uswallow) {
1570         if (!aflag)
1571 /*JP
1572             pline("What are you looking for?  The exit?");
1573 */
1574             pline("\89½\82ð\92T\82·\82ñ\82¾\82¢\81H\94ñ\8fí\8cû\81H");
1575     } else {
1576         int fund = (uwep && uwep->oartifact
1577                     && spec_ability(uwep, SPFX_SEARCH)) ? uwep->spe : 0;
1578
1579         if (ublindf && ublindf->otyp == LENSES && !Blind)
1580             fund += 2; /* JDS: lenses help searching */
1581         if (fund > 5)
1582             fund = 5;
1583         for (x = u.ux - 1; x < u.ux + 2; x++)
1584             for (y = u.uy - 1; y < u.uy + 2; y++) {
1585                 if (!isok(x, y))
1586                     continue;
1587                 if (x == u.ux && y == u.uy)
1588                     continue;
1589
1590                 if (Blind && !aflag)
1591                     feel_location(x, y);
1592                 if (levl[x][y].typ == SDOOR) {
1593                     if (rnl(7 - fund))
1594                         continue;
1595                     cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */
1596                     exercise(A_WIS, TRUE);
1597                     nomul(0);
1598                     feel_location(x, y); /* make sure it shows up */
1599 /*JP
1600                     You("find a hidden door.");
1601 */
1602                     You("\89B\82³\82ê\82½\94à\82ð\8c©\82Â\82¯\82½\81D");
1603                 } else if (levl[x][y].typ == SCORR) {
1604                     if (rnl(7 - fund))
1605                         continue;
1606                     levl[x][y].typ = CORR;
1607                     unblock_point(x, y); /* vision */
1608                     exercise(A_WIS, TRUE);
1609                     nomul(0);
1610                     feel_location(x, y); /* make sure it shows up */
1611 /*JP
1612                     You("find a hidden passage.");
1613 */
1614                     You("\89B\82³\82ê\82½\92Ê\98H\82ð\8c©\82Â\82¯\82½\81D");
1615                 } else {
1616                     /* Be careful not to find anything in an SCORR or SDOOR */
1617                     if ((mtmp = m_at(x, y)) != 0 && !aflag) {
1618                         if (mtmp->m_ap_type) {
1619                             seemimic(mtmp);
1620                         find:
1621                             exercise(A_WIS, TRUE);
1622                             if (!canspotmon(mtmp)) {
1623                                 if (glyph_is_invisible(levl[x][y].glyph)) {
1624                                     /* found invisible monster in a square
1625                                      * which already has an 'I' in it.
1626                                      * Logically, this should still take
1627                                      * time and lead to a return(1), but
1628                                      * if we did that the player would keep
1629                                      * finding the same monster every turn.
1630                                      */
1631                                     continue;
1632                                 } else {
1633 /*JP
1634                                     You_feel("an unseen monster!");
1635 */
1636                                     You("\8c©\82¦\82È\82¢\89ö\95¨\82Ì\8bC\94z\82ð\8a´\82\82½\81I");
1637                                     map_invisible(x, y);
1638                                 }
1639                             } else if (!sensemon(mtmp))
1640 /*JP
1641                                 You("find %s.", mtmp->mtame
1642 */
1643                                 You("%s\82ð\8c©\82Â\82¯\82½\81D", mtmp->mtame
1644                                                    ? y_monnam(mtmp)
1645                                                    : a_monnam(mtmp));
1646                             return 1;
1647                         }
1648                         if (!canspotmon(mtmp)) {
1649                             if (mtmp->mundetected
1650                                 && (is_hider(mtmp->data)
1651                                     || mtmp->data->mlet == S_EEL))
1652                                 mtmp->mundetected = 0;
1653                             newsym(x, y);
1654                             goto find;
1655                         }
1656                     }
1657
1658                     /* see if an invisible monster has moved--if Blind,
1659                      * feel_location() already did it
1660                      */
1661                     if (!aflag && !mtmp && !Blind
1662                         && glyph_is_invisible(levl[x][y].glyph)) {
1663                         unmap_object(x, y);
1664                         newsym(x, y);
1665                     }
1666
1667                     if ((trap = t_at(x, y)) && !trap->tseen && !rnl(8)) {
1668                         nomul(0);
1669                         if (trap->ttyp == STATUE_TRAP) {
1670                             if (activate_statue_trap(trap, x, y, FALSE))
1671                                 exercise(A_WIS, TRUE);
1672                             return 1;
1673                         } else {
1674                             find_trap(trap);
1675                         }
1676                     }
1677                 }
1678             }
1679     }
1680     return 1;
1681 }
1682
1683 /* the 's' command -- explicit searching */
1684 int
1685 dosearch()
1686 {
1687     return dosearch0(0);
1688 }
1689
1690 /* Pre-map the sokoban levels */
1691 void
1692 sokoban_detect()
1693 {
1694     register int x, y;
1695     register struct trap *ttmp;
1696     register struct obj *obj;
1697
1698     /* Map the background and boulders */
1699     for (x = 1; x < COLNO; x++)
1700         for (y = 0; y < ROWNO; y++) {
1701             levl[x][y].seenv = SVALL;
1702             levl[x][y].waslit = TRUE;
1703             map_background(x, y, 1);
1704             if ((obj = sobj_at(BOULDER, x, y)) != 0)
1705                 map_object(obj, 1);
1706         }
1707
1708     /* Map the traps */
1709     for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
1710         ttmp->tseen = 1;
1711         map_trap(ttmp, 1);
1712         /* set sokoban_rules when there is at least one pit or hole */
1713         if (ttmp->ttyp == PIT || ttmp->ttyp == HOLE)
1714             Sokoban = 1;
1715     }
1716 }
1717
1718 /* idea from crawl; show known portion of map without any monsters,
1719    objects, or traps occluding the view of the underlying terrain */
1720 void
1721 reveal_terrain(full, which_subset)
1722 int full; /* wizard|explore modes allow player to request full map */
1723 int which_subset; /* when not full, whether to suppress objs and/or traps */
1724 {
1725     if ((Hallucination || Stunned || Confusion) && !full) {
1726 /*JP
1727         You("are too disoriented for this.");
1728 */
1729         You("\8d¬\97\90\82µ\82Ä\82¢\82é\82Ì\82Å\82»\82ê\82Í\82Å\82«\82È\82¢\81D");
1730     } else {
1731         int x, y, glyph, levl_glyph, default_glyph;
1732         uchar seenv;
1733         unsigned save_swallowed;
1734         struct monst *mtmp;
1735         struct trap *t;
1736         char buf[BUFSZ];
1737         boolean keep_traps = (which_subset & 1) !=0,
1738                 keep_objs = (which_subset & 2) != 0,
1739                 keep_mons = (which_subset & 4) != 0; /* actually always 0 */
1740
1741         save_swallowed = u.uswallow;
1742         iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
1743         u.uinwater = u.uburied = 0;
1744         u.uswallow = 0;
1745         default_glyph = cmap_to_glyph(level.flags.arboreal ? S_tree : S_stone);
1746         /* for 'full', show the actual terrain for the entire level,
1747            otherwise what the hero remembers for seen locations with
1748            monsters, objects, and/or traps removed as caller dictates */
1749         for (x = 1; x < COLNO; x++)
1750             for (y = 0; y < ROWNO; y++) {
1751                 seenv = (full || level.flags.hero_memory)
1752                            ? levl[x][y].seenv : cansee(x, y) ? SVALL : 0;
1753                 if (full) {
1754                     levl[x][y].seenv = SVALL;
1755                     glyph = back_to_glyph(x, y);
1756                     levl[x][y].seenv = seenv;
1757                 } else {
1758                     levl_glyph = level.flags.hero_memory
1759                                     ? levl[x][y].glyph
1760                                     : seenv
1761                                        ? back_to_glyph(x, y)
1762                                        : default_glyph;
1763                     /* glyph_at() returns the displayed glyph, which might
1764                        be a monster.  levl[][].glyph contains the remembered
1765                        glyph, which will never be a monster (unless it is
1766                        the invisible monster glyph, which is handled like
1767                        an object, replacing any object or trap at its spot) */
1768                     glyph = !save_swallowed ? glyph_at(x, y) : levl_glyph;
1769                     if (keep_mons && x == u.ux && y == u.uy && save_swallowed)
1770                         glyph = mon_to_glyph(u.ustuck);
1771                     else if (((glyph_is_monster(glyph)
1772                                || glyph_is_warning(glyph)) && !keep_mons)
1773                              || glyph_is_swallow(glyph))
1774                         glyph = levl_glyph;
1775                     if (((glyph_is_object(glyph) && !keep_objs)
1776                          || glyph_is_invisible(glyph))
1777                         && keep_traps && !covers_traps(x, y)) {
1778                         if ((t = t_at(x, y)) != 0 && t->tseen)
1779                             glyph = trap_to_glyph(t);
1780                     }
1781                     if ((glyph_is_object(glyph) && !keep_objs)
1782                         || (glyph_is_trap(glyph) && !keep_traps)
1783                         || glyph_is_invisible(glyph)) {
1784                         if (!seenv) {
1785                             glyph = default_glyph;
1786                         } else if (lastseentyp[x][y] == levl[x][y].typ) {
1787                             glyph = back_to_glyph(x, y);
1788                         } else {
1789                             /* look for a mimic here posing as furniture;
1790                                if we don't find one, we'll have to fake it */
1791                             if ((mtmp = m_at(x, y)) != 0
1792                                 && mtmp->m_ap_type == M_AP_FURNITURE) {
1793                                 glyph = cmap_to_glyph(mtmp->mappearance);
1794                             } else {
1795                                 /* we have a topology type but we want a
1796                                    screen symbol in order to derive a glyph;
1797                                    some screen symbols need the flags field
1798                                    of levl[][] in addition to the type
1799                                    (to disambiguate STAIRS to S_upstair or
1800                                    S_dnstair, for example; current flags
1801                                    might not be intended for remembered
1802                                    type, but we've got no other choice) */
1803                                 schar save_typ = levl[x][y].typ;
1804
1805                                 levl[x][y].typ = lastseentyp[x][y];
1806                                 glyph = back_to_glyph(x, y);
1807                                 levl[x][y].typ = save_typ;
1808                             }
1809                         }
1810                     }
1811                 }
1812                 show_glyph(x, y, glyph);
1813             }
1814
1815         /* [TODO: highlight hero's location somehow] */
1816         u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
1817         if (save_swallowed)
1818             u.uswallow = 1;
1819         flush_screen(1);
1820         if (full) {
1821 /*JP
1822             Strcpy(buf, "underlying terrain");
1823 */
1824             Strcpy(buf, "\89º\82É\82 \82é\92n\8c`");
1825         } else {
1826 /*JP
1827             Strcpy(buf, "known terrain");
1828 */
1829             Strcpy(buf, "\92m\82Á\82Ä\82¢\82é\92n\8c`");
1830             if (keep_traps)
1831 #if 0 /*JP*/
1832                 Sprintf(eos(buf), "%s traps",
1833                         (keep_objs || keep_mons) ? "," : " and");
1834 #else
1835                 Strcat(buf, "\82Æã©");
1836 #endif
1837             if (keep_objs)
1838 #if 0 /*JP*/
1839                 Sprintf(eos(buf), "%s%s objects",
1840                         (keep_traps || keep_mons) ? "," : "",
1841                         keep_mons ? "" : " and");
1842 #else
1843                 Strcat(buf, "\82Æ\95¨\91Ì");
1844 #endif
1845             if (keep_mons)
1846 #if 0 /*JP*/
1847                 Sprintf(eos(buf), "%s and monsters",
1848                         (keep_traps || keep_objs) ? "," : "");
1849 #else
1850                 Strcat(buf, "\82Æ\89ö\95¨");
1851 #endif
1852         }
1853 /*JP
1854         pline("Showing %s only...", buf);
1855 */
1856         pline("%s\82¾\82¯\82ð\8c©\82é\81D\81D\81D", buf);
1857         display_nhwindow(WIN_MAP, TRUE); /* give "--More--" prompt */
1858         docrt(); /* redraw the screen, restoring regular map */
1859         if (Underwater)
1860             under_water(2);
1861         if (u.uburied)
1862             under_ground(2);
1863     }
1864     return;
1865 }
1866
1867 /*detect.c*/