1 /* NetHack 3.6 pager.c $NHDT-Date: 1555627307 2019/04/18 22:41:47 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.151 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019 */
9 /* JNetHack may be freely redistributed. See license for details. */
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, char *));
25 STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P));
26 STATIC_DCL void FDECL(do_supplemental_info, (char *, struct permonst *,
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);
41 extern void NDECL(port_help);
44 /* Returns "true" for characters that could represent a monster's stomach. */
51 for (i = S_sw_tl; i <= S_sw_br; i++)
52 if ((int) showsyms[i] == c)
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.
63 append_str(buf, new_str)
67 int space_left; /* space remaining in buf */
69 if (strstri(buf, new_str))
72 space_left = BUFSZ - strlen(buf) - 1;
76 (void) strncat(buf, " or ", space_left);
77 (void) strncat(buf, new_str, space_left - 4);
79 (void) strncat(buf, "
\82Ü
\82½
\82Í", space_left);
80 (void) strncat(buf, new_str, space_left - 6);
85 /* shared by monster probing (via query_objlist!) as well as lookat() */
92 /* include race with role unless polymorphed */
96 Sprintf(race, "%s ", urace.adj);
98 Sprintf(race, "%s", urace.adj);
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);
105 Sprintf(outbuf, "%s%s%s
\82Æ
\82¢
\82¤
\96¼
\82Ì%s",
106 (Invis && (senseself() || !Blind)) ? "
\8ep
\82Ì
\8c©
\82¦
\82È
\82¢" : "", race,
108 mons[u.umonnum].mname);
112 Sprintf(eos(outbuf), ", mounted on %s", y_monnam(u.usteed));
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));
120 /* describe a hidden monster; used for look_at during extended monster
121 detection and for probing; also when looking at self */
123 mhidden_description(mon, altmon, outbuf)
125 boolean altmon; /* for probing: if mimicking a monster, say so */
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
134 char suffixbuf[QBUFSZ];
141 if (M_AP_TYPE(mon) == M_AP_FURNITURE
142 || M_AP_TYPE(mon) == M_AP_OBJECT) {
144 Strcpy(outbuf, ", mimicking ");
145 #else /*
\8cã
\82Å
\92Ç
\89Á
\82·
\82é*/
146 Strcpy(suffixbuf, "
\82Ì
\82Ó
\82è
\82ð
\82µ
\82Ä
\82¢
\82é");
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)) {
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));
160 otmp->where = OBJ_FREE; /* object_from_map set to OBJ_FLOOR */
164 Strcat(outbuf, something);
167 Strcat(outbuf, suffixbuf);
169 } else if (M_AP_TYPE(mon) == M_AP_MONSTER) {
172 Sprintf(outbuf, ", masquerading as %s",
173 an(mons[mon->mappearance].mname));
175 Sprintf(outbuf, "%s
\82É
\82È
\82è
\82·
\82Ü
\82µ
\82Ä
\82¢
\82é",
176 mons[mon->mappearance].mname);
178 } else if (isyou ? u.uundetected : mon->mundetected) {
180 Strcpy(outbuf, ", hiding");
182 Strcpy(suffixbuf, "
\82É
\89B
\82ê
\82Ä
\82¢
\82é");
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 ");
188 /* remembered glyph, not glyph_at() which is 'mon' */
189 if (glyph_is_object(glyph))
191 Strcat(outbuf, something);
192 } else if (is_hider(mon->data)) {
194 Sprintf(eos(outbuf), " on the %s",
195 (is_flyer(mon->data) || mon->data->mlet == S_PIERCER)
197 : surface(x, y)); /* trapper */
199 Sprintf(eos(outbuf), "%s",
200 (is_flyer(mon->data) || mon->data->mlet == S_PIERCER)
202 : surface(x, y)); /* trapper */
205 if (mon->data->mlet == S_EEL && is_pool(x, y))
207 Strcat(outbuf, " in murky water");
209 Strcat(outbuf, "
\82É
\82²
\82Á
\82½
\90\85\82Ì
\92\86");
213 Strcat(outbuf, suffixbuf);
218 /* extracted from lookat(); also used by namefloorobj() */
220 object_from_map(glyph, x, y, obj_p)
224 boolean fakeobj = FALSE, mimic_obj = FALSE;
227 int glyphotyp = glyph_to_obj(glyph);
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)
236 /* there might be a mimic here posing as an object */
238 if (mtmp && is_obj_mappear(mtmp, (unsigned) glyphotyp)) {
244 if (!otmp || otmp->otyp != glyphotyp) {
245 /* this used to exclude STRANGE_OBJECT; now caller deals with it */
246 otmp = mksobj(glyphotyp, FALSE, FALSE);
250 if (otmp->oclass == COIN_CLASS)
251 otmp->quan = 2L; /* to force pluralization */
252 else if (otmp->otyp == SLIME_MOLD)
253 otmp->spe = context.current_fruit; /* give it a type */
254 if (mtmp && has_mcorpsenm(mtmp)) /* mimic as corpse/statue */
255 otmp->corpsenm = MCORPSENM(mtmp);
256 else if (otmp->otyp == CORPSE && glyph_is_body(glyph))
257 otmp->corpsenm = glyph - GLYPH_BODY_OFF;
258 else if (otmp->otyp == STATUE && glyph_is_statue(glyph))
259 otmp->corpsenm = glyph - GLYPH_STATUE_OFF;
260 if (otmp->otyp == LEASH)
262 /* extra fields needed for shop price with doname() formatting */
263 otmp->where = OBJ_FLOOR;
264 otmp->ox = x, otmp->oy = y;
265 otmp->no_charge = (otmp->otyp == STRANGE_OBJECT && costly_spot(x, y));
267 /* if located at adjacent spot, mark it as having been seen up close
268 (corpse type will be known even if dknown is 0, so we don't need a
269 touch check for cockatrice corpse--we're looking without touching) */
270 if (otmp && distu(x, y) <= 2 && !Blind && !Hallucination
271 /* redundant: we only look for an object which matches current
272 glyph among floor and buried objects; when !Blind, any buried
273 object's glyph will have been replaced by whatever is present
274 on the surface as soon as we moved next to its spot */
275 && (fakeobj || otmp->where == OBJ_FLOOR) /* not buried */
276 /* terrain mode views what's already known, doesn't learn new stuff */
277 && !iflags.terrainmode) /* so don't set dknown when in terrain mode */
278 otmp->dknown = 1; /* if a pile, clearly see the top item only */
279 if (fakeobj && mtmp && mimic_obj &&
280 (otmp->dknown || (M_AP_FLAG(mtmp) & M_AP_F_DKNOWN))) {
281 mtmp->m_ap_type |= M_AP_F_DKNOWN;
285 return fakeobj; /* when True, caller needs to dealloc *obj_p */
289 look_at_object(buf, x, y, glyph)
290 char *buf; /* output buffer */
293 struct obj *otmp = 0;
294 boolean fakeobj = object_from_map(glyph, x, y, &otmp);
297 Strcpy(buf, (otmp->otyp != STRANGE_OBJECT)
298 ? distant_name(otmp, otmp->dknown ? doname_with_price
300 : obj_descr[STRANGE_OBJECT].oc_name);
302 otmp->where = OBJ_FREE; /* object_from_map set it to OBJ_FLOOR */
303 dealloc_obj(otmp), otmp = 0;
306 Strcpy(buf, something); /* sanity precaution */
308 if (otmp && otmp->where == OBJ_BURIED)
310 Strcat(buf, " (buried)");
312 Strcat(buf, " (
\96\84\82Ü
\82Á
\82Ä
\82¢
\82é)");
313 else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
315 Strcat(buf, " embedded in stone");
317 Strcat(buf, "
\81C
\8aâ
\82É
\96\84\82ß
\82±
\82Ü
\82ê
\82Ä
\82¢
\82é");
318 else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR)
320 Strcat(buf, " embedded in a wall");
322 Strcat(buf, "
\81C
\95Ç
\82É
\96\84\82ß
\82±
\82Ü
\82ê
\82Ä
\82¢
\82é");
323 else if (closed_door(x, y))
325 Strcat(buf, " embedded in a door");
327 Strcat(buf, "
\81C
\94à
\82É
\96\84\82ß
\82±
\82Ü
\82ê
\82Ä
\82¢
\82é");
328 else if (is_pool(x, y))
329 /*JP 3.4.3
\82±
\82Ì
\95\94\95ª
\82Í
\95¨
\91Ì
\82É
\82µ
\82©
\8eg
\82í
\82ê
\82È
\82¢ */
331 Strcat(buf, " in water");
333 Strcat(buf, "
\81C
\90\85\92\86\82É
\82 \82é");
334 else if (is_lava(x, y))
336 Strcat(buf, " in molten lava"); /* [can this ever happen?] */
338 Strcat(buf, "
\81C
\97n
\8aâ
\82Ì
\92\86\82É
\82 \82é"); /* [can this ever happen?] */
344 look_at_monster(buf, monbuf, mtmp, x, y)
345 char *buf, *monbuf; /* buf: output, monbuf: optional output */
349 char *name, monnambuf[BUFSZ];
350 boolean accurate = !Hallucination;
352 name = (mtmp->data == &mons[PM_COYOTE] && accurate)
353 ? coyotename(mtmp, monnambuf)
354 : distant_monnam(mtmp, ARTICLE_NONE, monnambuf);
356 Sprintf(buf, "%s%s%s",
357 (mtmp->mx != x || mtmp->my != y)
358 ? ((mtmp->isshk && accurate) ? "tail of " : "tail of a ")
360 (mtmp->mtame && accurate)
362 : (mtmp->mpeaceful && accurate)
367 Sprintf(buf, "%s%s%s",
368 (mtmp->mtame && accurate)
369 ? "
\8eè
\82È
\82¸
\82¯
\82ç
\82ê
\82½"
370 : (mtmp->mpeaceful && accurate)
374 (mtmp->mx != x || mtmp->my != y)
375 ? ((mtmp->isshk && accurate) ? "
\82Ì
\90K
\94ö" : "
\82Ì
\90K
\94ö")
378 if (u.ustuck == mtmp) {
379 if (u.uswallow || iflags.save_uswallow) /* monster detection */
381 Strcat(buf, is_animal(mtmp->data)
382 ? ", swallowing you" : ", engulfing you");
384 Strcat(buf, ",
\82 \82È
\82½
\82ð
\88ù
\82Ý
\8d\9e\82ñ
\82Å
\82¢
\82é");
387 Strcat(buf, (Upolyd && sticks(youmonst.data))
389 ? ", being held" : ", holding you");
391 ? "
\81C
\82 \82È
\82½
\82ª
\92Í
\82Ü
\82¦
\82Ä
\82¢
\82é" : "
\81C
\82 \82È
\82½
\82ð
\92Í
\82Ü
\82¦
\82Ä
\82¢
\82é");
395 Strcat(buf, ", leashed to you");
397 Strcat(buf, "
\81C
\95R
\82Å
\8c\8b\82Î
\82ê
\82Ä
\82¢
\82é");
399 if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) {
400 struct trap *t = t_at(mtmp->mx, mtmp->my);
401 int tt = t ? t->ttyp : NO_TRAP;
403 /* newsym lets you know of the trap, so mention it here */
404 if (tt == BEAR_TRAP || is_pit(tt) || tt == WEB)
406 Sprintf(eos(buf), ", trapped in %s",
408 Sprintf(eos(buf), ", %s
\82É
\95ß
\82Ü
\82Á
\82Ä
\82¢
\82é",
409 an(defsyms[trap_to_defsym(tt)].explanation));
412 /* we know the hero sees a monster at this location, but if it's shown
413 due to persistant monster detection he might remember something else */
414 if (mtmp->mundetected || M_AP_TYPE(mtmp))
415 mhidden_description(mtmp, FALSE, eos(buf));
418 unsigned how_seen = howmonseen(mtmp);
421 if (how_seen != 0 && how_seen != MONSEEN_NORMAL) {
422 if (how_seen & MONSEEN_NORMAL) {
424 Strcat(monbuf, "normal vision");
426 Strcat(monbuf, "
\92Ê
\8fí
\82Ì
\8e\8b\8ao");
427 how_seen &= ~MONSEEN_NORMAL;
428 /* how_seen can't be 0 yet... */
430 Strcat(monbuf, ", ");
432 if (how_seen & MONSEEN_SEEINVIS) {
434 Strcat(monbuf, "see invisible");
436 Strcat(monbuf, "
\8c©
\82¦
\82È
\82¢
\82à
\82Ì
\82ð
\8c©
\82é
\8e\8b\8ao");
437 how_seen &= ~MONSEEN_SEEINVIS;
439 Strcat(monbuf, ", ");
441 if (how_seen & MONSEEN_INFRAVIS) {
443 Strcat(monbuf, "infravision");
445 Strcat(monbuf, "
\90Ô
\8aO
\90ü
\82ª
\8c©
\82¦
\82é
\8e\8b\8ao");
446 how_seen &= ~MONSEEN_INFRAVIS;
448 Strcat(monbuf, ", ");
450 if (how_seen & MONSEEN_TELEPAT) {
452 Strcat(monbuf, "telepathy");
454 Strcat(monbuf, "
\83e
\83\8c\83p
\83V
\81[");
455 how_seen &= ~MONSEEN_TELEPAT;
457 Strcat(monbuf, ", ");
459 if (how_seen & MONSEEN_XRAYVIS) {
460 /* Eyes of the Overworld */
462 Strcat(monbuf, "astral vision");
464 Strcat(monbuf, "
\90¸
\90_
\82É
\82æ
\82é
\8e\8b\8ao");
465 how_seen &= ~MONSEEN_XRAYVIS;
467 Strcat(monbuf, ", ");
469 if (how_seen & MONSEEN_DETECT) {
471 Strcat(monbuf, "monster detection");
473 Strcat(monbuf, "
\89ö
\95¨
\82ð
\94
\8c©
\82·
\82é
\94\
\97Í");
474 how_seen &= ~MONSEEN_DETECT;
476 Strcat(monbuf, ", ");
478 if (how_seen & MONSEEN_WARNMON) {
481 Strcat(monbuf, "paranoid delusion");
483 Strcat(monbuf, "
\95Î
\8e·
\93I
\96Ï
\91z");
485 unsigned long mW = (context.warntype.obj
486 | context.warntype.polyd),
487 m2 = mtmp->data->mflags2;
489 const char *whom = ((mW & M2_HUMAN & m2) ? "human"
490 : (mW & M2_ELF & m2) ? "elf"
491 : (mW & M2_ORC & m2) ? "orc"
492 : (mW & M2_DEMON & m2) ? "demon"
493 : mtmp->data->mname);
495 const char *whom = ((mW & M2_HUMAN & m2) ? "
\90l
\8aÔ"
496 : (mW & M2_ELF & m2) ? "
\83G
\83\8b\83t"
497 : (mW & M2_ORC & m2) ? "
\83I
\81[
\83N"
498 : (mW & M2_DEMON & m2) ? "
\88«
\96\82"
499 : mtmp->data->mname);
503 Sprintf(eos(monbuf), "warned of %s", makeplural(whom));
505 Sprintf(eos(monbuf), "%s
\82ð
\8cx
\8d\90\82µ
\82Ä
\82¢
\82é", whom);
507 how_seen &= ~MONSEEN_WARNMON;
509 Strcat(monbuf, ", ");
511 /* should have used up all the how_seen bits by now */
513 impossible("lookat: unknown method of seeing monster");
514 Sprintf(eos(monbuf), "(%u)", how_seen);
516 } /* seen by something other than normal vision */
517 } /* monbuf is non-null */
521 * Return the name of the glyph found at (x,y).
522 * If not hallucinating and the glyph is a monster, also monster data.
524 STATIC_OVL struct permonst *
525 lookat(x, y, buf, monbuf)
529 struct monst *mtmp = (struct monst *) 0;
530 struct permonst *pm = (struct permonst *) 0;
533 buf[0] = monbuf[0] = '\0';
534 glyph = glyph_at(x, y);
535 if (u.ux == x && u.uy == y && canspotself()
536 && !(iflags.save_uswallow &&
537 glyph == mon_to_glyph(u.ustuck, rn2_on_display_rng))
538 && (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)) {
540 (void) self_lookat(buf);
542 /* file lookup can't distinguish between "gnomish wizard" monster
543 and correspondingly named player character, always picking the
544 former; force it to find the general "wizard" entry instead */
545 if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd)
546 pm = &mons[PM_WIZARD];
548 /* When you see yourself normally, no explanation is appended
549 (even if you could also see yourself via other means).
550 Sensing self while blind or swallowed is treated as if it
551 were by normal vision (cf canseeself()). */
552 if ((Invisible || u.uundetected) && !Blind
553 && !(u.uswallow || iflags.save_uswallow)) {
565 Sprintf(eos(buf), " [seen: %s%s%s%s%s]",
566 (how & 1) ? "infravision" : "",
567 /* add comma if telep and infrav */
568 ((how & 3) > 2) ? ", " : "",
569 (how & 2) ? "telepathy" : "",
570 /* add comma if detect and (infrav or telep or both) */
571 ((how & 7) > 4) ? ", " : "",
572 (how & 4) ? "monster detection" : "");
574 Sprintf(eos(buf), " [
\8a´
\92m: %s%s%s%s%s]",
575 (how & 1) ? "
\90Ô
\8aO
\90ü" : "",
576 /* add comma if telep and infrav */
577 ((how & 3) > 2) ? ", " : "",
578 (how & 2) ? "
\83e
\83\8c\83p
\83V
\81[" : "",
579 /* add comma if detect and (infrav or telep or both) */
580 ((how & 7) > 4) ? ", " : "",
581 (how & 4) ? "
\89ö
\95¨
\8a´
\92m" : "");
584 } else if (u.uswallow) {
585 /* when swallowed, we're only called for spots adjacent to hero,
586 and blindness doesn't prevent hero from feeling what holds him */
588 Sprintf(buf, "interior of %s", a_monnam(u.ustuck));
590 Sprintf(buf, "%s
\82Ì
\93à
\95\94", a_monnam(u.ustuck));
592 } else if (glyph_is_monster(glyph)) {
595 if ((mtmp = m_at(x, y)) != 0) {
596 look_at_monster(buf, monbuf, mtmp, x, y);
598 } else if (Hallucination) {
599 /* 'monster' must actually be a statue */
600 Strcpy(buf, rndmonnam((char *) 0));
602 } else if (glyph_is_object(glyph)) {
603 look_at_object(buf, x, y, glyph); /* fill in buf[] */
604 } else if (glyph_is_trap(glyph)) {
605 int tnum = what_trap(glyph_to_trap(glyph), rn2_on_display_rng);
607 /* Trap detection displays a bear trap at locations having
608 * a trapped door or trapped container or both.
609 * TODO: we should create actual trap types for doors and
610 * chests so that they can have their own glyphs and tiles.
612 if (trapped_chest_at(tnum, x, y))
614 Strcpy(buf, "trapped chest"); /* might actually be a large box */
616 Strcpy(buf, "ã©
\82Ì
\8ed
\8a|
\82¯
\82ç
\82ê
\82½
\94 "); /* might actually be a large box */
618 else if (trapped_door_at(tnum, x, y))
620 Strcpy(buf, "trapped door"); /* not "trap door"... */
622 Strcpy(buf, "ã©
\82Ì
\8ed
\8a|
\82¯
\82ç
\82ê
\82½
\94à"); /* not "trap door"... */
625 Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
626 } else if (glyph_is_warning(glyph)) {
627 int warnindx = glyph_to_warning(glyph);
629 Strcpy(buf, def_warnsyms[warnindx].explanation);
630 } else if (!glyph_is_cmap(glyph)) {
632 Strcpy(buf, "unexplored area");
634 Strcpy(buf, "
\96¢
\92T
\8dõ
\82Ì
\8fê
\8f\8a");
636 switch (glyph_to_cmap(glyph)) {
639 Sprintf(buf, "%s %saltar",
641 Sprintf(buf, "%s%s
\8dÕ
\92d",
642 /* like endgame high priests, endgame high altars
643 are only recognizable when immediately adjacent */
644 (Is_astralevel(&u.uz) && distu(x, y) > 2)
650 Amask2align(levl[x][y].altarmask & ~AM_SHRINE)),
651 ((levl[x][y].altarmask & AM_SHRINE)
652 && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
660 if (is_drawbridge_wall(x, y) >= 0)
662 Strcpy(buf, "open drawbridge portcullis");
664 Strcpy(buf,"
\8aJ
\82¢
\82Ä
\82¢
\82é
\92µ
\82Ë
\8b´");
665 else if ((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN)
667 Strcpy(buf, "broken door");
669 Strcpy(buf,"
\89ó
\82ê
\82½
\94à");
672 Strcpy(buf, "doorway");
674 Strcpy(buf,"
\8fo
\93ü
\82è
\8cû");
679 Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud");
681 Is_airlevel(&u.uz) ? "
\93Ü
\82Á
\82Ä
\82¢
\82é
\8fê
\8f\8a" : "
\96¶/
\8fö
\8bC
\82Ì
\89_");
684 if (!levl[x][y].seenv) {
686 Strcpy(buf, "unexplored");
688 Strcpy(buf, "
\96¢
\92T
\8dõ");
690 } else if (Underwater && !Is_waterlevel(&u.uz)) {
691 /* "unknown" == previously mapped but not visible when
692 submerged; better terminology appreciated... */
693 Strcpy(buf, (distu(x, y) <= 2) ? "land" : "unknown");
695 } else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) {
697 Strcpy(buf, "stone");
699 Strcpy(buf, "
\8aâ
\94Õ");
704 Strcpy(buf, defsyms[glyph_to_cmap(glyph)].explanation);
708 return (pm && !Hallucination) ? pm : (struct permonst *) 0;
712 * Look in the "data" file for more info. Called if the user typed in the
713 * whole name (user_typed_name == TRUE), or we've found a possible match
714 * with a character/glyph and flags.help is TRUE.
716 * NOTE: when (user_typed_name == FALSE), inp is considered read-only and
717 * must not be changed directly, e.g. via lcase(). We want to force
718 * lcase() for data.base lookup so that we can have a clean key.
719 * Therefore, we create a copy of inp _just_ for data.base lookup.
722 checkfile(inp, pm, user_typed_name, without_asking, supplemental_name)
725 boolean user_typed_name, without_asking;
726 char *supplemental_name;
729 char buf[BUFSZ], newstr[BUFSZ], givenname[BUFSZ];
730 char *ep, *dbase_str;
731 unsigned long txt_offset = 0L;
732 winid datawin = WIN_ERR;
734 fp = dlb_fopen(DATAFILE, "r");
737 pline("Cannot open 'data' file!");
739 pline("
\83f
\81[
\83^
\83t
\83@
\83C
\83\8b\82ð
\8aJ
\82¯
\82È
\82¢
\81I");
742 /* If someone passed us garbage, prevent fault. */
743 if (!inp || strlen(inp) > (BUFSZ - 1)) {
744 impossible("bad do_look buffer passed (%s)!",
745 !inp ? "null" : "too long");
749 /* To prevent the need for entries in data.base like *ngel to account
750 * for Angel and angel, make the lookup string the same for both
751 * user_typed_name and picked name.
753 if (pm != (struct permonst *) 0 && !user_typed_name)
754 dbase_str = strcpy(newstr, pm->mname);
756 dbase_str = strcpy(newstr, inp);
757 (void) lcase(dbase_str);
759 /*JP:TODO:
\83f
\81[
\83^
\83x
\81[
\83X
\8c\9f\8dõ
\82Í
\93®
\82¢
\82Ä
\82¢
\82È
\82¢
\82Ì
\82Å
\97v
\8fC
\90³*/
762 * The switch from xname() to doname_vague_quan() in look_at_obj()
763 * had the unintendded side-effect of making names picked from
764 * pointing at map objects become harder to simplify for lookup.
765 * We should split the prefix and suffix handling used by wish
766 * parsing and also wizmode monster generation out into separate
767 * routines and use those routines here. This currently lacks
768 * erosion handling and probably lots of other bits and pieces
769 * that wishing already understands and most of this duplicates
770 * stuff already done for wish handling or monster generation.
772 if (!strncmp(dbase_str, "interior of ", 12))
774 if (!strncmp(dbase_str, "a ", 2))
776 else if (!strncmp(dbase_str, "an ", 3))
778 else if (!strncmp(dbase_str, "the ", 4))
780 else if (!strncmp(dbase_str, "some ", 5))
782 else if (digit(*dbase_str)) {
783 /* remove count prefix ("2 ya") which can come from looking at map */
784 while (digit(*dbase_str))
786 if (*dbase_str == ' ')
789 if (!strncmp(dbase_str, "pair of ", 8))
791 if (!strncmp(dbase_str, "tame ", 5))
793 else if (!strncmp(dbase_str, "peaceful ", 9))
795 if (!strncmp(dbase_str, "invisible ", 10))
797 if (!strncmp(dbase_str, "saddled ", 8))
799 if (!strncmp(dbase_str, "blessed ", 8))
801 else if (!strncmp(dbase_str, "uncursed ", 9))
803 else if (!strncmp(dbase_str, "cursed ", 7))
805 if (!strncmp(dbase_str, "empty ", 6))
807 if (!strncmp(dbase_str, "partly used ", 12))
809 else if (!strncmp(dbase_str, "partly eaten ", 13))
811 if (!strncmp(dbase_str, "statue of ", 10))
813 else if (!strncmp(dbase_str, "figurine of ", 12))
815 /* remove enchantment ("+0 aklys"); [for 3.6.0 and earlier, this wasn't
816 needed because looking at items on the map used xname() rather than
817 doname() hence known enchantment was implicitly suppressed] */
818 if (*dbase_str && index("+-", dbase_str[0]) && digit(dbase_str[1])) {
819 ++dbase_str; /* skip sign */
820 while (digit(*dbase_str))
822 if (*dbase_str == ' ')
825 /* "towel", "wet towel", and "moist towel" share one data.base entry;
826 for "wet towel", we keep prefix so that the prompt will ask about
827 "wet towel"; for "moist towel", we also want to ask about "wet towel".
828 (note: strncpy() only terminates output string if the specified
829 count is bigger than the length of the substring being copied) */
830 if (!strncmp(dbase_str, "moist towel", 11))
831 (void) strncpy(dbase_str += 2, "wet", 3); /* skip "mo" replace "ist" */
833 /* Make sure the name is non-empty. */
835 long pass1offset = -1L;
836 int chk_skip, pass = 1;
837 boolean yes_to_moreinfo, found_in_file, pass1found_in_file,
839 char *sp, *ap, *alt = 0; /* alternate description */
841 /* adjust the input to remove "named " and "called " */
842 if ((ep = strstri(dbase_str, " named ")) != 0) {
844 if ((ap = strstri(dbase_str, " called ")) != 0 && ap < ep)
845 ep = ap; /* "named" is alt but truncate at "called" */
846 } else if ((ep = strstri(dbase_str, " called ")) != 0) {
847 copynchars(givenname, ep + 8, BUFSZ - 1);
849 if (supplemental_name && (sp = strstri(inp, " called ")) != 0)
850 copynchars(supplemental_name, sp + 8, BUFSZ - 1);
852 ep = strstri(dbase_str, ", ");
853 if (ep && ep > dbase_str)
855 /* remove article from 'alt' name ("a pair of lenses named
856 The Eyes of the Overworld" simplified above to "lenses named
857 The Eyes of the Overworld", now reduced to "The Eyes of the
858 Overworld", skip "The" as with base name processing) */
859 if (alt && (!strncmpi(alt, "a ", 2)
860 || !strncmpi(alt, "an ", 3)
861 || !strncmpi(alt, "the ", 4)))
862 alt = index(alt, ' ') + 1;
863 /* remove charges or "(lit)" or wizmode "(N aum)" */
864 if ((ep = strstri(dbase_str, " (")) != 0 && ep > dbase_str)
866 if (alt && (ap = strstri(alt, " (")) != 0 && ap > alt)
870 * If the object is named, then the name is the alternate description;
871 * otherwise, the result of makesingular() applied to the name is.
872 * This isn't strictly optimal, but named objects of interest to the
873 * user will usually be found under their name, rather than under
874 * their object type, so looking for a singular form is pointless.
877 alt = makesingular(dbase_str);
879 pass1found_in_file = FALSE;
880 for (pass = !strcmp(alt, dbase_str) ? 0 : 1; pass >= 0; --pass) {
881 found_in_file = skipping_entry = FALSE;
883 if (dlb_fseek(fp, txt_offset, SEEK_SET) < 0 ) {
884 impossible("can't get to start of 'data' file");
887 /* skip first record; read second */
888 if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) {
889 impossible("can't read 'data' file");
891 } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1
895 /* look for the appropriate entry */
896 while (dlb_fgets(buf, BUFSZ, fp)) {
898 break; /* we passed last entry without success */
901 /* a number indicates the end of current entry */
902 skipping_entry = FALSE;
903 } else if (!skipping_entry) {
904 if (!(ep = index(buf, '\n')))
906 (void) strip_newline((ep > buf) ? ep - 1 : ep);
907 /* if we match a key that begins with "~", skip
909 chk_skip = (*buf == '~') ? 1 : 0;
910 if ((pass == 0 && pmatch(&buf[chk_skip], dbase_str))
911 || (pass == 1 && alt && pmatch(&buf[chk_skip], alt))) {
913 skipping_entry = TRUE;
916 found_in_file = TRUE;
918 pass1found_in_file = TRUE;
925 long entry_offset, fseekoffset;
929 /* skip over other possible matches for the info */
931 if (!dlb_fgets(buf, BUFSZ, fp))
933 } while (!digit(*buf));
934 if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2)
936 fseekoffset = (long) txt_offset + entry_offset;
938 pass1offset = fseekoffset;
939 else if (fseekoffset == pass1offset)
942 yes_to_moreinfo = FALSE;
943 if (!user_typed_name && !without_asking) {
944 char *entrytext = pass ? alt : dbase_str;
945 char question[QBUFSZ];
948 Strcpy(question, "More info about \"");
949 /* +2 => length of "\"?" */
950 copynchars(eos(question), entrytext,
951 (int) (sizeof question - 1
952 - (strlen(question) + 2)));
953 Strcat(question, "\"?");
955 Strcpy(question, "
\81u");
956 /* +16 => "
\81v
\82Ì
\8fÚ
\8d×
\82ð
\8c©
\82é
\81H"
\82Ì
\92·
\82³ */
957 copynchars(eos(question), entrytext,
958 (int) (sizeof question - 1
959 - (strlen(question) + 16)));
960 Strcat(question, "
\81v
\82Ì
\8fÚ
\8d×
\82ð
\8c©
\82é
\81H");
962 if (yn(question) == 'y')
963 yes_to_moreinfo = TRUE;
966 if (user_typed_name || without_asking || yes_to_moreinfo) {
967 if (dlb_fseek(fp, fseekoffset, SEEK_SET) < 0) {
969 pline("? Seek error on 'data' file!");
971 pline("'data'
\83t
\83@
\83C
\83\8b\82Ì
\83V
\81[
\83N
\83G
\83\89\81[
\81I");
974 datawin = create_nhwindow(NHW_MENU);
975 for (i = 0; i < entry_count; i++) {
976 if (!dlb_fgets(buf, BUFSZ, fp))
978 (void) strip_newline(buf);
979 if (index(buf + 1, '\t') != 0)
980 (void) tabexpand(buf + 1);
981 putstr(datawin, 0, buf + 1);
983 display_nhwindow(datawin, FALSE);
984 destroy_nhwindow(datawin), datawin = WIN_ERR;
986 } else if (user_typed_name && pass == 0 && !pass1found_in_file)
988 pline("I don't have any information on those things.");
990 pline("
\82»
\82ñ
\82È
\96¼
\91O
\82Í
\95·
\82¢
\82½
\82±
\82Æ
\82ª
\82È
\82¢
\81D");
993 goto checkfile_done; /* skip error feedback */
996 impossible("'data' file in wrong format or corrupted");
998 if (datawin != WIN_ERR)
999 destroy_nhwindow(datawin);
1000 (void) dlb_fclose(fp);
1005 do_screen_description(cc, looked, sym, out_str, firstmatch, for_supplement)
1010 const char **firstmatch;
1011 struct permonst **for_supplement;
1014 static const char mon_interior[] = "the interior of a monster",
1016 static const char mon_interior[] = "
\89ö
\95¨
\82Ì
\93à
\95\94",
1018 unreconnoitered[] = "unreconnoitered";
1020 unreconnoitered[] = "
\96¢
\8aÏ
\8e@";
1021 static char look_buf[BUFSZ];
1023 int i, alt_i, glyph = NO_GLYPH,
1024 skipped_venom = 0, found = 0; /* count of matching syms found */
1025 boolean hit_trap, need_to_look = FALSE,
1026 submerged = (Underwater && !Is_waterlevel(&u.uz));
1033 glyph = glyph_at(cc.x, cc.y);
1034 /* Convert glyph at selected position to a symbol for use below. */
1035 (void) mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y);
1037 Sprintf(prefix, "%s ", encglyph(glyph));
1039 Sprintf(prefix, "%c ", sym);
1042 * Check all the possibilities, saving all explanations in a buffer.
1043 * When all have been checked then the string is printed.
1047 * Handle restricted vision range (limited to adjacent spots when
1048 * swallowed or underwater) cases first.
1050 * 3.6.0 listed anywhere on map, other than self, as "interior
1051 * of a monster" when swallowed, and non-adjacent water or
1052 * non-water anywhere as "dark part of a room" when underwater.
1053 * "unreconnoitered" is an attempt to convey "even if you knew
1054 * what was there earlier, you don't know what is there in the
1055 * current circumstance".
1057 * (Note: 'self' will always be visible when swallowed so we don't
1058 * need special swallow handling for <ux,uy>.
1059 * Another note: for '#terrain' without monsters, u.uswallow and
1060 * submerged will always both be False and skip this code.)
1064 ; /* skip special handling */
1065 } else if (((u.uswallow || submerged) && distu(cc.x, cc.y) > 2)
1066 /* detection showing some category, so mostly background */
1067 || ((iflags.terrainmode & (TER_DETECT | TER_MAP)) == TER_DETECT
1068 && glyph == cmap_to_glyph(S_stone))) {
1069 x_str = unreconnoitered;
1070 need_to_look = FALSE;
1071 } else if (is_swallow_sym(sym)) {
1072 x_str = mon_interior;
1073 need_to_look = TRUE; /* for specific monster type */
1076 /* we know 'found' is zero here, but guard against some other
1077 special case being inserted ahead of us someday */
1079 Sprintf(out_str, "%s%s", prefix, x_str);
1080 *firstmatch = x_str;
1083 found += append_str(out_str, x_str); /* not 'an(x_str)' */
1085 /* for is_swallow_sym(), we want to list the current symbol's
1086 other possibilities (wand for '/', throne for '\\', &c) so
1087 don't jump to the end for the x_str==mon_interior case */
1088 if (x_str == unreconnoitered)
1092 /* Check for monsters */
1093 if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
1094 for (i = 1; i < MAXMCLASSES; i++) {
1095 if (sym == (looked ? showsyms[i + SYM_OFF_M] : def_monsyms[i].sym)
1096 && def_monsyms[i].explain && *def_monsyms[i].explain) {
1097 need_to_look = TRUE;
1099 Sprintf(out_str, "%s%s",
1100 prefix, an(def_monsyms[i].explain));
1101 *firstmatch = def_monsyms[i].explain;
1104 found += append_str(out_str, an(def_monsyms[i].explain));
1108 /* handle '@' as a special case if it refers to you and you're
1109 playing a character which isn't normally displayed by that
1110 symbol; firstmatch is assumed to already be set for '@' */
1111 if ((looked ? (sym == showsyms[S_HUMAN + SYM_OFF_M]
1112 && cc.x == u.ux && cc.y == u.uy)
1113 : (sym == def_monsyms[S_HUMAN].sym && !flags.showrace))
1114 && !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
1116 found += append_str(out_str, "you"); /* tack on "or you" */
1118 found += append_str(out_str, "
\82 \82È
\82½"); /* tack on "or you" */
1122 /* Now check for objects */
1123 if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
1124 for (i = 1; i < MAXOCLASSES; i++) {
1125 if (sym == (looked ? showsyms[i + SYM_OFF_O]
1126 : def_oc_syms[i].sym)
1127 || (looked && i == ROCK_CLASS && glyph_is_statue(glyph))) {
1128 need_to_look = TRUE;
1129 if (looked && i == VENOM_CLASS) {
1134 Sprintf(out_str, "%s%s",
1135 prefix, an(def_oc_syms[i].explain));
1136 *firstmatch = def_oc_syms[i].explain;
1139 found += append_str(out_str, an(def_oc_syms[i].explain));
1145 if (sym == DEF_INVISIBLE) {
1146 extern const char altinvisexplain[]; /* drawing.c */
1147 /* for active clairvoyance, use alternate "unseen creature" */
1148 boolean usealt = (EDetect_monsters & I_SPECIAL) != 0L;
1149 const char *unseen_explain = !usealt ? invisexplain : altinvisexplain;
1152 Sprintf(out_str, "%s%s", prefix, an(unseen_explain));
1153 *firstmatch = unseen_explain;
1156 found += append_str(out_str, an(unseen_explain));
1160 /* Now check for graphics symbols */
1161 alt_i = (sym == (looked ? showsyms[0] : defsyms[0].sym)) ? 0 : (2 + 1);
1162 for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
1163 /* when sym is the default background character, we process
1164 i == 0 three times: unexplored, stone, dark part of a room */
1167 x_str = !alt_i++ ? "unexplored" : submerged ? "unknown" : "stone";
1169 x_str = !alt_i++ ? "
\96¢
\92T
\8dõ" : submerged ? "
\96¢
\92m" : "
\8aâ
\94Õ";
1170 i = 0; /* for second iteration, undo loop increment */
1171 /* alt_i is now 1 or 2 */
1174 i = 0; /* undo loop increment */
1175 x_str = defsyms[i].explanation;
1176 if (submerged && !strcmp(x_str, defsyms[0].explanation))
1178 x_str = "land"; /* replace "dark part of a room" */
1180 x_str = "
\92n
\96Ê"; /* replace "dark part of a room" */
1182 /* alt_i is now 3 or more and no longer of interest */
1184 if (sym == (looked ? showsyms[i] : defsyms[i].sym) && *x_str) {
1185 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82É
\82Í
\8aÖ
\8cW
\82È
\82¢*/
1186 /* avoid "an unexplored", "an stone", "an air", "a water",
1187 "a floor of a room", "a dark part of a room";
1188 article==2 => "the", 1 => "an", 0 => (none) */
1189 int article = strstri(x_str, " of a room") ? 2
1191 || strcmp(x_str, "air") == 0
1192 || strcmp(x_str, "land") == 0
1193 || strcmp(x_str, "water") == 0);
1197 if (is_cmap_trap(i)) {
1199 Sprintf(out_str, "%sa trap", prefix);
1201 Sprintf(out_str, "%sã©", prefix);
1205 Sprintf(out_str, "%s%s", prefix,
1206 article == 2 ? the(x_str)
1207 : article == 1 ? an(x_str) : x_str);
1209 Sprintf(out_str, "%s%s", prefix, x_str);
1212 *firstmatch = x_str;
1214 } else if (!(hit_trap && is_cmap_trap(i))
1215 && !(found >= 3 && is_cmap_drawbridge(i))
1216 /* don't mention vibrating square outside of Gehennom
1217 unless this happens to be one (hallucination?) */
1218 && (i != S_vibrating_square || Inhell
1219 || (looked && glyph_is_trap(glyph)
1220 && glyph_to_trap(glyph) == VIBRATING_SQUARE))) {
1222 found += append_str(out_str, (article == 2) ? the(x_str)
1223 : (article == 1) ? an(x_str)
1226 found += append_str(out_str, x_str);
1228 if (is_cmap_trap(i))
1232 if (i == S_altar || is_cmap_trap(i))
1233 need_to_look = TRUE;
1237 /* Now check for warning symbols */
1238 for (i = 1; i < WARNCOUNT; i++) {
1239 x_str = def_warnsyms[i].explanation;
1240 if (sym == (looked ? warnsyms[i] : def_warnsyms[i].sym)) {
1242 Sprintf(out_str, "%s%s", prefix, def_warnsyms[i].explanation);
1243 *firstmatch = def_warnsyms[i].explanation;
1246 found += append_str(out_str, def_warnsyms[i].explanation);
1248 /* Kludge: warning trumps boulders on the display.
1249 Reveal the boulder too or player can get confused */
1250 if (looked && sobj_at(BOULDER, cc.x, cc.y))
1252 Strcat(out_str, " co-located with a boulder");
1254 Strcat(out_str, "(
\8b\90\8aâ
\82Æ
\93¯
\82¶
\88Ê
\92u
\82É
\82 \82é)");
1255 break; /* out of for loop*/
1259 /* if we ignored venom and list turned out to be short, put it back */
1260 if (skipped_venom && found < 2) {
1261 x_str = def_oc_syms[VENOM_CLASS].explain;
1263 Sprintf(out_str, "%s%s", prefix, an(x_str));
1264 *firstmatch = x_str;
1267 found += append_str(out_str, an(x_str));
1271 /* handle optional boulder symbol as a special case */
1272 if (iflags.bouldersym && sym == iflags.bouldersym) {
1275 *firstmatch = "boulder";
1277 *firstmatch = "
\8aâ";
1278 Sprintf(out_str, "%s%s", prefix, an(*firstmatch));
1282 found += append_str(out_str, "boulder");
1284 found += append_str(out_str, "
\8aâ");
1289 * If we are looking at the screen, follow multiple possibilities or
1290 * an ambiguous explanation by something more detailed.
1295 Sprintf(out_str, "%s", "That can be many things");
1297 Sprintf(out_str, "%s", "
\82±
\82±
\82É
\82Í
\91½
\82
\82Ì
\82à
\82Ì
\82ª
\82 \82é");
1301 struct permonst *pm = (struct permonst *)0;
1303 if (found > 1 || need_to_look) {
1305 char temp_buf[BUFSZ];
1307 pm = lookat(cc.x, cc.y, look_buf, monbuf);
1308 if (pm && for_supplement)
1309 *for_supplement = pm;
1310 *firstmatch = look_buf;
1311 if (*(*firstmatch)) {
1312 Sprintf(temp_buf, " (%s)", *firstmatch);
1313 (void) strncat(out_str, temp_buf,
1314 BUFSZ - strlen(out_str) - 1);
1315 found = 1; /* we have something to look up */
1319 Sprintf(temp_buf, " [seen: %s]", monbuf);
1321 Sprintf(temp_buf, " [
\8e\8b\8ao: %s]", monbuf);
1322 (void) strncat(out_str, temp_buf,
1323 BUFSZ - strlen(out_str) - 1);
1331 /* also used by getpos hack in do_name.c */
1333 const char what_is_an_unknown_object[] = "an unknown object";
1335 const char what_is_an_unknown_object[] = "
\93ä
\82Ì
\95¨
\91Ì";
1338 do_look(mode, click_cc)
1342 boolean quick = (mode == 1); /* use cursor; don't search for "more info" */
1343 boolean clicklook = (mode == 2); /* right mouse-click method */
1344 char out_str[BUFSZ] = DUMMY;
1345 const char *firstmatch = 0;
1346 struct permonst *pm = 0, *supplemental_pm = 0;
1347 int i = '\0', ans = 0;
1348 int sym; /* typed symbol or converted glyph */
1349 int found; /* count of matching syms found */
1350 coord cc; /* screen pos of unknown glyph */
1351 boolean save_verbose; /* saved value of flags.verbose */
1352 boolean from_screen; /* question from the screen */
1359 from_screen = TRUE; /* yes, we want to use the cursor */
1362 menu_item *pick_list = (menu_item *) 0;
1367 win = create_nhwindow(NHW_MENU);
1370 /* 'y' and 'n' to keep backwards compatibility with previous
1371 versions: "Specify unknown object by cursor?" */
1372 add_menu(win, NO_GLYPH, &any,
1373 flags.lootabc ? 0 : any.a_char, 'y', ATR_NONE,
1375 "something on the map", MENU_UNSELECTED);
1377 "
\92n
\90}
\8fã
\82É
\82 \82é
\82à
\82Ì", MENU_UNSELECTED);
1379 add_menu(win, NO_GLYPH, &any,
1380 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1382 "something you're carrying", MENU_UNSELECTED);
1384 "
\82 \82È
\82½
\82ª
\8e\9d\82Á
\82Ä
\82¢
\82é
\82à
\82Ì", MENU_UNSELECTED);
1386 add_menu(win, NO_GLYPH, &any,
1387 flags.lootabc ? 0 : any.a_char, 'n', ATR_NONE,
1389 "something else (by symbol or name)", MENU_UNSELECTED);
1391 "
\82»
\82ê
\88È
\8aO(
\83V
\83\93\83{
\83\8b\82©
\96¼
\91O
\82Å
\8ew
\92è)", MENU_UNSELECTED);
1392 if (!u.uswallow && !Hallucination) {
1394 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
1395 "", MENU_UNSELECTED);
1396 /* these options work sensibly for the swallowed case,
1397 but there's no reason for the player to use them then;
1398 objects work fine when hallucinating, but screen
1399 symbol/monster class letter doesn't match up with
1400 bogus monster type, so suppress when hallucinating */
1402 add_menu(win, NO_GLYPH, &any,
1403 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1405 "nearby monsters", MENU_UNSELECTED);
1407 "
\8bß
\82
\82É
\82¢
\82é
\89ö
\95¨", MENU_UNSELECTED);
1409 add_menu(win, NO_GLYPH, &any,
1410 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1412 "all monsters shown on map", MENU_UNSELECTED);
1414 "
\92n
\90}
\8fã
\82É
\82¢
\82é
\91S
\82Ä
\82Ì
\89ö
\95¨", MENU_UNSELECTED);
1416 add_menu(win, NO_GLYPH, &any,
1417 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1419 "nearby objects", MENU_UNSELECTED);
1421 "
\8bß
\82
\82É
\82 \82é
\82à
\82Ì", MENU_UNSELECTED);
1423 add_menu(win, NO_GLYPH, &any,
1424 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1426 "all objects shown on map", MENU_UNSELECTED);
1428 "
\92n
\90}
\8fã
\82É
\82 \82é
\91S
\82Ä
\82Ì
\82à
\82Ì", MENU_UNSELECTED);
1431 end_menu(win, "What do you want to look at:");
1433 end_menu(win, "
\89½
\82ð
\8c©
\82é
\81H");
1434 if (select_menu(win, PICK_ONE, &pick_list) > 0) {
1435 i = pick_list->item.a_char;
1436 free((genericptr_t) pick_list);
1438 destroy_nhwindow(win);
1457 invlet = display_inventory((const char *) 0, TRUE);
1458 if (!invlet || invlet == '\033')
1461 for (invobj = invent; invobj; invobj = invobj->nobj)
1462 if (invobj->invlet == invlet) {
1463 strcpy(out_str, singular(invobj, xname));
1467 checkfile(out_str, pm, TRUE, TRUE, (char *) 0);
1471 from_screen = FALSE;
1473 getlin("Specify what? (type the word)", out_str);
1475 getlin("
\89½
\82ð
\92²
\82×
\82é
\81H(
\95¶
\8e\9a\82ð
\93ü
\82ê
\82Ä
\82Ë)", out_str);
1476 if (strcmp(out_str, " ")) /* keep single space as-is */
1477 /* remove leading and trailing whitespace and
1478 condense consecutive internal whitespace */
1479 mungspaces(out_str);
1480 if (out_str[0] == '\0' || out_str[0] == '\033')
1483 if (out_str[1]) { /* user typed in a complete string */
1484 checkfile(out_str, pm, TRUE, TRUE, (char *) 0);
1490 look_all(TRUE, TRUE); /* list nearby monsters */
1493 look_all(FALSE, TRUE); /* list all monsters */
1496 look_all(TRUE, FALSE); /* list nearby objects */
1499 look_all(FALSE, FALSE); /* list all objects */
1502 } else { /* clicklook */
1506 from_screen = FALSE;
1509 /* Save the verbose flag, we change it later. */
1510 save_verbose = flags.verbose;
1511 flags.verbose = flags.verbose && !quick;
1513 * The user typed one letter, or we're identifying from the screen.
1516 /* Reset some variables. */
1517 pm = (struct permonst *) 0;
1521 if (from_screen || clicklook) {
1525 pline("Please move the cursor to %s.",
1526 what_is_an_unknown_object);
1528 pline("
\83J
\81[
\83\
\83\8b\82ð
\95¨
\91Ì
\82É
\88Ú
\93®
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D");
1532 pline("Pick an object.");
1534 pline("
\95¨
\91Ì
\82ð
\8ew
\92è
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D");
1536 ans = getpos(&cc, quick, what_is_an_unknown_object);
1537 if (ans < 0 || cc.x < 0)
1539 flags.verbose = FALSE; /* only print long question once */
1543 found = do_screen_description(cc, (from_screen || clicklook), sym,
1544 out_str, &firstmatch, &supplemental_pm);
1546 /* Finally, print out our explanation. */
1548 /* use putmixed() because there may be an encoded glyph present */
1549 putmixed(WIN_MESSAGE, 0, out_str);
1554 /* putmixed() bypasses pline() so doesn't write to DUMPLOG;
1555 tty puts it into ^P recall, so it ought to be there;
1556 DUMPLOG is plain text, so override graphics character;
1557 at present, force space, but we ought to use defsyms[]
1558 value for the glyph the graphics character came from */
1559 (void) decode_mixed(dmpbuf, out_str);
1560 if (dmpbuf[0] < ' ' || dmpbuf[0] >= 127) /* ASCII isprint() */
1566 /* check the data file for information about this thing */
1567 if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE
1568 && (ans == LOOK_VERBOSE || (flags.help && !quick))
1570 char temp_buf[BUFSZ], supplemental_name[BUFSZ];
1572 supplemental_name[0] = '\0';
1573 Strcpy(temp_buf, firstmatch);
1574 checkfile(temp_buf, pm, FALSE,
1575 (boolean) (ans == LOOK_VERBOSE), supplemental_name);
1576 if (supplemental_pm)
1577 do_supplemental_info(supplemental_name, supplemental_pm,
1578 (boolean) (ans == LOOK_VERBOSE));
1582 pline("I've never heard of such things.");
1584 pline("
\82»
\82ñ
\82È
\96¼
\91O
\82Í
\95·
\82¢
\82½
\82±
\82Æ
\82ª
\82È
\82¢
\81D");
1586 } while (from_screen && !quick && ans != LOOK_ONCE && !clicklook);
1588 flags.verbose = save_verbose;
1593 look_all(nearby, do_mons)
1594 boolean nearby; /* True => within BOLTLIM, False => entire map */
1595 boolean do_mons; /* True => monsters, False => objects */
1598 int x, y, lo_x, lo_y, hi_x, hi_y, glyph, count = 0;
1599 char lookbuf[BUFSZ], outbuf[BUFSZ];
1601 win = create_nhwindow(NHW_TEXT);
1602 lo_y = nearby ? max(u.uy - BOLT_LIM, 0) : 0;
1603 lo_x = nearby ? max(u.ux - BOLT_LIM, 1) : 1;
1604 hi_y = nearby ? min(u.uy + BOLT_LIM, ROWNO - 1) : ROWNO - 1;
1605 hi_x = nearby ? min(u.ux + BOLT_LIM, COLNO - 1) : COLNO - 1;
1606 for (y = lo_y; y <= hi_y; y++) {
1607 for (x = lo_x; x <= hi_x; x++) {
1609 glyph = glyph_at(x, y);
1611 if (glyph_is_monster(glyph)) {
1614 bhitpos.x = x; /* [is this actually necessary?] */
1616 if (x == u.ux && y == u.uy && canspotself()) {
1617 (void) self_lookat(lookbuf);
1619 } else if ((mtmp = m_at(x, y)) != 0) {
1620 look_at_monster(lookbuf, (char *) 0, mtmp, x, y);
1623 } else if (glyph_is_invisible(glyph)) {
1624 /* remembered, unseen, creature */
1625 Strcpy(lookbuf, invisexplain);
1627 } else if (glyph_is_warning(glyph)) {
1628 int warnindx = glyph_to_warning(glyph);
1630 Strcpy(lookbuf, def_warnsyms[warnindx].explanation);
1633 } else { /* !do_mons */
1634 if (glyph_is_object(glyph)) {
1635 look_at_object(lookbuf, x, y, glyph);
1640 char coordbuf[20], which[12], cmode;
1642 cmode = (iflags.getpos_coords != GPCOORDS_NONE)
1643 ? iflags.getpos_coords : GPCOORDS_MAP;
1645 Strcpy(which, do_mons ? "monsters" : "objects");
1647 Sprintf(outbuf, "%s currently shown near %s:",
1649 (cmode != GPCOORDS_COMPASS)
1650 ? coord_desc(u.ux, u.uy, coordbuf, cmode)
1651 : !canspotself() ? "your position" : "you");
1653 Sprintf(outbuf, "All %s currently shown on the map:",
1655 putstr(win, 0, outbuf);
1658 /* prefix: "coords C " where 'C' is mon or obj symbol */
1659 Sprintf(outbuf, (cmode == GPCOORDS_SCREEN) ? "%s "
1660 : (cmode == GPCOORDS_MAP) ? "%8s "
1662 coord_desc(x, y, coordbuf, cmode));
1663 Sprintf(eos(outbuf), "%s ", encglyph(glyph));
1664 /* guard against potential overflow */
1665 lookbuf[sizeof lookbuf - 1 - strlen(outbuf)] = '\0';
1666 Strcat(outbuf, lookbuf);
1667 putmixed(win, 0, outbuf);
1672 display_nhwindow(win, TRUE);
1675 pline("No %s are currently shown %s.",
1676 do_mons ? "monsters" : "objects",
1677 nearby ? "nearby" : "on the map");
1679 pline("
\8d¡
\82Ì
\82Æ
\82±
\82ë%s
\82É%s
\81D",
1680 nearby ? "
\8bß
\82" : "
\92n
\90}
\8fã",
1681 do_mons ? "
\89ö
\95¨
\82Í
\82¢
\82È
\82¢" : "
\82à
\82Ì
\82Í
\82È
\82¢");
1683 destroy_nhwindow(win);
1686 static const char *suptext1[] = {
1688 "%s is a member of a marauding horde of orcs",
1689 "rumored to have brutally attacked and plundered",
1690 "the ordinarily sheltered town that is located ",
1691 "deep within The Gnomish Mines.",
1693 "The members of that vicious horde proudly and ",
1694 "defiantly acclaim their allegiance to their",
1695 "leader %s in their names.",
1698 "%s
\82Í
\81C
\83m
\81[
\83\80\82Ì
\8dz
\8eR
\82Ì
\89\9c\82É
\88Ê
\92u
\82µ
\82Ä
\82¢
\82é",
1699 "
\92Ê
\8fí
\92Ê
\82è
\96h
\8cä
\82µ
\82Ä
\82¢
\82½
\8aX
\82ð
\97e
\8eÍ
\82È
\82
\8dU
\8c\82\82µ
\82Ä",
1700 "
\97ª
\92D
\82µ
\82½
\82Æ
\89\
\82³
\82ê
\82é
\81C
\83I
\81[
\83N
\82Ì
\8fP
\8c\82\8fW
\92c
\82Ì
\88ê
\88õ
\82Å
\82 \82é
\81D",
1702 "
\82»
\82Ì
\88«
\8e¿
\82È
\8fW
\92c
\82Ì
\83\81\83\93\83o
\81[
\82Í
\81C
\82»
\82Ì
\83\8a\81[
\83_
\81[
\82Å
\82 \82é%s
\82Ì
\96¼
\82Ì
\89º
\82É",
1703 "
\8cÖ
\82ç
\82µ
\82°
\82©
\82Â
\92§
\90í
\93I
\82É
\82»
\82Ì
\92\89\90½
\82ð
\8fÌ
\8e^
\82µ
\82Ä
\82¢
\82é
\81D",
1708 static const char *suptext2[] = {
1710 "\"%s\" is the common dungeon name of",
1711 "a nefarious orc who is known to acquire property",
1712 "from thieves and sell it off for profit.",
1714 "The perpetrator was last seen hanging around the",
1715 "stairs leading to the Gnomish Mines.",
1718 "\"%s\"
\82Í
\81C
\93\90\91¯
\82©
\82ç
\95¨
\95i
\82ð
\93ü
\8eè
\82µ
\82Ä",
1719 "
\97\98\89v
\82ð
\93¾
\82é
\82½
\82ß
\82É
\94\84\82è
\82³
\82Î
\82
\82±
\82Æ
\82Å
\92m
\82ç
\82ê
\82Ä
\82¢
\82é",
1720 "
\96³
\96@
\82È
\83I
\81[
\83N
\82Ì
\88ê
\94Ê
\93I
\82È
\96À
\8b{
\96¼
\82Å
\82 \82é
\81D",
1722 "
\94Æ
\90l
\82ª
\8dÅ
\8cã
\82É
\96Ú
\8c\82\82³
\82ê
\82½
\82Ì
\82Í",
1723 "
\83m
\81[
\83\80\82Ì
\92Y
\8dz
\82Ö
\91±
\82
\8aK
\92i
\82Ì
\8bß
\82
\82Å
\82 \82é
\81D",
1729 do_supplemental_info(name, pm, without_asking)
1731 struct permonst *pm;
1732 boolean without_asking;
1735 winid datawin = WIN_ERR;
1736 char *entrytext = name, *bp = (char *) 0, *bp2 = (char *) 0;
1737 char question[QBUFSZ];
1738 boolean yes_to_moreinfo = FALSE;
1739 boolean is_marauder = (name && pm && is_orc(pm));
1742 * Provide some info on some specific things
1743 * meant to support in-game mythology, and not
1744 * available from data.base or other sources.
1746 if (is_marauder && (strlen(name) < (BUFSZ - 1))) {
1747 char fullname[BUFSZ];
1749 bp = strstri(name, " of ");
1750 bp2 = strstri(name, " the Fence");
1753 Strcpy(fullname, name);
1754 if (!without_asking) {
1755 Strcpy(question, "More info about \"");
1756 /* +2 => length of "\"?" */
1757 copynchars(eos(question), entrytext,
1758 (int) (sizeof question - 1 - (strlen(question) + 2)));
1759 Strcat(question, "\"?");
1760 if (yn(question) == 'y')
1761 yes_to_moreinfo = TRUE;
1763 if (yes_to_moreinfo) {
1765 const char *gang = (char *) 0;
1775 datawin = create_nhwindow(NHW_MENU);
1776 for (i = 0; textp[i]; i++) {
1780 if (strstri(textp[i], "%s") != 0) {
1781 Sprintf(buf, textp[i], subs++ ? gang : fullname);
1785 putstr(datawin, 0, txt);
1787 display_nhwindow(datawin, FALSE);
1788 destroy_nhwindow(datawin), datawin = WIN_ERR;
1794 /* the '/' command */
1798 return do_look(0, (coord *) 0);
1801 /* the ';' command */
1805 return do_look(1, (coord *) 0);
1808 /* the '^' command */
1812 register struct trap *trap;
1813 int x, y, tt, glyph;
1820 /* check fake bear trap from confused gold detection */
1821 glyph = glyph_at(x, y);
1822 if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) {
1823 boolean chesttrap = trapped_chest_at(tt, x, y);
1825 if (chesttrap || trapped_door_at(tt, x, y)) {
1827 pline("That is a trapped %s.", chesttrap ? "chest" : "door");
1829 pline("
\82»
\82ê
\82Íã©
\82ª
\8ed
\8a|
\82¯
\82ç
\82ê
\82½%s
\82¾
\81D", chesttrap ? "
\94 " : "
\94à");
1830 return 0; /* trap ID'd, but no time elapses */
1834 for (trap = ftrap; trap; trap = trap->ntrap)
1835 if (trap->tx == x && trap->ty == y) {
1840 if (u.dz < 0 ? is_hole(tt) : tt == ROCKTRAP)
1843 tt = what_trap(tt, rn2_on_display_rng);
1845 pline("That is %s%s%s.",
1846 an(defsyms[trap_to_defsym(tt)].explanation),
1851 /* trap doors & spiked pits can't be made by
1852 player, and should be considered at least
1853 as much "set" as "dug" anyway */
1854 : (tt == HOLE || tt == PIT)
1857 !trap->madeby_u ? "" : " by you");
1859 pline("
\82»
\82ê
\82Í%s%s
\82¾
\81D",
1863 ? "
\82 \82È
\82½
\82ª
\92£
\82Á
\82½"
1864 : (tt == HOLE || tt == PIT)
1865 ? "
\82 \82È
\82½
\82ª
\8c@
\82Á
\82½"
1866 : "
\82 \82È
\82½
\82ª
\8ed
\8a|
\82¯
\82½",
1867 defsyms[trap_to_defsym(tt)].explanation);
1872 pline("I can't see a trap there.");
1874 pline("
\82»
\82±
\82É
\82Íã©
\82Í
\82Ý
\82 \82½
\82ç
\82È
\82¢
\81D");
1879 Implements a rudimentary if/elif/else/endif interpretor and use
1880 conditionals in dat/cmdhelp to describe what command each keystroke
1881 currently invokes, so that there isn't a lot of "(debug mode only)"
1882 and "(if number_pad is off)" cluttering the feedback that the user
1883 sees. (The conditionals add quite a bit of clutter to the raw data
1884 but users don't see that. number_pad produces a lot of conditional
1885 commands: basic letters vs digits, 'g' vs 'G' for '5', phone
1886 keypad vs normal layout of digits, and QWERTZ keyboard swap between
1887 y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.)
1889 The interpretor understands
1891 '&? option' for 'if' (also '&? !option'
1892 or '&? option=value[,value2,...]'
1893 or '&? !option=value[,value2,...]'),
1894 '&: option' for 'elif' (with argument variations same as 'if';
1895 any number of instances for each 'if'),
1896 '&:' for 'else' (also '&: #comment';
1897 0 or 1 instance for a given 'if'), and
1898 '&.' for 'endif' (also '&. #comment'; required for each 'if').
1900 The option handling is a bit of a mess, with no generality for
1901 which options to deal with and only a comma separated list of
1902 integer values for the '=value' part. number_pad is the only
1903 supported option that has a value; the few others (wizard/debug,
1904 rest_on_space, #if SHELL, #if SUSPEND) are booleans.
1911 char *p, buf[BUFSZ];
1912 winid tmpwin = create_nhwindow(NHW_TEXT);
1914 fp = dlb_fopen(KEYHELP, "r");
1917 pline("Cannot open \"%s\" data file!", KEYHELP);
1919 pline("
\83f
\81[
\83^
\83t
\83@
\83C
\83\8b\"%s\"
\82ð
\8aJ
\82¯
\82È
\82¢
\81I", KEYHELP);
1920 display_nhwindow(WIN_MESSAGE, TRUE);
1923 while (dlb_fgets(buf, (int) sizeof buf, fp)) {
1926 for (p = buf; *p; p++)
1927 if (*p != ' ' && *p != '\t')
1929 putstr(tmpwin, 0, p);
1931 (void) dlb_fclose(fp);
1932 display_nhwindow(tmpwin, TRUE);
1933 destroy_nhwindow(tmpwin);
1937 #define WD_STACKLIMIT 5
1938 struct wd_stack_frame {
1939 Bitfield(active, 1);
1940 Bitfield(been_true, 1);
1941 Bitfield(else_seen, 1);
1944 STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
1948 whatdoes_cond(buf, stack, depth, lnum)
1950 struct wd_stack_frame *stack;
1953 const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
1954 boolean newcond, neg, gotopt;
1955 char *p, *q, act = buf[1];
1958 newcond = (act == '?' || !stack[*depth].been_true);
1961 if (act == '#' || *buf == '#' || !*buf || !newcond) {
1962 gotopt = (*buf && *buf != '#');
1964 neg = FALSE; /* lint suppression */
1968 if ((neg = (*buf == '!')) != 0)
1971 p = index(buf, '='), q = index(buf, ':');
1972 if (!p || (q && q < p))
1974 if (p) { /* we have a value specified */
1975 /* handle a space before or after (or both) '=' (or ':') */
1976 if (p > buf && p[-1] == ' ')
1977 p[-1] = '\0'; /* end of keyword in buf[] */
1978 *p++ = '\0'; /* terminate keyword, advance to start of value */
1983 if (*buf && (act == '?' || act == ':')) {
1984 if (!strcmpi(buf, "number_pad")) {
1986 newcond = iflags.num_pad;
1988 /* convert internal encoding (separate yes/no and 0..3)
1989 back to user-visible one (-1..4) */
1990 np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
1991 : (-1 * iflags.num_pad_mode); /* -1..0 */
1997 if (atoi(p) == np) {
2003 } else if (!strcmpi(buf, "rest_on_space")) {
2004 newcond = flags.rest_on_space;
2005 } else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
2006 newcond = flags.debug; /* == wizard */
2007 } else if (!strcmpi(buf, "shell")) {
2009 /* should we also check sysopt.shellers? */
2014 } else if (!strcmpi(buf, "suspend")) {
2016 /* sysopt.shellers is also used for dosuspend()... */
2023 "cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
2027 /* this works for number_pad too: &? !number_pad:-1,0
2028 would be true for 1..4 after negation */
2034 case '#': /* comment */
2036 case '.': /* endif */
2038 impossible(badstackfmt, '.', lnum);
2042 case ':': /* else or elif */
2043 if (*depth == 0 || stack[*depth].else_seen) {
2044 impossible(badstackfmt, ':', lnum);
2045 *depth = 1; /* so that stack[*depth - 1] is a valid access */
2047 if (stack[*depth].active || stack[*depth].been_true
2048 || !stack[*depth - 1].active)
2049 stack[*depth].active = 0;
2051 stack[*depth].active = stack[*depth].been_true = 1;
2053 stack[*depth].else_seen = 1;
2056 if (++*depth >= WD_STACKLIMIT) {
2057 impossible(badstackfmt, '?', lnum);
2058 *depth = WD_STACKLIMIT - 1;
2060 stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
2061 stack[*depth].been_true = stack[*depth].active;
2062 stack[*depth].else_seen = 0;
2065 return stack[*depth].active ? TRUE : FALSE;
2070 dowhatdoes_core(q, cbuf)
2077 struct wd_stack_frame stack[WD_STACKLIMIT];
2079 int ctrl, meta, depth = 0, lnum = 0;
2081 const char *ec_desc;
2083 if ((ec_desc = key2extcmddesc(q)) != NULL) {
2084 char keybuf[QBUFSZ];
2086 Sprintf(buf, "%-8s%s.", key2txt(q, keybuf), ec_desc);
2092 fp = dlb_fopen(CMDHELPFILE, "r");
2094 pline("Cannot open \"%s\" data file!", CMDHELPFILE);
2098 meta = (0x80 & (uchar) q) != 0;
2101 ctrl = (0x1f & (uchar) q) == (uchar) q;
2103 q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
2107 (void) memset((genericptr_t) stack, 0, sizeof stack);
2108 cond = stack[0].active = 1;
2109 while (dlb_fgets(buf, sizeof buf, fp)) {
2111 if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
2112 cond = whatdoes_cond(buf, stack, &depth, lnum);
2117 if (meta ? (buf[0] == 'M' && buf[1] == '-'
2118 && (ctrl ? buf[2] == '^' && highc(buf[3]) == q
2120 : (ctrl ? buf[0] == '^' && highc(buf[1]) == q
2122 (void) strip_newline(buf);
2123 if (index(buf, '\t'))
2124 (void) tabexpand(buf);
2125 if (meta && ctrl && buf[4] == ' ') {
2126 (void) strncpy(buf, "M-^? ", 8);
2128 } else if (meta && buf[3] == ' ') {
2129 (void) strncpy(buf, "M-? ", 8);
2131 } else if (ctrl && buf[2] == ' ') {
2132 (void) strncpy(buf, "^? ", 8);
2134 } else if (buf[1] == ' ') {
2135 (void) strncpy(buf, "? ", 8);
2138 (void) dlb_fclose(fp);
2143 (void) dlb_fclose(fp);
2145 impossible("cmdhelp: mismatched &? &: &. conditionals.");
2153 static boolean once = FALSE;
2159 pline("Ask about '&' or '?' to get more info.%s",
2161 iflags.altmeta ? " (For ESC, type it twice.)" :
2165 pline("
\82³
\82ç
\82È
\82é
\8fî
\95ñ
\82É
\82Â
\82¢
\82Ä
\82Í '&'
\82© '?'
\82É
\82Â
\82¢
\82Ä
\82½
\82¸
\82Ë
\82Ü
\82·
\81D%s",
2167 iflags.altmeta ? " (ESC
\82É
\82Â
\82¢
\82Ä
\82Í
\81C2
\89ñ
\83^
\83C
\83v
\82µ
\82Ü
\82·
\81D)" :
2173 #if defined(UNIX) || defined(VMS)
2174 introff(); /* disables ^C but not ^\ */
2177 q = yn_function("What command?", (char *) 0, '\0');
2179 q = yn_function("
\82Ç
\82¤
\82¢
\82¤
\83R
\83}
\83\93\83h
\81H", (char *) 0, '\0');
2181 if (q == '\033' && iflags.altmeta) {
2182 /* in an ideal world, we would know whether another keystroke
2183 was already pending, but this is not an ideal world...
2184 if user typed ESC, we'll essentially hang until another
2185 character is typed */
2186 q = yn_function("]", (char *) 0, '\0');
2188 q = (char) ((uchar) q | 0200);
2191 #if defined(UNIX) || defined(VMS)
2192 intron(); /* reenables ^C */
2194 reslt = dowhatdoes_core(q, bufr);
2196 if (q == '&' || q == '?')
2201 pline("No such command '%s', char code %d (0%03o or 0x%02x).",
2202 visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2204 pline("
\82»
\82ñ
\82È
\83R
\83}
\83\93\83h'%s'
\81C
\95¶
\8e\9a\83R
\81[
\83h%d(0%03o
\82Ü
\82½
\82Í 0x%02x)
\82Í
\82È
\82¢
\81D",
2205 visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2212 docontact(VOID_ARGS)
2214 winid cwin = create_nhwindow(NHW_TEXT);
2217 if (sysopt.support) {
2218 /*XXX overflow possibilities*/
2219 Sprintf(buf, "To contact local support, %s", sysopt.support);
2220 putstr(cwin, 0, buf);
2221 putstr(cwin, 0, "");
2222 } else if (sysopt.fmtd_wizard_list) { /* formatted SYSCF WIZARDS */
2223 Sprintf(buf, "To contact local support, contact %s.",
2224 sysopt.fmtd_wizard_list);
2225 putstr(cwin, 0, buf);
2226 putstr(cwin, 0, "");
2228 putstr(cwin, 0, "To contact the NetHack development team directly,");
2229 /*XXX overflow possibilities*/
2230 Sprintf(buf, "see the 'Contact' form on our website or email <%s>.",
2232 putstr(cwin, 0, buf);
2233 putstr(cwin, 0, "");
2234 putstr(cwin, 0, "For more information on NetHack, or to report a bug,");
2235 Sprintf(buf, "visit our website \"%s\".", DEVTEAM_URL);
2236 putstr(cwin, 0, buf);
2237 display_nhwindow(cwin, FALSE);
2238 destroy_nhwindow(cwin);
2242 dispfile_help(VOID_ARGS)
2244 display_file(HELP, TRUE);
2248 dispfile_shelp(VOID_ARGS)
2250 display_file(SHELP, TRUE);
2254 dispfile_optionfile(VOID_ARGS)
2256 display_file(OPTIONFILE, TRUE);
2260 dispfile_license(VOID_ARGS)
2262 display_file(LICENSE, TRUE);
2266 dispfile_debughelp(VOID_ARGS)
2268 display_file(DEBUGHELP, TRUE);
2272 hmenu_doextversion(VOID_ARGS)
2274 (void) doextversion();
2278 hmenu_dohistory(VOID_ARGS)
2284 hmenu_dowhatis(VOID_ARGS)
2290 hmenu_dowhatdoes(VOID_ARGS)
2292 (void) dowhatdoes();
2296 hmenu_doextlist(VOID_ARGS)
2302 domenucontrols(VOID_ARGS)
2304 winid cwin = create_nhwindow(NHW_TEXT);
2305 show_menu_controls(cwin, FALSE);
2306 display_nhwindow(cwin, FALSE);
2307 destroy_nhwindow(cwin);
2310 /* data for dohelp() */
2314 } help_menu_items[] = {
2316 { hmenu_doextversion, "About NetHack (version information)." },
2318 { hmenu_doextversion, "NetHack
\82É
\82Â
\82¢
\82Ä(
\83o
\81[
\83W
\83\87\83\93\8fî
\95ñ)" },
2320 { dispfile_help, "Long description of the game and commands." },
2322 { dispfile_help, "
\83Q
\81[
\83\80\82¨
\82æ
\82Ñ
\83R
\83}
\83\93\83h
\82Ì
\89ð
\90à(
\92·
\95¶)" },
2324 { dispfile_shelp, "List of game commands." },
2326 { dispfile_shelp, "
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2328 { hmenu_dohistory, "Concise history of NetHack." },
2330 { hmenu_dohistory, "NetHack
\82Ì
\8aÈ
\92P
\82È
\97ð
\8ej" },
2332 { hmenu_dowhatis, "Info on a character in the game display." },
2334 { hmenu_dowhatis, "
\89æ
\96Ê
\82É
\95\
\8e¦
\82³
\82ê
\82é
\95¶
\8e\9a\82Ì
\90à
\96¾" },
2336 { hmenu_dowhatdoes, "Info on what a given key does." },
2338 { hmenu_dowhatdoes, "
\82±
\82Ì
\83L
\81[
\82ª
\89½
\82ð
\88Ó
\96¡
\82·
\82é
\82©
\82Ì
\90à
\96¾" },
2340 { option_help, "List of game options." },
2342 { option_help, "
\83Q
\81[
\83\80\82Ì
\83I
\83v
\83V
\83\87\83\93\88ê
\97\97" },
2344 { dispfile_optionfile, "Longer explanation of game options." },
2346 { dispfile_optionfile, "
\83Q
\81[
\83\80\82Ì
\83I
\83v
\83V
\83\87\83\93\88ê
\97\97(
\92·
\95¶)" },
2348 { dokeylist, "Full list of keyboard commands" },
2350 { dokeylist, "
\83L
\81[
\83{
\81[
\83h
\83R
\83}
\83\93\83h
\82Ì
\8a®
\91S
\82È
\88ê
\97\97" },
2352 { hmenu_doextlist, "List of extended commands." },
2354 { hmenu_doextlist, "
\8ag
\92£
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2356 { domenucontrols, "List menu control keys" },
2358 { domenucontrols, "
\83\81\83j
\83\85\81[
\90§
\8cä
\83L
\81[
\88ê
\97\97s" },
2360 { dispfile_license, "The NetHack license." },
2362 { dispfile_license, "NetHack
\82Ì
\83\89\83C
\83Z
\83\93\83X" },
2364 { docontact, "Support information." },
2366 { docontact, "
\83T
\83|
\81[
\83g
\8fî
\95ñ" },
2369 { port_help, "%s-specific help and commands." },
2371 { port_help, "%s
\82É
\93Á
\97L
\82Ì
\83w
\83\8b\83v
\82Æ
\83R
\83}
\83\93\83h" },
2374 { dispfile_debughelp, "List of wizard-mode commands." },
2376 { dispfile_debughelp, "
\83E
\83B
\83U
\81[
\83h
\83\82\81[
\83h
\82Ì
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2377 { (void NDECL((*))) 0, (char *) 0 }
2380 /* the '?' command */
2384 winid tmpwin = create_nhwindow(NHW_MENU);
2385 char helpbuf[QBUFSZ];
2387 menu_item *selected;
2391 any = zeroany; /* zero all bits */
2394 for (i = 0; help_menu_items[i].text; i++) {
2395 if (!wizard && help_menu_items[i].f == dispfile_debughelp)
2397 if (help_menu_items[i].text[0] == '%') {
2398 Sprintf(helpbuf, help_menu_items[i].text, PORT_ID);
2400 Strcpy(helpbuf, help_menu_items[i].text);
2403 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
2404 helpbuf, MENU_UNSELECTED);
2407 end_menu(tmpwin, "Select one item:");
2409 end_menu(tmpwin, "
\91I
\82ñ
\82Å
\82
\82¾
\82³
\82¢
\81F");
2410 n = select_menu(tmpwin, PICK_ONE, &selected);
2411 destroy_nhwindow(tmpwin);
2413 sel = selected[0].item.a_int - 1;
2414 free((genericptr_t) selected);
2415 (void) (*help_menu_items[sel].f)();
2420 /* the 'V' command; also a choice for '?' */
2424 display_file(HISTORY, TRUE);