OSDN Git Service

4c924fb95675db12d7bc52a034b845371ba6f30f
[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     "%s is a member of a marauding horde of orcs",
1688     "rumored to have brutally attacked and plundered",
1689     "the ordinarily sheltered town that is located ",
1690     "deep within The Gnomish Mines.",
1691     "",
1692     "The members of that vicious horde proudly and ",
1693     "defiantly acclaim their allegiance to their",
1694     "leader %s in their names.",
1695     (char *) 0,
1696 };
1697
1698 static const char *suptext2[] = {
1699     "\"%s\" is the common dungeon name of",
1700     "a nefarious orc who is known to acquire property",
1701     "from thieves and sell it off for profit.",
1702     "",
1703     "The perpetrator was last seen hanging around the",
1704     "stairs leading to the Gnomish Mines.",
1705     (char *) 0,
1706 };
1707
1708 void
1709 do_supplemental_info(name, pm, without_asking)
1710 char *name;
1711 struct permonst *pm;
1712 boolean without_asking;
1713 {
1714     const char **textp;
1715     winid datawin = WIN_ERR;
1716     char *entrytext = name, *bp = (char *) 0, *bp2 = (char *) 0;
1717     char question[QBUFSZ];
1718     boolean yes_to_moreinfo = FALSE;
1719     boolean is_marauder = (name && pm && is_orc(pm));
1720
1721     /*
1722      * Provide some info on some specific things
1723      * meant to support in-game mythology, and not
1724      * available from data.base or other sources.
1725      */
1726     if (is_marauder && (strlen(name) < (BUFSZ - 1))) {
1727         char fullname[BUFSZ];
1728
1729         bp = strstri(name, " of ");
1730         bp2 = strstri(name, " the Fence");
1731
1732         if (bp || bp2) {
1733             Strcpy(fullname, name);
1734             if (!without_asking) {
1735                 Strcpy(question, "More info about \"");
1736                 /* +2 => length of "\"?" */
1737                 copynchars(eos(question), entrytext,
1738                     (int) (sizeof question - 1 - (strlen(question) + 2)));
1739                 Strcat(question, "\"?");
1740                 if (yn(question) == 'y')
1741                 yes_to_moreinfo = TRUE;
1742             }
1743             if (yes_to_moreinfo) {
1744                 int i, subs = 0;
1745                 const char *gang = (char *) 0;
1746
1747                 if (bp) {
1748                     textp = suptext1;
1749                     gang = bp + 4;
1750                     *bp = '\0';
1751                 } else {
1752                     textp = suptext2;
1753                     gang = "";
1754                 }
1755                 datawin = create_nhwindow(NHW_MENU);
1756                 for (i = 0; textp[i]; i++) {
1757                     char buf[BUFSZ];
1758                     const char *txt;
1759
1760                     if (strstri(textp[i], "%s") != 0) {
1761                         Sprintf(buf, textp[i], subs++ ? gang : fullname);
1762                         txt = buf;
1763                     } else
1764                         txt = textp[i];
1765                     putstr(datawin, 0, txt);
1766                 }
1767                 display_nhwindow(datawin, FALSE);
1768                 destroy_nhwindow(datawin), datawin = WIN_ERR;
1769             }
1770         }
1771     }
1772 }
1773
1774 /* the '/' command */
1775 int
1776 dowhatis()
1777 {
1778     return do_look(0, (coord *) 0);
1779 }
1780
1781 /* the ';' command */
1782 int
1783 doquickwhatis()
1784 {
1785     return do_look(1, (coord *) 0);
1786 }
1787
1788 /* the '^' command */
1789 int
1790 doidtrap()
1791 {
1792     register struct trap *trap;
1793     int x, y, tt, glyph;
1794
1795     if (!getdir("^"))
1796         return 0;
1797     x = u.ux + u.dx;
1798     y = u.uy + u.dy;
1799
1800     /* check fake bear trap from confused gold detection */
1801     glyph = glyph_at(x, y);
1802     if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) {
1803         boolean chesttrap = trapped_chest_at(tt, x, y);
1804
1805         if (chesttrap || trapped_door_at(tt, x, y)) {
1806             pline("That is a trapped %s.", chesttrap ? "chest" : "door");
1807             return 0; /* trap ID'd, but no time elapses */
1808         }
1809     }
1810
1811     for (trap = ftrap; trap; trap = trap->ntrap)
1812         if (trap->tx == x && trap->ty == y) {
1813             if (!trap->tseen)
1814                 break;
1815             tt = trap->ttyp;
1816             if (u.dz) {
1817                 if (u.dz < 0 ? is_hole(tt) : tt == ROCKTRAP)
1818                     break;
1819             }
1820             tt = what_trap(tt, rn2_on_display_rng);
1821 #if 0 /*JP*/
1822             pline("That is %s%s%s.",
1823                   an(defsyms[trap_to_defsym(tt)].explanation),
1824                   !trap->madeby_u
1825                      ? ""
1826                      : (tt == WEB)
1827                         ? " woven"
1828                         /* trap doors & spiked pits can't be made by
1829                            player, and should be considered at least
1830                            as much "set" as "dug" anyway */
1831                         : (tt == HOLE || tt == PIT)
1832                            ? " dug"
1833                            : " set",
1834                   !trap->madeby_u ? "" : " by you");
1835 #else
1836             pline("\82»\82ê\82Í%s%s\82¾\81D",
1837                   !trap->madeby_u
1838                      ? ""
1839                      : (tt == WEB)
1840                         ? "\82 \82È\82½\82ª\92£\82Á\82½"
1841                         : (tt == HOLE || tt == PIT)
1842                            ? "\82 \82È\82½\82ª\8c@\82Á\82½"
1843                            : "\82 \82È\82½\82ª\8ed\8a|\82¯\82½",
1844                   defsyms[trap_to_defsym(tt)].explanation);
1845 #endif
1846             return 0;
1847         }
1848 /*JP
1849     pline("I can't see a trap there.");
1850 */
1851     pline("\82»\82±\82É\82Íã©\82Í\82Ý\82 \82½\82ç\82È\82¢\81D");
1852     return 0;
1853 }
1854
1855 /*
1856     Implements a rudimentary if/elif/else/endif interpretor and use
1857     conditionals in dat/cmdhelp to describe what command each keystroke
1858     currently invokes, so that there isn't a lot of "(debug mode only)"
1859     and "(if number_pad is off)" cluttering the feedback that the user
1860     sees.  (The conditionals add quite a bit of clutter to the raw data
1861     but users don't see that.  number_pad produces a lot of conditional
1862     commands:  basic letters vs digits, 'g' vs 'G' for '5', phone
1863     keypad vs normal layout of digits, and QWERTZ keyboard swap between
1864     y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.)
1865
1866     The interpretor understands
1867      '&#' for comment,
1868      '&? option' for 'if' (also '&? !option'
1869                            or '&? option=value[,value2,...]'
1870                            or '&? !option=value[,value2,...]'),
1871      '&: option' for 'elif' (with argument variations same as 'if';
1872                              any number of instances for each 'if'),
1873      '&:' for 'else' (also '&: #comment';
1874                       0 or 1 instance for a given 'if'), and
1875      '&.' for 'endif' (also '&. #comment'; required for each 'if').
1876
1877     The option handling is a bit of a mess, with no generality for
1878     which options to deal with and only a comma separated list of
1879     integer values for the '=value' part.  number_pad is the only
1880     supported option that has a value; the few others (wizard/debug,
1881     rest_on_space, #if SHELL, #if SUSPEND) are booleans.
1882 */
1883
1884 STATIC_DCL void
1885 whatdoes_help()
1886 {
1887     dlb *fp;
1888     char *p, buf[BUFSZ];
1889     winid tmpwin = create_nhwindow(NHW_TEXT);
1890
1891     fp = dlb_fopen(KEYHELP, "r");
1892     if (!fp) {
1893 /*JP
1894         pline("Cannot open \"%s\" data file!", KEYHELP);
1895 */
1896         pline("\83f\81[\83^\83t\83@\83C\83\8b\"%s\"\82ð\8aJ\82¯\82È\82¢\81I", KEYHELP);
1897         display_nhwindow(WIN_MESSAGE, TRUE);
1898         return;
1899     }
1900     while (dlb_fgets(buf, (int) sizeof buf, fp)) {
1901         if (*buf == '#')
1902             continue;
1903         for (p = buf; *p; p++)
1904             if (*p != ' ' && *p != '\t')
1905                 break;
1906         putstr(tmpwin, 0, p);
1907     }
1908     (void) dlb_fclose(fp);
1909     display_nhwindow(tmpwin, TRUE);
1910     destroy_nhwindow(tmpwin);
1911 }
1912
1913 #if 0
1914 #define WD_STACKLIMIT 5
1915 struct wd_stack_frame {
1916     Bitfield(active, 1);
1917     Bitfield(been_true, 1);
1918     Bitfield(else_seen, 1);
1919 };
1920
1921 STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
1922                                          int *, int));
1923
1924 STATIC_OVL boolean
1925 whatdoes_cond(buf, stack, depth, lnum)
1926 char *buf;
1927 struct wd_stack_frame *stack;
1928 int *depth, lnum;
1929 {
1930     const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
1931     boolean newcond, neg, gotopt;
1932     char *p, *q, act = buf[1];
1933     int np = 0;
1934
1935     newcond = (act == '?' || !stack[*depth].been_true);
1936     buf += 2;
1937     mungspaces(buf);
1938     if (act == '#' || *buf == '#' || !*buf || !newcond) {
1939         gotopt = (*buf && *buf != '#');
1940         *buf = '\0';
1941         neg = FALSE; /* lint suppression */
1942         p = q = (char *) 0;
1943     } else {
1944         gotopt = TRUE;
1945         if ((neg = (*buf == '!')) != 0)
1946             if (*++buf == ' ')
1947                 ++buf;
1948         p = index(buf, '='), q = index(buf, ':');
1949         if (!p || (q && q < p))
1950             p = q;
1951         if (p) { /* we have a value specified */
1952             /* handle a space before or after (or both) '=' (or ':') */
1953             if (p > buf && p[-1] == ' ')
1954                 p[-1] = '\0'; /* end of keyword in buf[] */
1955             *p++ = '\0'; /* terminate keyword, advance to start of value */
1956             if (*p == ' ')
1957                 p++;
1958         }
1959     }
1960     if (*buf && (act == '?' || act == ':')) {
1961         if (!strcmpi(buf, "number_pad")) {
1962             if (!p) {
1963                 newcond = iflags.num_pad;
1964             } else {
1965                 /* convert internal encoding (separate yes/no and 0..3)
1966                    back to user-visible one (-1..4) */
1967                 np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
1968                                     : (-1 * iflags.num_pad_mode); /* -1..0 */
1969                 newcond = FALSE;
1970                 for (; p; p = q) {
1971                     q = index(p, ',');
1972                     if (q)
1973                         *q++ = '\0';
1974                     if (atoi(p) == np) {
1975                         newcond = TRUE;
1976                         break;
1977                     }
1978                 }
1979             }
1980         } else if (!strcmpi(buf, "rest_on_space")) {
1981             newcond = flags.rest_on_space;
1982         } else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
1983             newcond = flags.debug; /* == wizard */
1984         } else if (!strcmpi(buf, "shell")) {
1985 #ifdef SHELL
1986             /* should we also check sysopt.shellers? */
1987             newcond = TRUE;
1988 #else
1989             newcond = FALSE;
1990 #endif
1991         } else if (!strcmpi(buf, "suspend")) {
1992 #ifdef SUSPEND
1993             /* sysopt.shellers is also used for dosuspend()... */
1994             newcond = TRUE;
1995 #else
1996             newcond = FALSE;
1997 #endif
1998         } else {
1999             impossible(
2000                 "cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
2001                        act, lnum, buf);
2002             neg = FALSE;
2003         }
2004         /* this works for number_pad too: &? !number_pad:-1,0
2005            would be true for 1..4 after negation */
2006         if (neg)
2007             newcond = !newcond;
2008     }
2009     switch (act) {
2010     default:
2011     case '#': /* comment */
2012         break;
2013     case '.': /* endif */
2014         if (--*depth < 0) {
2015             impossible(badstackfmt, '.', lnum);
2016             *depth = 0;
2017         }
2018         break;
2019     case ':': /* else or elif */
2020         if (*depth == 0 || stack[*depth].else_seen) {
2021             impossible(badstackfmt, ':', lnum);
2022             *depth = 1; /* so that stack[*depth - 1] is a valid access */
2023         }
2024         if (stack[*depth].active || stack[*depth].been_true
2025             || !stack[*depth - 1].active)
2026             stack[*depth].active = 0;
2027         else if (newcond)
2028             stack[*depth].active = stack[*depth].been_true = 1;
2029         if (!gotopt)
2030             stack[*depth].else_seen = 1;
2031         break;
2032     case '?': /* if */
2033         if (++*depth >= WD_STACKLIMIT) {
2034             impossible(badstackfmt, '?', lnum);
2035             *depth = WD_STACKLIMIT - 1;
2036         }
2037         stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
2038         stack[*depth].been_true = stack[*depth].active;
2039         stack[*depth].else_seen = 0;
2040         break;
2041     }
2042     return stack[*depth].active ? TRUE : FALSE;
2043 }
2044 #endif /* 0 */
2045
2046 char *
2047 dowhatdoes_core(q, cbuf)
2048 char q;
2049 char *cbuf;
2050 {
2051     char buf[BUFSZ];
2052 #if 0
2053     dlb *fp;
2054     struct wd_stack_frame stack[WD_STACKLIMIT];
2055     boolean cond;
2056     int ctrl, meta, depth = 0, lnum = 0;
2057 #endif /* 0 */
2058     const char *ec_desc;
2059
2060     if ((ec_desc = key2extcmddesc(q)) != NULL) {
2061         char keybuf[QBUFSZ];
2062
2063         Sprintf(buf, "%-8s%s.", key2txt(q, keybuf), ec_desc);
2064         Strcpy(cbuf, buf);
2065         return cbuf;
2066     }
2067     return 0;
2068 #if 0
2069     fp = dlb_fopen(CMDHELPFILE, "r");
2070     if (!fp) {
2071         pline("Cannot open \"%s\" data file!", CMDHELPFILE);
2072         return 0;
2073     }
2074
2075     meta = (0x80 & (uchar) q) != 0;
2076     if (meta)
2077         q &= 0x7f;
2078     ctrl = (0x1f & (uchar) q) == (uchar) q;
2079     if (ctrl)
2080         q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
2081     else if (q == 0x7f)
2082         ctrl = 1, q = '?';
2083
2084     (void) memset((genericptr_t) stack, 0, sizeof stack);
2085     cond = stack[0].active = 1;
2086     while (dlb_fgets(buf, sizeof buf, fp)) {
2087         ++lnum;
2088         if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
2089             cond = whatdoes_cond(buf, stack, &depth, lnum);
2090             continue;
2091         }
2092         if (!cond)
2093             continue;
2094         if (meta ? (buf[0] == 'M' && buf[1] == '-'
2095                     && (ctrl ? buf[2] == '^' && highc(buf[3]) == q
2096                              : buf[2] == q))
2097                  : (ctrl ? buf[0] == '^' && highc(buf[1]) == q
2098                          : buf[0] == q)) {
2099             (void) strip_newline(buf);
2100             if (index(buf, '\t'))
2101                 (void) tabexpand(buf);
2102             if (meta && ctrl && buf[4] == ' ') {
2103                 (void) strncpy(buf, "M-^?    ", 8);
2104                 buf[3] = q;
2105             } else if (meta && buf[3] == ' ') {
2106                 (void) strncpy(buf, "M-?     ", 8);
2107                 buf[2] = q;
2108             } else if (ctrl && buf[2] == ' ') {
2109                 (void) strncpy(buf, "^?      ", 8);
2110                 buf[1] = q;
2111             } else if (buf[1] == ' ') {
2112                 (void) strncpy(buf, "?       ", 8);
2113                 buf[0] = q;
2114             }
2115             (void) dlb_fclose(fp);
2116             Strcpy(cbuf, buf);
2117             return cbuf;
2118         }
2119     }
2120     (void) dlb_fclose(fp);
2121     if (depth != 0)
2122         impossible("cmdhelp: mismatched &? &: &. conditionals.");
2123     return (char *) 0;
2124 #endif /* 0 */
2125 }
2126
2127 int
2128 dowhatdoes()
2129 {
2130     static boolean once = FALSE;
2131     char bufr[BUFSZ];
2132     char q, *reslt;
2133
2134     if (!once) {
2135         pline("Ask about '&' or '?' to get more info.%s",
2136 #ifdef ALTMETA
2137               iflags.altmeta ? "  (For ESC, type it twice.)" :
2138 #endif
2139               "");
2140         once = TRUE;
2141     }
2142 #if defined(UNIX) || defined(VMS)
2143     introff(); /* disables ^C but not ^\ */
2144 #endif
2145 /*JP
2146     q = yn_function("What command?", (char *) 0, '\0');
2147 */
2148     q = yn_function("\82Ç\82¤\82¢\82¤\83R\83}\83\93\83h\81H", (char *) 0, '\0');
2149 #ifdef ALTMETA
2150     if (q == '\033' && iflags.altmeta) {
2151         /* in an ideal world, we would know whether another keystroke
2152            was already pending, but this is not an ideal world...
2153            if user typed ESC, we'll essentially hang until another
2154            character is typed */
2155         q = yn_function("]", (char *) 0, '\0');
2156         if (q != '\033')
2157             q = (char) ((uchar) q | 0200);
2158     }
2159 #endif /*ALTMETA*/
2160 #if defined(UNIX) || defined(VMS)
2161     intron(); /* reenables ^C */
2162 #endif
2163     reslt = dowhatdoes_core(q, bufr);
2164     if (reslt) {
2165         if (q == '&' || q == '?')
2166             whatdoes_help();
2167         pline("%s", reslt);
2168     } else {
2169 #if 0 /*JP*/
2170         pline("No such command '%s', char code %d (0%03o or 0x%02x).",
2171               visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2172 #else
2173         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",
2174               visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2175 #endif
2176     }
2177     return 0;
2178 }
2179
2180 STATIC_OVL void
2181 docontact(VOID_ARGS)
2182 {
2183     winid cwin = create_nhwindow(NHW_TEXT);
2184     char buf[BUFSZ];
2185
2186     if (sysopt.support) {
2187         /*XXX overflow possibilities*/
2188         Sprintf(buf, "To contact local support, %s", sysopt.support);
2189         putstr(cwin, 0, buf);
2190         putstr(cwin, 0, "");
2191     } else if (sysopt.fmtd_wizard_list) { /* formatted SYSCF WIZARDS */
2192         Sprintf(buf, "To contact local support, contact %s.",
2193                 sysopt.fmtd_wizard_list);
2194         putstr(cwin, 0, buf);
2195         putstr(cwin, 0, "");
2196     }
2197     putstr(cwin, 0, "To contact the NetHack development team directly,");
2198     /*XXX overflow possibilities*/
2199     Sprintf(buf, "see the 'Contact' form on our website or email <%s>.",
2200             DEVTEAM_EMAIL);
2201     putstr(cwin, 0, buf);
2202     putstr(cwin, 0, "");
2203     putstr(cwin, 0, "For more information on NetHack, or to report a bug,");
2204     Sprintf(buf, "visit our website \"%s\".", DEVTEAM_URL);
2205     putstr(cwin, 0, buf);
2206     display_nhwindow(cwin, FALSE);
2207     destroy_nhwindow(cwin);
2208 }
2209
2210 void
2211 dispfile_help(VOID_ARGS)
2212 {
2213     display_file(HELP, TRUE);
2214 }
2215
2216 void
2217 dispfile_shelp(VOID_ARGS)
2218 {
2219     display_file(SHELP, TRUE);
2220 }
2221
2222 void
2223 dispfile_optionfile(VOID_ARGS)
2224 {
2225     display_file(OPTIONFILE, TRUE);
2226 }
2227
2228 void
2229 dispfile_license(VOID_ARGS)
2230 {
2231     display_file(LICENSE, TRUE);
2232 }
2233
2234 void
2235 dispfile_debughelp(VOID_ARGS)
2236 {
2237     display_file(DEBUGHELP, TRUE);
2238 }
2239
2240 void
2241 hmenu_doextversion(VOID_ARGS)
2242 {
2243     (void) doextversion();
2244 }
2245
2246 void
2247 hmenu_dohistory(VOID_ARGS)
2248 {
2249     (void) dohistory();
2250 }
2251
2252 void
2253 hmenu_dowhatis(VOID_ARGS)
2254 {
2255     (void) dowhatis();
2256 }
2257
2258 void
2259 hmenu_dowhatdoes(VOID_ARGS)
2260 {
2261     (void) dowhatdoes();
2262 }
2263
2264 void
2265 hmenu_doextlist(VOID_ARGS)
2266 {
2267     (void) doextlist();
2268 }
2269
2270 void
2271 domenucontrols(VOID_ARGS)
2272 {
2273     winid cwin = create_nhwindow(NHW_TEXT);
2274     show_menu_controls(cwin, FALSE);
2275     display_nhwindow(cwin, FALSE);
2276     destroy_nhwindow(cwin);
2277 }
2278
2279 /* data for dohelp() */
2280 static struct {
2281     void NDECL((*f));
2282     const char *text;
2283 } help_menu_items[] = {
2284 /*JP
2285     { hmenu_doextversion, "About NetHack (version information)." },
2286 */
2287     { hmenu_doextversion, "NetHack\82É\82Â\82¢\82Ä(\83o\81[\83W\83\87\83\93\8fî\95ñ)" },
2288 /*JP
2289     { dispfile_help, "Long description of the game and commands." },
2290 */
2291     { dispfile_help, "\83Q\81[\83\80\82¨\82æ\82Ñ\83R\83}\83\93\83h\82Ì\89ð\90à(\92·\95¶)" },
2292 /*JP
2293     { dispfile_shelp, "List of game commands." },
2294 */
2295     { dispfile_shelp, "\83R\83}\83\93\83h\88ê\97\97" },
2296 /*JP
2297     { hmenu_dohistory, "Concise history of NetHack." },
2298 */
2299     { hmenu_dohistory, "NetHack\82Ì\8aÈ\92P\82È\97ð\8ej" },
2300 /*JP
2301     { hmenu_dowhatis, "Info on a character in the game display." },
2302 */
2303     { hmenu_dowhatis, "\89æ\96Ê\82É\95\\8e¦\82³\82ê\82é\95\8e\9a\82Ì\90à\96¾" },
2304 /*JP
2305     { hmenu_dowhatdoes, "Info on what a given key does." },
2306 */
2307     { hmenu_dowhatdoes, "\82±\82Ì\83L\81[\82ª\89½\82ð\88Ó\96¡\82·\82é\82©\82Ì\90à\96¾" },
2308 /*JP
2309     { option_help, "List of game options." },
2310 */
2311     { option_help, "\83Q\81[\83\80\82Ì\83I\83v\83V\83\87\83\93\88ê\97\97" },
2312 /*JP
2313     { dispfile_optionfile, "Longer explanation of game options." },
2314 */
2315     { dispfile_optionfile, "\83Q\81[\83\80\82Ì\83I\83v\83V\83\87\83\93\88ê\97\97(\92·\95¶)" },
2316 /*JP
2317     { dokeylist, "Full list of keyboard commands" },
2318 */
2319     { dokeylist, "\83L\81[\83{\81[\83h\83R\83}\83\93\83h\82Ì\8a®\91S\82È\88ê\97\97" },
2320 /*JP
2321     { hmenu_doextlist, "List of extended commands." },
2322 */
2323     { hmenu_doextlist, "\8ag\92£\83R\83}\83\93\83h\88ê\97\97" },
2324 /*JP
2325     { domenucontrols, "List menu control keys" },
2326 */
2327     { domenucontrols, "\83\81\83j\83\85\81[\90§\8cä\83L\81[\88ê\97\97s" },
2328 /*JP
2329     { dispfile_license, "The NetHack license." },
2330 */
2331     { dispfile_license, "NetHack\82Ì\83\89\83C\83Z\83\93\83X" },
2332 /*JP
2333     { docontact, "Support information." },
2334 */
2335     { docontact, "\83T\83|\81[\83g\8fî\95ñ" },
2336 #ifdef PORT_HELP
2337 /*JP
2338     { port_help, "%s-specific help and commands." },
2339 */
2340     { port_help, "%s\82É\93Á\97L\82Ì\83w\83\8b\83v\82Æ\83R\83}\83\93\83h" },
2341 #endif
2342 /*JP
2343     { dispfile_debughelp, "List of wizard-mode commands." },
2344 */
2345     { dispfile_debughelp, "\83E\83B\83U\81[\83h\83\82\81[\83h\82Ì\83R\83}\83\93\83h\88ê\97\97" },
2346     { (void NDECL((*))) 0, (char *) 0 }
2347 };
2348
2349 /* the '?' command */
2350 int
2351 dohelp()
2352 {
2353     winid tmpwin = create_nhwindow(NHW_MENU);
2354     char helpbuf[QBUFSZ];
2355     int i, n;
2356     menu_item *selected;
2357     anything any;
2358     int sel;
2359
2360     any = zeroany; /* zero all bits */
2361     start_menu(tmpwin);
2362
2363     for (i = 0; help_menu_items[i].text; i++) {
2364         if (!wizard && help_menu_items[i].f == dispfile_debughelp)
2365             continue;
2366         if (help_menu_items[i].text[0] == '%') {
2367             Sprintf(helpbuf, help_menu_items[i].text, PORT_ID);
2368         } else {
2369             Strcpy(helpbuf, help_menu_items[i].text);
2370         }
2371         any.a_int = i + 1;
2372         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
2373                  helpbuf, MENU_UNSELECTED);
2374     }
2375 /*JP
2376     end_menu(tmpwin, "Select one item:");
2377 */
2378     end_menu(tmpwin, "\91I\82ñ\82Å\82­\82¾\82³\82¢\81F");
2379     n = select_menu(tmpwin, PICK_ONE, &selected);
2380     destroy_nhwindow(tmpwin);
2381     if (n > 0) {
2382         sel = selected[0].item.a_int - 1;
2383         free((genericptr_t) selected);
2384         (void) (*help_menu_items[sel].f)();
2385     }
2386     return 0;
2387 }
2388
2389 /* the 'V' command; also a choice for '?' */
2390 int
2391 dohistory()
2392 {
2393     display_file(HISTORY, TRUE);
2394     return 0;
2395 }
2396
2397 /*pager.c*/