OSDN Git Service

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