1 /* NetHack 3.6 pager.c $NHDT-Date: 1574722864 2019/11/25 23:01:04 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.162 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2021 */
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 if (otmp->otyp == SLIME_MOLD)
256 /* override context.current_fruit to avoid
257 look, use 'O' to make new named fruit, look again
258 giving different results when current_fruit changes */
259 otmp->spe = MCORPSENM(mtmp);
261 otmp->corpsenm = MCORPSENM(mtmp);
262 } else if (otmp->otyp == CORPSE && glyph_is_body(glyph)) {
263 otmp->corpsenm = glyph - GLYPH_BODY_OFF;
264 } else if (otmp->otyp == STATUE && glyph_is_statue(glyph)) {
265 otmp->corpsenm = glyph - GLYPH_STATUE_OFF;
267 if (otmp->otyp == LEASH)
269 /* extra fields needed for shop price with doname() formatting */
270 otmp->where = OBJ_FLOOR;
271 otmp->ox = x, otmp->oy = y;
272 otmp->no_charge = (otmp->otyp == STRANGE_OBJECT && costly_spot(x, y));
274 /* if located at adjacent spot, mark it as having been seen up close
275 (corpse type will be known even if dknown is 0, so we don't need a
276 touch check for cockatrice corpse--we're looking without touching) */
277 if (otmp && distu(x, y) <= 2 && !Blind && !Hallucination
278 /* redundant: we only look for an object which matches current
279 glyph among floor and buried objects; when !Blind, any buried
280 object's glyph will have been replaced by whatever is present
281 on the surface as soon as we moved next to its spot */
282 && (fakeobj || otmp->where == OBJ_FLOOR) /* not buried */
283 /* terrain mode views what's already known, doesn't learn new stuff */
284 && !iflags.terrainmode) /* so don't set dknown when in terrain mode */
285 otmp->dknown = 1; /* if a pile, clearly see the top item only */
286 if (fakeobj && mtmp && mimic_obj &&
287 (otmp->dknown || (M_AP_FLAG(mtmp) & M_AP_F_DKNOWN))) {
288 mtmp->m_ap_type |= M_AP_F_DKNOWN;
292 return fakeobj; /* when True, caller needs to dealloc *obj_p */
296 look_at_object(buf, x, y, glyph)
297 char *buf; /* output buffer */
300 struct obj *otmp = 0;
301 boolean fakeobj = object_from_map(glyph, x, y, &otmp);
304 Strcpy(buf, (otmp->otyp != STRANGE_OBJECT)
305 ? distant_name(otmp, otmp->dknown ? doname_with_price
307 : obj_descr[STRANGE_OBJECT].oc_name);
309 otmp->where = OBJ_FREE; /* object_from_map set it to OBJ_FLOOR */
310 dealloc_obj(otmp), otmp = 0;
313 Strcpy(buf, something); /* sanity precaution */
315 if (otmp && otmp->where == OBJ_BURIED)
317 Strcat(buf, " (buried)");
319 Strcat(buf, " (
\96\84\82Ü
\82Á
\82Ä
\82¢
\82é)");
320 else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
322 Strcat(buf, " embedded in stone");
324 Strcat(buf, "
\81C
\8aâ
\82É
\96\84\82ß
\82±
\82Ü
\82ê
\82Ä
\82¢
\82é");
325 else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR)
327 Strcat(buf, " embedded in a wall");
329 Strcat(buf, "
\81C
\95Ç
\82É
\96\84\82ß
\82±
\82Ü
\82ê
\82Ä
\82¢
\82é");
330 else if (closed_door(x, y))
332 Strcat(buf, " embedded in a door");
334 Strcat(buf, "
\81C
\94à
\82É
\96\84\82ß
\82±
\82Ü
\82ê
\82Ä
\82¢
\82é");
335 else if (is_pool(x, y))
336 /*JP 3.4.3
\82±
\82Ì
\95\94\95ª
\82Í
\95¨
\91Ì
\82É
\82µ
\82©
\8eg
\82í
\82ê
\82È
\82¢ */
338 Strcat(buf, " in water");
340 Strcat(buf, "
\81C
\90\85\92\86\82É
\82 \82é");
341 else if (is_lava(x, y))
343 Strcat(buf, " in molten lava"); /* [can this ever happen?] */
345 Strcat(buf, "
\81C
\97n
\8aâ
\82Ì
\92\86\82É
\82 \82é"); /* [can this ever happen?] */
351 look_at_monster(buf, monbuf, mtmp, x, y)
352 char *buf, *monbuf; /* buf: output, monbuf: optional output */
356 char *name, monnambuf[BUFSZ];
357 boolean accurate = !Hallucination;
359 name = (mtmp->data == &mons[PM_COYOTE] && accurate)
360 ? coyotename(mtmp, monnambuf)
361 : distant_monnam(mtmp, ARTICLE_NONE, monnambuf);
363 Sprintf(buf, "%s%s%s",
364 (mtmp->mx != x || mtmp->my != y)
365 ? ((mtmp->isshk && accurate) ? "tail of " : "tail of a ")
367 (mtmp->mtame && accurate)
369 : (mtmp->mpeaceful && accurate)
374 Sprintf(buf, "%s%s%s",
375 (mtmp->mtame && accurate)
376 ? "
\8eè
\82È
\82¸
\82¯
\82ç
\82ê
\82½"
377 : (mtmp->mpeaceful && accurate)
381 (mtmp->mx != x || mtmp->my != y)
382 ? ((mtmp->isshk && accurate) ? "
\82Ì
\90K
\94ö" : "
\82Ì
\90K
\94ö")
385 if (u.ustuck == mtmp) {
386 if (u.uswallow || iflags.save_uswallow) /* monster detection */
388 Strcat(buf, is_animal(mtmp->data)
389 ? ", swallowing you" : ", engulfing you");
391 Strcat(buf, ",
\82 \82È
\82½
\82ð
\88ù
\82Ý
\8d\9e\82ñ
\82Å
\82¢
\82é");
394 Strcat(buf, (Upolyd && sticks(youmonst.data))
396 ? ", being held" : ", holding you");
398 ? "
\81C
\82 \82È
\82½
\82ª
\92Í
\82Ü
\82¦
\82Ä
\82¢
\82é" : "
\81C
\82 \82È
\82½
\82ð
\92Í
\82Ü
\82¦
\82Ä
\82¢
\82é");
402 Strcat(buf, ", leashed to you");
404 Strcat(buf, "
\81C
\95R
\82Å
\8c\8b\82Î
\82ê
\82Ä
\82¢
\82é");
406 if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) {
407 struct trap *t = t_at(mtmp->mx, mtmp->my);
408 int tt = t ? t->ttyp : NO_TRAP;
410 /* newsym lets you know of the trap, so mention it here */
411 if (tt == BEAR_TRAP || is_pit(tt) || tt == WEB) {
413 Sprintf(eos(buf), ", trapped in %s",
415 Sprintf(eos(buf), ", %s
\82É
\95ß
\82Ü
\82Á
\82Ä
\82¢
\82é",
416 an(defsyms[trap_to_defsym(tt)].explanation));
421 /* we know the hero sees a monster at this location, but if it's shown
422 due to persistant monster detection he might remember something else */
423 if (mtmp->mundetected || M_AP_TYPE(mtmp))
424 mhidden_description(mtmp, FALSE, eos(buf));
427 unsigned how_seen = howmonseen(mtmp);
430 if (how_seen != 0 && how_seen != MONSEEN_NORMAL) {
431 if (how_seen & MONSEEN_NORMAL) {
433 Strcat(monbuf, "normal vision");
435 Strcat(monbuf, "
\92Ê
\8fí
\82Ì
\8e\8b\8ao");
436 how_seen &= ~MONSEEN_NORMAL;
437 /* how_seen can't be 0 yet... */
439 Strcat(monbuf, ", ");
441 if (how_seen & MONSEEN_SEEINVIS) {
443 Strcat(monbuf, "see invisible");
445 Strcat(monbuf, "
\8c©
\82¦
\82È
\82¢
\82à
\82Ì
\82ð
\8c©
\82é
\8e\8b\8ao");
446 how_seen &= ~MONSEEN_SEEINVIS;
448 Strcat(monbuf, ", ");
450 if (how_seen & MONSEEN_INFRAVIS) {
452 Strcat(monbuf, "infravision");
454 Strcat(monbuf, "
\90Ô
\8aO
\90ü
\82ª
\8c©
\82¦
\82é
\8e\8b\8ao");
455 how_seen &= ~MONSEEN_INFRAVIS;
457 Strcat(monbuf, ", ");
459 if (how_seen & MONSEEN_TELEPAT) {
461 Strcat(monbuf, "telepathy");
463 Strcat(monbuf, "
\83e
\83\8c\83p
\83V
\81[");
464 how_seen &= ~MONSEEN_TELEPAT;
466 Strcat(monbuf, ", ");
468 if (how_seen & MONSEEN_XRAYVIS) {
469 /* Eyes of the Overworld */
471 Strcat(monbuf, "astral vision");
473 Strcat(monbuf, "
\90¸
\90_
\82É
\82æ
\82é
\8e\8b\8ao");
474 how_seen &= ~MONSEEN_XRAYVIS;
476 Strcat(monbuf, ", ");
478 if (how_seen & MONSEEN_DETECT) {
480 Strcat(monbuf, "monster detection");
482 Strcat(monbuf, "
\89ö
\95¨
\82ð
\94
\8c©
\82·
\82é
\94\
\97Í");
483 how_seen &= ~MONSEEN_DETECT;
485 Strcat(monbuf, ", ");
487 if (how_seen & MONSEEN_WARNMON) {
490 Strcat(monbuf, "paranoid delusion");
492 Strcat(monbuf, "
\95Î
\8e·
\93I
\96Ï
\91z");
494 unsigned long mW = (context.warntype.obj
495 | context.warntype.polyd),
496 m2 = mtmp->data->mflags2;
498 const char *whom = ((mW & M2_HUMAN & m2) ? "human"
499 : (mW & M2_ELF & m2) ? "elf"
500 : (mW & M2_ORC & m2) ? "orc"
501 : (mW & M2_DEMON & m2) ? "demon"
502 : mtmp->data->mname);
504 const char *whom = ((mW & M2_HUMAN & m2) ? "
\90l
\8aÔ"
505 : (mW & M2_ELF & m2) ? "
\83G
\83\8b\83t"
506 : (mW & M2_ORC & m2) ? "
\83I
\81[
\83N"
507 : (mW & M2_DEMON & m2) ? "
\88«
\96\82"
508 : mtmp->data->mname);
512 Sprintf(eos(monbuf), "warned of %s", makeplural(whom));
514 Sprintf(eos(monbuf), "%s
\82ð
\8cx
\8d\90\82µ
\82Ä
\82¢
\82é", whom);
516 how_seen &= ~MONSEEN_WARNMON;
518 Strcat(monbuf, ", ");
520 /* should have used up all the how_seen bits by now */
522 impossible("lookat: unknown method of seeing monster");
523 Sprintf(eos(monbuf), "(%u)", how_seen);
525 } /* seen by something other than normal vision */
526 } /* monbuf is non-null */
530 * Return the name of the glyph found at (x,y).
531 * If not hallucinating and the glyph is a monster, also monster data.
533 STATIC_OVL struct permonst *
534 lookat(x, y, buf, monbuf)
538 struct monst *mtmp = (struct monst *) 0;
539 struct permonst *pm = (struct permonst *) 0;
542 buf[0] = monbuf[0] = '\0';
543 glyph = glyph_at(x, y);
544 if (u.ux == x && u.uy == y && canspotself()
545 && !(iflags.save_uswallow &&
546 glyph == mon_to_glyph(u.ustuck, rn2_on_display_rng))
547 && (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)) {
549 (void) self_lookat(buf);
551 /* file lookup can't distinguish between "gnomish wizard" monster
552 and correspondingly named player character, always picking the
553 former; force it to find the general "wizard" entry instead */
554 if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd)
555 pm = &mons[PM_WIZARD];
557 /* When you see yourself normally, no explanation is appended
558 (even if you could also see yourself via other means).
559 Sensing self while blind or swallowed is treated as if it
560 were by normal vision (cf canseeself()). */
561 if ((Invisible || u.uundetected) && !Blind
562 && !(u.uswallow || iflags.save_uswallow)) {
574 Sprintf(eos(buf), " [seen: %s%s%s%s%s]",
575 (how & 1) ? "infravision" : "",
576 /* add comma if telep and infrav */
577 ((how & 3) > 2) ? ", " : "",
578 (how & 2) ? "telepathy" : "",
579 /* add comma if detect and (infrav or telep or both) */
580 ((how & 7) > 4) ? ", " : "",
581 (how & 4) ? "monster detection" : "");
583 Sprintf(eos(buf), " [
\8a´
\92m: %s%s%s%s%s]",
584 (how & 1) ? "
\90Ô
\8aO
\90ü" : "",
585 /* add comma if telep and infrav */
586 ((how & 3) > 2) ? ", " : "",
587 (how & 2) ? "
\83e
\83\8c\83p
\83V
\81[" : "",
588 /* add comma if detect and (infrav or telep or both) */
589 ((how & 7) > 4) ? ", " : "",
590 (how & 4) ? "
\89ö
\95¨
\8a´
\92m" : "");
593 } else if (u.uswallow) {
594 /* when swallowed, we're only called for spots adjacent to hero,
595 and blindness doesn't prevent hero from feeling what holds him */
597 Sprintf(buf, "interior of %s", a_monnam(u.ustuck));
599 Sprintf(buf, "%s
\82Ì
\93à
\95\94", a_monnam(u.ustuck));
601 } else if (glyph_is_monster(glyph)) {
604 if ((mtmp = m_at(x, y)) != 0) {
605 look_at_monster(buf, monbuf, mtmp, x, y);
607 } else if (Hallucination) {
608 /* 'monster' must actually be a statue */
609 Strcpy(buf, rndmonnam((char *) 0));
611 } else if (glyph_is_object(glyph)) {
612 look_at_object(buf, x, y, glyph); /* fill in buf[] */
613 } else if (glyph_is_trap(glyph)) {
614 int tnum = what_trap(glyph_to_trap(glyph), rn2_on_display_rng);
616 /* Trap detection displays a bear trap at locations having
617 * a trapped door or trapped container or both.
618 * TODO: we should create actual trap types for doors and
619 * chests so that they can have their own glyphs and tiles.
621 if (trapped_chest_at(tnum, x, y))
623 Strcpy(buf, "trapped chest"); /* might actually be a large box */
625 Strcpy(buf, "ã©
\82Ì
\8ed
\8a|
\82¯
\82ç
\82ê
\82½
\94 "); /* might actually be a large box */
627 else if (trapped_door_at(tnum, x, y))
629 Strcpy(buf, "trapped door"); /* not "trap door"... */
631 Strcpy(buf, "ã©
\82Ì
\8ed
\8a|
\82¯
\82ç
\82ê
\82½
\94à"); /* not "trap door"... */
634 Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
635 } else if (glyph_is_warning(glyph)) {
636 int warnindx = glyph_to_warning(glyph);
638 Strcpy(buf, def_warnsyms[warnindx].explanation);
639 } else if (!glyph_is_cmap(glyph)) {
641 Strcpy(buf, "unexplored area");
643 Strcpy(buf, "
\96¢
\92T
\8dõ
\82Ì
\8fê
\8f\8a");
648 switch (glyph_to_cmap(glyph)) {
650 amsk = ((mtmp = m_at(x, y)) != 0 && has_mcorpsenm(mtmp)
651 && M_AP_TYPE(mtmp) == M_AP_FURNITURE
652 && mtmp->mappearance == S_altar) ? MCORPSENM(mtmp)
653 : levl[x][y].altarmask;
654 algn = Amask2align(amsk & ~AM_SHRINE);
656 Sprintf(buf, "%s %saltar",
658 Sprintf(buf, "%s%s
\8dÕ
\92d",
659 /* like endgame high priests, endgame high altars
660 are only recognizable when immediately adjacent */
661 (Is_astralevel(&u.uz) && distu(x, y) > 2)
667 ((amsk & AM_SHRINE) != 0
668 && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
676 if (is_drawbridge_wall(x, y) >= 0)
678 Strcpy(buf, "open drawbridge portcullis");
680 Strcpy(buf,"
\8aJ
\82¢
\82Ä
\82¢
\82é
\92µ
\82Ë
\8b´");
681 else if ((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN)
683 Strcpy(buf, "broken door");
685 Strcpy(buf,"
\89ó
\82ê
\82½
\94à");
688 Strcpy(buf, "doorway");
690 Strcpy(buf,"
\8fo
\93ü
\82è
\8cû");
695 Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud");
697 Is_airlevel(&u.uz) ? "
\93Ü
\82Á
\82Ä
\82¢
\82é
\8fê
\8f\8a" : "
\96¶/
\8fö
\8bC
\82Ì
\89_");
700 if (!levl[x][y].seenv) {
702 Strcpy(buf, "unexplored");
704 Strcpy(buf, "
\96¢
\92T
\8dõ");
706 } else if (Underwater && !Is_waterlevel(&u.uz)) {
707 /* "unknown" == previously mapped but not visible when
708 submerged; better terminology appreciated... */
709 Strcpy(buf, (distu(x, y) <= 2) ? "land" : "unknown");
711 } else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) {
713 Strcpy(buf, "stone");
715 Strcpy(buf, "
\8aâ
\94Õ");
720 Strcpy(buf, defsyms[glyph_to_cmap(glyph)].explanation);
724 return (pm && !Hallucination) ? pm : (struct permonst *) 0;
728 * Look in the "data" file for more info. Called if the user typed in the
729 * whole name (user_typed_name == TRUE), or we've found a possible match
730 * with a character/glyph and flags.help is TRUE.
732 * NOTE: when (user_typed_name == FALSE), inp is considered read-only and
733 * must not be changed directly, e.g. via lcase(). We want to force
734 * lcase() for data.base lookup so that we can have a clean key.
735 * Therefore, we create a copy of inp _just_ for data.base lookup.
738 checkfile(inp, pm, user_typed_name, without_asking, supplemental_name)
741 boolean user_typed_name, without_asking;
742 char *supplemental_name;
745 char buf[BUFSZ], newstr[BUFSZ], givenname[BUFSZ];
746 char *ep, *dbase_str;
747 unsigned long txt_offset = 0L;
748 winid datawin = WIN_ERR;
750 fp = dlb_fopen(DATAFILE, "r");
753 pline("Cannot open 'data' file!");
755 pline("
\83f
\81[
\83^
\83t
\83@
\83C
\83\8b\82ð
\8aJ
\82¯
\82È
\82¢
\81I");
758 /* If someone passed us garbage, prevent fault. */
759 if (!inp || strlen(inp) > (BUFSZ - 1)) {
760 impossible("bad do_look buffer passed (%s)!",
761 !inp ? "null" : "too long");
765 /* To prevent the need for entries in data.base like *ngel to account
766 * for Angel and angel, make the lookup string the same for both
767 * user_typed_name and picked name.
769 if (pm != (struct permonst *) 0 && !user_typed_name)
770 dbase_str = strcpy(newstr, pm->mname);
772 dbase_str = strcpy(newstr, inp);
773 (void) lcase(dbase_str);
775 /*JP:TODO:
\83f
\81[
\83^
\83x
\81[
\83X
\8c\9f\8dõ
\82Í
\93®
\82¢
\82Ä
\82¢
\82È
\82¢
\82Ì
\82Å
\97v
\8fC
\90³*/
778 * The switch from xname() to doname_vague_quan() in look_at_obj()
779 * had the unintendded side-effect of making names picked from
780 * pointing at map objects become harder to simplify for lookup.
781 * We should split the prefix and suffix handling used by wish
782 * parsing and also wizmode monster generation out into separate
783 * routines and use those routines here. This currently lacks
784 * erosion handling and probably lots of other bits and pieces
785 * that wishing already understands and most of this duplicates
786 * stuff already done for wish handling or monster generation.
788 if (!strncmp(dbase_str, "interior of ", 12))
790 if (!strncmp(dbase_str, "a ", 2))
792 else if (!strncmp(dbase_str, "an ", 3))
794 else if (!strncmp(dbase_str, "the ", 4))
796 else if (!strncmp(dbase_str, "some ", 5))
798 else if (digit(*dbase_str)) {
799 /* remove count prefix ("2 ya") which can come from looking at map */
800 while (digit(*dbase_str))
802 if (*dbase_str == ' ')
805 if (!strncmp(dbase_str, "pair of ", 8))
807 if (!strncmp(dbase_str, "tame ", 5))
809 else if (!strncmp(dbase_str, "peaceful ", 9))
811 if (!strncmp(dbase_str, "invisible ", 10))
813 if (!strncmp(dbase_str, "saddled ", 8))
815 if (!strncmp(dbase_str, "blessed ", 8))
817 else if (!strncmp(dbase_str, "uncursed ", 9))
819 else if (!strncmp(dbase_str, "cursed ", 7))
821 if (!strncmp(dbase_str, "empty ", 6))
823 if (!strncmp(dbase_str, "partly used ", 12))
825 else if (!strncmp(dbase_str, "partly eaten ", 13))
827 if (!strncmp(dbase_str, "statue of ", 10))
829 else if (!strncmp(dbase_str, "figurine of ", 12))
831 /* remove enchantment ("+0 aklys"); [for 3.6.0 and earlier, this wasn't
832 needed because looking at items on the map used xname() rather than
833 doname() hence known enchantment was implicitly suppressed] */
834 if (*dbase_str && index("+-", dbase_str[0]) && digit(dbase_str[1])) {
835 ++dbase_str; /* skip sign */
836 while (digit(*dbase_str))
838 if (*dbase_str == ' ')
841 /* "towel", "wet towel", and "moist towel" share one data.base entry;
842 for "wet towel", we keep prefix so that the prompt will ask about
843 "wet towel"; for "moist towel", we also want to ask about "wet towel".
844 (note: strncpy() only terminates output string if the specified
845 count is bigger than the length of the substring being copied) */
847 if (!strncmp(dbase_str, "moist towel", 11))
848 (void) strncpy(dbase_str += 2, "wet", 3); /* skip "mo" replace "ist" */
851 /* Make sure the name is non-empty. */
853 long pass1offset = -1L;
854 int chk_skip, pass = 1;
855 boolean yes_to_moreinfo, found_in_file, pass1found_in_file,
857 char *sp, *ap, *alt = 0; /* alternate description */
859 /* adjust the input to remove "named " and "called " */
860 if ((ep = strstri(dbase_str, " named ")) != 0) {
862 if ((ap = strstri(dbase_str, " called ")) != 0 && ap < ep)
863 ep = ap; /* "named" is alt but truncate at "called" */
864 } else if ((ep = strstri(dbase_str, " called ")) != 0) {
865 copynchars(givenname, ep + 8, BUFSZ - 1);
867 if (supplemental_name && (sp = strstri(inp, " called ")) != 0)
868 copynchars(supplemental_name, sp + 8, BUFSZ - 1);
870 ep = strstri(dbase_str, ", ");
871 if (ep && ep > dbase_str)
873 /* remove article from 'alt' name ("a pair of lenses named
874 The Eyes of the Overworld" simplified above to "lenses named
875 The Eyes of the Overworld", now reduced to "The Eyes of the
876 Overworld", skip "The" as with base name processing) */
877 if (alt && (!strncmpi(alt, "a ", 2)
878 || !strncmpi(alt, "an ", 3)
879 || !strncmpi(alt, "the ", 4)))
880 alt = index(alt, ' ') + 1;
881 /* remove charges or "(lit)" or wizmode "(N aum)" */
882 if ((ep = strstri(dbase_str, " (")) != 0 && ep > dbase_str)
884 if (alt && (ap = strstri(alt, " (")) != 0 && ap > alt)
888 * If the object is named, then the name is the alternate description;
889 * otherwise, the result of makesingular() applied to the name is.
890 * This isn't strictly optimal, but named objects of interest to the
891 * user will usually be found under their name, rather than under
892 * their object type, so looking for a singular form is pointless.
895 alt = makesingular(dbase_str);
897 pass1found_in_file = FALSE;
898 for (pass = !strcmp(alt, dbase_str) ? 0 : 1; pass >= 0; --pass) {
899 found_in_file = skipping_entry = FALSE;
901 if (dlb_fseek(fp, txt_offset, SEEK_SET) < 0 ) {
902 impossible("can't get to start of 'data' file");
905 /* skip first record; read second */
906 if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) {
907 impossible("can't read 'data' file");
909 } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1
913 /* look for the appropriate entry */
914 while (dlb_fgets(buf, BUFSZ, fp)) {
916 break; /* we passed last entry without success */
919 /* a number indicates the end of current entry */
920 skipping_entry = FALSE;
921 } else if (!skipping_entry) {
922 if (!(ep = index(buf, '\n')))
924 (void) strip_newline((ep > buf) ? ep - 1 : ep);
925 /* if we match a key that begins with "~", skip
927 chk_skip = (*buf == '~') ? 1 : 0;
928 if ((pass == 0 && pmatch(&buf[chk_skip], dbase_str))
929 || (pass == 1 && alt && pmatch(&buf[chk_skip], alt))) {
931 skipping_entry = TRUE;
934 found_in_file = TRUE;
936 pass1found_in_file = TRUE;
943 long entry_offset, fseekoffset;
947 /* skip over other possible matches for the info */
949 if (!dlb_fgets(buf, BUFSZ, fp))
951 } while (!digit(*buf));
952 if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2)
954 fseekoffset = (long) txt_offset + entry_offset;
956 pass1offset = fseekoffset;
957 else if (fseekoffset == pass1offset)
960 yes_to_moreinfo = FALSE;
961 if (!user_typed_name && !without_asking) {
962 char *entrytext = pass ? alt : dbase_str;
963 char question[QBUFSZ];
966 Strcpy(question, "More info about \"");
967 /* +2 => length of "\"?" */
968 copynchars(eos(question), entrytext,
969 (int) (sizeof question - 1
970 - (strlen(question) + 2)));
971 Strcat(question, "\"?");
973 Strcpy(question, "
\81u");
974 /* +16 => "
\81v
\82Ì
\8fÚ
\8d×
\82ð
\8c©
\82é
\81H"
\82Ì
\92·
\82³ */
975 copynchars(eos(question), entrytext,
976 (int) (sizeof question - 1
977 - (strlen(question) + 16)));
978 Strcat(question, "
\81v
\82Ì
\8fÚ
\8d×
\82ð
\8c©
\82é
\81H");
980 if (yn(question) == 'y')
981 yes_to_moreinfo = TRUE;
984 if (user_typed_name || without_asking || yes_to_moreinfo) {
985 if (dlb_fseek(fp, fseekoffset, SEEK_SET) < 0) {
987 pline("? Seek error on 'data' file!");
989 pline("'data'
\83t
\83@
\83C
\83\8b\82Ì
\83V
\81[
\83N
\83G
\83\89\81[
\81I");
992 datawin = create_nhwindow(NHW_MENU);
993 for (i = 0; i < entry_count; i++) {
994 if (!dlb_fgets(buf, BUFSZ, fp))
996 (void) strip_newline(buf);
997 if (index(buf + 1, '\t') != 0)
998 (void) tabexpand(buf + 1);
999 putstr(datawin, 0, buf + 1);
1001 display_nhwindow(datawin, FALSE);
1002 destroy_nhwindow(datawin), datawin = WIN_ERR;
1004 } else if (user_typed_name && pass == 0 && !pass1found_in_file)
1006 pline("I don't have any information on those things.");
1008 pline("
\82»
\82ñ
\82È
\96¼
\91O
\82Í
\95·
\82¢
\82½
\82±
\82Æ
\82ª
\82È
\82¢
\81D");
1011 goto checkfile_done; /* skip error feedback */
1014 impossible("'data' file in wrong format or corrupted");
1016 if (datawin != WIN_ERR)
1017 destroy_nhwindow(datawin);
1018 (void) dlb_fclose(fp);
1023 do_screen_description(cc, looked, sym, out_str, firstmatch, for_supplement)
1028 const char **firstmatch;
1029 struct permonst **for_supplement;
1032 static const char mon_interior[] = "the interior of a monster",
1034 static const char mon_interior[] = "
\89ö
\95¨
\82Ì
\93à
\95\94",
1036 unreconnoitered[] = "unreconnoitered";
1038 unreconnoitered[] = "
\96¢
\8aÏ
\8e@";
1039 static char look_buf[BUFSZ];
1041 int i, alt_i, j, glyph = NO_GLYPH,
1042 skipped_venom = 0, found = 0; /* count of matching syms found */
1043 boolean hit_trap, need_to_look = FALSE,
1044 submerged = (Underwater && !Is_waterlevel(&u.uz));
1052 glyph = glyph_at(cc.x, cc.y);
1053 /* Convert glyph at selected position to a symbol for use below. */
1054 (void) mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y, 0);
1056 Sprintf(prefix, "%s ", encglyph(glyph));
1058 Sprintf(prefix, "%c ", sym);
1061 * Check all the possibilities, saving all explanations in a buffer.
1062 * When all have been checked then the string is printed.
1066 * Handle restricted vision range (limited to adjacent spots when
1067 * swallowed or underwater) cases first.
1069 * 3.6.0 listed anywhere on map, other than self, as "interior
1070 * of a monster" when swallowed, and non-adjacent water or
1071 * non-water anywhere as "dark part of a room" when underwater.
1072 * "unreconnoitered" is an attempt to convey "even if you knew
1073 * what was there earlier, you don't know what is there in the
1074 * current circumstance".
1076 * (Note: 'self' will always be visible when swallowed so we don't
1077 * need special swallow handling for <ux,uy>.
1078 * Another note: for '#terrain' without monsters, u.uswallow and
1079 * submerged will always both be False and skip this code.)
1083 ; /* skip special handling */
1084 } else if (((u.uswallow || submerged) && distu(cc.x, cc.y) > 2)
1085 /* detection showing some category, so mostly background */
1086 || ((iflags.terrainmode & (TER_DETECT | TER_MAP)) == TER_DETECT
1087 && glyph == cmap_to_glyph(S_stone))) {
1088 x_str = unreconnoitered;
1089 need_to_look = FALSE;
1090 } else if (is_swallow_sym(sym)) {
1091 x_str = mon_interior;
1092 need_to_look = TRUE; /* for specific monster type */
1095 /* we know 'found' is zero here, but guard against some other
1096 special case being inserted ahead of us someday */
1098 Sprintf(out_str, "%s%s", prefix, x_str);
1099 *firstmatch = x_str;
1102 found += append_str(out_str, x_str); /* not 'an(x_str)' */
1104 /* for is_swallow_sym(), we want to list the current symbol's
1105 other possibilities (wand for '/', throne for '\\', &c) so
1106 don't jump to the end for the x_str==mon_interior case */
1107 if (x_str == unreconnoitered)
1111 /* Check for monsters */
1112 if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
1113 for (i = 1; i < MAXMCLASSES; i++) {
1114 if (sym == (looked ? showsyms[i + SYM_OFF_M] : def_monsyms[i].sym)
1115 && def_monsyms[i].explain && *def_monsyms[i].explain) {
1116 need_to_look = TRUE;
1118 Sprintf(out_str, "%s%s",
1119 prefix, an(def_monsyms[i].explain));
1120 *firstmatch = def_monsyms[i].explain;
1123 found += append_str(out_str, an(def_monsyms[i].explain));
1127 /* handle '@' as a special case if it refers to you and you're
1128 playing a character which isn't normally displayed by that
1129 symbol; firstmatch is assumed to already be set for '@' */
1130 if ((looked ? (sym == showsyms[S_HUMAN + SYM_OFF_M]
1131 && cc.x == u.ux && cc.y == u.uy)
1132 : (sym == def_monsyms[S_HUMAN].sym && !flags.showrace))
1133 && !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
1135 found += append_str(out_str, "you"); /* tack on "or you" */
1137 found += append_str(out_str, "
\82 \82È
\82½"); /* tack on "or you" */
1141 /* Now check for objects */
1142 if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
1143 for (i = 1; i < MAXOCLASSES; i++) {
1144 if (sym == (looked ? showsyms[i + SYM_OFF_O]
1145 : def_oc_syms[i].sym)
1146 || (looked && i == ROCK_CLASS && glyph_is_statue(glyph))) {
1147 need_to_look = TRUE;
1148 if (looked && i == VENOM_CLASS) {
1153 Sprintf(out_str, "%s%s",
1154 prefix, an(def_oc_syms[i].explain));
1155 *firstmatch = def_oc_syms[i].explain;
1158 found += append_str(out_str, an(def_oc_syms[i].explain));
1164 if (sym == DEF_INVISIBLE) {
1165 extern const char altinvisexplain[]; /* drawing.c */
1166 /* for active clairvoyance, use alternate "unseen creature" */
1167 boolean usealt = (EDetect_monsters & I_SPECIAL) != 0L;
1168 const char *unseen_explain = !usealt ? invisexplain : altinvisexplain;
1171 Sprintf(out_str, "%s%s", prefix, an(unseen_explain));
1172 *firstmatch = unseen_explain;
1175 found += append_str(out_str, an(unseen_explain));
1179 /* Now check for graphics symbols */
1180 alt_i = (sym == (looked ? showsyms[0] : defsyms[0].sym)) ? 0 : (2 + 1);
1181 for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
1182 /* when sym is the default background character, we process
1183 i == 0 three times: unexplored, stone, dark part of a room */
1186 x_str = !alt_i++ ? "unexplored" : submerged ? "unknown" : "stone";
1188 x_str = !alt_i++ ? "
\96¢
\92T
\8dõ" : submerged ? "
\96¢
\92m" : "
\8aâ
\94Õ";
1189 i = 0; /* for second iteration, undo loop increment */
1190 /* alt_i is now 1 or 2 */
1193 i = 0; /* undo loop increment */
1194 x_str = defsyms[i].explanation;
1195 if (submerged && !strcmp(x_str, defsyms[0].explanation))
1197 x_str = "land"; /* replace "dark part of a room" */
1199 x_str = "
\92n
\96Ê"; /* replace "dark part of a room" */
1201 /* alt_i is now 3 or more and no longer of interest */
1203 if (sym == (looked ? showsyms[i] : defsyms[i].sym) && *x_str) {
1204 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82É
\82Í
\8aÖ
\8cW
\82È
\82¢*/
1205 /* avoid "an unexplored", "an stone", "an air", "a water",
1206 "a floor of a room", "a dark part of a room";
1207 article==2 => "the", 1 => "an", 0 => (none) */
1208 int article = strstri(x_str, " of a room") ? 2
1210 || strcmp(x_str, "air") == 0
1211 || strcmp(x_str, "land") == 0
1212 || strcmp(x_str, "water") == 0);
1216 if (is_cmap_trap(i)) {
1218 Sprintf(out_str, "%sa trap", prefix);
1220 Sprintf(out_str, "%sã©", prefix);
1224 Sprintf(out_str, "%s%s", prefix,
1225 article == 2 ? the(x_str)
1226 : article == 1 ? an(x_str) : x_str);
1228 Sprintf(out_str, "%s%s", prefix, x_str);
1231 *firstmatch = x_str;
1233 } else if (!(hit_trap && is_cmap_trap(i))
1234 && !(found >= 3 && is_cmap_drawbridge(i))
1235 /* don't mention vibrating square outside of Gehennom
1236 unless this happens to be one (hallucination?) */
1237 && (i != S_vibrating_square || Inhell
1238 || (looked && glyph_is_trap(glyph)
1239 && glyph_to_trap(glyph) == VIBRATING_SQUARE))) {
1241 found += append_str(out_str, (article == 2) ? the(x_str)
1242 : (article == 1) ? an(x_str)
1245 found += append_str(out_str, x_str);
1247 if (is_cmap_trap(i))
1251 if (i == S_altar || is_cmap_trap(i))
1252 need_to_look = TRUE;
1256 /* Now check for warning symbols */
1257 for (i = 1; i < WARNCOUNT; i++) {
1258 x_str = def_warnsyms[i].explanation;
1259 if (sym == (looked ? warnsyms[i] : def_warnsyms[i].sym)) {
1261 Sprintf(out_str, "%s%s", prefix, def_warnsyms[i].explanation);
1262 *firstmatch = def_warnsyms[i].explanation;
1265 found += append_str(out_str, def_warnsyms[i].explanation);
1267 /* Kludge: warning trumps boulders on the display.
1268 Reveal the boulder too or player can get confused */
1269 if (looked && sobj_at(BOULDER, cc.x, cc.y))
1271 Strcat(out_str, " co-located with a boulder");
1273 Strcat(out_str, "(
\8b\90\8aâ
\82Æ
\93¯
\82¶
\88Ê
\92u
\82É
\82 \82é)");
1274 break; /* out of for loop*/
1278 /* if we ignored venom and list turned out to be short, put it back */
1279 if (skipped_venom && found < 2) {
1280 x_str = def_oc_syms[VENOM_CLASS].explain;
1282 Sprintf(out_str, "%s%s", prefix, an(x_str));
1283 *firstmatch = x_str;
1286 found += append_str(out_str, an(x_str));
1290 /* Finally, handle some optional overriding symbols */
1291 for (j = SYM_OFF_X; j < SYM_MAX; ++j) {
1292 if (j == (SYM_INVISIBLE + SYM_OFF_X))
1293 continue; /* already handled above */
1294 tmpsym = Is_rogue_level(&u.uz) ? ov_rogue_syms[j]
1295 : ov_primary_syms[j];
1296 if (tmpsym && sym == tmpsym) {
1298 case SYM_BOULDER + SYM_OFF_X:
1301 *firstmatch = "boulder";
1303 *firstmatch = "
\8aâ";
1304 Sprintf(out_str, "%s%s", prefix, an(*firstmatch));
1308 found += append_str(out_str, "boulder");
1310 found += append_str(out_str, "
\8aâ");
1313 case SYM_PET_OVERRIDE + SYM_OFF_X:
1318 /* convert to symbol without override in effect */
1319 (void) mapglyph(glyph, &sym, &oc, &os,
1320 cc.x, cc.y, MG_FLAG_NOOVERRIDE);
1321 goto check_monsters;
1324 case SYM_HERO_OVERRIDE + SYM_OFF_X:
1325 sym = showsyms[S_HUMAN + SYM_OFF_M];
1326 goto check_monsters;
1331 /* handle optional boulder symbol as a special case */
1332 if (o_syms[SYM_BOULDER + SYM_OFF_X]
1333 && sym == o_syms[SYM_BOULDER + SYM_OFF_X]) {
1335 *firstmatch = "boulder";
1336 Sprintf(out_str, "%s%s", prefix, an(*firstmatch));
1339 found += append_str(out_str, "boulder");
1345 * If we are looking at the screen, follow multiple possibilities or
1346 * an ambiguous explanation by something more detailed.
1350 /* 3.6.3: this used to be "That can be many things" (without prefix)
1351 which turned it into a sentence that lacked its terminating period;
1352 we could add one below but reinstating the prefix here is better */
1354 Sprintf(out_str, "%scan be many things", prefix);
1356 Sprintf(out_str, "%s
\82±
\82±
\82É
\82Í
\91½
\82
\82Ì
\82à
\82Ì
\82ª
\82 \82é", prefix);
1360 struct permonst *pm = (struct permonst *)0;
1362 if (found > 1 || need_to_look) {
1364 char temp_buf[BUFSZ];
1366 pm = lookat(cc.x, cc.y, look_buf, monbuf);
1367 if (pm && for_supplement)
1368 *for_supplement = pm;
1369 *firstmatch = look_buf;
1370 if (*(*firstmatch)) {
1371 Sprintf(temp_buf, " (%s)", *firstmatch);
1372 (void) strncat(out_str, temp_buf,
1373 BUFSZ - strlen(out_str) - 1);
1374 found = 1; /* we have something to look up */
1378 Sprintf(temp_buf, " [seen: %s]", monbuf);
1380 Sprintf(temp_buf, " [
\8e\8b\8ao: %s]", monbuf);
1381 (void) strncat(out_str, temp_buf,
1382 BUFSZ - strlen(out_str) - 1);
1390 /* also used by getpos hack in do_name.c */
1392 const char what_is_an_unknown_object[] = "an unknown object";
1394 const char what_is_an_unknown_object[] = "
\93ä
\82Ì
\95¨
\91Ì";
1397 do_look(mode, click_cc)
1401 boolean quick = (mode == 1); /* use cursor; don't search for "more info" */
1402 boolean clicklook = (mode == 2); /* right mouse-click method */
1403 char out_str[BUFSZ] = DUMMY;
1404 const char *firstmatch = 0;
1405 struct permonst *pm = 0, *supplemental_pm = 0;
1406 int i = '\0', ans = 0;
1407 int sym; /* typed symbol or converted glyph */
1408 int found; /* count of matching syms found */
1409 coord cc; /* screen pos of unknown glyph */
1410 boolean save_verbose; /* saved value of flags.verbose */
1411 boolean from_screen; /* question from the screen */
1418 from_screen = TRUE; /* yes, we want to use the cursor */
1421 menu_item *pick_list = (menu_item *) 0;
1426 win = create_nhwindow(NHW_MENU);
1429 /* 'y' and 'n' to keep backwards compatibility with previous
1430 versions: "Specify unknown object by cursor?" */
1431 add_menu(win, NO_GLYPH, &any,
1432 flags.lootabc ? 0 : any.a_char, 'y', ATR_NONE,
1434 "something on the map", MENU_UNSELECTED);
1436 "
\92n
\90}
\8fã
\82É
\82 \82é
\82à
\82Ì", MENU_UNSELECTED);
1438 add_menu(win, NO_GLYPH, &any,
1439 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1441 "something you're carrying", MENU_UNSELECTED);
1443 "
\82 \82È
\82½
\82ª
\8e\9d\82Á
\82Ä
\82¢
\82é
\82à
\82Ì", MENU_UNSELECTED);
1445 add_menu(win, NO_GLYPH, &any,
1446 flags.lootabc ? 0 : any.a_char, 'n', ATR_NONE,
1448 "something else (by symbol or name)", MENU_UNSELECTED);
1450 "
\82»
\82ê
\88È
\8aO(
\83V
\83\93\83{
\83\8b\82©
\96¼
\91O
\82Å
\8ew
\92è)", MENU_UNSELECTED);
1451 if (!u.uswallow && !Hallucination) {
1453 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
1454 "", MENU_UNSELECTED);
1455 /* these options work sensibly for the swallowed case,
1456 but there's no reason for the player to use them then;
1457 objects work fine when hallucinating, but screen
1458 symbol/monster class letter doesn't match up with
1459 bogus monster type, so suppress when hallucinating */
1461 add_menu(win, NO_GLYPH, &any,
1462 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1464 "nearby monsters", MENU_UNSELECTED);
1466 "
\8bß
\82
\82É
\82¢
\82é
\89ö
\95¨", MENU_UNSELECTED);
1468 add_menu(win, NO_GLYPH, &any,
1469 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1471 "all monsters shown on map", MENU_UNSELECTED);
1473 "
\92n
\90}
\8fã
\82É
\82¢
\82é
\91S
\82Ä
\82Ì
\89ö
\95¨", MENU_UNSELECTED);
1475 add_menu(win, NO_GLYPH, &any,
1476 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1478 "nearby objects", MENU_UNSELECTED);
1480 "
\8bß
\82
\82É
\82 \82é
\82à
\82Ì", MENU_UNSELECTED);
1482 add_menu(win, NO_GLYPH, &any,
1483 flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
1485 "all objects shown on map", MENU_UNSELECTED);
1487 "
\92n
\90}
\8fã
\82É
\82 \82é
\91S
\82Ä
\82Ì
\82à
\82Ì", MENU_UNSELECTED);
1490 end_menu(win, "What do you want to look at:");
1492 end_menu(win, "
\89½
\82ð
\8c©
\82é
\81H");
1493 if (select_menu(win, PICK_ONE, &pick_list) > 0) {
1494 i = pick_list->item.a_char;
1495 free((genericptr_t) pick_list);
1497 destroy_nhwindow(win);
1516 invlet = display_inventory((const char *) 0, TRUE);
1517 if (!invlet || invlet == '\033')
1520 for (invobj = invent; invobj; invobj = invobj->nobj)
1521 if (invobj->invlet == invlet) {
1522 strcpy(out_str, singular(invobj, xname));
1526 checkfile(out_str, pm, TRUE, TRUE, (char *) 0);
1530 from_screen = FALSE;
1532 getlin("Specify what? (type the word)", out_str);
1534 getlin("
\89½
\82ð
\92²
\82×
\82é
\81H(
\95¶
\8e\9a\82ð
\93ü
\82ê
\82Ä
\82Ë)", out_str);
1535 if (strcmp(out_str, " ")) /* keep single space as-is */
1536 /* remove leading and trailing whitespace and
1537 condense consecutive internal whitespace */
1538 mungspaces(out_str);
1539 if (out_str[0] == '\0' || out_str[0] == '\033')
1542 if (out_str[1]) { /* user typed in a complete string */
1543 checkfile(out_str, pm, TRUE, TRUE, (char *) 0);
1549 look_all(TRUE, TRUE); /* list nearby monsters */
1552 look_all(FALSE, TRUE); /* list all monsters */
1555 look_all(TRUE, FALSE); /* list nearby objects */
1558 look_all(FALSE, FALSE); /* list all objects */
1561 } else { /* clicklook */
1565 from_screen = FALSE;
1568 /* Save the verbose flag, we change it later. */
1569 save_verbose = flags.verbose;
1570 flags.verbose = flags.verbose && !quick;
1572 * The user typed one letter, or we're identifying from the screen.
1575 /* Reset some variables. */
1576 pm = (struct permonst *) 0;
1580 if (from_screen || clicklook) {
1584 pline("Please move the cursor to %s.",
1585 what_is_an_unknown_object);
1587 pline("
\83J
\81[
\83\
\83\8b\82ð
\95¨
\91Ì
\82É
\88Ú
\93®
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D");
1591 pline("Pick an object.");
1593 pline("
\95¨
\91Ì
\82ð
\8ew
\92è
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81D");
1595 ans = getpos(&cc, quick, what_is_an_unknown_object);
1596 if (ans < 0 || cc.x < 0)
1598 flags.verbose = FALSE; /* only print long question once */
1602 found = do_screen_description(cc, (from_screen || clicklook), sym,
1603 out_str, &firstmatch, &supplemental_pm);
1605 /* Finally, print out our explanation. */
1607 /* use putmixed() because there may be an encoded glyph present */
1608 putmixed(WIN_MESSAGE, 0, out_str);
1613 /* putmixed() bypasses pline() so doesn't write to DUMPLOG;
1614 tty puts it into ^P recall, so it ought to be there;
1615 DUMPLOG is plain text, so override graphics character;
1616 at present, force space, but we ought to use defsyms[]
1617 value for the glyph the graphics character came from */
1618 (void) decode_mixed(dmpbuf, out_str);
1619 if (dmpbuf[0] < ' ' || dmpbuf[0] >= 127) /* ASCII isprint() */
1625 /* check the data file for information about this thing */
1626 if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE
1627 && (ans == LOOK_VERBOSE || (flags.help && !quick))
1629 char temp_buf[BUFSZ], supplemental_name[BUFSZ];
1631 supplemental_name[0] = '\0';
1632 Strcpy(temp_buf, firstmatch);
1633 checkfile(temp_buf, pm, FALSE,
1634 (boolean) (ans == LOOK_VERBOSE), supplemental_name);
1635 if (supplemental_pm)
1636 do_supplemental_info(supplemental_name, supplemental_pm,
1637 (boolean) (ans == LOOK_VERBOSE));
1641 pline("I've never heard of such things.");
1643 pline("
\82»
\82ñ
\82È
\96¼
\91O
\82Í
\95·
\82¢
\82½
\82±
\82Æ
\82ª
\82È
\82¢
\81D");
1645 } while (from_screen && !quick && ans != LOOK_ONCE && !clicklook);
1647 flags.verbose = save_verbose;
1652 look_all(nearby, do_mons)
1653 boolean nearby; /* True => within BOLTLIM, False => entire map */
1654 boolean do_mons; /* True => monsters, False => objects */
1657 int x, y, lo_x, lo_y, hi_x, hi_y, glyph, count = 0;
1658 char lookbuf[BUFSZ], outbuf[BUFSZ];
1660 win = create_nhwindow(NHW_TEXT);
1661 lo_y = nearby ? max(u.uy - BOLT_LIM, 0) : 0;
1662 lo_x = nearby ? max(u.ux - BOLT_LIM, 1) : 1;
1663 hi_y = nearby ? min(u.uy + BOLT_LIM, ROWNO - 1) : ROWNO - 1;
1664 hi_x = nearby ? min(u.ux + BOLT_LIM, COLNO - 1) : COLNO - 1;
1665 for (y = lo_y; y <= hi_y; y++) {
1666 for (x = lo_x; x <= hi_x; x++) {
1668 glyph = glyph_at(x, y);
1670 if (glyph_is_monster(glyph)) {
1673 bhitpos.x = x; /* [is this actually necessary?] */
1675 if (x == u.ux && y == u.uy && canspotself()) {
1676 (void) self_lookat(lookbuf);
1678 } else if ((mtmp = m_at(x, y)) != 0) {
1679 look_at_monster(lookbuf, (char *) 0, mtmp, x, y);
1682 } else if (glyph_is_invisible(glyph)) {
1683 /* remembered, unseen, creature */
1684 Strcpy(lookbuf, invisexplain);
1686 } else if (glyph_is_warning(glyph)) {
1687 int warnindx = glyph_to_warning(glyph);
1689 Strcpy(lookbuf, def_warnsyms[warnindx].explanation);
1692 } else { /* !do_mons */
1693 if (glyph_is_object(glyph)) {
1694 look_at_object(lookbuf, x, y, glyph);
1699 char coordbuf[20], which[12], cmode;
1701 cmode = (iflags.getpos_coords != GPCOORDS_NONE)
1702 ? iflags.getpos_coords : GPCOORDS_MAP;
1704 Strcpy(which, do_mons ? "monsters" : "objects");
1706 Sprintf(outbuf, "%s currently shown near %s:",
1708 (cmode != GPCOORDS_COMPASS)
1709 ? coord_desc(u.ux, u.uy, coordbuf, cmode)
1710 : !canspotself() ? "your position" : "you");
1712 Sprintf(outbuf, "All %s currently shown on the map:",
1714 putstr(win, 0, outbuf);
1717 /* prefix: "coords C " where 'C' is mon or obj symbol */
1718 Sprintf(outbuf, (cmode == GPCOORDS_SCREEN) ? "%s "
1719 : (cmode == GPCOORDS_MAP) ? "%8s "
1721 coord_desc(x, y, coordbuf, cmode));
1722 Sprintf(eos(outbuf), "%s ", encglyph(glyph));
1723 /* guard against potential overflow */
1724 lookbuf[sizeof lookbuf - 1 - strlen(outbuf)] = '\0';
1725 Strcat(outbuf, lookbuf);
1726 putmixed(win, 0, outbuf);
1731 display_nhwindow(win, TRUE);
1734 pline("No %s are currently shown %s.",
1735 do_mons ? "monsters" : "objects",
1736 nearby ? "nearby" : "on the map");
1738 pline("
\8d¡
\82Ì
\82Æ
\82±
\82ë%s
\82É%s
\81D",
1739 nearby ? "
\8bß
\82" : "
\92n
\90}
\8fã",
1740 do_mons ? "
\89ö
\95¨
\82Í
\82¢
\82È
\82¢" : "
\82à
\82Ì
\82Í
\82È
\82¢");
1742 destroy_nhwindow(win);
1745 static const char *suptext1[] = {
1747 "%s is a member of a marauding horde of orcs",
1748 "rumored to have brutally attacked and plundered",
1749 "the ordinarily sheltered town that is located ",
1750 "deep within The Gnomish Mines.",
1752 "The members of that vicious horde proudly and ",
1753 "defiantly acclaim their allegiance to their",
1754 "leader %s in their names.",
1757 "%s
\82Í
\81C
\83m
\81[
\83\80\82Ì
\8dz
\8eR
\82Ì
\89\9c\82É
\88Ê
\92u
\82µ
\82Ä
\82¢
\82é",
1758 "
\92Ê
\8fí
\92Ê
\82è
\96h
\8cä
\82µ
\82Ä
\82¢
\82½
\8aX
\82ð
\97e
\8eÍ
\82È
\82
\8dU
\8c\82\82µ
\82Ä",
1759 "
\97ª
\92D
\82µ
\82½
\82Æ
\89\
\82³
\82ê
\82é
\81C
\83I
\81[
\83N
\82Ì
\8fP
\8c\82\8fW
\92c
\82Ì
\88ê
\88õ
\82Å
\82 \82é
\81D",
1761 "
\82»
\82Ì
\88«
\8e¿
\82È
\8fW
\92c
\82Ì
\83\81\83\93\83o
\81[
\82Í
\81C
\82»
\82Ì
\83\8a\81[
\83_
\81[
\82Å
\82 \82é%s
\82Ì
\96¼
\82Ì
\89º
\82É",
1762 "
\8cÖ
\82ç
\82µ
\82°
\82©
\82Â
\92§
\90í
\93I
\82É
\82»
\82Ì
\92\89\90½
\82ð
\8fÌ
\8e^
\82µ
\82Ä
\82¢
\82é
\81D",
1767 static const char *suptext2[] = {
1769 "\"%s\" is the common dungeon name of",
1770 "a nefarious orc who is known to acquire property",
1771 "from thieves and sell it off for profit.",
1773 "The perpetrator was last seen hanging around the",
1774 "stairs leading to the Gnomish Mines.",
1777 "\"%s\"
\82Í
\81C
\93\90\91¯
\82©
\82ç
\95¨
\95i
\82ð
\93ü
\8eè
\82µ
\82Ä",
1778 "
\97\98\89v
\82ð
\93¾
\82é
\82½
\82ß
\82É
\94\84\82è
\82³
\82Î
\82
\82±
\82Æ
\82Å
\92m
\82ç
\82ê
\82Ä
\82¢
\82é",
1779 "
\96³
\96@
\82È
\83I
\81[
\83N
\82Ì
\88ê
\94Ê
\93I
\82È
\96À
\8b{
\96¼
\82Å
\82 \82é
\81D",
1781 "
\94Æ
\90l
\82ª
\8dÅ
\8cã
\82É
\96Ú
\8c\82\82³
\82ê
\82½
\82Ì
\82Í",
1782 "
\83m
\81[
\83\80\82Ì
\92Y
\8dz
\82Ö
\91±
\82
\8aK
\92i
\82Ì
\8bß
\82
\82Å
\82 \82é
\81D",
1788 do_supplemental_info(name, pm, without_asking)
1790 struct permonst *pm;
1791 boolean without_asking;
1794 winid datawin = WIN_ERR;
1795 char *entrytext = name, *bp = (char *) 0, *bp2 = (char *) 0;
1796 char question[QBUFSZ];
1797 boolean yes_to_moreinfo = FALSE;
1798 boolean is_marauder = (name && pm && is_orc(pm));
1801 * Provide some info on some specific things
1802 * meant to support in-game mythology, and not
1803 * available from data.base or other sources.
1805 if (is_marauder && (strlen(name) < (BUFSZ - 1))) {
1806 char fullname[BUFSZ];
1808 bp = strstri(name, " of ");
1809 bp2 = strstri(name, " the Fence");
1812 Strcpy(fullname, name);
1813 if (!without_asking) {
1814 Strcpy(question, "More info about \"");
1815 /* +2 => length of "\"?" */
1816 copynchars(eos(question), entrytext,
1817 (int) (sizeof question - 1 - (strlen(question) + 2)));
1818 Strcat(question, "\"?");
1819 if (yn(question) == 'y')
1820 yes_to_moreinfo = TRUE;
1822 if (yes_to_moreinfo) {
1824 const char *gang = (char *) 0;
1834 datawin = create_nhwindow(NHW_MENU);
1835 for (i = 0; textp[i]; i++) {
1839 if (strstri(textp[i], "%s") != 0) {
1840 Sprintf(buf, textp[i], subs++ ? gang : fullname);
1844 putstr(datawin, 0, txt);
1846 display_nhwindow(datawin, FALSE);
1847 destroy_nhwindow(datawin), datawin = WIN_ERR;
1853 /* the '/' command */
1857 return do_look(0, (coord *) 0);
1860 /* the ';' command */
1864 return do_look(1, (coord *) 0);
1867 /* the '^' command */
1871 register struct trap *trap;
1872 int x, y, tt, glyph;
1879 /* check fake bear trap from confused gold detection */
1880 glyph = glyph_at(x, y);
1881 if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) {
1882 boolean chesttrap = trapped_chest_at(tt, x, y);
1884 if (chesttrap || trapped_door_at(tt, x, y)) {
1886 pline("That is a trapped %s.", chesttrap ? "chest" : "door");
1888 pline("
\82»
\82ê
\82Íã©
\82ª
\8ed
\8a|
\82¯
\82ç
\82ê
\82½%s
\82¾
\81D", chesttrap ? "
\94 " : "
\94à");
1889 return 0; /* trap ID'd, but no time elapses */
1893 for (trap = ftrap; trap; trap = trap->ntrap)
1894 if (trap->tx == x && trap->ty == y) {
1899 if (u.dz < 0 ? is_hole(tt) : tt == ROCKTRAP)
1902 tt = what_trap(tt, rn2_on_display_rng);
1904 pline("That is %s%s%s.",
1905 an(defsyms[trap_to_defsym(tt)].explanation),
1910 /* trap doors & spiked pits can't be made by
1911 player, and should be considered at least
1912 as much "set" as "dug" anyway */
1913 : (tt == HOLE || tt == PIT)
1916 !trap->madeby_u ? "" : " by you");
1918 pline("
\82»
\82ê
\82Í%s%s
\82¾
\81D",
1922 ? "
\82 \82È
\82½
\82ª
\92£
\82Á
\82½"
1923 : (tt == HOLE || tt == PIT)
1924 ? "
\82 \82È
\82½
\82ª
\8c@
\82Á
\82½"
1925 : "
\82 \82È
\82½
\82ª
\8ed
\8a|
\82¯
\82½",
1926 defsyms[trap_to_defsym(tt)].explanation);
1931 pline("I can't see a trap there.");
1933 pline("
\82»
\82±
\82É
\82Íã©
\82Í
\82Ý
\82 \82½
\82ç
\82È
\82¢
\81D");
1938 Implements a rudimentary if/elif/else/endif interpretor and use
1939 conditionals in dat/cmdhelp to describe what command each keystroke
1940 currently invokes, so that there isn't a lot of "(debug mode only)"
1941 and "(if number_pad is off)" cluttering the feedback that the user
1942 sees. (The conditionals add quite a bit of clutter to the raw data
1943 but users don't see that. number_pad produces a lot of conditional
1944 commands: basic letters vs digits, 'g' vs 'G' for '5', phone
1945 keypad vs normal layout of digits, and QWERTZ keyboard swap between
1946 y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.)
1948 The interpretor understands
1950 '&? option' for 'if' (also '&? !option'
1951 or '&? option=value[,value2,...]'
1952 or '&? !option=value[,value2,...]'),
1953 '&: option' for 'elif' (with argument variations same as 'if';
1954 any number of instances for each 'if'),
1955 '&:' for 'else' (also '&: #comment';
1956 0 or 1 instance for a given 'if'), and
1957 '&.' for 'endif' (also '&. #comment'; required for each 'if').
1959 The option handling is a bit of a mess, with no generality for
1960 which options to deal with and only a comma separated list of
1961 integer values for the '=value' part. number_pad is the only
1962 supported option that has a value; the few others (wizard/debug,
1963 rest_on_space, #if SHELL, #if SUSPEND) are booleans.
1970 char *p, buf[BUFSZ];
1973 fp = dlb_fopen(KEYHELP, "r");
1976 pline("Cannot open \"%s\" data file!", KEYHELP);
1978 pline("
\83f
\81[
\83^
\83t
\83@
\83C
\83\8b\"%s\"
\82ð
\8aJ
\82¯
\82È
\82¢
\81I", KEYHELP);
1979 display_nhwindow(WIN_MESSAGE, TRUE);
1982 tmpwin = create_nhwindow(NHW_TEXT);
1983 while (dlb_fgets(buf, (int) sizeof buf, fp)) {
1986 for (p = buf; *p; p++)
1987 if (*p != ' ' && *p != '\t')
1989 putstr(tmpwin, 0, p);
1991 (void) dlb_fclose(fp);
1992 display_nhwindow(tmpwin, TRUE);
1993 destroy_nhwindow(tmpwin);
1997 #define WD_STACKLIMIT 5
1998 struct wd_stack_frame {
1999 Bitfield(active, 1);
2000 Bitfield(been_true, 1);
2001 Bitfield(else_seen, 1);
2004 STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
2008 whatdoes_cond(buf, stack, depth, lnum)
2010 struct wd_stack_frame *stack;
2013 const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
2014 boolean newcond, neg, gotopt;
2015 char *p, *q, act = buf[1];
2018 newcond = (act == '?' || !stack[*depth].been_true);
2021 if (act == '#' || *buf == '#' || !*buf || !newcond) {
2022 gotopt = (*buf && *buf != '#');
2024 neg = FALSE; /* lint suppression */
2028 if ((neg = (*buf == '!')) != 0)
2031 p = index(buf, '='), q = index(buf, ':');
2032 if (!p || (q && q < p))
2034 if (p) { /* we have a value specified */
2035 /* handle a space before or after (or both) '=' (or ':') */
2036 if (p > buf && p[-1] == ' ')
2037 p[-1] = '\0'; /* end of keyword in buf[] */
2038 *p++ = '\0'; /* terminate keyword, advance to start of value */
2043 if (*buf && (act == '?' || act == ':')) {
2044 if (!strcmpi(buf, "number_pad")) {
2046 newcond = iflags.num_pad;
2048 /* convert internal encoding (separate yes/no and 0..3)
2049 back to user-visible one (-1..4) */
2050 np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
2051 : (-1 * iflags.num_pad_mode); /* -1..0 */
2057 if (atoi(p) == np) {
2063 } else if (!strcmpi(buf, "rest_on_space")) {
2064 newcond = flags.rest_on_space;
2065 } else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
2066 newcond = flags.debug; /* == wizard */
2067 } else if (!strcmpi(buf, "shell")) {
2069 /* should we also check sysopt.shellers? */
2074 } else if (!strcmpi(buf, "suspend")) {
2076 /* sysopt.shellers is also used for dosuspend()... */
2083 "cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
2087 /* this works for number_pad too: &? !number_pad:-1,0
2088 would be true for 1..4 after negation */
2094 case '#': /* comment */
2096 case '.': /* endif */
2098 impossible(badstackfmt, '.', lnum);
2102 case ':': /* else or elif */
2103 if (*depth == 0 || stack[*depth].else_seen) {
2104 impossible(badstackfmt, ':', lnum);
2105 *depth = 1; /* so that stack[*depth - 1] is a valid access */
2107 if (stack[*depth].active || stack[*depth].been_true
2108 || !stack[*depth - 1].active)
2109 stack[*depth].active = 0;
2111 stack[*depth].active = stack[*depth].been_true = 1;
2113 stack[*depth].else_seen = 1;
2116 if (++*depth >= WD_STACKLIMIT) {
2117 impossible(badstackfmt, '?', lnum);
2118 *depth = WD_STACKLIMIT - 1;
2120 stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
2121 stack[*depth].been_true = stack[*depth].active;
2122 stack[*depth].else_seen = 0;
2125 return stack[*depth].active ? TRUE : FALSE;
2130 dowhatdoes_core(q, cbuf)
2137 struct wd_stack_frame stack[WD_STACKLIMIT];
2139 int ctrl, meta, depth = 0, lnum = 0;
2141 const char *ec_desc;
2143 if ((ec_desc = key2extcmddesc(q)) != NULL) {
2144 char keybuf[QBUFSZ];
2146 Sprintf(buf, "%-8s%s.", key2txt(q, keybuf), ec_desc);
2152 fp = dlb_fopen(CMDHELPFILE, "r");
2154 pline("Cannot open \"%s\" data file!", CMDHELPFILE);
2158 meta = (0x80 & (uchar) q) != 0;
2161 ctrl = (0x1f & (uchar) q) == (uchar) q;
2163 q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
2167 (void) memset((genericptr_t) stack, 0, sizeof stack);
2168 cond = stack[0].active = 1;
2169 while (dlb_fgets(buf, sizeof buf, fp)) {
2171 if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
2172 cond = whatdoes_cond(buf, stack, &depth, lnum);
2177 if (meta ? (buf[0] == 'M' && buf[1] == '-'
2178 && (ctrl ? buf[2] == '^' && highc(buf[3]) == q
2180 : (ctrl ? buf[0] == '^' && highc(buf[1]) == q
2182 (void) strip_newline(buf);
2183 if (index(buf, '\t'))
2184 (void) tabexpand(buf);
2185 if (meta && ctrl && buf[4] == ' ') {
2186 (void) strncpy(buf, "M-^? ", 8);
2188 } else if (meta && buf[3] == ' ') {
2189 (void) strncpy(buf, "M-? ", 8);
2191 } else if (ctrl && buf[2] == ' ') {
2192 (void) strncpy(buf, "^? ", 8);
2194 } else if (buf[1] == ' ') {
2195 (void) strncpy(buf, "? ", 8);
2198 (void) dlb_fclose(fp);
2203 (void) dlb_fclose(fp);
2205 impossible("cmdhelp: mismatched &? &: &. conditionals.");
2213 static boolean once = FALSE;
2219 pline("Ask about '&' or '?' to get more info.%s",
2221 iflags.altmeta ? " (For ESC, type it twice.)" :
2225 pline("
\82³
\82ç
\82È
\82é
\8fî
\95ñ
\82É
\82Â
\82¢
\82Ä
\82Í '&'
\82© '?'
\82É
\82Â
\82¢
\82Ä
\82½
\82¸
\82Ë
\82Ü
\82·
\81D%s",
2227 iflags.altmeta ? " (ESC
\82É
\82Â
\82¢
\82Ä
\82Í
\81C2
\89ñ
\83^
\83C
\83v
\82µ
\82Ü
\82·
\81D)" :
2233 #if defined(UNIX) || defined(VMS)
2234 introff(); /* disables ^C but not ^\ */
2237 q = yn_function("What command?", (char *) 0, '\0');
2239 q = yn_function("
\82Ç
\82¤
\82¢
\82¤
\83R
\83}
\83\93\83h
\81H", (char *) 0, '\0');
2241 if (q == '\033' && iflags.altmeta) {
2242 /* in an ideal world, we would know whether another keystroke
2243 was already pending, but this is not an ideal world...
2244 if user typed ESC, we'll essentially hang until another
2245 character is typed */
2246 q = yn_function("]", (char *) 0, '\0');
2248 q = (char) ((uchar) q | 0200);
2251 #if defined(UNIX) || defined(VMS)
2252 intron(); /* reenables ^C */
2254 reslt = dowhatdoes_core(q, bufr);
2256 if (q == '&' || q == '?')
2261 pline("No such command '%s', char code %d (0%03o or 0x%02x).",
2262 visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2264 pline("
\82»
\82ñ
\82È
\83R
\83}
\83\93\83h'%s'
\81C
\95¶
\8e\9a\83R
\81[
\83h%d(0%03o
\82Ü
\82½
\82Í 0x%02x)
\82Í
\82È
\82¢
\81D",
2265 visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2272 docontact(VOID_ARGS)
2274 winid cwin = create_nhwindow(NHW_TEXT);
2277 if (sysopt.support) {
2278 /*XXX overflow possibilities*/
2279 Sprintf(buf, "To contact local support, %s", sysopt.support);
2280 putstr(cwin, 0, buf);
2281 putstr(cwin, 0, "");
2282 } else if (sysopt.fmtd_wizard_list) { /* formatted SYSCF WIZARDS */
2283 Sprintf(buf, "To contact local support, contact %s.",
2284 sysopt.fmtd_wizard_list);
2285 putstr(cwin, 0, buf);
2286 putstr(cwin, 0, "");
2288 putstr(cwin, 0, "To contact the NetHack development team directly,");
2289 /*XXX overflow possibilities*/
2290 Sprintf(buf, "see the 'Contact' form on our website or email <%s>.",
2292 putstr(cwin, 0, buf);
2293 putstr(cwin, 0, "");
2294 putstr(cwin, 0, "For more information on NetHack, or to report a bug,");
2295 Sprintf(buf, "visit our website \"%s\".", DEVTEAM_URL);
2296 putstr(cwin, 0, buf);
2297 display_nhwindow(cwin, FALSE);
2298 destroy_nhwindow(cwin);
2302 dispfile_help(VOID_ARGS)
2304 display_file(HELP, TRUE);
2308 dispfile_shelp(VOID_ARGS)
2310 display_file(SHELP, TRUE);
2314 dispfile_optionfile(VOID_ARGS)
2316 display_file(OPTIONFILE, TRUE);
2320 dispfile_license(VOID_ARGS)
2322 display_file(LICENSE, TRUE);
2326 dispfile_debughelp(VOID_ARGS)
2328 display_file(DEBUGHELP, TRUE);
2332 hmenu_doextversion(VOID_ARGS)
2334 (void) doextversion();
2338 hmenu_dohistory(VOID_ARGS)
2344 hmenu_dowhatis(VOID_ARGS)
2350 hmenu_dowhatdoes(VOID_ARGS)
2352 (void) dowhatdoes();
2356 hmenu_doextlist(VOID_ARGS)
2362 domenucontrols(VOID_ARGS)
2364 winid cwin = create_nhwindow(NHW_TEXT);
2365 show_menu_controls(cwin, FALSE);
2366 display_nhwindow(cwin, FALSE);
2367 destroy_nhwindow(cwin);
2370 /* data for dohelp() */
2374 } help_menu_items[] = {
2376 { hmenu_doextversion, "About NetHack (version information)." },
2378 { hmenu_doextversion, "NetHack
\82É
\82Â
\82¢
\82Ä(
\83o
\81[
\83W
\83\87\83\93\8fî
\95ñ)" },
2380 { dispfile_help, "Long description of the game and commands." },
2382 { dispfile_help, "
\83Q
\81[
\83\80\82¨
\82æ
\82Ñ
\83R
\83}
\83\93\83h
\82Ì
\89ð
\90à(
\92·
\95¶)" },
2384 { dispfile_shelp, "List of game commands." },
2386 { dispfile_shelp, "
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2388 { hmenu_dohistory, "Concise history of NetHack." },
2390 { hmenu_dohistory, "NetHack
\82Ì
\8aÈ
\92P
\82È
\97ð
\8ej" },
2392 { hmenu_dowhatis, "Info on a character in the game display." },
2394 { hmenu_dowhatis, "
\89æ
\96Ê
\82É
\95\
\8e¦
\82³
\82ê
\82é
\95¶
\8e\9a\82Ì
\90à
\96¾" },
2396 { hmenu_dowhatdoes, "Info on what a given key does." },
2398 { hmenu_dowhatdoes, "
\82±
\82Ì
\83L
\81[
\82ª
\89½
\82ð
\88Ó
\96¡
\82·
\82é
\82©
\82Ì
\90à
\96¾" },
2400 { option_help, "List of game options." },
2402 { option_help, "
\83Q
\81[
\83\80\82Ì
\83I
\83v
\83V
\83\87\83\93\88ê
\97\97" },
2404 { dispfile_optionfile, "Longer explanation of game options." },
2406 { dispfile_optionfile, "
\83Q
\81[
\83\80\82Ì
\83I
\83v
\83V
\83\87\83\93\88ê
\97\97(
\92·
\95¶)" },
2408 { dokeylist, "Full list of keyboard commands" },
2410 { dokeylist, "
\83L
\81[
\83{
\81[
\83h
\83R
\83}
\83\93\83h
\82Ì
\8a®
\91S
\82È
\88ê
\97\97" },
2412 { hmenu_doextlist, "List of extended commands." },
2414 { hmenu_doextlist, "
\8ag
\92£
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2416 { domenucontrols, "List menu control keys" },
2418 { domenucontrols, "
\83\81\83j
\83\85\81[
\90§
\8cä
\83L
\81[
\88ê
\97\97s" },
2420 { dispfile_license, "The NetHack license." },
2422 { dispfile_license, "NetHack
\82Ì
\83\89\83C
\83Z
\83\93\83X" },
2424 { docontact, "Support information." },
2426 { docontact, "
\83T
\83|
\81[
\83g
\8fî
\95ñ" },
2429 { port_help, "%s-specific help and commands." },
2431 { port_help, "%s
\82É
\93Á
\97L
\82Ì
\83w
\83\8b\83v
\82Æ
\83R
\83}
\83\93\83h" },
2434 { dispfile_debughelp, "List of wizard-mode commands." },
2436 { dispfile_debughelp, "
\83E
\83B
\83U
\81[
\83h
\83\82\81[
\83h
\82Ì
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2437 { (void NDECL((*))) 0, (char *) 0 }
2440 /* the '?' command */
2444 winid tmpwin = create_nhwindow(NHW_MENU);
2445 char helpbuf[QBUFSZ];
2447 menu_item *selected;
2451 any = zeroany; /* zero all bits */
2454 for (i = 0; help_menu_items[i].text; i++) {
2455 if (!wizard && help_menu_items[i].f == dispfile_debughelp)
2457 if (help_menu_items[i].text[0] == '%') {
2458 Sprintf(helpbuf, help_menu_items[i].text, PORT_ID);
2460 Strcpy(helpbuf, help_menu_items[i].text);
2463 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
2464 helpbuf, MENU_UNSELECTED);
2467 end_menu(tmpwin, "Select one item:");
2469 end_menu(tmpwin, "
\91I
\82ñ
\82Å
\82
\82¾
\82³
\82¢
\81F");
2470 n = select_menu(tmpwin, PICK_ONE, &selected);
2471 destroy_nhwindow(tmpwin);
2473 sel = selected[0].item.a_int - 1;
2474 free((genericptr_t) selected);
2475 (void) (*help_menu_items[sel].f)();
2480 /* the 'V' command; also a choice for '?' */
2484 display_file(HISTORY, TRUE);