1 /* NetHack 3.6 pager.c $NHDT-Date: 1523142395 2018/04/07 23:06:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.123 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
9 /* JNetHack may be freely redistributed. See license for details. */
11 /* This file contains the command routines dowhatis() and dohelp() and */
12 /* a few other help related facilities */
17 STATIC_DCL boolean FDECL(is_swallow_sym, (int));
18 STATIC_DCL int FDECL(append_str, (char *, const char *));
19 STATIC_DCL void FDECL(look_at_object, (char *, int, int, int));
20 STATIC_DCL void FDECL(look_at_monster, (char *, char *,
21 struct monst *, int, int));
22 STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *));
23 STATIC_DCL void FDECL(checkfile, (char *, struct permonst *,
24 BOOLEAN_P, BOOLEAN_P));
25 STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P));
26 STATIC_DCL void NDECL(whatdoes_help);
27 STATIC_DCL void NDECL(docontact);
28 STATIC_DCL void NDECL(dispfile_help);
29 STATIC_DCL void NDECL(dispfile_shelp);
30 STATIC_DCL void NDECL(dispfile_optionfile);
31 STATIC_DCL void NDECL(dispfile_license);
32 STATIC_DCL void NDECL(dispfile_debughelp);
33 STATIC_DCL void NDECL(hmenu_doextversion);
34 STATIC_DCL void NDECL(hmenu_dohistory);
35 STATIC_DCL void NDECL(hmenu_dowhatis);
36 STATIC_DCL void NDECL(hmenu_dowhatdoes);
37 STATIC_DCL void NDECL(hmenu_doextlist);
39 extern void NDECL(port_help);
42 /* Returns "true" for characters that could represent a monster's stomach. */
49 for (i = S_sw_tl; i <= S_sw_br; i++)
50 if ((int) showsyms[i] == c)
56 * Append new_str to the end of buf if new_str doesn't already exist as
57 * a substring of buf. Return 1 if the string was appended, 0 otherwise.
58 * It is expected that buf is of size BUFSZ.
61 append_str(buf, new_str)
65 int space_left; /* space remaining in buf */
67 if (strstri(buf, new_str))
70 space_left = BUFSZ - strlen(buf) - 1;
74 (void) strncat(buf, " or ", space_left);
75 (void) strncat(buf, new_str, space_left - 4);
77 (void) strncat(buf, "
\82Ü
\82½
\82Í", space_left);
78 (void) strncat(buf, new_str, space_left - 6);
83 /* shared by monster probing (via query_objlist!) as well as lookat() */
90 /* include race with role unless polymorphed */
94 Sprintf(race, "%s ", urace.adj);
96 Sprintf(race, "%s", urace.adj);
98 Sprintf(outbuf, "%s%s%s called %s",
99 /* being blinded may hide invisibility from self */
100 (Invis && (senseself() || !Blind)) ? "invisible " : "", race,
101 mons[u.umonnum].mname, plname);
103 Sprintf(outbuf, "%s%s%s
\82Æ
\82¢
\82¤
\96¼
\82Ì%s",
104 (Invis && (senseself() || !Blind)) ? "
\8ep
\82Ì
\8c©
\82¦
\82È
\82¢" : "", race,
106 mons[u.umonnum].mname);
110 Sprintf(eos(outbuf), ", mounted on %s", y_monnam(u.usteed));
112 Sprintf(eos(outbuf), "
\81C%s
\82É
\8fæ
\82Á
\82Ä
\82¢
\82é", y_monnam(u.usteed));
113 if (u.uundetected || (Upolyd && youmonst.m_ap_type))
114 mhidden_description(&youmonst, FALSE, eos(outbuf));
118 /* describe a hidden monster; used for look_at during extended monster
119 detection and for probing; also when looking at self */
121 mhidden_description(mon, altmon, outbuf)
123 boolean altmon; /* for probing: if mimicking a monster, say so */
127 boolean fakeobj, isyou = (mon == &youmonst);
128 int x = isyou ? u.ux : mon->mx, y = isyou ? u.uy : mon->my,
129 glyph = (level.flags.hero_memory && !isyou) ? levl[x][y].glyph
132 char suffixbuf[QBUFSZ];
139 if (mon->m_ap_type == M_AP_FURNITURE
140 || mon->m_ap_type == M_AP_OBJECT) {
142 Strcpy(outbuf, ", mimicking ");
143 #else /*
\8cã
\82Å
\92Ç
\89Á
\82·
\82é*/
144 Strcpy(suffixbuf, "
\82Ì
\82Ó
\82è
\82ð
\82µ
\82Ä
\82¢
\82é");
146 if (mon->m_ap_type == M_AP_FURNITURE) {
147 Strcat(outbuf, an(defsyms[mon->mappearance].explanation));
148 } else if (mon->m_ap_type == M_AP_OBJECT
149 /* remembered glyph, not glyph_at() which is 'mon' */
150 && glyph_is_object(glyph)) {
152 otmp = (struct obj *) 0;
153 fakeobj = object_from_map(glyph, x, y, &otmp);
154 Strcat(outbuf, (otmp && otmp->otyp != STRANGE_OBJECT)
155 ? ansimpleoname(otmp)
156 : an(obj_descr[STRANGE_OBJECT].oc_name));
160 Strcat(outbuf, something);
163 Strcat(outbuf, suffixbuf);
165 } else if (mon->m_ap_type == M_AP_MONSTER) {
168 Sprintf(outbuf, ", masquerading as %s",
169 an(mons[mon->mappearance].mname));
171 Sprintf(outbuf, "%s
\82É
\82È
\82è
\82·
\82Ü
\82µ
\82Ä
\82¢
\82é",
172 mons[mon->mappearance].mname);
174 } else if (isyou ? u.uundetected : mon->mundetected) {
176 Strcpy(outbuf, ", hiding");
178 Strcpy(suffixbuf, "
\82É
\89B
\82ê
\82Ä
\82¢
\82é");
180 if (hides_under(mon->data)) {
181 #if 0 /*JP*//*
\92n
\8c`
\82Ì
\8fê
\8d\87\81u
\82Ì
\89º
\82É
\81v
\82È
\82Ç
\82Í
\95s
\8e©
\91R
\82È
\82Ì
\82Å
\81A
\92P
\82É
\8fÈ
\97ª
\82µ
\82Ä
\82¨
\82*/
182 Strcat(outbuf, " under ");
184 /* remembered glyph, not glyph_at() which is 'mon' */
185 if (glyph_is_object(glyph))
187 Strcat(outbuf, something);
188 } else if (is_hider(mon->data)) {
190 Sprintf(eos(outbuf), " on the %s",
191 (is_flyer(mon->data) || mon->data->mlet == S_PIERCER)
193 : surface(x, y)); /* trapper */
195 Sprintf(eos(outbuf), "%s",
196 (is_flyer(mon->data) || mon->data->mlet == S_PIERCER)
198 : surface(x, y)); /* trapper */
201 if (mon->data->mlet == S_EEL && is_pool(x, y))
203 Strcat(outbuf, " in murky water");
205 Strcat(outbuf, "
\82É
\82²
\82Á
\82½
\90\85\82Ì
\92\86");
209 Strcat(outbuf, suffixbuf);
214 /* extracted from lookat(); also used by namefloorobj() */
216 object_from_map(glyph, x, y, obj_p)
220 boolean fakeobj = FALSE;
223 int glyphotyp = glyph_to_obj(glyph);
225 *obj_p = (struct obj *) 0;
226 /* TODO: check inside containers in case glyph came from detection */
227 if ((otmp = sobj_at(glyphotyp, x, y)) == 0)
228 for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj)
229 if (otmp->ox == x && otmp->oy == y && otmp->otyp == glyphotyp)
232 /* there might be a mimic here posing as an object */
234 if (mtmp && is_obj_mappear(mtmp, (unsigned) glyphotyp))
239 if (!otmp || otmp->otyp != glyphotyp) {
240 /* this used to exclude STRANGE_OBJECT; now caller deals with it */
241 otmp = mksobj(glyphotyp, FALSE, FALSE);
245 if (otmp->oclass == COIN_CLASS)
246 otmp->quan = 2L; /* to force pluralization */
247 else if (otmp->otyp == SLIME_MOLD)
248 otmp->spe = context.current_fruit; /* give it a type */
249 if (mtmp && has_mcorpsenm(mtmp)) /* mimic as corpse/statue */
250 otmp->corpsenm = MCORPSENM(mtmp);
252 /* if located at adjacent spot, mark it as having been seen up close
253 (corpse type will be known even if dknown is 0, so we don't need a
254 touch check for cockatrice corpse--we're looking without touching) */
255 if (otmp && distu(x, y) <= 2 && !Blind && !Hallucination
256 /* redundant: we only look for an object which matches current
257 glyph among floor and buried objects; when !Blind, any buried
258 object's glyph will have been replaced by whatever is present
259 on the surface as soon as we moved next to its spot */
260 && (fakeobj || otmp->where == OBJ_FLOOR) /* not buried */
261 /* terrain mode views what's already known, doesn't learn new stuff */
262 && !iflags.terrainmode) /* so don't set dknown when in terrain mode */
263 otmp->dknown = 1; /* if a pile, clearly see the top item only */
266 return fakeobj; /* when True, caller needs to dealloc *obj_p */
270 look_at_object(buf, x, y, glyph)
271 char *buf; /* output buffer */
274 struct obj *otmp = 0;
275 boolean fakeobj = object_from_map(glyph, x, y, &otmp);
278 Strcpy(buf, (otmp->otyp != STRANGE_OBJECT)
279 ? distant_name(otmp, doname_vague_quan)
280 : obj_descr[STRANGE_OBJECT].oc_name);
282 dealloc_obj(otmp), otmp = 0;
284 Strcpy(buf, something); /* sanity precaution */
286 if (otmp && otmp->where == OBJ_BURIED)
288 Strcat(buf, " (buried)");
290 Strcat(buf, " (
\96\84\82Ü
\82Á
\82Ä
\82¢
\82é)");
291 else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
293 Strcat(buf, " embedded in stone");
295 Strcat(buf, "
\81C
\8aâ
\82É
\96\84\82ß
\82±
\82Ü
\82ê
\82Ä
\82¢
\82é");
296 else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR)
298 Strcat(buf, " embedded in a wall");
300 Strcat(buf, "
\81C
\95Ç
\82É
\96\84\82ß
\82±
\82Ü
\82ê
\82Ä
\82¢
\82é");
301 else if (closed_door(x, y))
303 Strcat(buf, " embedded in a door");
305 Strcat(buf, "
\81C
\94à
\82É
\96\84\82ß
\82±
\82Ü
\82ê
\82Ä
\82¢
\82é");
306 else if (is_pool(x, y))
307 /*JP 3.4.3
\82±
\82Ì
\95\94\95ª
\82Í
\95¨
\91Ì
\82É
\82µ
\82©
\8eg
\82í
\82ê
\82È
\82¢ */
309 Strcat(buf, " in water");
311 Strcat(buf, "
\81C
\90\85\92\86\82É
\82 \82é");
312 else if (is_lava(x, y))
314 Strcat(buf, " in molten lava"); /* [can this ever happen?] */
316 Strcat(buf, "
\81C
\97n
\8aâ
\82Ì
\92\86\82É
\82 \82é"); /* [can this ever happen?] */
322 look_at_monster(buf, monbuf, mtmp, x, y)
323 char *buf, *monbuf; /* buf: output, monbuf: optional output */
327 char *name, monnambuf[BUFSZ];
328 boolean accurate = !Hallucination;
330 name = (mtmp->data == &mons[PM_COYOTE] && accurate)
331 ? coyotename(mtmp, monnambuf)
332 : distant_monnam(mtmp, ARTICLE_NONE, monnambuf);
334 Sprintf(buf, "%s%s%s",
335 (mtmp->mx != x || mtmp->my != y)
336 ? ((mtmp->isshk && accurate) ? "tail of " : "tail of a ")
338 (mtmp->mtame && accurate)
340 : (mtmp->mpeaceful && accurate)
345 Sprintf(buf, "%s%s%s",
346 (mtmp->mtame && accurate)
347 ? "
\8eè
\82È
\82¸
\82¯
\82ç
\82ê
\82½"
348 : (mtmp->mpeaceful && accurate)
352 (mtmp->mx != x || mtmp->my != y)
353 ? ((mtmp->isshk && accurate) ? "
\82Ì
\90K
\94ö" : "
\82Ì
\90K
\94ö")
356 if (u.ustuck == mtmp) {
357 if (u.uswallow || iflags.save_uswallow) /* monster detection */
359 Strcat(buf, is_animal(mtmp->data)
360 ? ", swallowing you" : ", engulfing you");
362 Strcat(buf, ",
\82 \82È
\82½
\82ð
\88ù
\82Ý
\8d\9e\82ñ
\82Å
\82¢
\82é");
365 Strcat(buf, (Upolyd && sticks(youmonst.data))
367 ? ", being held" : ", holding you");
369 ? "
\81C
\82 \82È
\82½
\82ª
\92Í
\82Ü
\82¦
\82Ä
\82¢
\82é" : "
\81C
\82 \82È
\82½
\82ð
\92Í
\82Ü
\82¦
\82Ä
\82¢
\82é");
373 Strcat(buf, ", leashed to you");
375 Strcat(buf, "
\81C
\95R
\82Å
\8c\8b\82Î
\82ê
\82Ä
\82¢
\82é");
377 if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) {
378 struct trap *t = t_at(mtmp->mx, mtmp->my);
379 int tt = t ? t->ttyp : NO_TRAP;
381 /* newsym lets you know of the trap, so mention it here */
382 if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT || tt == WEB)
384 Sprintf(eos(buf), ", trapped in %s",
386 Sprintf(eos(buf), ", %s
\82É
\95ß
\82Ü
\82Á
\82Ä
\82¢
\82é",
387 an(defsyms[trap_to_defsym(tt)].explanation));
390 /* we know the hero sees a monster at this location, but if it's shown
391 due to persistant monster detection he might remember something else */
392 if (mtmp->mundetected || mtmp->m_ap_type)
393 mhidden_description(mtmp, FALSE, eos(buf));
396 unsigned how_seen = howmonseen(mtmp);
399 if (how_seen != 0 && how_seen != MONSEEN_NORMAL) {
400 if (how_seen & MONSEEN_NORMAL) {
402 Strcat(monbuf, "normal vision");
404 Strcat(monbuf, "
\92Ê
\8fí
\82Ì
\8e\8b\8ao");
405 how_seen &= ~MONSEEN_NORMAL;
406 /* how_seen can't be 0 yet... */
408 Strcat(monbuf, ", ");
410 if (how_seen & MONSEEN_SEEINVIS) {
412 Strcat(monbuf, "see invisible");
414 Strcat(monbuf, "
\8c©
\82¦
\82È
\82¢
\82à
\82Ì
\82ð
\8c©
\82é
\8e\8b\8ao");
415 how_seen &= ~MONSEEN_SEEINVIS;
417 Strcat(monbuf, ", ");
419 if (how_seen & MONSEEN_INFRAVIS) {
421 Strcat(monbuf, "infravision");
423 Strcat(monbuf, "
\90Ô
\8aO
\90ü
\82ª
\8c©
\82¦
\82é
\8e\8b\8ao");
424 how_seen &= ~MONSEEN_INFRAVIS;
426 Strcat(monbuf, ", ");
428 if (how_seen & MONSEEN_TELEPAT) {
430 Strcat(monbuf, "telepathy");
432 Strcat(monbuf, "
\83e
\83\8c\83p
\83V
\81[");
433 how_seen &= ~MONSEEN_TELEPAT;
435 Strcat(monbuf, ", ");
437 if (how_seen & MONSEEN_XRAYVIS) {
438 /* Eyes of the Overworld */
440 Strcat(monbuf, "astral vision");
442 Strcat(monbuf, "
\90¸
\90_
\82É
\82æ
\82é
\8e\8b\8ao");
443 how_seen &= ~MONSEEN_XRAYVIS;
445 Strcat(monbuf, ", ");
447 if (how_seen & MONSEEN_DETECT) {
449 Strcat(monbuf, "monster detection");
451 Strcat(monbuf, "
\89ö
\95¨
\82ð
\94
\8c©
\82·
\82é
\94\
\97Í");
452 how_seen &= ~MONSEEN_DETECT;
454 Strcat(monbuf, ", ");
456 if (how_seen & MONSEEN_WARNMON) {
459 Strcat(monbuf, "paranoid delusion");
461 Strcat(monbuf, "
\95Î
\8e·
\93I
\96Ï
\91z");
463 unsigned long mW = (context.warntype.obj
464 | context.warntype.polyd),
465 m2 = mtmp->data->mflags2;
467 const char *whom = ((mW & M2_HUMAN & m2) ? "human"
468 : (mW & M2_ELF & m2) ? "elf"
469 : (mW & M2_ORC & m2) ? "orc"
470 : (mW & M2_DEMON & m2) ? "demon"
471 : mtmp->data->mname);
473 const char *whom = ((mW & M2_HUMAN & m2) ? "
\90l
\8aÔ"
474 : (mW & M2_ELF & m2) ? "
\83G
\83\8b\83t"
475 : (mW & M2_ORC & m2) ? "
\83I
\81[
\83N"
476 : (mW & M2_DEMON & m2) ? "
\88«
\96\82"
477 : mtmp->data->mname);
481 Sprintf(eos(monbuf), "warned of %s", makeplural(whom));
483 Sprintf(eos(monbuf), "%s
\82ð
\8cx
\8d\90\82µ
\82Ä
\82¢
\82é", whom);
485 how_seen &= ~MONSEEN_WARNMON;
487 Strcat(monbuf, ", ");
489 /* should have used up all the how_seen bits by now */
491 impossible("lookat: unknown method of seeing monster");
492 Sprintf(eos(monbuf), "(%u)", how_seen);
494 } /* seen by something other than normal vision */
495 } /* monbuf is non-null */
499 * Return the name of the glyph found at (x,y).
500 * If not hallucinating and the glyph is a monster, also monster data.
502 STATIC_OVL struct permonst *
503 lookat(x, y, buf, monbuf)
507 struct monst *mtmp = (struct monst *) 0;
508 struct permonst *pm = (struct permonst *) 0;
511 buf[0] = monbuf[0] = '\0';
512 glyph = glyph_at(x, y);
513 if (u.ux == x && u.uy == y && canspotself()
514 && !(iflags.save_uswallow && glyph == mon_to_glyph(u.ustuck))
515 && (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)) {
517 (void) self_lookat(buf);
519 /* file lookup can't distinguish between "gnomish wizard" monster
520 and correspondingly named player character, always picking the
521 former; force it to find the general "wizard" entry instead */
522 if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd)
523 pm = &mons[PM_WIZARD];
525 /* When you see yourself normally, no explanation is appended
526 (even if you could also see yourself via other means).
527 Sensing self while blind or swallowed is treated as if it
528 were by normal vision (cf canseeself()). */
529 if ((Invisible || u.uundetected) && !Blind
530 && !(u.uswallow || iflags.save_uswallow)) {
542 Sprintf(eos(buf), " [seen: %s%s%s%s%s]",
543 (how & 1) ? "infravision" : "",
544 /* add comma if telep and infrav */
545 ((how & 3) > 2) ? ", " : "",
546 (how & 2) ? "telepathy" : "",
547 /* add comma if detect and (infrav or telep or both) */
548 ((how & 7) > 4) ? ", " : "",
549 (how & 4) ? "monster detection" : "");
551 Sprintf(eos(buf), " [
\8a´
\92m: %s%s%s%s%s]",
552 (how & 1) ? "
\90Ô
\8aO
\90ü" : "",
553 /* add comma if telep and infrav */
554 ((how & 3) > 2) ? ", " : "",
555 (how & 2) ? "
\83e
\83\8c\83p
\83V
\81[" : "",
556 /* add comma if detect and (infrav or telep or both) */
557 ((how & 7) > 4) ? ", " : "",
558 (how & 4) ? "
\89ö
\95¨
\8a´
\92m" : "");
561 } else if (u.uswallow) {
562 /* when swallowed, we're only called for spots adjacent to hero,
563 and blindness doesn't prevent hero from feeling what holds him */
565 Sprintf(buf, "interior of %s", a_monnam(u.ustuck));
567 Sprintf(buf, "%s
\82Ì
\93à
\95\94", a_monnam(u.ustuck));
569 } else if (glyph_is_monster(glyph)) {
572 if ((mtmp = m_at(x, y)) != 0) {
573 look_at_monster(buf, monbuf, mtmp, x, y);
575 } else if (Hallucination) {
576 /* 'monster' must actually be a statue */
577 Strcpy(buf, rndmonnam((char *) 0));
579 } else if (glyph_is_object(glyph)) {
580 look_at_object(buf, x, y, glyph); /* fill in buf[] */
581 } else if (glyph_is_trap(glyph)) {
582 int tnum = what_trap(glyph_to_trap(glyph));
584 /* Trap detection displays a bear trap at locations having
585 * a trapped door or trapped container or both.
586 * TODO: we should create actual trap types for doors and
587 * chests so that they can have their own glyphs and tiles.
589 if (trapped_chest_at(tnum, x, y))
591 Strcpy(buf, "trapped chest"); /* might actually be a large box */
593 Strcpy(buf, "ã©
\82Ì
\8ed
\8a|
\82¯
\82ç
\82ê
\82½
\94 "); /* might actually be a large box */
595 else if (trapped_door_at(tnum, x, y))
597 Strcpy(buf, "trapped door"); /* not "trap door"... */
599 Strcpy(buf, "ã©
\82Ì
\8ed
\8a|
\82¯
\82ç
\82ê
\82½
\94à"); /* not "trap door"... */
602 Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
603 } else if (glyph_is_warning(glyph)) {
604 int warnindx = glyph_to_warning(glyph);
606 Strcpy(buf, def_warnsyms[warnindx].explanation);
607 } else if (!glyph_is_cmap(glyph)) {
609 Strcpy(buf, "unexplored area");
611 Strcpy(buf, "
\96¢
\92T
\8dõ
\82Ì
\8fê
\8f\8a");
613 switch (glyph_to_cmap(glyph)) {
616 Sprintf(buf, "%s %saltar",
618 Sprintf(buf, "%s%s
\8dÕ
\92d",
619 /* like endgame high priests, endgame high altars
620 are only recognizable when immediately adjacent */
621 (Is_astralevel(&u.uz) && distu(x, y) > 2)
627 Amask2align(levl[x][y].altarmask & ~AM_SHRINE)),
628 ((levl[x][y].altarmask & AM_SHRINE)
629 && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
637 if (is_drawbridge_wall(x, y) >= 0)
639 Strcpy(buf, "open drawbridge portcullis");
641 Strcpy(buf,"
\8aJ
\82¢
\82Ä
\82¢
\82é
\92µ
\82Ë
\8b´");
642 else if ((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN)
644 Strcpy(buf, "broken door");
646 Strcpy(buf,"
\89ó
\82ê
\82½
\94à");
649 Strcpy(buf, "doorway");
651 Strcpy(buf,"
\8fo
\93ü
\82è
\8cû");
656 Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud");
658 Is_airlevel(&u.uz) ? "
\93Ü
\82Á
\82Ä
\82¢
\82é
\8fê
\8f\8a" : "
\96¶/
\8fö
\8bC
\82Ì
\89_");
661 if (!levl[x][y].seenv) {
663 Strcpy(buf, "unexplored");
665 Strcpy(buf, "
\96¢
\92T
\8dõ");
667 } else if (Underwater && !Is_waterlevel(&u.uz)) {
668 /* "unknown" == previously mapped but not visible when
669 submerged; better terminology appreciated... */
670 Strcpy(buf, (distu(x, y) <= 2) ? "land" : "unknown");
672 } else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) {
674 Strcpy(buf, "stone");
676 Strcpy(buf, "
\8aâ
\94Õ");
681 Strcpy(buf, defsyms[glyph_to_cmap(glyph)].explanation);
685 return (pm && !Hallucination) ? pm : (struct permonst *) 0;
689 * Look in the "data" file for more info. Called if the user typed in the
690 * whole name (user_typed_name == TRUE), or we've found a possible match
691 * with a character/glyph and flags.help is TRUE.
693 * NOTE: when (user_typed_name == FALSE), inp is considered read-only and
694 * must not be changed directly, e.g. via lcase(). We want to force
695 * lcase() for data.base lookup so that we can have a clean key.
696 * Therefore, we create a copy of inp _just_ for data.base lookup.
699 checkfile(inp, pm, user_typed_name, without_asking)
702 boolean user_typed_name, without_asking;
705 char buf[BUFSZ], newstr[BUFSZ], givenname[BUFSZ];
706 char *ep, *dbase_str;
707 unsigned long txt_offset = 0L;
708 winid datawin = WIN_ERR;
710 fp = dlb_fopen(DATAFILE, "r");
713 pline("Cannot open data file!");
715 pline("
\83f
\81[
\83^
\83t
\83@
\83C
\83\8b\82ð
\8aJ
\82¯
\82È
\82¢
\81I");
719 /* If someone passed us garbage, prevent fault. */
720 if (!inp || strlen(inp) > (BUFSZ - 1)) {
721 impossible("bad do_look buffer passed (%s)!",
722 !inp ? "null" : "too long");
726 /* To prevent the need for entries in data.base like *ngel to account
727 * for Angel and angel, make the lookup string the same for both
728 * user_typed_name and picked name.
730 if (pm != (struct permonst *) 0 && !user_typed_name)
731 dbase_str = strcpy(newstr, pm->mname);
733 dbase_str = strcpy(newstr, inp);
734 (void) lcase(dbase_str);
736 /*JP:TODO:
\83f
\81[
\83^
\83x
\81[
\83X
\8c\9f\8dõ
\82Í
\93®
\82¢
\82Ä
\82¢
\82È
\82¢
\82Ì
\82Å
\97v
\8fC
\90³*/
739 * The switch from xname() to doname_vague_quan() in look_at_obj()
740 * had the unintendded side-effect of making names picked from
741 * pointing at map objects become harder to simplify for lookup.
742 * We should split the prefix and suffix handling used by wish
743 * parsing and also wizmode monster generation out into separate
744 * routines and use those routines here. This currently lacks
745 * erosion handling and probably lots of other bits and pieces
746 * that wishing already understands and most of this duplicates
747 * stuff already done for wish handling or monster generation.
749 if (!strncmp(dbase_str, "interior of ", 12))
751 if (!strncmp(dbase_str, "a ", 2))
753 else if (!strncmp(dbase_str, "an ", 3))
755 else if (!strncmp(dbase_str, "the ", 4))
757 else if (!strncmp(dbase_str, "some ", 5))
759 else if (digit(*dbase_str)) {
760 /* remove count prefix ("2 ya") which can come from looking at map */
761 while (digit(*dbase_str))
763 if (*dbase_str == ' ')
766 if (!strncmp(dbase_str, "tame ", 5))
768 else if (!strncmp(dbase_str, "peaceful ", 9))
770 if (!strncmp(dbase_str, "invisible ", 10))
772 if (!strncmp(dbase_str, "saddled ", 8))
774 if (!strncmp(dbase_str, "blessed ", 8))
776 else if (!strncmp(dbase_str, "uncursed ", 9))
778 else if (!strncmp(dbase_str, "cursed ", 7))
780 if (!strncmp(dbase_str, "empty ", 6))
782 if (!strncmp(dbase_str, "partly used ", 12))
784 else if (!strncmp(dbase_str, "partly eaten ", 13))
786 if (!strncmp(dbase_str, "statue of ", 10))
788 else if (!strncmp(dbase_str, "figurine of ", 12))
790 /* remove enchantment ("+0 aklys"); [for 3.6.0 and earlier, this wasn't
791 needed because looking at items on the map used xname() rather than
792 doname() hence known enchantment was implicitly suppressed] */
793 if (*dbase_str && index("+-", dbase_str[0]) && digit(dbase_str[1])) {
794 ++dbase_str; /* skip sign */
795 while (digit(*dbase_str))
797 if (*dbase_str == ' ')
800 /* "towel", "wet towel", and "moist towel" share one data.base entry;
801 for "wet towel", we keep prefix so that the prompt will ask about
802 "wet towel"; for "moist towel", we also want to ask about "wet towel".
803 (note: strncpy() only terminates output string if the specified
804 count is bigger than the length of the substring being copied) */
805 if (!strncmp(dbase_str, "moist towel", 11))
806 (void) strncpy(dbase_str += 2, "wet", 3); /* skip "mo" replace "ist" */
808 /* Make sure the name is non-empty. */
810 long pass1offset = -1L;
811 int chk_skip, pass = 1;
812 boolean yes_to_moreinfo, found_in_file, pass1found_in_file,
814 char *ap, *alt = 0; /* alternate description */
816 /* adjust the input to remove "named " and "called " */
817 if ((ep = strstri(dbase_str, " named ")) != 0) {
819 if ((ap = strstri(dbase_str, " called ")) != 0 && ap < ep)
820 ep = ap; /* "named" is alt but truncate at "called" */
821 } else if ((ep = strstri(dbase_str, " called ")) != 0) {
822 copynchars(givenname, ep + 8, BUFSZ - 1);
825 ep = strstri(dbase_str, ", ");
826 if (ep && ep > dbase_str)
828 /* remove charges or "(lit)" or wizmode "(N aum)" */
829 if ((ep = strstri(dbase_str, " (")) != 0 && ep > dbase_str)
831 if (alt && (ap = strstri(alt, " (")) != 0 && ap > alt)
835 * If the object is named, then the name is the alternate description;
836 * otherwise, the result of makesingular() applied to the name is.
837 * This isn't strictly optimal, but named objects of interest to the
838 * user will usually be found under their name, rather than under
839 * their object type, so looking for a singular form is pointless.
842 alt = makesingular(dbase_str);
844 pass1found_in_file = FALSE;
845 for (pass = !strcmp(alt, dbase_str) ? 0 : 1; pass >= 0; --pass) {
846 found_in_file = skipping_entry = FALSE;
848 if (dlb_fseek(fp, txt_offset, SEEK_SET) < 0 ) {
849 impossible("can't get to start of 'data' file");
852 /* skip first record; read second */
853 if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) {
854 impossible("can't read 'data' file");
856 } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1
860 /* look for the appropriate entry */
861 while (dlb_fgets(buf, BUFSZ, fp)) {
863 break; /* we passed last entry without success */
866 /* a number indicates the end of current entry */
867 skipping_entry = FALSE;
868 } else if (!skipping_entry) {
869 if (!(ep = index(buf, '\n')))
871 (void) strip_newline((ep > buf) ? ep - 1 : ep);
872 /* if we match a key that begins with "~", skip
874 chk_skip = (*buf == '~') ? 1 : 0;
875 if ((pass == 0 && pmatch(&buf[chk_skip], dbase_str))
876 || (pass == 1 && alt && pmatch(&buf[chk_skip], alt))) {
878 skipping_entry = TRUE;
881 found_in_file = TRUE;
883 pass1found_in_file = TRUE;
890 long entry_offset, fseekoffset;
894 /* skip over other possible matches for the info */
896 if (!dlb_fgets(buf, BUFSZ, fp))
898 } while (!digit(*buf));
899 if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2)
901 fseekoffset = (long) txt_offset + entry_offset;
903 pass1offset = fseekoffset;
904 else if (fseekoffset == pass1offset)
907 yes_to_moreinfo = FALSE;
908 if (!user_typed_name && !without_asking) {
909 char *entrytext = pass ? alt : dbase_str;
910 char question[QBUFSZ];
913 Strcpy(question, "More info about \"");
914 /* +2 => length of "\"?" */
915 copynchars(eos(question), entrytext,
916 (int) (sizeof question - 1
917 - (strlen(question) + 2)));
918 Strcat(question, "\"?");
920 Strcpy(question, "
\81u");
921 /* +16 => "
\81v
\82Ì
\8fÚ
\8d×
\82ð
\8c©
\82é
\81H"
\82Ì
\92·
\82³ */
922 copynchars(eos(question), entrytext,
923 (int) (sizeof question - 1
924 - (strlen(question) + 16)));
925 Strcat(question, "
\81v
\82Ì
\8fÚ
\8d×
\82ð
\8c©
\82é
\81H");
927 if (yn(question) == 'y')
928 yes_to_moreinfo = TRUE;
931 if (user_typed_name || without_asking || yes_to_moreinfo) {
932 if (dlb_fseek(fp, fseekoffset, SEEK_SET) < 0) {
934 pline("? Seek error on 'data' file!");
936 pline("'data'
\83t
\83@
\83C
\83\8b\82Ì
\83V
\81[
\83N
\83G
\83\89\81[
\81I");
939 datawin = create_nhwindow(NHW_MENU);
940 for (i = 0; i < entry_count; i++) {
941 if (!dlb_fgets(buf, BUFSZ, fp))
943 (void) strip_newline(buf);
944 if (index(buf + 1, '\t') != 0)
945 (void) tabexpand(buf + 1);
946 putstr(datawin, 0, buf + 1);
948 display_nhwindow(datawin, FALSE);
949 destroy_nhwindow(datawin), datawin = WIN_ERR;
951 } else if (user_typed_name && pass == 0 && !pass1found_in_file)
953 pline("I don't have any information on those things.");
955 pline("
\82»
\82ñ
\82È
\96¼
\91O
\82Í
\95·
\82¢
\82½
\82±
\82Æ
\82ª
\82È
\82¢
\81D");
958 goto checkfile_done; /* skip error feedback */
961 impossible("'data' file in wrong format or corrupted");
963 if (datawin != WIN_ERR)
964 destroy_nhwindow(datawin);
965 (void) dlb_fclose(fp);
970 do_screen_description(cc, looked, sym, out_str, firstmatch)
975 const char **firstmatch;
978 static const char mon_interior[] = "the interior of a monster",
980 static const char mon_interior[] = "
\89ö
\95¨
\82Ì
\93à
\95\94",
982 unreconnoitered[] = "unreconnoitered";
984 unreconnoitered[] = "
\96¢
\8aÏ
\8e@";
985 static char look_buf[BUFSZ];
987 int i, alt_i, glyph = NO_GLYPH,
988 skipped_venom = 0, found = 0; /* count of matching syms found */
989 boolean hit_trap, need_to_look = FALSE,
990 submerged = (Underwater && !Is_waterlevel(&u.uz));
997 glyph = glyph_at(cc.x, cc.y);
998 /* Convert glyph at selected position to a symbol for use below. */
999 (void) mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y);
1001 Sprintf(prefix, "%s ", encglyph(glyph));
1003 Sprintf(prefix, "%c ", sym);
1006 * Check all the possibilities, saving all explanations in a buffer.
1007 * When all have been checked then the string is printed.
1011 * Handle restricted vision range (limited to adjacent spots when
1012 * swallowed or underwater) cases first.
1014 * 3.6.0 listed anywhere on map, other than self, as "interior
1015 * of a monster" when swallowed, and non-adjacent water or
1016 * non-water anywhere as "dark part of a room" when underwater.
1017 * "unreconnoitered" is an attempt to convey "even if you knew
1018 * what was there earlier, you don't know what is there in the
1019 * current circumstance".
1021 * (Note: 'self' will always be visible when swallowed so we don't
1022 * need special swallow handling for <ux,uy>.
1023 * Another note: for '#terrain' without monsters, u.uswallow and
1024 * submerged will always both be False and skip this code.)
1028 ; /* skip special handling */
1029 } else if (((u.uswallow || submerged) && distu(cc.x, cc.y) > 2)
1030 /* detection showing some category, so mostly background */
1031 || ((iflags.terrainmode & (TER_DETECT | TER_MAP)) == TER_DETECT
1032 && glyph == cmap_to_glyph(S_stone))) {
1033 x_str = unreconnoitered;
1034 need_to_look = FALSE;
1035 } else if (is_swallow_sym(sym)) {
1036 x_str = mon_interior;
1037 need_to_look = TRUE; /* for specific monster type */
1040 /* we know 'found' is zero here, but guard against some other
1041 special case being inserted ahead of us someday */
1043 Sprintf(out_str, "%s%s", prefix, x_str);
1044 *firstmatch = x_str;
1047 found += append_str(out_str, x_str); /* not 'an(x_str)' */
1049 /* for is_swallow_sym(), we want to list the current symbol's
1050 other possibilities (wand for '/', throne for '\\', &c) so
1051 don't jump to the end for the x_str==mon_interior case */
1052 if (x_str == unreconnoitered)
1056 /* Check for monsters */
1057 if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
1058 for (i = 0; i < MAXMCLASSES; i++) {
1059 if (sym == (looked ? showsyms[i + SYM_OFF_M] : def_monsyms[i].sym)
1060 && def_monsyms[i].explain) {
1061 need_to_look = TRUE;
1063 Sprintf(out_str, "%s%s",
1064 prefix, an(def_monsyms[i].explain));
1065 *firstmatch = def_monsyms[i].explain;
1068 found += append_str(out_str, an(def_monsyms[i].explain));
1072 /* handle '@' as a special case if it refers to you and you're
1073 playing a character which isn't normally displayed by that
1074 symbol; firstmatch is assumed to already be set for '@' */
1075 if ((looked ? (sym == showsyms[S_HUMAN + SYM_OFF_M]
1076 && cc.x == u.ux && cc.y == u.uy)
1077 : (sym == def_monsyms[S_HUMAN].sym && !flags.showrace))
1078 && !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
1080 found += append_str(out_str, "you"); /* tack on "or you" */
1082 found += append_str(out_str, "
\82 \82È
\82½"); /* tack on "or you" */
1086 /* Now check for objects */
1087 if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
1088 for (i = 1; i < MAXOCLASSES; i++) {
1089 if (sym == (looked ? showsyms[i + SYM_OFF_O]
1090 : def_oc_syms[i].sym)
1091 || (looked && i == ROCK_CLASS && glyph_is_statue(glyph))) {
1092 need_to_look = TRUE;
1093 if (looked && i == VENOM_CLASS) {
1098 Sprintf(out_str, "%s%s",
1099 prefix, an(def_oc_syms[i].explain));
1100 *firstmatch = def_oc_syms[i].explain;
1103 found += append_str(out_str, an(def_oc_syms[i].explain));
1109 if (sym == DEF_INVISIBLE) {
1111 Sprintf(out_str, "%s%s", prefix, an(invisexplain));
1112 *firstmatch = invisexplain;
1115 found += append_str(out_str, an(invisexplain));
1119 /* Now check for graphics symbols */
1120 alt_i = (sym == (looked ? showsyms[0] : defsyms[0].sym)) ? 0 : (2 + 1);
1121 for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
1122 /* when sym is the default background character, we process
1123 i == 0 three times: unexplored, stone, dark part of a room */
1126 x_str = !alt_i++ ? "unexplored" : submerged ? "unknown" : "stone";
1128 x_str = !alt_i++ ? "
\96¢
\92T
\8dõ" : submerged ? "
\96¢
\92m" : "
\8aâ
\94Õ";
1129 i = 0; /* for second iteration, undo loop increment */
1130 /* alt_i is now 1 or 2 */
1133 i = 0; /* undo loop increment */
1134 x_str = defsyms[i].explanation;
1135 if (submerged && !strcmp(x_str, defsyms[0].explanation))
1137 x_str = "land"; /* replace "dark part of a room" */
1139 x_str = "
\92n
\96Ê"; /* replace "dark part of a room" */
1141 /* alt_i is now 3 or more and no longer of interest */
1143 if (sym == (looked ? showsyms[i] : defsyms[i].sym) && *x_str) {
1144 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82É
\82Í
\8aÖ
\8cW
\82È
\82¢*/
1145 /* avoid "an unexplored", "an stone", "an air", "a water",
1146 "a floor of a room", "a dark part of a room";
1147 article==2 => "the", 1 => "an", 0 => (none) */
1148 int article = strstri(x_str, " of a room") ? 2
1150 || strcmp(x_str, "air") == 0
1151 || strcmp(x_str, "land") == 0
1152 || strcmp(x_str, "water") == 0);
1156 if (is_cmap_trap(i)) {
1158 Sprintf(out_str, "%sa trap", prefix);
1160 Sprintf(out_str, "%sã©", prefix);
1164 Sprintf(out_str, "%s%s", prefix,
1165 article == 2 ? the(x_str)
1166 : article == 1 ? an(x_str) : x_str);
1168 Sprintf(out_str, "%s%s", prefix, x_str);
1171 *firstmatch = x_str;
1173 } else if (!(hit_trap && is_cmap_trap(i))
1174 && !(found >= 3 && is_cmap_drawbridge(i))
1175 /* don't mention vibrating square outside of Gehennom
1176 unless this happens to be one (hallucination?) */
1177 && (i != S_vibrating_square || Inhell
1178 || (looked && glyph_is_trap(glyph)
1179 && glyph_to_trap(glyph) == VIBRATING_SQUARE))) {
1181 found += append_str(out_str, (article == 2) ? the(x_str)
1182 : (article == 1) ? an(x_str)
1185 found += append_str(out_str, x_str);
1187 if (is_cmap_trap(i))
1191 if (i == S_altar || is_cmap_trap(i))
1192 need_to_look = TRUE;
1196 /* Now check for warning symbols */
1197 for (i = 1; i < WARNCOUNT; i++) {
1198 x_str = def_warnsyms[i].explanation;
1199 if (sym == (looked ? warnsyms[i] : def_warnsyms[i].sym)) {
1201 Sprintf(out_str, "%s%s", prefix, def_warnsyms[i].explanation);
1202 *firstmatch = def_warnsyms[i].explanation;
1205 found += append_str(out_str, def_warnsyms[i].explanation);
1207 /* Kludge: warning trumps boulders on the display.
1208 Reveal the boulder too or player can get confused */
1209 if (looked && sobj_at(BOULDER, cc.x, cc.y))
1211 Strcat(out_str, " co-located with a boulder");
1213 Strcat(out_str, "(
\8b\90\8aâ
\82Æ
\93¯
\82¶
\88Ê
\92u
\82É
\82 \82é)");
1214 break; /* out of for loop*/
1218 /* if we ignored venom and list turned out to be short, put it back */
1219 if (skipped_venom && found < 2) {
1220 x_str = def_oc_syms[VENOM_CLASS].explain;
1222 Sprintf(out_str, "%s%s", prefix, an(x_str));
1223 *firstmatch = x_str;
1226 found += append_str(out_str, an(x_str));
1230 /* handle optional boulder symbol as a special case */
1231 if (iflags.bouldersym && sym == iflags.bouldersym) {
1234 *firstmatch = "boulder";
1236 *firstmatch = "
\8aâ";
1237 Sprintf(out_str, "%s%s", prefix, an(*firstmatch));
1241 found += append_str(out_str, "boulder");
1243 found += append_str(out_str, "
\8aâ");
1248 * If we are looking at the screen, follow multiple possibilities or
1249 * an ambiguous explanation by something more detailed.
1254 Sprintf(out_str, "%s", "That can be many things");
1256 Sprintf(out_str, "%s", "
\82±
\82±
\82É
\82Í
\91½
\82
\82Ì
\82à
\82Ì
\82ª
\82 \82é");
1260 if (found > 1 || need_to_look) {
1262 char temp_buf[BUFSZ];
1264 (void) lookat(cc.x, cc.y, look_buf, monbuf);
1265 *firstmatch = look_buf;
1266 if (*(*firstmatch)) {
1267 Sprintf(temp_buf, " (%s)", *firstmatch);
1268 (void) strncat(out_str, temp_buf,
1269 BUFSZ - strlen(out_str) - 1);
1270 found = 1; /* we have something to look up */
1274 Sprintf(temp_buf, " [seen: %s]", monbuf);
1276 Sprintf(temp_buf, " [
\8e\8b\8ao: %s]", monbuf);
1277 (void) strncat(out_str, temp_buf,
1278 BUFSZ - strlen(out_str) - 1);
1286 /* also used by getpos hack in do_name.c */
1288 const char what_is_an_unknown_object[] = "an unknown object";
1290 const char what_is_an_unknown_object[] = "
\93ä
\82Ì
\95¨
\91Ì";
1293 do_look(mode, click_cc)
1297 boolean quick = (mode == 1); /* use cursor; don't search for "more info" */
1298 boolean clicklook = (mode == 2); /* right mouse-click method */
1299 char out_str[BUFSZ] = DUMMY;
1300 const char *firstmatch = 0;
1301 struct permonst *pm = 0;
1302 int i = '\0', ans = 0;
1303 int sym; /* typed symbol or converted glyph */
1304 int found; /* count of matching syms found */
1305 coord cc; /* screen pos of unknown glyph */
1306 boolean save_verbose; /* saved value of flags.verbose */
1307 boolean from_screen; /* question from the screen */
1311 from_screen = TRUE; /* yes, we want to use the cursor */
1314 menu_item *pick_list = (menu_item *) 0;
1319 win = create_nhwindow(NHW_MENU);
1322 /* 'y' and 'n' to keep backwards compatibility with previous
1323 versions: "Specify unknown object by cursor?" */
1324 add_menu(win, NO_GLYPH, &any,
1325 flags.lootabc ? 0 : any.a_char, 'y', ATR_NONE,
1327 "something on the map", MENU_UNSELECTED);
1329 "
\92n
\90}
\8fã
\82É
\82 \82é
\82à
\82Ì", MENU_UNSELECTED);
1331 add_menu(win, NO_GLYPH, &any,
1332 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1334 "something you're carrying", MENU_UNSELECTED);
1336 "
\82 \82È
\82½
\82ª
\8e\9d\82Á
\82Ä
\82¢
\82é
\82à
\82Ì", MENU_UNSELECTED);
1338 add_menu(win, NO_GLYPH, &any,
1339 flags.lootabc ? 0 : any.a_char, 'n', ATR_NONE,
1341 "something else (by symbol or name)", MENU_UNSELECTED);
1343 "
\82»
\82ê
\88È
\8aO(
\83V
\83\93\83{
\83\8b\82©
\96¼
\91O
\82Å
\8ew
\92è)", MENU_UNSELECTED);
1344 if (!u.uswallow && !Hallucination) {
1346 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
1347 "", MENU_UNSELECTED);
1348 /* these options work sensibly for the swallowed case,
1349 but there's no reason for the player to use them then;
1350 objects work fine when hallucinating, but screen
1351 symbol/monster class letter doesn't match up with
1352 bogus monster type, so suppress when hallucinating */
1354 add_menu(win, NO_GLYPH, &any,
1355 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1357 "nearby monsters", MENU_UNSELECTED);
1359 "
\8bß
\82
\82É
\82¢
\82é
\89ö
\95¨", MENU_UNSELECTED);
1361 add_menu(win, NO_GLYPH, &any,
1362 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1364 "all monsters shown on map", MENU_UNSELECTED);
1366 "
\92n
\90}
\8fã
\82É
\82¢
\82é
\91S
\82Ä
\82Ì
\89ö
\95¨", MENU_UNSELECTED);
1368 add_menu(win, NO_GLYPH, &any,
1369 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1371 "nearby objects", MENU_UNSELECTED);
1373 "
\8bß
\82
\82É
\82 \82é
\82à
\82Ì", MENU_UNSELECTED);
1375 add_menu(win, NO_GLYPH, &any,
1376 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1378 "all objects shown on map", MENU_UNSELECTED);
1380 "
\92n
\90}
\8fã
\82É
\82 \82é
\91S
\82Ä
\82Ì
\82à
\82Ì", MENU_UNSELECTED);
1383 end_menu(win, "What do you want to look at:");
1385 end_menu(win, "
\89½
\82ð
\8c©
\82é
\81H");
1386 if (select_menu(win, PICK_ONE, &pick_list) > 0) {
1387 i = pick_list->item.a_char;
1388 free((genericptr_t) pick_list);
1390 destroy_nhwindow(win);
1409 invlet = display_inventory((const char *) 0, TRUE);
1410 if (!invlet || invlet == '\033')
1413 for (invobj = invent; invobj; invobj = invobj->nobj)
1414 if (invobj->invlet == invlet) {
1415 strcpy(out_str, singular(invobj, xname));
1419 checkfile(out_str, pm, TRUE, TRUE);
1423 from_screen = FALSE;
1425 getlin("Specify what? (type the word)", out_str);
1427 getlin("
\89½
\82ð
\92²
\82×
\82é
\81H(
\95¶
\8e\9a\82ð
\93ü
\82ê
\82Ä
\82Ë)", out_str);
1428 if (strcmp(out_str, " ")) /* keep single space as-is */
1429 /* remove leading and trailing whitespace and
1430 condense consecutive internal whitespace */
1431 mungspaces(out_str);
1432 if (out_str[0] == '\0' || out_str[0] == '\033')
1435 if (out_str[1]) { /* user typed in a complete string */
1436 checkfile(out_str, pm, TRUE, TRUE);
1442 look_all(TRUE, TRUE); /* list nearby monsters */
1445 look_all(FALSE, TRUE); /* list all monsters */
1448 look_all(TRUE, FALSE); /* list nearby objects */
1451 look_all(FALSE, FALSE); /* list all objects */
1454 } else { /* clicklook */
1458 from_screen = FALSE;
1461 /* Save the verbose flag, we change it later. */
1462 save_verbose = flags.verbose;
1463 flags.verbose = flags.verbose && !quick;
1465 * The user typed one letter, or we're identifying from the screen.
1468 /* Reset some variables. */
1469 pm = (struct permonst *) 0;
1473 if (from_screen || clicklook) {
1477 pline("Please move the cursor to %s.",
1478 what_is_an_unknown_object);
1480 pline("
\83J
\81[
\83\
\83\8b\82ð
\95¨
\91Ì
\82É
\88Ú
\93®
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D");
1484 pline("Pick an object.");
1486 pline("
\95¨
\91Ì
\82ð
\8ew
\92è
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D");
1488 ans = getpos(&cc, quick, what_is_an_unknown_object);
1489 if (ans < 0 || cc.x < 0)
1491 flags.verbose = FALSE; /* only print long question once */
1495 found = do_screen_description(cc, (from_screen || clicklook), sym,
1496 out_str, &firstmatch);
1498 /* Finally, print out our explanation. */
1500 /* use putmixed() because there may be an encoded glyph present */
1501 putmixed(WIN_MESSAGE, 0, out_str);
1503 /* check the data file for information about this thing */
1504 if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE
1505 && (ans == LOOK_VERBOSE || (flags.help && !quick))
1507 char temp_buf[BUFSZ];
1509 Strcpy(temp_buf, firstmatch);
1510 checkfile(temp_buf, pm, FALSE,
1511 (boolean) (ans == LOOK_VERBOSE));
1515 pline("I've never heard of such things.");
1517 pline("
\82»
\82ñ
\82È
\96¼
\91O
\82Í
\95·
\82¢
\82½
\82±
\82Æ
\82ª
\82È
\82¢
\81D");
1520 } while (from_screen && !quick && ans != LOOK_ONCE && !clicklook);
1522 flags.verbose = save_verbose;
1527 look_all(nearby, do_mons)
1528 boolean nearby; /* True => within BOLTLIM, False => entire map */
1529 boolean do_mons; /* True => monsters, False => objects */
1532 int x, y, lo_x, lo_y, hi_x, hi_y, glyph, count = 0;
1533 char lookbuf[BUFSZ], outbuf[BUFSZ];
1535 win = create_nhwindow(NHW_TEXT);
1536 lo_y = nearby ? max(u.uy - BOLT_LIM, 0) : 0;
1537 lo_x = nearby ? max(u.ux - BOLT_LIM, 1) : 1;
1538 hi_y = nearby ? min(u.uy + BOLT_LIM, ROWNO - 1) : ROWNO - 1;
1539 hi_x = nearby ? min(u.ux + BOLT_LIM, COLNO - 1) : COLNO - 1;
1540 for (y = lo_y; y <= hi_y; y++) {
1541 for (x = lo_x; x <= hi_x; x++) {
1543 glyph = glyph_at(x, y);
1545 if (glyph_is_monster(glyph)) {
1548 bhitpos.x = x; /* [is this actually necessary?] */
1550 if (x == u.ux && y == u.uy && canspotself()) {
1551 (void) self_lookat(lookbuf);
1553 } else if ((mtmp = m_at(x, y)) != 0) {
1554 look_at_monster(lookbuf, (char *) 0, mtmp, x, y);
1557 } else if (glyph_is_invisible(glyph)) {
1558 /* remembered, unseen, creature */
1559 Strcpy(lookbuf, invisexplain);
1561 } else if (glyph_is_warning(glyph)) {
1562 int warnindx = glyph_to_warning(glyph);
1564 Strcpy(lookbuf, def_warnsyms[warnindx].explanation);
1567 } else { /* !do_mons */
1568 if (glyph_is_object(glyph)) {
1569 look_at_object(lookbuf, x, y, glyph);
1574 char coordbuf[20], which[12], cmode;
1576 cmode = (iflags.getpos_coords != GPCOORDS_NONE)
1577 ? iflags.getpos_coords : GPCOORDS_MAP;
1579 Strcpy(which, do_mons ? "monsters" : "objects");
1581 Sprintf(outbuf, "%s currently shown near %s:",
1583 (cmode != GPCOORDS_COMPASS)
1584 ? coord_desc(u.ux, u.uy, coordbuf, cmode)
1585 : !canspotself() ? "your position" : "you");
1587 Sprintf(outbuf, "All %s currently shown on the map:",
1589 putstr(win, 0, outbuf);
1592 /* prefix: "coords C " where 'C' is mon or obj symbol */
1593 Sprintf(outbuf, (cmode == GPCOORDS_SCREEN) ? "%s "
1594 : (cmode == GPCOORDS_MAP) ? "%8s "
1596 coord_desc(x, y, coordbuf, cmode));
1597 Sprintf(eos(outbuf), "%s ", encglyph(glyph));
1598 /* guard against potential overflow */
1599 lookbuf[sizeof lookbuf - 1 - strlen(outbuf)] = '\0';
1600 Strcat(outbuf, lookbuf);
1601 putmixed(win, 0, outbuf);
1606 display_nhwindow(win, TRUE);
1609 pline("No %s are currently shown %s.",
1610 do_mons ? "monsters" : "objects",
1611 nearby ? "nearby" : "on the map");
1613 pline("
\8d¡
\82Ì
\82Æ
\82±
\82ë%s
\82É%s
\81D",
1614 nearby ? "
\8bß
\82" : "
\92n
\90}
\8fã",
1615 do_mons ? "
\89ö
\95¨
\82Í
\82¢
\82È
\82¢" : "
\82à
\82Ì
\82Í
\82È
\82¢");
1617 destroy_nhwindow(win);
1620 /* the '/' command */
1624 return do_look(0, (coord *) 0);
1627 /* the ';' command */
1631 return do_look(1, (coord *) 0);
1634 /* the '^' command */
1638 register struct trap *trap;
1639 int x, y, tt, glyph;
1646 /* check fake bear trap from confused gold detection */
1647 glyph = glyph_at(x, y);
1648 if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) {
1649 boolean chesttrap = trapped_chest_at(tt, x, y);
1651 if (chesttrap || trapped_door_at(tt, x, y)) {
1652 pline("That is a trapped %s.", chesttrap ? "chest" : "door");
1653 return 0; /* trap ID'd, but no time elapses */
1657 for (trap = ftrap; trap; trap = trap->ntrap)
1658 if (trap->tx == x && trap->ty == y) {
1663 if (u.dz < 0 ? (tt == TRAPDOOR || tt == HOLE)
1669 pline("That is %s%s%s.",
1670 an(defsyms[trap_to_defsym(tt)].explanation),
1675 /* trap doors & spiked pits can't be made by
1676 player, and should be considered at least
1677 as much "set" as "dug" anyway */
1678 : (tt == HOLE || tt == PIT)
1681 !trap->madeby_u ? "" : " by you");
1683 pline("
\82»
\82ê
\82Í%s%s
\82¾
\81D",
1687 ? "
\82 \82È
\82½
\82ª
\92£
\82Á
\82½"
1688 : (tt == HOLE || tt == PIT)
1689 ? "
\82 \82È
\82½
\82ª
\8c@
\82Á
\82½"
1690 : "
\82 \82È
\82½
\82ª
\8ed
\8a|
\82¯
\82½",
1691 defsyms[trap_to_defsym(tt)].explanation);
1696 pline("I can't see a trap there.");
1698 pline("
\82»
\82±
\82É
\82Íã©
\82Í
\82Ý
\82 \82½
\82ç
\82È
\82¢
\81D");
1703 Implements a rudimentary if/elif/else/endif interpretor and use
1704 conditionals in dat/cmdhelp to describe what command each keystroke
1705 currently invokes, so that there isn't a lot of "(debug mode only)"
1706 and "(if number_pad is off)" cluttering the feedback that the user
1707 sees. (The conditionals add quite a bit of clutter to the raw data
1708 but users don't see that. number_pad produces a lot of conditional
1709 commands: basic letters vs digits, 'g' vs 'G' for '5', phone
1710 keypad vs normal layout of digits, and QWERTZ keyboard swap between
1711 y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.)
1713 The interpretor understands
1715 '&? option' for 'if' (also '&? !option'
1716 or '&? option=value[,value2,...]'
1717 or '&? !option=value[,value2,...]'),
1718 '&: option' for 'elif' (with argument variations same as 'if';
1719 any number of instances for each 'if'),
1720 '&:' for 'else' (also '&: #comment';
1721 0 or 1 instance for a given 'if'), and
1722 '&.' for 'endif' (also '&. #comment'; required for each 'if').
1724 The option handling is a bit of a mess, with no generality for
1725 which options to deal with and only a comma separated list of
1726 integer values for the '=value' part. number_pad is the only
1727 supported option that has a value; the few others (wizard/debug,
1728 rest_on_space, #if SHELL, #if SUSPEND) are booleans.
1735 char *p, buf[BUFSZ];
1736 winid tmpwin = create_nhwindow(NHW_TEXT);
1738 fp = dlb_fopen(KEYHELP, "r");
1741 pline("Cannot open \"%s\" data file!", KEYHELP);
1743 pline("
\83f
\81[
\83^
\83t
\83@
\83C
\83\8b\"%s\"
\82ð
\8aJ
\82¯
\82È
\82¢
\81I", KEYHELP);
1744 display_nhwindow(WIN_MESSAGE, TRUE);
1747 while (dlb_fgets(buf, (int) sizeof buf, fp)) {
1750 for (p = buf; *p; p++)
1751 if (*p != ' ' && *p != '\t')
1753 putstr(tmpwin, 0, p);
1755 (void) dlb_fclose(fp);
1756 display_nhwindow(tmpwin, TRUE);
1757 destroy_nhwindow(tmpwin);
1761 #define WD_STACKLIMIT 5
1762 struct wd_stack_frame {
1763 Bitfield(active, 1);
1764 Bitfield(been_true, 1);
1765 Bitfield(else_seen, 1);
1768 STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
1772 whatdoes_cond(buf, stack, depth, lnum)
1774 struct wd_stack_frame *stack;
1777 const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
1778 boolean newcond, neg, gotopt;
1779 char *p, *q, act = buf[1];
1782 newcond = (act == '?' || !stack[*depth].been_true);
1785 if (act == '#' || *buf == '#' || !*buf || !newcond) {
1786 gotopt = (*buf && *buf != '#');
1788 neg = FALSE; /* lint suppression */
1792 if ((neg = (*buf == '!')) != 0)
1795 p = index(buf, '='), q = index(buf, ':');
1796 if (!p || (q && q < p))
1798 if (p) { /* we have a value specified */
1799 /* handle a space before or after (or both) '=' (or ':') */
1800 if (p > buf && p[-1] == ' ')
1801 p[-1] = '\0'; /* end of keyword in buf[] */
1802 *p++ = '\0'; /* terminate keyword, advance to start of value */
1807 if (*buf && (act == '?' || act == ':')) {
1808 if (!strcmpi(buf, "number_pad")) {
1810 newcond = iflags.num_pad;
1812 /* convert internal encoding (separate yes/no and 0..3)
1813 back to user-visible one (-1..4) */
1814 np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
1815 : (-1 * iflags.num_pad_mode); /* -1..0 */
1821 if (atoi(p) == np) {
1827 } else if (!strcmpi(buf, "rest_on_space")) {
1828 newcond = flags.rest_on_space;
1829 } else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
1830 newcond = flags.debug; /* == wizard */
1831 } else if (!strcmpi(buf, "shell")) {
1833 /* should we also check sysopt.shellers? */
1838 } else if (!strcmpi(buf, "suspend")) {
1840 /* sysopt.shellers is also used for dosuspend()... */
1847 "cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
1851 /* this works for number_pad too: &? !number_pad:-1,0
1852 would be true for 1..4 after negation */
1858 case '#': /* comment */
1860 case '.': /* endif */
1862 impossible(badstackfmt, '.', lnum);
1866 case ':': /* else or elif */
1867 if (*depth == 0 || stack[*depth].else_seen) {
1868 impossible(badstackfmt, ':', lnum);
1869 *depth = 1; /* so that stack[*depth - 1] is a valid access */
1871 if (stack[*depth].active || stack[*depth].been_true
1872 || !stack[*depth - 1].active)
1873 stack[*depth].active = 0;
1875 stack[*depth].active = stack[*depth].been_true = 1;
1877 stack[*depth].else_seen = 1;
1880 if (++*depth >= WD_STACKLIMIT) {
1881 impossible(badstackfmt, '?', lnum);
1882 *depth = WD_STACKLIMIT - 1;
1884 stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
1885 stack[*depth].been_true = stack[*depth].active;
1886 stack[*depth].else_seen = 0;
1889 return stack[*depth].active ? TRUE : FALSE;
1894 dowhatdoes_core(q, cbuf)
1901 struct wd_stack_frame stack[WD_STACKLIMIT];
1903 int ctrl, meta, depth = 0, lnum = 0;
1905 const char *ec_desc;
1907 if ((ec_desc = key2extcmddesc(q)) != NULL) {
1908 char keybuf[QBUFSZ];
1910 Sprintf(buf, "%-8s%s.", key2txt(q, keybuf), ec_desc);
1916 fp = dlb_fopen(CMDHELPFILE, "r");
1918 pline("Cannot open \"%s\" data file!", CMDHELPFILE);
1922 meta = (0x80 & (uchar) q) != 0;
1925 ctrl = (0x1f & (uchar) q) == (uchar) q;
1927 q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
1931 (void) memset((genericptr_t) stack, 0, sizeof stack);
1932 cond = stack[0].active = 1;
1933 while (dlb_fgets(buf, sizeof buf, fp)) {
1935 if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
1936 cond = whatdoes_cond(buf, stack, &depth, lnum);
1941 if (meta ? (buf[0] == 'M' && buf[1] == '-'
1942 && (ctrl ? buf[2] == '^' && highc(buf[3]) == q
1944 : (ctrl ? buf[0] == '^' && highc(buf[1]) == q
1946 (void) strip_newline(buf);
1947 if (index(buf, '\t'))
1948 (void) tabexpand(buf);
1949 if (meta && ctrl && buf[4] == ' ') {
1950 (void) strncpy(buf, "M-^? ", 8);
1952 } else if (meta && buf[3] == ' ') {
1953 (void) strncpy(buf, "M-? ", 8);
1955 } else if (ctrl && buf[2] == ' ') {
1956 (void) strncpy(buf, "^? ", 8);
1958 } else if (buf[1] == ' ') {
1959 (void) strncpy(buf, "? ", 8);
1962 (void) dlb_fclose(fp);
1967 (void) dlb_fclose(fp);
1969 impossible("cmdhelp: mismatched &? &: &. conditionals.");
1977 static boolean once = FALSE;
1982 pline("Ask about '&' or '?' to get more info.%s",
1984 iflags.altmeta ? " (For ESC, type it twice.)" :
1989 #if defined(UNIX) || defined(VMS)
1990 introff(); /* disables ^C but not ^\ */
1993 q = yn_function("What command?", (char *) 0, '\0');
1995 q = yn_function("
\82Ç
\82¤
\82¢
\82¤
\83R
\83}
\83\93\83h
\81H", (char *) 0, '\0');
1997 if (q == '\033' && iflags.altmeta) {
1998 /* in an ideal world, we would know whether another keystroke
1999 was already pending, but this is not an ideal world...
2000 if user typed ESC, we'll essentially hang until another
2001 character is typed */
2002 q = yn_function("]", (char *) 0, '\0');
2004 q = (char) ((uchar) q | 0200);
2007 #if defined(UNIX) || defined(VMS)
2008 intron(); /* reenables ^C */
2010 reslt = dowhatdoes_core(q, bufr);
2012 if (q == '&' || q == '?')
2017 pline("No such command '%s', char code %d (0%03o or 0x%02x).",
2018 visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2020 pline("
\82»
\82ñ
\82È
\83R
\83}
\83\93\83h'%s'
\81C
\95¶
\8e\9a\83R
\81[
\83h%d(0%03o
\82Ü
\82½
\82Í 0x%02x)
\82Í
\82È
\82¢
\81D",
2021 visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2030 winid cwin = create_nhwindow(NHW_TEXT);
2033 if (sysopt.support) {
2034 /*XXX overflow possibilities*/
2035 Sprintf(buf, "To contact local support, %s", sysopt.support);
2036 putstr(cwin, 0, buf);
2037 putstr(cwin, 0, "");
2038 } else if (sysopt.fmtd_wizard_list) { /* formatted SYSCF WIZARDS */
2039 Sprintf(buf, "To contact local support, contact %s.",
2040 sysopt.fmtd_wizard_list);
2041 putstr(cwin, 0, buf);
2042 putstr(cwin, 0, "");
2044 putstr(cwin, 0, "To contact the NetHack development team directly,");
2045 /*XXX overflow possibilities*/
2046 Sprintf(buf, "see the 'Contact' form on our website or email <%s>.",
2048 putstr(cwin, 0, buf);
2049 putstr(cwin, 0, "");
2050 putstr(cwin, 0, "For more information on NetHack, or to report a bug,");
2051 Sprintf(buf, "visit our website \"%s\".", DEVTEAM_URL);
2052 putstr(cwin, 0, buf);
2053 display_nhwindow(cwin, FALSE);
2054 destroy_nhwindow(cwin);
2060 display_file(HELP, TRUE);
2066 display_file(SHELP, TRUE);
2070 dispfile_optionfile()
2072 display_file(OPTIONFILE, TRUE);
2078 display_file(LICENSE, TRUE);
2082 dispfile_debughelp()
2084 display_file(DEBUGHELP, TRUE);
2088 hmenu_doextversion()
2090 (void) doextversion();
2108 (void) dowhatdoes();
2120 winid cwin = create_nhwindow(NHW_TEXT);
2121 show_menu_controls(cwin, FALSE);
2122 display_nhwindow(cwin, FALSE);
2123 destroy_nhwindow(cwin);
2126 /* data for dohelp() */
2130 } help_menu_items[] = {
2132 { hmenu_doextversion, "About NetHack (version information)." },
2134 { hmenu_doextversion, "NetHack
\82É
\82Â
\82¢
\82Ä(
\83o
\81[
\83W
\83\87\83\93\8fî
\95ñ)" },
2136 { dispfile_help, "Long description of the game and commands." },
2138 { dispfile_help, "
\83Q
\81[
\83\80\82¨
\82æ
\82Ñ
\83R
\83}
\83\93\83h
\82Ì
\89ð
\90à(
\92·
\95¶)" },
2140 { dispfile_shelp, "List of game commands." },
2142 { dispfile_shelp, "
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2144 { hmenu_dohistory, "Concise history of NetHack." },
2146 { hmenu_dohistory, "NetHack
\82Ì
\8aÈ
\92P
\82È
\97ð
\8ej" },
2148 { hmenu_dowhatis, "Info on a character in the game display." },
2150 { hmenu_dowhatis, "
\89æ
\96Ê
\82É
\95\
\8e¦
\82³
\82ê
\82é
\95¶
\8e\9a\82Ì
\90à
\96¾" },
2152 { hmenu_dowhatdoes, "Info on what a given key does." },
2154 { hmenu_dowhatdoes, "
\82±
\82Ì
\83L
\81[
\82ª
\89½
\82ð
\88Ó
\96¡
\82·
\82é
\82©
\82Ì
\90à
\96¾" },
2156 { option_help, "List of game options." },
2158 { option_help, "
\83Q
\81[
\83\80\82Ì
\83I
\83v
\83V
\83\87\83\93\88ê
\97\97" },
2160 { dispfile_optionfile, "Longer explanation of game options." },
2162 { dispfile_optionfile, "
\83Q
\81[
\83\80\82Ì
\83I
\83v
\83V
\83\87\83\93\88ê
\97\97(
\92·
\95¶)" },
2164 { dokeylist, "Full list of keyboard commands" },
2166 { dokeylist, "
\83L
\81[
\83{
\81[
\83h
\83R
\83}
\83\93\83h
\82Ì
\8a®
\91S
\82È
\88ê
\97\97" },
2168 { hmenu_doextlist, "List of extended commands." },
2170 { hmenu_doextlist, "
\8ag
\92£
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2172 { domenucontrols, "List menu control keys" },
2174 { domenucontrols, "
\83\81\83j
\83\85\81[
\90§
\8cä
\83L
\81[
\88ê
\97\97s" },
2176 { dispfile_license, "The NetHack license." },
2178 { dispfile_license, "NetHack
\82Ì
\83\89\83C
\83Z
\83\93\83X" },
2180 { docontact, "Support information." },
2182 { docontact, "
\83T
\83|
\81[
\83g
\8fî
\95ñ" },
2185 { port_help, "%s-specific help and commands." },
2187 { port_help, "%s
\82É
\93Á
\97L
\82Ì
\83w
\83\8b\83v
\82Æ
\83R
\83}
\83\93\83h" },
2190 { dispfile_debughelp, "List of wizard-mode commands." },
2192 { dispfile_debughelp, "
\83E
\83B
\83U
\81[
\83h
\83\82\81[
\83h
\82Ì
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2193 { NULL, (char *) 0 }
2196 /* the '?' command */
2200 winid tmpwin = create_nhwindow(NHW_MENU);
2201 char helpbuf[QBUFSZ];
2203 menu_item *selected;
2208 any = zeroany; /* zero all bits */
2211 for (i = 0; help_menu_items[i].text; i++) {
2212 if (!wizard && help_menu_items[i].f == dispfile_debughelp)
2214 if (help_menu_items[i].text[0] == '%') {
2215 Sprintf(helpbuf, help_menu_items[i].text, PORT_ID);
2218 bufptr = (char *)help_menu_items[i].text;
2221 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
2222 bufptr, MENU_UNSELECTED);
2225 end_menu(tmpwin, "Select one item:");
2227 end_menu(tmpwin, "
\91I
\82ñ
\82Å
\82
\82¾
\82³
\82¢
\81F");
2228 n = select_menu(tmpwin, PICK_ONE, &selected);
2229 destroy_nhwindow(tmpwin);
2231 sel = selected[0].item.a_int - 1;
2232 free((genericptr_t) selected);
2233 (void)(*help_menu_items[sel].f)();
2238 /* the 'V' command; also a choice for '?' */
2242 display_file(HISTORY, TRUE);