OSDN Git Service

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