OSDN Git Service

add translation
[jnethack/source.git] / src / pager.c
1 /* NetHack 3.6  pager.c $NHDT-Date: 1523142395 2018/04/07 23:06:35 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.123 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2018. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 /* This file contains the command routines dowhatis() and dohelp() and */
12 /* a few other help related facilities */
13
14 #include "hack.h"
15 #include "dlb.h"
16
17 STATIC_DCL boolean FDECL(is_swallow_sym, (int));
18 STATIC_DCL int FDECL(append_str, (char *, const char *));
19 STATIC_DCL void FDECL(look_at_object, (char *, int, int, int));
20 STATIC_DCL void FDECL(look_at_monster, (char *, char *,
21                                         struct monst *, int, int));
22 STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *));
23 STATIC_DCL void FDECL(checkfile, (char *, struct permonst *,
24                                   BOOLEAN_P, BOOLEAN_P));
25 STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P));
26 STATIC_DCL void NDECL(whatdoes_help);
27 STATIC_DCL void NDECL(docontact);
28 STATIC_DCL void NDECL(dispfile_help);
29 STATIC_DCL void NDECL(dispfile_shelp);
30 STATIC_DCL void NDECL(dispfile_optionfile);
31 STATIC_DCL void NDECL(dispfile_license);
32 STATIC_DCL void NDECL(dispfile_debughelp);
33 STATIC_DCL void NDECL(hmenu_doextversion);
34 STATIC_DCL void NDECL(hmenu_dohistory);
35 STATIC_DCL void NDECL(hmenu_dowhatis);
36 STATIC_DCL void NDECL(hmenu_dowhatdoes);
37 STATIC_DCL void NDECL(hmenu_doextlist);
38 #ifdef PORT_HELP
39 extern void NDECL(port_help);
40 #endif
41
42 /* Returns "true" for characters that could represent a monster's stomach. */
43 STATIC_OVL boolean
44 is_swallow_sym(c)
45 int c;
46 {
47     int i;
48
49     for (i = S_sw_tl; i <= S_sw_br; i++)
50         if ((int) showsyms[i] == c)
51             return TRUE;
52     return FALSE;
53 }
54
55 /*
56  * Append new_str to the end of buf if new_str doesn't already exist as
57  * a substring of buf.  Return 1 if the string was appended, 0 otherwise.
58  * It is expected that buf is of size BUFSZ.
59  */
60 STATIC_OVL int
61 append_str(buf, new_str)
62 char *buf;
63 const char *new_str;
64 {
65     int space_left; /* space remaining in buf */
66
67     if (strstri(buf, new_str))
68         return 0;
69
70     space_left = BUFSZ - strlen(buf) - 1;
71     if (space_left < 1)
72         return 0;
73 #if 0 /*JP*/
74     (void) strncat(buf, " or ", space_left);
75     (void) strncat(buf, new_str, space_left - 4);
76 #else
77     (void) strncat(buf, "\82Ü\82½\82Í", space_left);
78     (void) strncat(buf, new_str, space_left - 6);
79 #endif
80     return 1;
81 }
82
83 /* shared by monster probing (via query_objlist!) as well as lookat() */
84 char *
85 self_lookat(outbuf)
86 char *outbuf;
87 {
88     char race[QBUFSZ];
89
90     /* include race with role unless polymorphed */
91     race[0] = '\0';
92     if (!Upolyd)
93 /*JP
94         Sprintf(race, "%s ", urace.adj);
95 */
96         Sprintf(race, "%s", urace.adj);
97 #if 0 /*JP*/
98     Sprintf(outbuf, "%s%s%s called %s",
99             /* being blinded may hide invisibility from self */
100             (Invis && (senseself() || !Blind)) ? "invisible " : "", race,
101             mons[u.umonnum].mname, plname);
102 #else
103     Sprintf(outbuf, "%s%s%s\82Æ\82¢\82¤\96¼\82Ì%s",
104             (Invis && (senseself() || !Blind)) ? "\8ep\82Ì\8c©\82¦\82È\82¢" : "", race,
105             plname,
106             mons[u.umonnum].mname);
107 #endif
108     if (u.usteed)
109 /*JP
110         Sprintf(eos(outbuf), ", mounted on %s", y_monnam(u.usteed));
111 */
112         Sprintf(eos(outbuf), "\81C%s\82É\8fæ\82Á\82Ä\82¢\82é", y_monnam(u.usteed));
113     if (u.uundetected || (Upolyd && youmonst.m_ap_type))
114         mhidden_description(&youmonst, FALSE, eos(outbuf));
115     return outbuf;
116 }
117
118 /* describe a hidden monster; used for look_at during extended monster
119    detection and for probing; also when looking at self */
120 void
121 mhidden_description(mon, altmon, outbuf)
122 struct monst *mon;
123 boolean altmon; /* for probing: if mimicking a monster, say so */
124 char *outbuf;
125 {
126     struct obj *otmp;
127     boolean fakeobj, isyou = (mon == &youmonst);
128     int x = isyou ? u.ux : mon->mx, y = isyou ? u.uy : mon->my,
129         glyph = (level.flags.hero_memory && !isyou) ? levl[x][y].glyph
130                                                     : glyph_at(x, y);
131 #if 1 /*JP*/
132     char suffixbuf[QBUFSZ];
133 #endif
134
135     *outbuf = '\0';
136 #if 1 /*JP*/
137     suffixbuf[0] = '\0';
138 #endif
139     if (mon->m_ap_type == M_AP_FURNITURE
140         || mon->m_ap_type == M_AP_OBJECT) {
141 #if 0 /*JP*/
142         Strcpy(outbuf, ", mimicking ");
143 #else /*\8cã\82Å\92Ç\89Á\82·\82é*/
144         Strcpy(suffixbuf, "\82Ì\82Ó\82è\82ð\82µ\82Ä\82¢\82é");
145 #endif
146         if (mon->m_ap_type == M_AP_FURNITURE) {
147             Strcat(outbuf, an(defsyms[mon->mappearance].explanation));
148         } else if (mon->m_ap_type == M_AP_OBJECT
149                    /* remembered glyph, not glyph_at() which is 'mon' */
150                    && glyph_is_object(glyph)) {
151         objfrommap:
152             otmp = (struct obj *) 0;
153             fakeobj = object_from_map(glyph, x, y, &otmp);
154             Strcat(outbuf, (otmp && otmp->otyp != STRANGE_OBJECT)
155                               ? ansimpleoname(otmp)
156                               : an(obj_descr[STRANGE_OBJECT].oc_name));
157             if (fakeobj)
158                 dealloc_obj(otmp);
159         } else {
160             Strcat(outbuf, something);
161         }
162 #if 1 /*JP*/
163         Strcat(outbuf, suffixbuf);
164 #endif
165     } else if (mon->m_ap_type == M_AP_MONSTER) {
166         if (altmon)
167 #if 0 /*JP*/
168             Sprintf(outbuf, ", masquerading as %s",
169                     an(mons[mon->mappearance].mname));
170 #else
171             Sprintf(outbuf, "%s\82É\82È\82è\82·\82Ü\82µ\82Ä\82¢\82é",
172                     mons[mon->mappearance].mname);
173 #endif
174     } else if (isyou ? u.uundetected : mon->mundetected) {
175 #if 0 /*JP*/
176         Strcpy(outbuf, ", hiding");
177 #else
178         Strcpy(suffixbuf, "\82É\89B\82ê\82Ä\82¢\82é");
179 #endif
180         if (hides_under(mon->data)) {
181 #if 0 /*JP*//*\92n\8c`\82Ì\8fê\8d\87\81u\82Ì\89º\82É\81v\82È\82Ç\82Í\95s\8e©\91R\82È\82Ì\82Å\81A\92P\82É\8fÈ\97ª\82µ\82Ä\82¨\82­*/
182             Strcat(outbuf, " under ");
183 #endif
184             /* remembered glyph, not glyph_at() which is 'mon' */
185             if (glyph_is_object(glyph))
186                 goto objfrommap;
187             Strcat(outbuf, something);
188         } else if (is_hider(mon->data)) {
189 #if 0 /*JP*/
190             Sprintf(eos(outbuf), " on the %s",
191                     (is_flyer(mon->data) || mon->data->mlet == S_PIERCER)
192                        ? "ceiling"
193                        : surface(x, y)); /* trapper */
194 #else
195             Sprintf(eos(outbuf), "%s",
196                     (is_flyer(mon->data) || mon->data->mlet == S_PIERCER)
197                        ? "\93V\88ä"
198                        : surface(x, y)); /* trapper */
199 #endif
200         } else {
201             if (mon->data->mlet == S_EEL && is_pool(x, y))
202 #if 0 /*JP*/
203                 Strcat(outbuf, " in murky water");
204 #else
205                 Strcat(outbuf, "\82É\82²\82Á\82½\90\85\82Ì\92\86");
206 #endif
207         }
208 #if 1 /*JP*/
209         Strcat(outbuf, suffixbuf);
210 #endif
211     }
212 }
213
214 /* extracted from lookat(); also used by namefloorobj() */
215 boolean
216 object_from_map(glyph, x, y, obj_p)
217 int glyph, x, y;
218 struct obj **obj_p;
219 {
220     boolean fakeobj = FALSE;
221     struct monst *mtmp;
222     struct obj *otmp;
223     int glyphotyp = glyph_to_obj(glyph);
224
225     *obj_p = (struct obj *) 0;
226     /* TODO: check inside containers in case glyph came from detection */
227     if ((otmp = sobj_at(glyphotyp, x, y)) == 0)
228         for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj)
229             if (otmp->ox == x && otmp->oy == y && otmp->otyp == glyphotyp)
230                 break;
231
232     /* there might be a mimic here posing as an object */
233     mtmp = m_at(x, y);
234     if (mtmp && is_obj_mappear(mtmp, (unsigned) glyphotyp))
235         otmp = 0;
236     else
237         mtmp = 0;
238
239     if (!otmp || otmp->otyp != glyphotyp) {
240         /* this used to exclude STRANGE_OBJECT; now caller deals with it */
241         otmp = mksobj(glyphotyp, FALSE, FALSE);
242         if (!otmp)
243             return FALSE;
244         fakeobj = TRUE;
245         if (otmp->oclass == COIN_CLASS)
246             otmp->quan = 2L; /* to force pluralization */
247         else if (otmp->otyp == SLIME_MOLD)
248             otmp->spe = context.current_fruit; /* give it a type */
249         if (mtmp && has_mcorpsenm(mtmp)) /* mimic as corpse/statue */
250             otmp->corpsenm = MCORPSENM(mtmp);
251     }
252     /* if located at adjacent spot, mark it as having been seen up close
253        (corpse type will be known even if dknown is 0, so we don't need a
254        touch check for cockatrice corpse--we're looking without touching) */
255     if (otmp && distu(x, y) <= 2 && !Blind && !Hallucination
256         /* redundant: we only look for an object which matches current
257            glyph among floor and buried objects; when !Blind, any buried
258            object's glyph will have been replaced by whatever is present
259            on the surface as soon as we moved next to its spot */
260         && (fakeobj || otmp->where == OBJ_FLOOR) /* not buried */
261         /* terrain mode views what's already known, doesn't learn new stuff */
262         && !iflags.terrainmode) /* so don't set dknown when in terrain mode */
263         otmp->dknown = 1; /* if a pile, clearly see the top item only */
264
265     *obj_p = otmp;
266     return fakeobj; /* when True, caller needs to dealloc *obj_p */
267 }
268
269 STATIC_OVL void
270 look_at_object(buf, x, y, glyph)
271 char *buf; /* output buffer */
272 int x, y, glyph;
273 {
274     struct obj *otmp = 0;
275     boolean fakeobj = object_from_map(glyph, x, y, &otmp);
276
277     if (otmp) {
278         Strcpy(buf, (otmp->otyp != STRANGE_OBJECT)
279                      ? distant_name(otmp, doname_vague_quan)
280                      : obj_descr[STRANGE_OBJECT].oc_name);
281         if (fakeobj)
282             dealloc_obj(otmp), otmp = 0;
283     } else
284         Strcpy(buf, something); /* sanity precaution */
285
286     if (otmp && otmp->where == OBJ_BURIED)
287 /*JP
288         Strcat(buf, " (buried)");
289 */
290         Strcat(buf, " (\96\84\82Ü\82Á\82Ä\82¢\82é)");
291     else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
292 /*JP
293         Strcat(buf, " embedded in stone");
294 */
295         Strcat(buf, "\81C\8aâ\82É\96\84\82ß\82±\82Ü\82ê\82Ä\82¢\82é");
296     else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR)
297 /*JP
298         Strcat(buf, " embedded in a wall");
299 */
300         Strcat(buf, "\81C\95Ç\82É\96\84\82ß\82±\82Ü\82ê\82Ä\82¢\82é");
301     else if (closed_door(x, y))
302 /*JP
303         Strcat(buf, " embedded in a door");
304 */
305         Strcat(buf, "\81C\94à\82É\96\84\82ß\82±\82Ü\82ê\82Ä\82¢\82é");
306     else if (is_pool(x, y))
307       /*JP 3.4.3 \82±\82Ì\95\94\95ª\82Í\95¨\91Ì\82É\82µ\82©\8eg\82í\82ê\82È\82¢ */
308 /*JP
309         Strcat(buf, " in water");
310 */
311         Strcat(buf, "\81C\90\85\92\86\82É\82 \82é");
312     else if (is_lava(x, y))
313 #if 0 /*JP*/
314         Strcat(buf, " in molten lava"); /* [can this ever happen?] */
315 #else
316         Strcat(buf, "\81C\97n\8aâ\82Ì\92\86\82É\82 \82é");        /* [can this ever happen?] */
317 #endif
318     return;
319 }
320
321 STATIC_OVL void
322 look_at_monster(buf, monbuf, mtmp, x, y)
323 char *buf, *monbuf; /* buf: output, monbuf: optional output */
324 struct monst *mtmp;
325 int x, y;
326 {
327     char *name, monnambuf[BUFSZ];
328     boolean accurate = !Hallucination;
329
330     name = (mtmp->data == &mons[PM_COYOTE] && accurate)
331               ? coyotename(mtmp, monnambuf)
332               : distant_monnam(mtmp, ARTICLE_NONE, monnambuf);
333 #if 0 /*JP*/
334     Sprintf(buf, "%s%s%s",
335             (mtmp->mx != x || mtmp->my != y)
336                 ? ((mtmp->isshk && accurate) ? "tail of " : "tail of a ")
337                 : "",
338             (mtmp->mtame && accurate)
339                 ? "tame "
340                 : (mtmp->mpeaceful && accurate)
341                     ? "peaceful "
342                     : "",
343             name);
344 #else
345     Sprintf(buf, "%s%s%s",
346             (mtmp->mtame && accurate)
347                 ? "\8eè\82È\82¸\82¯\82ç\82ê\82½"
348                 : (mtmp->mpeaceful && accurate)
349                     ? "\97F\8dD\93I\82È"
350                     : "",
351             name,
352             (mtmp->mx != x || mtmp->my != y)
353                 ? ((mtmp->isshk && accurate) ? "\82Ì\90K\94ö" : "\82Ì\90K\94ö")
354                 : "");
355 #endif
356     if (u.ustuck == mtmp) {
357         if (u.uswallow || iflags.save_uswallow) /* monster detection */
358 #if 0 /*JP*/
359             Strcat(buf, is_animal(mtmp->data)
360                           ? ", swallowing you" : ", engulfing you");
361 #else
362             Strcat(buf, ", \82 \82È\82½\82ð\88ù\82Ý\8d\9e\82ñ\82Å\82¢\82é");
363 #endif
364         else
365             Strcat(buf, (Upolyd && sticks(youmonst.data))
366 /*JP
367                      ? ", being held" : ", holding you");
368 */
369                      ? "\81C\82 \82È\82½\82ª\92Í\82Ü\82¦\82Ä\82¢\82é" : "\81C\82 \82È\82½\82ð\92Í\82Ü\82¦\82Ä\82¢\82é");
370     }
371     if (mtmp->mleashed)
372 /*JP
373         Strcat(buf, ", leashed to you");
374 */
375         Strcat(buf, "\81C\95R\82Å\8c\8b\82Î\82ê\82Ä\82¢\82é");
376
377     if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) {
378         struct trap *t = t_at(mtmp->mx, mtmp->my);
379         int tt = t ? t->ttyp : NO_TRAP;
380
381         /* newsym lets you know of the trap, so mention it here */
382         if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT || tt == WEB)
383 /*JP
384             Sprintf(eos(buf), ", trapped in %s",
385 */
386             Sprintf(eos(buf), ", %s\82É\95ß\82Ü\82Á\82Ä\82¢\82é",
387                     an(defsyms[trap_to_defsym(tt)].explanation));
388     }
389
390     /* we know the hero sees a monster at this location, but if it's shown
391        due to persistant monster detection he might remember something else */
392     if (mtmp->mundetected || mtmp->m_ap_type)
393         mhidden_description(mtmp, FALSE, eos(buf));
394
395     if (monbuf) {
396         unsigned how_seen = howmonseen(mtmp);
397
398         monbuf[0] = '\0';
399         if (how_seen != 0 && how_seen != MONSEEN_NORMAL) {
400             if (how_seen & MONSEEN_NORMAL) {
401 /*JP
402                 Strcat(monbuf, "normal vision");
403 */
404                 Strcat(monbuf, "\92Ê\8fí\82Ì\8e\8b\8ao");
405                 how_seen &= ~MONSEEN_NORMAL;
406                 /* how_seen can't be 0 yet... */
407                 if (how_seen)
408                     Strcat(monbuf, ", ");
409             }
410             if (how_seen & MONSEEN_SEEINVIS) {
411 /*JP
412                 Strcat(monbuf, "see invisible");
413 */
414                 Strcat(monbuf, "\8c©\82¦\82È\82¢\82à\82Ì\82ð\8c©\82é\8e\8b\8ao");
415                 how_seen &= ~MONSEEN_SEEINVIS;
416                 if (how_seen)
417                     Strcat(monbuf, ", ");
418             }
419             if (how_seen & MONSEEN_INFRAVIS) {
420 /*JP
421                 Strcat(monbuf, "infravision");
422 */
423                 Strcat(monbuf, "\90Ô\8aO\90ü\82ª\8c©\82¦\82é\8e\8b\8ao");
424                 how_seen &= ~MONSEEN_INFRAVIS;
425                 if (how_seen)
426                     Strcat(monbuf, ", ");
427             }
428             if (how_seen & MONSEEN_TELEPAT) {
429 /*JP
430                 Strcat(monbuf, "telepathy");
431 */
432                 Strcat(monbuf, "\83e\83\8c\83p\83V\81[");
433                 how_seen &= ~MONSEEN_TELEPAT;
434                 if (how_seen)
435                     Strcat(monbuf, ", ");
436             }
437             if (how_seen & MONSEEN_XRAYVIS) {
438                 /* Eyes of the Overworld */
439 /*JP
440                 Strcat(monbuf, "astral vision");
441 */
442                 Strcat(monbuf, "\90¸\90_\82É\82æ\82é\8e\8b\8ao");
443                 how_seen &= ~MONSEEN_XRAYVIS;
444                 if (how_seen)
445                     Strcat(monbuf, ", ");
446             }
447             if (how_seen & MONSEEN_DETECT) {
448 /*JP
449                 Strcat(monbuf, "monster detection");
450 */
451                 Strcat(monbuf, "\89ö\95¨\82ð\94­\8c©\82·\82é\94\\97Í");
452                 how_seen &= ~MONSEEN_DETECT;
453                 if (how_seen)
454                     Strcat(monbuf, ", ");
455             }
456             if (how_seen & MONSEEN_WARNMON) {
457                 if (Hallucination) {
458 /*JP
459                     Strcat(monbuf, "paranoid delusion");
460 */
461                     Strcat(monbuf, "\95Î\8e·\93I\96Ï\91z");
462                 } else {
463                     unsigned long mW = (context.warntype.obj
464                                         | context.warntype.polyd),
465                                   m2 = mtmp->data->mflags2;
466 #if 0 /*JP*/
467                     const char *whom = ((mW & M2_HUMAN & m2) ? "human"
468                                         : (mW & M2_ELF & m2) ? "elf"
469                                           : (mW & M2_ORC & m2) ? "orc"
470                                             : (mW & M2_DEMON & m2) ? "demon"
471                                               : mtmp->data->mname);
472 #else
473                     const char *whom = ((mW & M2_HUMAN & m2) ? "\90l\8aÔ"
474                                         : (mW & M2_ELF & m2) ? "\83G\83\8b\83t"
475                                           : (mW & M2_ORC & m2) ? "\83I\81[\83N"
476                                             : (mW & M2_DEMON & m2) ? "\88«\96\82"
477                                               : mtmp->data->mname);
478 #endif
479
480 /*JP
481                     Sprintf(eos(monbuf), "warned of %s", makeplural(whom));
482 */
483                     Sprintf(eos(monbuf), "%s\82ð\8cx\8d\90\82µ\82Ä\82¢\82é", whom);
484                 }
485                 how_seen &= ~MONSEEN_WARNMON;
486                 if (how_seen)
487                     Strcat(monbuf, ", ");
488             }
489             /* should have used up all the how_seen bits by now */
490             if (how_seen) {
491                 impossible("lookat: unknown method of seeing monster");
492                 Sprintf(eos(monbuf), "(%u)", how_seen);
493             }
494         } /* seen by something other than normal vision */
495     } /* monbuf is non-null */
496 }
497
498 /*
499  * Return the name of the glyph found at (x,y).
500  * If not hallucinating and the glyph is a monster, also monster data.
501  */
502 STATIC_OVL struct permonst *
503 lookat(x, y, buf, monbuf)
504 int x, y;
505 char *buf, *monbuf;
506 {
507     struct monst *mtmp = (struct monst *) 0;
508     struct permonst *pm = (struct permonst *) 0;
509     int glyph;
510
511     buf[0] = monbuf[0] = '\0';
512     glyph = glyph_at(x, y);
513     if (u.ux == x && u.uy == y && canspotself()
514         && !(iflags.save_uswallow && glyph == mon_to_glyph(u.ustuck))
515         && (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)) {
516         /* fill in buf[] */
517         (void) self_lookat(buf);
518
519         /* file lookup can't distinguish between "gnomish wizard" monster
520            and correspondingly named player character, always picking the
521            former; force it to find the general "wizard" entry instead */
522         if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd)
523             pm = &mons[PM_WIZARD];
524
525         /* When you see yourself normally, no explanation is appended
526            (even if you could also see yourself via other means).
527            Sensing self while blind or swallowed is treated as if it
528            were by normal vision (cf canseeself()). */
529         if ((Invisible || u.uundetected) && !Blind
530             && !(u.uswallow || iflags.save_uswallow)) {
531             unsigned how = 0;
532
533             if (Infravision)
534                 how |= 1;
535             if (Unblind_telepat)
536                 how |= 2;
537             if (Detect_monsters)
538                 how |= 4;
539
540             if (how)
541 #if 0 /*JP*/
542                 Sprintf(eos(buf), " [seen: %s%s%s%s%s]",
543                         (how & 1) ? "infravision" : "",
544                         /* add comma if telep and infrav */
545                         ((how & 3) > 2) ? ", " : "",
546                         (how & 2) ? "telepathy" : "",
547                         /* add comma if detect and (infrav or telep or both) */
548                         ((how & 7) > 4) ? ", " : "",
549                         (how & 4) ? "monster detection" : "");
550 #else
551                 Sprintf(eos(buf), " [\8a´\92m: %s%s%s%s%s]",
552                         (how & 1) ? "\90Ô\8aO\90ü" : "",
553                         /* add comma if telep and infrav */
554                         ((how & 3) > 2) ? ", " : "",
555                         (how & 2) ? "\83e\83\8c\83p\83V\81[" : "",
556                         /* add comma if detect and (infrav or telep or both) */
557                         ((how & 7) > 4) ? ", " : "",
558                         (how & 4) ? "\89ö\95¨\8a´\92m" : "");
559 #endif
560         }
561     } else if (u.uswallow) {
562         /* when swallowed, we're only called for spots adjacent to hero,
563            and blindness doesn't prevent hero from feeling what holds him */
564 /*JP
565         Sprintf(buf, "interior of %s", a_monnam(u.ustuck));
566 */
567         Sprintf(buf, "%s\82Ì\93à\95\94", a_monnam(u.ustuck));
568         pm = u.ustuck->data;
569     } else if (glyph_is_monster(glyph)) {
570         bhitpos.x = x;
571         bhitpos.y = y;
572         if ((mtmp = m_at(x, y)) != 0) {
573             look_at_monster(buf, monbuf, mtmp, x, y);
574             pm = mtmp->data;
575         } else if (Hallucination) {
576             /* 'monster' must actually be a statue */
577             Strcpy(buf, rndmonnam((char *) 0));
578         }
579     } else if (glyph_is_object(glyph)) {
580         look_at_object(buf, x, y, glyph); /* fill in buf[] */
581     } else if (glyph_is_trap(glyph)) {
582         int tnum = what_trap(glyph_to_trap(glyph));
583
584         /* Trap detection displays a bear trap at locations having
585          * a trapped door or trapped container or both.
586          * TODO: we should create actual trap types for doors and
587          * chests so that they can have their own glyphs and tiles.
588          */
589         if (trapped_chest_at(tnum, x, y))
590 #if 0 /*JP*/
591             Strcpy(buf, "trapped chest"); /* might actually be a large box */
592 #else
593             Strcpy(buf, "ã©\82Ì\8ed\8a|\82¯\82ç\82ê\82½\94 "); /* might actually be a large box */
594 #endif
595         else if (trapped_door_at(tnum, x, y))
596 #if 0 /*JP*/
597             Strcpy(buf, "trapped door"); /* not "trap door"... */
598 #else
599             Strcpy(buf, "ã©\82Ì\8ed\8a|\82¯\82ç\82ê\82½\94à"); /* not "trap door"... */
600 #endif
601         else
602             Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
603     } else if (glyph_is_warning(glyph)) {
604         int warnindx = glyph_to_warning(glyph);
605
606         Strcpy(buf, def_warnsyms[warnindx].explanation);
607     } else if (!glyph_is_cmap(glyph)) {
608 /*JP
609         Strcpy(buf, "unexplored area");
610 */
611         Strcpy(buf, "\96¢\92T\8dõ\82Ì\8fê\8f\8a");
612     } else
613         switch (glyph_to_cmap(glyph)) {
614         case S_altar:
615 /*JP
616             Sprintf(buf, "%s %saltar",
617 */
618             Sprintf(buf, "%s%s\8dÕ\92d",
619                     /* like endgame high priests, endgame high altars
620                        are only recognizable when immediately adjacent */
621                     (Is_astralevel(&u.uz) && distu(x, y) > 2)
622 /*JP
623                         ? "aligned"
624 */
625                         ? "\91®\90«\82Ì"
626                         : align_str(
627                               Amask2align(levl[x][y].altarmask & ~AM_SHRINE)),
628                     ((levl[x][y].altarmask & AM_SHRINE)
629                      && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
630 /*JP
631                         ? "high "
632 */
633                         ? "\8d\82\88Ê\82Ì"
634                         : "");
635             break;
636         case S_ndoor:
637             if (is_drawbridge_wall(x, y) >= 0)
638 /*JP
639                 Strcpy(buf, "open drawbridge portcullis");
640 */
641                 Strcpy(buf,"\8aJ\82¢\82Ä\82¢\82é\92µ\82Ë\8b´");
642             else if ((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN)
643 /*JP
644                 Strcpy(buf, "broken door");
645 */
646                 Strcpy(buf,"\89ó\82ê\82½\94à");
647             else
648 /*JP
649                 Strcpy(buf, "doorway");
650 */
651                 Strcpy(buf,"\8fo\93ü\82è\8cû");
652             break;
653         case S_cloud:
654             Strcpy(buf,
655 /*JP
656                    Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud");
657 */
658                    Is_airlevel(&u.uz) ? "\93Ü\82Á\82Ä\82¢\82é\8fê\8f\8a" : "\96¶/\8fö\8bC\82Ì\89_");
659             break;
660         case S_stone:
661             if (!levl[x][y].seenv) {
662 /*JP
663                 Strcpy(buf, "unexplored");
664 */
665                 Strcpy(buf, "\96¢\92T\8dõ");
666                 break;
667             } else if (Underwater && !Is_waterlevel(&u.uz)) {
668                 /* "unknown" == previously mapped but not visible when
669                    submerged; better terminology appreciated... */
670                 Strcpy(buf, (distu(x, y) <= 2) ? "land" : "unknown");
671                 break;
672             } else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) {
673 /*JP
674                 Strcpy(buf, "stone");
675 */
676                 Strcpy(buf, "\8aâ\94Õ");
677                 break;
678             }
679             /*FALLTHRU*/
680         default:
681             Strcpy(buf, defsyms[glyph_to_cmap(glyph)].explanation);
682             break;
683         }
684
685     return (pm && !Hallucination) ? pm : (struct permonst *) 0;
686 }
687
688 /*
689  * Look in the "data" file for more info.  Called if the user typed in the
690  * whole name (user_typed_name == TRUE), or we've found a possible match
691  * with a character/glyph and flags.help is TRUE.
692  *
693  * NOTE: when (user_typed_name == FALSE), inp is considered read-only and
694  *       must not be changed directly, e.g. via lcase(). We want to force
695  *       lcase() for data.base lookup so that we can have a clean key.
696  *       Therefore, we create a copy of inp _just_ for data.base lookup.
697  */
698 STATIC_OVL void
699 checkfile(inp, pm, user_typed_name, without_asking)
700 char *inp;
701 struct permonst *pm;
702 boolean user_typed_name, without_asking;
703 {
704     dlb *fp;
705     char buf[BUFSZ], newstr[BUFSZ], givenname[BUFSZ];
706     char *ep, *dbase_str;
707     unsigned long txt_offset = 0L;
708     winid datawin = WIN_ERR;
709
710     fp = dlb_fopen(DATAFILE, "r");
711     if (!fp) {
712 #if 0 /*JP*/
713         pline("Cannot open data file!");
714 #else
715         pline("\83f\81[\83^\83t\83@\83C\83\8b\82ð\8aJ\82¯\82È\82¢\81I");
716 #endif
717         return;
718     }
719     /* If someone passed us garbage, prevent fault. */
720     if (!inp || strlen(inp) > (BUFSZ - 1)) {
721         impossible("bad do_look buffer passed (%s)!",
722                    !inp ? "null" : "too long");
723         return;
724     }
725
726     /* To prevent the need for entries in data.base like *ngel to account
727      * for Angel and angel, make the lookup string the same for both
728      * user_typed_name and picked name.
729      */
730     if (pm != (struct permonst *) 0 && !user_typed_name)
731         dbase_str = strcpy(newstr, pm->mname);
732     else
733         dbase_str = strcpy(newstr, inp);
734     (void) lcase(dbase_str);
735
736     /*JP:TODO:\83f\81[\83^\83x\81[\83X\8c\9f\8dõ\82Í\93®\82¢\82Ä\82¢\82È\82¢\82Ì\82Å\97v\8fC\90³*/
737     /*
738      * TODO:
739      * The switch from xname() to doname_vague_quan() in look_at_obj()
740      * had the unintendded side-effect of making names picked from
741      * pointing at map objects become harder to simplify for lookup.
742      * We should split the prefix and suffix handling used by wish
743      * parsing and also wizmode monster generation out into separate
744      * routines and use those routines here.  This currently lacks
745      * erosion handling and probably lots of other bits and pieces
746      * that wishing already understands and most of this duplicates
747      * stuff already done for wish handling or monster generation.
748      */
749     if (!strncmp(dbase_str, "interior of ", 12))
750         dbase_str += 12;
751     if (!strncmp(dbase_str, "a ", 2))
752         dbase_str += 2;
753     else if (!strncmp(dbase_str, "an ", 3))
754         dbase_str += 3;
755     else if (!strncmp(dbase_str, "the ", 4))
756         dbase_str += 4;
757     else if (!strncmp(dbase_str, "some ", 5))
758         dbase_str += 5;
759     else if (digit(*dbase_str)) {
760         /* remove count prefix ("2 ya") which can come from looking at map */
761         while (digit(*dbase_str))
762             ++dbase_str;
763         if (*dbase_str == ' ')
764             ++dbase_str;
765     }
766     if (!strncmp(dbase_str, "tame ", 5))
767         dbase_str += 5;
768     else if (!strncmp(dbase_str, "peaceful ", 9))
769         dbase_str += 9;
770     if (!strncmp(dbase_str, "invisible ", 10))
771         dbase_str += 10;
772     if (!strncmp(dbase_str, "saddled ", 8))
773         dbase_str += 8;
774     if (!strncmp(dbase_str, "blessed ", 8))
775         dbase_str += 8;
776     else if (!strncmp(dbase_str, "uncursed ", 9))
777         dbase_str += 9;
778     else if (!strncmp(dbase_str, "cursed ", 7))
779         dbase_str += 7;
780     if (!strncmp(dbase_str, "empty ", 6))
781         dbase_str += 6;
782     if (!strncmp(dbase_str, "partly used ", 12))
783         dbase_str += 12;
784     else if (!strncmp(dbase_str, "partly eaten ", 13))
785         dbase_str += 13;
786     if (!strncmp(dbase_str, "statue of ", 10))
787         dbase_str[6] = '\0';
788     else if (!strncmp(dbase_str, "figurine of ", 12))
789         dbase_str[8] = '\0';
790     /* remove enchantment ("+0 aklys"); [for 3.6.0 and earlier, this wasn't
791        needed because looking at items on the map used xname() rather than
792        doname() hence known enchantment was implicitly suppressed] */
793     if (*dbase_str && index("+-", dbase_str[0]) && digit(dbase_str[1])) {
794         ++dbase_str; /* skip sign */
795         while (digit(*dbase_str))
796             ++dbase_str;
797         if (*dbase_str == ' ')
798             ++dbase_str;
799     }
800     /* "towel", "wet towel", and "moist towel" share one data.base entry;
801        for "wet towel", we keep prefix so that the prompt will ask about
802        "wet towel"; for "moist towel", we also want to ask about "wet towel".
803        (note: strncpy() only terminates output string if the specified
804        count is bigger than the length of the substring being copied) */
805     if (!strncmp(dbase_str, "moist towel", 11))
806         (void) strncpy(dbase_str += 2, "wet", 3); /* skip "mo" replace "ist" */
807
808     /* Make sure the name is non-empty. */
809     if (*dbase_str) {
810         long pass1offset = -1L;
811         int chk_skip, pass = 1;
812         boolean yes_to_moreinfo, found_in_file, pass1found_in_file,
813                 skipping_entry;
814         char *ap, *alt = 0; /* alternate description */
815
816         /* adjust the input to remove "named " and "called " */
817         if ((ep = strstri(dbase_str, " named ")) != 0) {
818             alt = ep + 7;
819             if ((ap = strstri(dbase_str, " called ")) != 0 && ap < ep)
820                 ep = ap; /* "named" is alt but truncate at "called" */
821         } else if ((ep = strstri(dbase_str, " called ")) != 0) {
822             copynchars(givenname, ep + 8, BUFSZ - 1);
823             alt = givenname;
824         } else
825             ep = strstri(dbase_str, ", ");
826         if (ep && ep > dbase_str)
827             *ep = '\0';
828         /* remove charges or "(lit)" or wizmode "(N aum)" */
829         if ((ep = strstri(dbase_str, " (")) != 0 && ep > dbase_str)
830             *ep = '\0';
831         if (alt && (ap = strstri(alt, " (")) != 0 && ap > alt)
832             *ap = '\0';
833
834         /*
835          * If the object is named, then the name is the alternate description;
836          * otherwise, the result of makesingular() applied to the name is.
837          * This isn't strictly optimal, but named objects of interest to the
838          * user will usually be found under their name, rather than under
839          * their object type, so looking for a singular form is pointless.
840          */
841         if (!alt)
842             alt = makesingular(dbase_str);
843
844         pass1found_in_file = FALSE;
845         for (pass = !strcmp(alt, dbase_str) ? 0 : 1; pass >= 0; --pass) {
846             found_in_file = skipping_entry = FALSE;
847             txt_offset = 0L;
848             if (dlb_fseek(fp, txt_offset, SEEK_SET) < 0 ) {
849                 impossible("can't get to start of 'data' file");
850                 goto checkfile_done;
851             }
852             /* skip first record; read second */
853             if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) {
854                 impossible("can't read 'data' file");
855                 goto checkfile_done;
856             } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1
857                        || txt_offset == 0L)
858                 goto bad_data_file;
859
860             /* look for the appropriate entry */
861             while (dlb_fgets(buf, BUFSZ, fp)) {
862                 if (*buf == '.')
863                     break; /* we passed last entry without success */
864
865                 if (digit(*buf)) {
866                     /* a number indicates the end of current entry */
867                     skipping_entry = FALSE;
868                 } else if (!skipping_entry) {
869                     if (!(ep = index(buf, '\n')))
870                         goto bad_data_file;
871                     (void) strip_newline((ep > buf) ? ep - 1 : ep);
872                     /* if we match a key that begins with "~", skip
873                        this entry */
874                     chk_skip = (*buf == '~') ? 1 : 0;
875                     if ((pass == 0 && pmatch(&buf[chk_skip], dbase_str))
876                         || (pass == 1 && alt && pmatch(&buf[chk_skip], alt))) {
877                         if (chk_skip) {
878                             skipping_entry = TRUE;
879                             continue;
880                         } else {
881                             found_in_file = TRUE;
882                             if (pass == 1)
883                                 pass1found_in_file = TRUE;
884                             break;
885                         }
886                     }
887                 }
888             }
889             if (found_in_file) {
890                 long entry_offset, fseekoffset;
891                 int entry_count;
892                 int i;
893
894                 /* skip over other possible matches for the info */
895                 do {
896                     if (!dlb_fgets(buf, BUFSZ, fp))
897                         goto bad_data_file;
898                 } while (!digit(*buf));
899                 if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2)
900                     goto bad_data_file;
901                 fseekoffset = (long) txt_offset + entry_offset;
902                 if (pass == 1)
903                     pass1offset = fseekoffset;
904                 else if (fseekoffset == pass1offset)
905                     goto checkfile_done;
906
907                 yes_to_moreinfo = FALSE;
908                 if (!user_typed_name && !without_asking) {
909                     char *entrytext = pass ? alt : dbase_str;
910                     char question[QBUFSZ];
911
912 #if 0 /*JP*/
913                     Strcpy(question, "More info about \"");
914                     /* +2 => length of "\"?" */
915                     copynchars(eos(question), entrytext,
916                                (int) (sizeof question - 1
917                                       - (strlen(question) + 2)));
918                     Strcat(question, "\"?");
919 #else
920                     Strcpy(question, "\81u");
921                     /* +16 => "\81v\82Ì\8fÚ\8d×\82ð\8c©\82é\81H"\82Ì\92·\82³ */
922                     copynchars(eos(question), entrytext,
923                                (int) (sizeof question - 1
924                                       - (strlen(question) + 16)));
925                     Strcat(question, "\81v\82Ì\8fÚ\8d×\82ð\8c©\82é\81H");
926 #endif
927                     if (yn(question) == 'y')
928                         yes_to_moreinfo = TRUE;
929                 }
930
931                 if (user_typed_name || without_asking || yes_to_moreinfo) {
932                     if (dlb_fseek(fp, fseekoffset, SEEK_SET) < 0) {
933 /*JP
934                 pline("? Seek error on 'data' file!");
935 */
936                 pline("'data'\83t\83@\83C\83\8b\82Ì\83V\81[\83N\83G\83\89\81[\81I");
937                         goto checkfile_done;
938                     }
939                     datawin = create_nhwindow(NHW_MENU);
940                     for (i = 0; i < entry_count; i++) {
941                         if (!dlb_fgets(buf, BUFSZ, fp))
942                             goto bad_data_file;
943                         (void) strip_newline(buf);
944                         if (index(buf + 1, '\t') != 0)
945                             (void) tabexpand(buf + 1);
946                         putstr(datawin, 0, buf + 1);
947                     }
948                     display_nhwindow(datawin, FALSE);
949                     destroy_nhwindow(datawin), datawin = WIN_ERR;
950                 }
951             } else if (user_typed_name && pass == 0 && !pass1found_in_file)
952 /*JP
953         pline("I don't have any information on those things.");
954 */
955         pline("\82»\82ñ\82È\96¼\91O\82Í\95·\82¢\82½\82±\82Æ\82ª\82È\82¢\81D");
956         }
957     }
958     goto checkfile_done; /* skip error feedback */
959
960  bad_data_file:
961     impossible("'data' file in wrong format or corrupted");
962  checkfile_done:
963     if (datawin != WIN_ERR)
964         destroy_nhwindow(datawin);
965     (void) dlb_fclose(fp);
966     return;
967 }
968
969 int
970 do_screen_description(cc, looked, sym, out_str, firstmatch)
971 coord cc;
972 boolean looked;
973 int sym;
974 char *out_str;
975 const char **firstmatch;
976 {
977 /*JP
978     static const char mon_interior[] = "the interior of a monster",
979 */
980     static const char mon_interior[] = "\89ö\95¨\82Ì\93à\95\94",
981 /*JP
982                       unreconnoitered[] = "unreconnoitered";
983 */
984                       unreconnoitered[] = "\96¢\8aÏ\8e@";
985     static char look_buf[BUFSZ];
986     char prefix[BUFSZ];
987     int i, alt_i, glyph = NO_GLYPH,
988         skipped_venom = 0, found = 0; /* count of matching syms found */
989     boolean hit_trap, need_to_look = FALSE,
990             submerged = (Underwater && !Is_waterlevel(&u.uz));
991     const char *x_str;
992
993     if (looked) {
994         int oc;
995         unsigned os;
996
997         glyph = glyph_at(cc.x, cc.y);
998         /* Convert glyph at selected position to a symbol for use below. */
999         (void) mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y);
1000
1001         Sprintf(prefix, "%s        ", encglyph(glyph));
1002     } else
1003         Sprintf(prefix, "%c        ", sym);
1004
1005     /*
1006      * Check all the possibilities, saving all explanations in a buffer.
1007      * When all have been checked then the string is printed.
1008      */
1009
1010     /*
1011      * Handle restricted vision range (limited to adjacent spots when
1012      * swallowed or underwater) cases first.
1013      *
1014      * 3.6.0 listed anywhere on map, other than self, as "interior
1015      * of a monster" when swallowed, and non-adjacent water or
1016      * non-water anywhere as "dark part of a room" when underwater.
1017      * "unreconnoitered" is an attempt to convey "even if you knew
1018      * what was there earlier, you don't know what is there in the
1019      * current circumstance".
1020      *
1021      * (Note: 'self' will always be visible when swallowed so we don't
1022      * need special swallow handling for <ux,uy>.
1023      * Another note: for '#terrain' without monsters, u.uswallow and
1024      * submerged will always both be False and skip this code.)
1025      */
1026     x_str = 0;
1027     if (!looked) {
1028         ; /* skip special handling */
1029     } else if (((u.uswallow || submerged) && distu(cc.x, cc.y) > 2)
1030                /* detection showing some category, so mostly background */
1031                || ((iflags.terrainmode & (TER_DETECT | TER_MAP)) == TER_DETECT
1032                    && glyph == cmap_to_glyph(S_stone))) {
1033         x_str = unreconnoitered;
1034         need_to_look = FALSE;
1035     } else if (is_swallow_sym(sym)) {
1036         x_str = mon_interior;
1037         need_to_look = TRUE; /* for specific monster type */
1038     }
1039     if (x_str) {
1040         /* we know 'found' is zero here, but guard against some other
1041            special case being inserted ahead of us someday */
1042         if (!found) {
1043             Sprintf(out_str, "%s%s", prefix, x_str);
1044             *firstmatch = x_str;
1045             found++;
1046         } else {
1047             found += append_str(out_str, x_str); /* not 'an(x_str)' */
1048         }
1049         /* for is_swallow_sym(), we want to list the current symbol's
1050            other possibilities (wand for '/', throne for '\\', &c) so
1051            don't jump to the end for the x_str==mon_interior case */
1052         if (x_str == unreconnoitered)
1053             goto didlook;
1054     }
1055
1056     /* Check for monsters */
1057     if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
1058         for (i = 0; i < MAXMCLASSES; i++) {
1059             if (sym == (looked ? showsyms[i + SYM_OFF_M] : def_monsyms[i].sym)
1060                 && def_monsyms[i].explain) {
1061                 need_to_look = TRUE;
1062                 if (!found) {
1063                     Sprintf(out_str, "%s%s",
1064                             prefix, an(def_monsyms[i].explain));
1065                     *firstmatch = def_monsyms[i].explain;
1066                     found++;
1067                 } else {
1068                     found += append_str(out_str, an(def_monsyms[i].explain));
1069                 }
1070             }
1071         }
1072         /* handle '@' as a special case if it refers to you and you're
1073            playing a character which isn't normally displayed by that
1074            symbol; firstmatch is assumed to already be set for '@' */
1075         if ((looked ? (sym == showsyms[S_HUMAN + SYM_OFF_M]
1076                        && cc.x == u.ux && cc.y == u.uy)
1077                     : (sym == def_monsyms[S_HUMAN].sym && !flags.showrace))
1078             && !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
1079 #if 0 /*JP:T*/
1080             found += append_str(out_str, "you"); /* tack on "or you" */
1081 #else
1082             found += append_str(out_str, "\82 \82È\82½"); /* tack on "or you" */
1083 #endif
1084     }
1085
1086     /* Now check for objects */
1087     if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
1088         for (i = 1; i < MAXOCLASSES; i++) {
1089             if (sym == (looked ? showsyms[i + SYM_OFF_O]
1090                                : def_oc_syms[i].sym)
1091                 || (looked && i == ROCK_CLASS && glyph_is_statue(glyph))) {
1092                 need_to_look = TRUE;
1093                 if (looked && i == VENOM_CLASS) {
1094                     skipped_venom++;
1095                     continue;
1096                 }
1097                 if (!found) {
1098                     Sprintf(out_str, "%s%s",
1099                             prefix, an(def_oc_syms[i].explain));
1100                     *firstmatch = def_oc_syms[i].explain;
1101                     found++;
1102                 } else {
1103                     found += append_str(out_str, an(def_oc_syms[i].explain));
1104                 }
1105             }
1106         }
1107     }
1108
1109     if (sym == DEF_INVISIBLE) {
1110         if (!found) {
1111             Sprintf(out_str, "%s%s", prefix, an(invisexplain));
1112             *firstmatch = invisexplain;
1113             found++;
1114         } else {
1115             found += append_str(out_str, an(invisexplain));
1116         }
1117     }
1118
1119     /* Now check for graphics symbols */
1120     alt_i = (sym == (looked ? showsyms[0] : defsyms[0].sym)) ? 0 : (2 + 1);
1121     for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
1122         /* when sym is the default background character, we process
1123            i == 0 three times: unexplored, stone, dark part of a room */
1124         if (alt_i < 2) {
1125 /*JP
1126             x_str = !alt_i++ ? "unexplored" : submerged ? "unknown" : "stone";
1127 */
1128             x_str = !alt_i++ ? "\96¢\92T\8dõ" : submerged ? "\96¢\92m" : "\8aâ\94Õ";
1129             i = 0; /* for second iteration, undo loop increment */
1130             /* alt_i is now 1 or 2 */
1131         } else {
1132             if (alt_i++ == 2)
1133                 i = 0; /* undo loop increment */
1134             x_str = defsyms[i].explanation;
1135             if (submerged && !strcmp(x_str, defsyms[0].explanation))
1136 #if 0 /*JP*/
1137                 x_str = "land"; /* replace "dark part of a room" */
1138 #else
1139                 x_str = "\92n\96Ê"; /* replace "dark part of a room" */
1140 #endif
1141             /* alt_i is now 3 or more and no longer of interest */
1142         }
1143         if (sym == (looked ? showsyms[i] : defsyms[i].sym) && *x_str) {
1144 #if 0 /*JP*//*\93ú\96{\8cê\82É\82Í\8aÖ\8cW\82È\82¢*/
1145             /* avoid "an unexplored", "an stone", "an air", "a water",
1146                "a floor of a room", "a dark part of a room";
1147                article==2 => "the", 1 => "an", 0 => (none) */
1148             int article = strstri(x_str, " of a room") ? 2
1149                           : !(alt_i <= 2
1150                               || strcmp(x_str, "air") == 0
1151                               || strcmp(x_str, "land") == 0
1152                               || strcmp(x_str, "water") == 0);
1153
1154 #endif
1155             if (!found) {
1156                 if (is_cmap_trap(i)) {
1157 /*JP
1158                     Sprintf(out_str, "%sa trap", prefix);
1159 */
1160                     Sprintf(out_str, "%sã©", prefix);
1161                     hit_trap = TRUE;
1162                 } else {
1163 #if 0 /*JP*/
1164                     Sprintf(out_str, "%s%s", prefix,
1165                             article == 2 ? the(x_str)
1166                             : article == 1 ? an(x_str) : x_str);
1167 #else
1168                     Sprintf(out_str, "%s%s", prefix, x_str);
1169 #endif
1170                 }
1171                 *firstmatch = x_str;
1172                 found++;
1173             } else if (!(hit_trap && is_cmap_trap(i))
1174                        && !(found >= 3 && is_cmap_drawbridge(i))
1175                        /* don't mention vibrating square outside of Gehennom
1176                           unless this happens to be one (hallucination?) */
1177                        && (i != S_vibrating_square || Inhell
1178                            || (looked && glyph_is_trap(glyph)
1179                                && glyph_to_trap(glyph) == VIBRATING_SQUARE))) {
1180 #if 0 /*JP*/
1181                 found += append_str(out_str, (article == 2) ? the(x_str)
1182                                              : (article == 1) ? an(x_str)
1183                                                : x_str);
1184 #else
1185                 found += append_str(out_str, x_str);
1186 #endif
1187                 if (is_cmap_trap(i))
1188                     hit_trap = TRUE;
1189             }
1190
1191             if (i == S_altar || is_cmap_trap(i))
1192                 need_to_look = TRUE;
1193         }
1194     }
1195
1196     /* Now check for warning symbols */
1197     for (i = 1; i < WARNCOUNT; i++) {
1198         x_str = def_warnsyms[i].explanation;
1199         if (sym == (looked ? warnsyms[i] : def_warnsyms[i].sym)) {
1200             if (!found) {
1201                 Sprintf(out_str, "%s%s", prefix, def_warnsyms[i].explanation);
1202                 *firstmatch = def_warnsyms[i].explanation;
1203                 found++;
1204             } else {
1205                 found += append_str(out_str, def_warnsyms[i].explanation);
1206             }
1207             /* Kludge: warning trumps boulders on the display.
1208                Reveal the boulder too or player can get confused */
1209             if (looked && sobj_at(BOULDER, cc.x, cc.y))
1210 /*JP
1211                 Strcat(out_str, " co-located with a boulder");
1212 */
1213                 Strcat(out_str, "(\8b\90\8aâ\82Æ\93¯\82\88Ê\92u\82É\82 \82é)");
1214             break; /* out of for loop*/
1215         }
1216     }
1217
1218     /* if we ignored venom and list turned out to be short, put it back */
1219     if (skipped_venom && found < 2) {
1220         x_str = def_oc_syms[VENOM_CLASS].explain;
1221         if (!found) {
1222             Sprintf(out_str, "%s%s", prefix, an(x_str));
1223             *firstmatch = x_str;
1224             found++;
1225         } else {
1226             found += append_str(out_str, an(x_str));
1227         }
1228     }
1229
1230     /* handle optional boulder symbol as a special case */
1231     if (iflags.bouldersym && sym == iflags.bouldersym) {
1232         if (!found) {
1233 /*JP
1234             *firstmatch = "boulder";
1235 */
1236             *firstmatch = "\8aâ";
1237             Sprintf(out_str, "%s%s", prefix, an(*firstmatch));
1238             found++;
1239         } else {
1240 /*JP
1241             found += append_str(out_str, "boulder");
1242 */
1243             found += append_str(out_str, "\8aâ");
1244         }
1245     }
1246
1247     /*
1248      * If we are looking at the screen, follow multiple possibilities or
1249      * an ambiguous explanation by something more detailed.
1250      */
1251
1252     if (found > 4)
1253 /*JP
1254         Sprintf(out_str, "%s", "That can be many things");
1255 */
1256         Sprintf(out_str, "%s", "\82±\82±\82É\82Í\91½\82­\82Ì\82à\82Ì\82ª\82 \82é");
1257
1258  didlook:
1259     if (looked) {
1260         if (found > 1 || need_to_look) {
1261             char monbuf[BUFSZ];
1262             char temp_buf[BUFSZ];
1263
1264             (void) lookat(cc.x, cc.y, look_buf, monbuf);
1265             *firstmatch = look_buf;
1266             if (*(*firstmatch)) {
1267                 Sprintf(temp_buf, " (%s)", *firstmatch);
1268                 (void) strncat(out_str, temp_buf,
1269                                BUFSZ - strlen(out_str) - 1);
1270                 found = 1; /* we have something to look up */
1271             }
1272             if (monbuf[0]) {
1273 /*JP
1274                 Sprintf(temp_buf, " [seen: %s]", monbuf);
1275 */
1276                 Sprintf(temp_buf, " [\8e\8b\8ao: %s]", monbuf);
1277                 (void) strncat(out_str, temp_buf,
1278                                BUFSZ - strlen(out_str) - 1);
1279             }
1280         }
1281     }
1282
1283     return found;
1284 }
1285
1286 /* also used by getpos hack in do_name.c */
1287 /*JP
1288 const char what_is_an_unknown_object[] = "an unknown object";
1289 */
1290 const char what_is_an_unknown_object[] = "\93ä\82Ì\95¨\91Ì";
1291
1292 int
1293 do_look(mode, click_cc)
1294 int mode;
1295 coord *click_cc;
1296 {
1297     boolean quick = (mode == 1); /* use cursor; don't search for "more info" */
1298     boolean clicklook = (mode == 2); /* right mouse-click method */
1299     char out_str[BUFSZ] = DUMMY;
1300     const char *firstmatch = 0;
1301     struct permonst *pm = 0;
1302     int i = '\0', ans = 0;
1303     int sym;              /* typed symbol or converted glyph */
1304     int found;            /* count of matching syms found */
1305     coord cc;             /* screen pos of unknown glyph */
1306     boolean save_verbose; /* saved value of flags.verbose */
1307     boolean from_screen;  /* question from the screen */
1308
1309     if (!clicklook) {
1310         if (quick) {
1311             from_screen = TRUE; /* yes, we want to use the cursor */
1312             i = 'y';
1313         } else {
1314             menu_item *pick_list = (menu_item *) 0;
1315             winid win;
1316             anything any;
1317
1318             any = zeroany;
1319             win = create_nhwindow(NHW_MENU);
1320             start_menu(win);
1321             any.a_char = '/';
1322             /* 'y' and 'n' to keep backwards compatibility with previous
1323                versions: "Specify unknown object by cursor?" */
1324             add_menu(win, NO_GLYPH, &any,
1325                      flags.lootabc ? 0 : any.a_char, 'y', ATR_NONE,
1326 /*JP
1327                      "something on the map", MENU_UNSELECTED);
1328 */
1329                      "\92n\90}\8fã\82É\82 \82é\82à\82Ì", MENU_UNSELECTED);
1330             any.a_char = 'i';
1331             add_menu(win, NO_GLYPH, &any,
1332                      flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1333 /*JP
1334                      "something you're carrying", MENU_UNSELECTED);
1335 */
1336                      "\82 \82È\82½\82ª\8e\9d\82Á\82Ä\82¢\82é\82à\82Ì", MENU_UNSELECTED);
1337             any.a_char = '?';
1338             add_menu(win, NO_GLYPH, &any,
1339                      flags.lootabc ? 0 : any.a_char, 'n', ATR_NONE,
1340 /*JP
1341                      "something else (by symbol or name)", MENU_UNSELECTED);
1342 */
1343                      "\82»\82ê\88È\8aO(\83V\83\93\83{\83\8b\82©\96¼\91O\82Å\8ew\92è)", MENU_UNSELECTED);
1344             if (!u.uswallow && !Hallucination) {
1345                 any = zeroany;
1346                 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
1347                          "", MENU_UNSELECTED);
1348                 /* these options work sensibly for the swallowed case,
1349                    but there's no reason for the player to use them then;
1350                    objects work fine when hallucinating, but screen
1351                    symbol/monster class letter doesn't match up with
1352                    bogus monster type, so suppress when hallucinating */
1353                 any.a_char = 'm';
1354                 add_menu(win, NO_GLYPH, &any,
1355                          flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1356 /*JP
1357                          "nearby monsters", MENU_UNSELECTED);
1358 */
1359                          "\8bß\82­\82É\82¢\82é\89ö\95¨", MENU_UNSELECTED);
1360                 any.a_char = 'M';
1361                 add_menu(win, NO_GLYPH, &any,
1362                          flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1363 /*JP
1364                          "all monsters shown on map", MENU_UNSELECTED);
1365 */
1366                          "\92n\90}\8fã\82É\82¢\82é\91S\82Ä\82Ì\89ö\95¨", MENU_UNSELECTED);
1367                 any.a_char = 'o';
1368                 add_menu(win, NO_GLYPH, &any,
1369                          flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1370 /*JP
1371                          "nearby objects", MENU_UNSELECTED);
1372 */
1373                          "\8bß\82­\82É\82 \82é\82à\82Ì", MENU_UNSELECTED);
1374                 any.a_char = 'O';
1375                 add_menu(win, NO_GLYPH, &any,
1376                          flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1377 /*JP
1378                          "all objects shown on map", MENU_UNSELECTED);
1379 */
1380                          "\92n\90}\8fã\82É\82 \82é\91S\82Ä\82Ì\82à\82Ì", MENU_UNSELECTED);
1381             }
1382 /*JP
1383             end_menu(win, "What do you want to look at:");
1384 */
1385             end_menu(win, "\89½\82ð\8c©\82é\81H");
1386             if (select_menu(win, PICK_ONE, &pick_list) > 0) {
1387                 i = pick_list->item.a_char;
1388                 free((genericptr_t) pick_list);
1389             }
1390             destroy_nhwindow(win);
1391         }
1392
1393         switch (i) {
1394         default:
1395         case 'q':
1396             return 0;
1397         case 'y':
1398         case '/':
1399             from_screen = TRUE;
1400             sym = 0;
1401             cc.x = u.ux;
1402             cc.y = u.uy;
1403             break;
1404         case 'i':
1405           {
1406             char invlet;
1407             struct obj *invobj;
1408
1409             invlet = display_inventory((const char *) 0, TRUE);
1410             if (!invlet || invlet == '\033')
1411                 return 0;
1412             *out_str = '\0';
1413             for (invobj = invent; invobj; invobj = invobj->nobj)
1414                 if (invobj->invlet == invlet) {
1415                     strcpy(out_str, singular(invobj, xname));
1416                     break;
1417                 }
1418             if (*out_str)
1419                 checkfile(out_str, pm, TRUE, TRUE);
1420             return 0;
1421           }
1422         case '?':
1423             from_screen = FALSE;
1424 /*JP
1425             getlin("Specify what? (type the word)", out_str);
1426 */
1427             getlin("\89½\82ð\92²\82×\82é\81H(\95\8e\9a\82ð\93ü\82ê\82Ä\82Ë)", out_str);
1428             if (strcmp(out_str, " ")) /* keep single space as-is */
1429                 /* remove leading and trailing whitespace and
1430                    condense consecutive internal whitespace */
1431                 mungspaces(out_str);
1432             if (out_str[0] == '\0' || out_str[0] == '\033')
1433                 return 0;
1434
1435             if (out_str[1]) { /* user typed in a complete string */
1436                 checkfile(out_str, pm, TRUE, TRUE);
1437                 return 0;
1438             }
1439             sym = out_str[0];
1440             break;
1441         case 'm':
1442             look_all(TRUE, TRUE); /* list nearby monsters */
1443             return 0;
1444         case 'M':
1445             look_all(FALSE, TRUE); /* list all monsters */
1446             return 0;
1447         case 'o':
1448             look_all(TRUE, FALSE); /* list nearby objects */
1449             return 0;
1450         case 'O':
1451             look_all(FALSE, FALSE); /* list all objects */
1452             return 0;
1453         }
1454     } else { /* clicklook */
1455         cc.x = click_cc->x;
1456         cc.y = click_cc->y;
1457         sym = 0;
1458         from_screen = FALSE;
1459     }
1460
1461     /* Save the verbose flag, we change it later. */
1462     save_verbose = flags.verbose;
1463     flags.verbose = flags.verbose && !quick;
1464     /*
1465      * The user typed one letter, or we're identifying from the screen.
1466      */
1467     do {
1468         /* Reset some variables. */
1469         pm = (struct permonst *) 0;
1470         found = 0;
1471         out_str[0] = '\0';
1472
1473         if (from_screen || clicklook) {
1474             if (from_screen) {
1475                 if (flags.verbose)
1476 #if 0 /*JP*/
1477                     pline("Please move the cursor to %s.",
1478                           what_is_an_unknown_object);
1479 #else
1480                     pline("\83J\81[\83\\83\8b\82ð\95¨\91Ì\82É\88Ú\93®\82µ\82Ä\82­\82¾\82³\82¢\81D");
1481 #endif
1482                 else
1483 /*JP
1484                     pline("Pick an object.");
1485 */
1486                     pline("\95¨\91Ì\82ð\8ew\92è\82µ\82Ä\82­\82¾\82³\82¢\81D");
1487
1488                 ans = getpos(&cc, quick, what_is_an_unknown_object);
1489                 if (ans < 0 || cc.x < 0)
1490                     break; /* done */
1491                 flags.verbose = FALSE; /* only print long question once */
1492             }
1493         }
1494
1495         found = do_screen_description(cc, (from_screen || clicklook), sym,
1496                                       out_str, &firstmatch);
1497
1498         /* Finally, print out our explanation. */
1499         if (found) {
1500             /* use putmixed() because there may be an encoded glyph present */
1501             putmixed(WIN_MESSAGE, 0, out_str);
1502
1503             /* check the data file for information about this thing */
1504             if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE
1505                 && (ans == LOOK_VERBOSE || (flags.help && !quick))
1506                 && !clicklook) {
1507                 char temp_buf[BUFSZ];
1508
1509                 Strcpy(temp_buf, firstmatch);
1510                 checkfile(temp_buf, pm, FALSE,
1511                           (boolean) (ans == LOOK_VERBOSE));
1512             }
1513         } else {
1514 /*JP
1515             pline("I've never heard of such things.");
1516 */
1517             pline("\82»\82ñ\82È\96¼\91O\82Í\95·\82¢\82½\82±\82Æ\82ª\82È\82¢\81D");
1518         }
1519
1520     } while (from_screen && !quick && ans != LOOK_ONCE && !clicklook);
1521
1522     flags.verbose = save_verbose;
1523     return 0;
1524 }
1525
1526 STATIC_OVL void
1527 look_all(nearby, do_mons)
1528 boolean nearby; /* True => within BOLTLIM, False => entire map */
1529 boolean do_mons; /* True => monsters, False => objects */
1530 {
1531     winid win;
1532     int x, y, lo_x, lo_y, hi_x, hi_y, glyph, count = 0;
1533     char lookbuf[BUFSZ], outbuf[BUFSZ];
1534
1535     win = create_nhwindow(NHW_TEXT);
1536     lo_y = nearby ? max(u.uy - BOLT_LIM, 0) : 0;
1537     lo_x = nearby ? max(u.ux - BOLT_LIM, 1) : 1;
1538     hi_y = nearby ? min(u.uy + BOLT_LIM, ROWNO - 1) : ROWNO - 1;
1539     hi_x = nearby ? min(u.ux + BOLT_LIM, COLNO - 1) : COLNO - 1;
1540     for (y = lo_y; y <= hi_y; y++) {
1541         for (x = lo_x; x <= hi_x; x++) {
1542             lookbuf[0] = '\0';
1543             glyph = glyph_at(x, y);
1544             if (do_mons) {
1545                 if (glyph_is_monster(glyph)) {
1546                     struct monst *mtmp;
1547
1548                     bhitpos.x = x; /* [is this actually necessary?] */
1549                     bhitpos.y = y;
1550                     if (x == u.ux && y == u.uy && canspotself()) {
1551                         (void) self_lookat(lookbuf);
1552                         ++count;
1553                     } else if ((mtmp = m_at(x, y)) != 0) {
1554                         look_at_monster(lookbuf, (char *) 0, mtmp, x, y);
1555                         ++count;
1556                     }
1557                 } else if (glyph_is_invisible(glyph)) {
1558                     /* remembered, unseen, creature */
1559                     Strcpy(lookbuf, invisexplain);
1560                     ++count;
1561                 } else if (glyph_is_warning(glyph)) {
1562                     int warnindx = glyph_to_warning(glyph);
1563
1564                     Strcpy(lookbuf, def_warnsyms[warnindx].explanation);
1565                     ++count;
1566                 }
1567             } else { /* !do_mons */
1568                 if (glyph_is_object(glyph)) {
1569                     look_at_object(lookbuf, x, y, glyph);
1570                     ++count;
1571                 }
1572             }
1573             if (*lookbuf) {
1574                 char coordbuf[20], which[12], cmode;
1575
1576                 cmode = (iflags.getpos_coords != GPCOORDS_NONE)
1577                            ? iflags.getpos_coords : GPCOORDS_MAP;
1578                 if (count == 1) {
1579                     Strcpy(which, do_mons ? "monsters" : "objects");
1580                     if (nearby)
1581                         Sprintf(outbuf, "%s currently shown near %s:",
1582                                 upstart(which),
1583                                 (cmode != GPCOORDS_COMPASS)
1584                                   ? coord_desc(u.ux, u.uy, coordbuf, cmode)
1585                                   : !canspotself() ? "your position" : "you");
1586                     else
1587                         Sprintf(outbuf, "All %s currently shown on the map:",
1588                                 which);
1589                     putstr(win, 0, outbuf);
1590                     putstr(win, 0, "");
1591                 }
1592                 /* prefix: "coords  C  " where 'C' is mon or obj symbol */
1593                 Sprintf(outbuf, (cmode == GPCOORDS_SCREEN) ? "%s  "
1594                                   : (cmode == GPCOORDS_MAP) ? "%8s  "
1595                                       : "%12s  ",
1596                         coord_desc(x, y, coordbuf, cmode));
1597                 Sprintf(eos(outbuf), "%s  ", encglyph(glyph));
1598                 /* guard against potential overflow */
1599                 lookbuf[sizeof lookbuf - 1 - strlen(outbuf)] = '\0';
1600                 Strcat(outbuf, lookbuf);
1601                 putmixed(win, 0, outbuf);
1602             }
1603         }
1604     }
1605     if (count)
1606         display_nhwindow(win, TRUE);
1607     else
1608 #if 0 /*JP*/
1609         pline("No %s are currently shown %s.",
1610               do_mons ? "monsters" : "objects",
1611               nearby ? "nearby" : "on the map");
1612 #else
1613         pline("\8d¡\82Ì\82Æ\82±\82ë%s\82É%s\81D",
1614               nearby ? "\8bß\82­" : "\92n\90}\8fã",
1615               do_mons ? "\89ö\95¨\82Í\82¢\82È\82¢" : "\82à\82Ì\82Í\82È\82¢");
1616 #endif
1617     destroy_nhwindow(win);
1618 }
1619
1620 /* the '/' command */
1621 int
1622 dowhatis()
1623 {
1624     return do_look(0, (coord *) 0);
1625 }
1626
1627 /* the ';' command */
1628 int
1629 doquickwhatis()
1630 {
1631     return do_look(1, (coord *) 0);
1632 }
1633
1634 /* the '^' command */
1635 int
1636 doidtrap()
1637 {
1638     register struct trap *trap;
1639     int x, y, tt, glyph;
1640
1641     if (!getdir("^"))
1642         return 0;
1643     x = u.ux + u.dx;
1644     y = u.uy + u.dy;
1645
1646     /* check fake bear trap from confused gold detection */
1647     glyph = glyph_at(x, y);
1648     if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) {
1649         boolean chesttrap = trapped_chest_at(tt, x, y);
1650
1651         if (chesttrap || trapped_door_at(tt, x, y)) {
1652             pline("That is a trapped %s.", chesttrap ? "chest" : "door");
1653             return 0; /* trap ID'd, but no time elapses */
1654         }
1655     }
1656
1657     for (trap = ftrap; trap; trap = trap->ntrap)
1658         if (trap->tx == x && trap->ty == y) {
1659             if (!trap->tseen)
1660                 break;
1661             tt = trap->ttyp;
1662             if (u.dz) {
1663                 if (u.dz < 0 ? (tt == TRAPDOOR || tt == HOLE)
1664                              : tt == ROCKTRAP)
1665                     break;
1666             }
1667             tt = what_trap(tt);
1668 #if 0 /*JP*/
1669             pline("That is %s%s%s.",
1670                   an(defsyms[trap_to_defsym(tt)].explanation),
1671                   !trap->madeby_u
1672                      ? ""
1673                      : (tt == WEB)
1674                         ? " woven"
1675                         /* trap doors & spiked pits can't be made by
1676                            player, and should be considered at least
1677                            as much "set" as "dug" anyway */
1678                         : (tt == HOLE || tt == PIT)
1679                            ? " dug"
1680                            : " set",
1681                   !trap->madeby_u ? "" : " by you");
1682 #else
1683             pline("\82»\82ê\82Í%s%s\82¾\81D",
1684                   !trap->madeby_u
1685                      ? ""
1686                      : (tt == WEB)
1687                         ? "\82 \82È\82½\82ª\92£\82Á\82½"
1688                         : (tt == HOLE || tt == PIT)
1689                            ? "\82 \82È\82½\82ª\8c@\82Á\82½"
1690                            : "\82 \82È\82½\82ª\8ed\8a|\82¯\82½",
1691                   defsyms[trap_to_defsym(tt)].explanation);
1692 #endif
1693             return 0;
1694         }
1695 /*JP
1696     pline("I can't see a trap there.");
1697 */
1698     pline("\82»\82±\82É\82Íã©\82Í\82Ý\82 \82½\82ç\82È\82¢\81D");
1699     return 0;
1700 }
1701
1702 /*
1703     Implements a rudimentary if/elif/else/endif interpretor and use
1704     conditionals in dat/cmdhelp to describe what command each keystroke
1705     currently invokes, so that there isn't a lot of "(debug mode only)"
1706     and "(if number_pad is off)" cluttering the feedback that the user
1707     sees.  (The conditionals add quite a bit of clutter to the raw data
1708     but users don't see that.  number_pad produces a lot of conditional
1709     commands:  basic letters vs digits, 'g' vs 'G' for '5', phone
1710     keypad vs normal layout of digits, and QWERTZ keyboard swap between
1711     y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.)
1712     
1713     The interpretor understands
1714      '&#' for comment,
1715      '&? option' for 'if' (also '&? !option'
1716                            or '&? option=value[,value2,...]'
1717                            or '&? !option=value[,value2,...]'),
1718      '&: option' for 'elif' (with argument variations same as 'if';
1719                              any number of instances for each 'if'),
1720      '&:' for 'else' (also '&: #comment';
1721                       0 or 1 instance for a given 'if'), and
1722      '&.' for 'endif' (also '&. #comment'; required for each 'if').
1723     
1724     The option handling is a bit of a mess, with no generality for
1725     which options to deal with and only a comma separated list of
1726     integer values for the '=value' part.  number_pad is the only
1727     supported option that has a value; the few others (wizard/debug,
1728     rest_on_space, #if SHELL, #if SUSPEND) are booleans.
1729 */
1730
1731 STATIC_DCL void
1732 whatdoes_help()
1733 {
1734     dlb *fp;
1735     char *p, buf[BUFSZ];
1736     winid tmpwin = create_nhwindow(NHW_TEXT);
1737
1738     fp = dlb_fopen(KEYHELP, "r");
1739     if (!fp) {
1740 /*JP
1741         pline("Cannot open \"%s\" data file!", KEYHELP);
1742 */
1743         pline("\83f\81[\83^\83t\83@\83C\83\8b\"%s\"\82ð\8aJ\82¯\82È\82¢\81I", KEYHELP);
1744         display_nhwindow(WIN_MESSAGE, TRUE);
1745         return;
1746     }
1747     while (dlb_fgets(buf, (int) sizeof buf, fp)) {
1748         if (*buf == '#')
1749             continue;
1750         for (p = buf; *p; p++)
1751             if (*p != ' ' && *p != '\t')
1752                 break;
1753         putstr(tmpwin, 0, p);
1754     }
1755     (void) dlb_fclose(fp);
1756     display_nhwindow(tmpwin, TRUE);
1757     destroy_nhwindow(tmpwin);
1758 }
1759
1760 #if 0
1761 #define WD_STACKLIMIT 5
1762 struct wd_stack_frame {
1763     Bitfield(active, 1);
1764     Bitfield(been_true, 1);
1765     Bitfield(else_seen, 1);
1766 };
1767
1768 STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
1769                                          int *, int));
1770
1771 STATIC_OVL boolean
1772 whatdoes_cond(buf, stack, depth, lnum)
1773 char *buf;
1774 struct wd_stack_frame *stack;
1775 int *depth, lnum;
1776 {
1777     const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
1778     boolean newcond, neg, gotopt;
1779     char *p, *q, act = buf[1];
1780     int np = 0;
1781
1782     newcond = (act == '?' || !stack[*depth].been_true);
1783     buf += 2;
1784     mungspaces(buf);
1785     if (act == '#' || *buf == '#' || !*buf || !newcond) {
1786         gotopt = (*buf && *buf != '#');
1787         *buf = '\0';
1788         neg = FALSE; /* lint suppression */
1789         p = q = (char *) 0;
1790     } else {
1791         gotopt = TRUE;
1792         if ((neg = (*buf == '!')) != 0)
1793             if (*++buf == ' ')
1794                 ++buf;
1795         p = index(buf, '='), q = index(buf, ':');
1796         if (!p || (q && q < p))
1797             p = q;
1798         if (p) { /* we have a value specified */
1799             /* handle a space before or after (or both) '=' (or ':') */
1800             if (p > buf && p[-1] == ' ')
1801                 p[-1] = '\0'; /* end of keyword in buf[] */
1802             *p++ = '\0'; /* terminate keyword, advance to start of value */
1803             if (*p == ' ')
1804                 p++;
1805         }
1806     }
1807     if (*buf && (act == '?' || act == ':')) {
1808         if (!strcmpi(buf, "number_pad")) {
1809             if (!p) {
1810                 newcond = iflags.num_pad;
1811             } else {
1812                 /* convert internal encoding (separate yes/no and 0..3)
1813                    back to user-visible one (-1..4) */
1814                 np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
1815                                     : (-1 * iflags.num_pad_mode); /* -1..0 */
1816                 newcond = FALSE;
1817                 for (; p; p = q) {
1818                     q = index(p, ',');
1819                     if (q)
1820                         *q++ = '\0';
1821                     if (atoi(p) == np) {
1822                         newcond = TRUE;
1823                         break;
1824                     }
1825                 }
1826             }
1827         } else if (!strcmpi(buf, "rest_on_space")) {
1828             newcond = flags.rest_on_space;
1829         } else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
1830             newcond = flags.debug; /* == wizard */
1831         } else if (!strcmpi(buf, "shell")) {
1832 #ifdef SHELL
1833             /* should we also check sysopt.shellers? */
1834             newcond = TRUE;
1835 #else
1836             newcond = FALSE;
1837 #endif
1838         } else if (!strcmpi(buf, "suspend")) {
1839 #ifdef SUSPEND
1840             /* sysopt.shellers is also used for dosuspend()... */
1841             newcond = TRUE;
1842 #else
1843             newcond = FALSE;
1844 #endif
1845         } else {
1846             impossible(
1847                 "cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
1848                        act, lnum, buf);
1849             neg = FALSE;
1850         }
1851         /* this works for number_pad too: &? !number_pad:-1,0
1852            would be true for 1..4 after negation */
1853         if (neg)
1854             newcond = !newcond;
1855     }
1856     switch (act) {
1857     default:
1858     case '#': /* comment */
1859         break;
1860     case '.': /* endif */
1861         if (--*depth < 0) {
1862             impossible(badstackfmt, '.', lnum);
1863             *depth = 0;
1864         }
1865         break;
1866     case ':': /* else or elif */
1867         if (*depth == 0 || stack[*depth].else_seen) {
1868             impossible(badstackfmt, ':', lnum);
1869             *depth = 1; /* so that stack[*depth - 1] is a valid access */
1870         }
1871         if (stack[*depth].active || stack[*depth].been_true
1872             || !stack[*depth - 1].active)
1873             stack[*depth].active = 0;
1874         else if (newcond)
1875             stack[*depth].active = stack[*depth].been_true = 1;
1876         if (!gotopt)
1877             stack[*depth].else_seen = 1;
1878         break;
1879     case '?': /* if */
1880         if (++*depth >= WD_STACKLIMIT) {
1881             impossible(badstackfmt, '?', lnum);
1882             *depth = WD_STACKLIMIT - 1;
1883         }
1884         stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
1885         stack[*depth].been_true = stack[*depth].active;
1886         stack[*depth].else_seen = 0;
1887         break;
1888     }
1889     return stack[*depth].active ? TRUE : FALSE;
1890 }
1891 #endif /* 0 */
1892
1893 char *
1894 dowhatdoes_core(q, cbuf)
1895 char q;
1896 char *cbuf;
1897 {
1898     char buf[BUFSZ];
1899 #if 0
1900     dlb *fp;
1901     struct wd_stack_frame stack[WD_STACKLIMIT];
1902     boolean cond;
1903     int ctrl, meta, depth = 0, lnum = 0;
1904 #endif /* 0 */
1905     const char *ec_desc;
1906
1907     if ((ec_desc = key2extcmddesc(q)) != NULL) {
1908         char keybuf[QBUFSZ];
1909
1910         Sprintf(buf, "%-8s%s.", key2txt(q, keybuf), ec_desc);
1911         Strcpy(cbuf, buf);
1912         return cbuf;
1913     }
1914     return 0;
1915 #if 0
1916     fp = dlb_fopen(CMDHELPFILE, "r");
1917     if (!fp) {
1918         pline("Cannot open \"%s\" data file!", CMDHELPFILE);
1919         return 0;
1920     }
1921
1922     meta = (0x80 & (uchar) q) != 0;
1923     if (meta)
1924         q &= 0x7f;
1925     ctrl = (0x1f & (uchar) q) == (uchar) q;
1926     if (ctrl)
1927         q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
1928     else if (q == 0x7f)
1929         ctrl = 1, q = '?';
1930
1931     (void) memset((genericptr_t) stack, 0, sizeof stack);
1932     cond = stack[0].active = 1;
1933     while (dlb_fgets(buf, sizeof buf, fp)) {
1934         ++lnum;
1935         if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
1936             cond = whatdoes_cond(buf, stack, &depth, lnum);
1937             continue;
1938         }
1939         if (!cond)
1940             continue;
1941         if (meta ? (buf[0] == 'M' && buf[1] == '-'
1942                     && (ctrl ? buf[2] == '^' && highc(buf[3]) == q
1943                              : buf[2] == q))
1944                  : (ctrl ? buf[0] == '^' && highc(buf[1]) == q
1945                          : buf[0] == q)) {
1946             (void) strip_newline(buf);
1947             if (index(buf, '\t'))
1948                 (void) tabexpand(buf);
1949             if (meta && ctrl && buf[4] == ' ') {
1950                 (void) strncpy(buf, "M-^?    ", 8);
1951                 buf[3] = q;
1952             } else if (meta && buf[3] == ' ') {
1953                 (void) strncpy(buf, "M-?     ", 8);
1954                 buf[2] = q;
1955             } else if (ctrl && buf[2] == ' ') {
1956                 (void) strncpy(buf, "^?      ", 8);
1957                 buf[1] = q;
1958             } else if (buf[1] == ' ') {
1959                 (void) strncpy(buf, "?       ", 8);
1960                 buf[0] = q;
1961             }
1962             (void) dlb_fclose(fp);
1963             Strcpy(cbuf, buf);
1964             return cbuf;
1965         }
1966     }
1967     (void) dlb_fclose(fp);
1968     if (depth != 0)
1969         impossible("cmdhelp: mismatched &? &: &. conditionals.");
1970     return (char *) 0;
1971 #endif /* 0 */
1972 }
1973
1974 int
1975 dowhatdoes()
1976 {
1977     static boolean once = FALSE;
1978     char bufr[BUFSZ];
1979     char q, *reslt;
1980
1981     if (!once) {
1982         pline("Ask about '&' or '?' to get more info.%s",
1983 #ifdef ALTMETA
1984               iflags.altmeta ? "  (For ESC, type it twice.)" :
1985 #endif
1986               "");
1987         once = TRUE;
1988     }
1989 #if defined(UNIX) || defined(VMS)
1990     introff(); /* disables ^C but not ^\ */
1991 #endif
1992 /*JP
1993     q = yn_function("What command?", (char *) 0, '\0');
1994 */
1995     q = yn_function("\82Ç\82¤\82¢\82¤\83R\83}\83\93\83h\81H", (char *) 0, '\0');
1996 #ifdef ALTMETA
1997     if (q == '\033' && iflags.altmeta) {
1998         /* in an ideal world, we would know whether another keystroke
1999            was already pending, but this is not an ideal world...
2000            if user typed ESC, we'll essentially hang until another
2001            character is typed */
2002         q = yn_function("]", (char *) 0, '\0');
2003         if (q != '\033')
2004             q = (char) ((uchar) q | 0200);
2005     }
2006 #endif /*ALTMETA*/
2007 #if defined(UNIX) || defined(VMS)
2008     intron(); /* reenables ^C */
2009 #endif
2010     reslt = dowhatdoes_core(q, bufr);
2011     if (reslt) {
2012         if (q == '&' || q == '?')
2013             whatdoes_help();
2014         pline("%s", reslt);
2015     } else {
2016 #if 0 /*JP*/
2017         pline("No such command '%s', char code %d (0%03o or 0x%02x).",
2018               visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2019 #else
2020         pline("\82»\82ñ\82È\83R\83}\83\93\83h'%s'\81C\95\8e\9a\83R\81[\83h%d(0%03o \82Ü\82½\82Í 0x%02x)\82Í\82È\82¢\81D",
2021               visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2022 #endif
2023     }
2024     return 0;
2025 }
2026
2027 STATIC_OVL void
2028 docontact()
2029 {
2030     winid cwin = create_nhwindow(NHW_TEXT);
2031     char buf[BUFSZ];
2032
2033     if (sysopt.support) {
2034         /*XXX overflow possibilities*/
2035         Sprintf(buf, "To contact local support, %s", sysopt.support);
2036         putstr(cwin, 0, buf);
2037         putstr(cwin, 0, "");
2038     } else if (sysopt.fmtd_wizard_list) { /* formatted SYSCF WIZARDS */
2039         Sprintf(buf, "To contact local support, contact %s.",
2040                 sysopt.fmtd_wizard_list);
2041         putstr(cwin, 0, buf);
2042         putstr(cwin, 0, "");
2043     }
2044     putstr(cwin, 0, "To contact the NetHack development team directly,");
2045     /*XXX overflow possibilities*/
2046     Sprintf(buf, "see the 'Contact' form on our website or email <%s>.",
2047             DEVTEAM_EMAIL);
2048     putstr(cwin, 0, buf);
2049     putstr(cwin, 0, "");
2050     putstr(cwin, 0, "For more information on NetHack, or to report a bug,");
2051     Sprintf(buf, "visit our website \"%s\".", DEVTEAM_URL);
2052     putstr(cwin, 0, buf);
2053     display_nhwindow(cwin, FALSE);
2054     destroy_nhwindow(cwin);
2055 }
2056
2057 void
2058 dispfile_help()
2059 {
2060     display_file(HELP, TRUE);
2061 }
2062
2063 void
2064 dispfile_shelp()
2065 {
2066     display_file(SHELP, TRUE);
2067 }
2068
2069 void
2070 dispfile_optionfile()
2071 {
2072     display_file(OPTIONFILE, TRUE);
2073 }
2074
2075 void
2076 dispfile_license()
2077 {
2078     display_file(LICENSE, TRUE);
2079 }
2080
2081 void
2082 dispfile_debughelp()
2083 {
2084     display_file(DEBUGHELP, TRUE);
2085 }
2086
2087 void
2088 hmenu_doextversion()
2089 {
2090     (void) doextversion();
2091 }
2092
2093 void
2094 hmenu_dohistory()
2095 {
2096     (void) dohistory();
2097 }
2098
2099 void
2100 hmenu_dowhatis()
2101 {
2102     (void) dowhatis();
2103 }
2104
2105 void
2106 hmenu_dowhatdoes()
2107 {
2108     (void) dowhatdoes();
2109 }
2110
2111 void
2112 hmenu_doextlist()
2113 {
2114     (void) doextlist();
2115 }
2116
2117 void
2118 domenucontrols()
2119 {
2120     winid cwin = create_nhwindow(NHW_TEXT);
2121     show_menu_controls(cwin, FALSE);
2122     display_nhwindow(cwin, FALSE);
2123     destroy_nhwindow(cwin);
2124 }
2125
2126 /* data for dohelp() */
2127 static struct {
2128     void (*f)();
2129     const char *text;
2130 } help_menu_items[] = {
2131 /*JP
2132     { hmenu_doextversion, "About NetHack (version information)." },
2133 */
2134     { hmenu_doextversion, "NetHack\82É\82Â\82¢\82Ä(\83o\81[\83W\83\87\83\93\8fî\95ñ)" },
2135 /*JP
2136     { dispfile_help, "Long description of the game and commands." },
2137 */
2138     { dispfile_help, "\83Q\81[\83\80\82¨\82æ\82Ñ\83R\83}\83\93\83h\82Ì\89ð\90à(\92·\95¶)" },
2139 /*JP
2140     { dispfile_shelp, "List of game commands." },
2141 */
2142     { dispfile_shelp, "\83R\83}\83\93\83h\88ê\97\97" },
2143 /*JP
2144     { hmenu_dohistory, "Concise history of NetHack." },
2145 */
2146     { hmenu_dohistory, "NetHack\82Ì\8aÈ\92P\82È\97ð\8ej" },
2147 /*JP
2148     { hmenu_dowhatis, "Info on a character in the game display." },
2149 */
2150     { hmenu_dowhatis, "\89æ\96Ê\82É\95\\8e¦\82³\82ê\82é\95\8e\9a\82Ì\90à\96¾" },
2151 /*JP
2152     { hmenu_dowhatdoes, "Info on what a given key does." },
2153 */
2154     { hmenu_dowhatdoes, "\82±\82Ì\83L\81[\82ª\89½\82ð\88Ó\96¡\82·\82é\82©\82Ì\90à\96¾" },
2155 /*JP
2156     { option_help, "List of game options." },
2157 */
2158     { option_help, "\83Q\81[\83\80\82Ì\83I\83v\83V\83\87\83\93\88ê\97\97" },
2159 /*JP
2160     { dispfile_optionfile, "Longer explanation of game options." },
2161 */
2162     { dispfile_optionfile, "\83Q\81[\83\80\82Ì\83I\83v\83V\83\87\83\93\88ê\97\97(\92·\95¶)" },
2163 /*JP
2164     { dokeylist, "Full list of keyboard commands" },
2165 */
2166     { dokeylist, "\83L\81[\83{\81[\83h\83R\83}\83\93\83h\82Ì\8a®\91S\82È\88ê\97\97" },
2167 /*JP
2168     { hmenu_doextlist, "List of extended commands." },
2169 */
2170     { hmenu_doextlist, "\8ag\92£\83R\83}\83\93\83h\88ê\97\97" },
2171 /*JP
2172     { domenucontrols, "List menu control keys" },
2173 */
2174     { domenucontrols, "\83\81\83j\83\85\81[\90§\8cä\83L\81[\88ê\97\97s" },
2175 /*JP
2176     { dispfile_license, "The NetHack license." },
2177 */
2178     { dispfile_license, "NetHack\82Ì\83\89\83C\83Z\83\93\83X" },
2179 /*JP
2180     { docontact, "Support information." },
2181 */
2182     { docontact, "\83T\83|\81[\83g\8fî\95ñ" },
2183 #ifdef PORT_HELP
2184 /*JP
2185     { port_help, "%s-specific help and commands." },
2186 */
2187     { port_help, "%s\82É\93Á\97L\82Ì\83w\83\8b\83v\82Æ\83R\83}\83\93\83h" },
2188 #endif
2189 /*JP
2190     { dispfile_debughelp, "List of wizard-mode commands." },
2191 */
2192     { dispfile_debughelp, "\83E\83B\83U\81[\83h\83\82\81[\83h\82Ì\83R\83}\83\93\83h\88ê\97\97" },
2193     { NULL, (char *) 0 }
2194 };
2195
2196 /* the '?' command */
2197 int
2198 dohelp()
2199 {
2200     winid tmpwin = create_nhwindow(NHW_MENU);
2201     char helpbuf[QBUFSZ];
2202     int i, n;
2203     menu_item *selected;
2204     anything any;
2205     int sel;
2206     char *bufptr;
2207
2208     any = zeroany; /* zero all bits */
2209     start_menu(tmpwin);
2210
2211     for (i = 0; help_menu_items[i].text; i++) {
2212         if (!wizard && help_menu_items[i].f == dispfile_debughelp)
2213             continue;
2214         if (help_menu_items[i].text[0] == '%') {
2215             Sprintf(helpbuf, help_menu_items[i].text, PORT_ID);
2216             bufptr = helpbuf;
2217         } else {
2218             bufptr = (char *)help_menu_items[i].text;
2219         }
2220         any.a_int = i + 1;
2221         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
2222                  bufptr, MENU_UNSELECTED);
2223     }
2224 /*JP
2225     end_menu(tmpwin, "Select one item:");
2226 */
2227     end_menu(tmpwin, "\91I\82ñ\82Å\82­\82¾\82³\82¢\81F");
2228     n = select_menu(tmpwin, PICK_ONE, &selected);
2229     destroy_nhwindow(tmpwin);
2230     if (n > 0) {
2231         sel = selected[0].item.a_int - 1;
2232         free((genericptr_t) selected);
2233         (void)(*help_menu_items[sel].f)();
2234     }
2235     return 0;
2236 }
2237
2238 /* the 'V' command; also a choice for '?' */
2239 int
2240 dohistory()
2241 {
2242     display_file(HISTORY, TRUE);
2243     return 0;
2244 }
2245
2246 /*pager.c*/