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[] = {
1687 "%s is a member of a marauding horde of orcs",
1688 "rumored to have brutally attacked and plundered",
1689 "the ordinarily sheltered town that is located ",
1690 "deep within The Gnomish Mines.",
1692 "The members of that vicious horde proudly and ",
1693 "defiantly acclaim their allegiance to their",
1694 "leader %s in their names.",
1698 static const char *suptext2[] = {
1699 "\"%s\" is the common dungeon name of",
1700 "a nefarious orc who is known to acquire property",
1701 "from thieves and sell it off for profit.",
1703 "The perpetrator was last seen hanging around the",
1704 "stairs leading to the Gnomish Mines.",
1709 do_supplemental_info(name, pm, without_asking)
1711 struct permonst *pm;
1712 boolean without_asking;
1715 winid datawin = WIN_ERR;
1716 char *entrytext = name, *bp = (char *) 0, *bp2 = (char *) 0;
1717 char question[QBUFSZ];
1718 boolean yes_to_moreinfo = FALSE;
1719 boolean is_marauder = (name && pm && is_orc(pm));
1722 * Provide some info on some specific things
1723 * meant to support in-game mythology, and not
1724 * available from data.base or other sources.
1726 if (is_marauder && (strlen(name) < (BUFSZ - 1))) {
1727 char fullname[BUFSZ];
1729 bp = strstri(name, " of ");
1730 bp2 = strstri(name, " the Fence");
1733 Strcpy(fullname, name);
1734 if (!without_asking) {
1735 Strcpy(question, "More info about \"");
1736 /* +2 => length of "\"?" */
1737 copynchars(eos(question), entrytext,
1738 (int) (sizeof question - 1 - (strlen(question) + 2)));
1739 Strcat(question, "\"?");
1740 if (yn(question) == 'y')
1741 yes_to_moreinfo = TRUE;
1743 if (yes_to_moreinfo) {
1745 const char *gang = (char *) 0;
1755 datawin = create_nhwindow(NHW_MENU);
1756 for (i = 0; textp[i]; i++) {
1760 if (strstri(textp[i], "%s") != 0) {
1761 Sprintf(buf, textp[i], subs++ ? gang : fullname);
1765 putstr(datawin, 0, txt);
1767 display_nhwindow(datawin, FALSE);
1768 destroy_nhwindow(datawin), datawin = WIN_ERR;
1774 /* the '/' command */
1778 return do_look(0, (coord *) 0);
1781 /* the ';' command */
1785 return do_look(1, (coord *) 0);
1788 /* the '^' command */
1792 register struct trap *trap;
1793 int x, y, tt, glyph;
1800 /* check fake bear trap from confused gold detection */
1801 glyph = glyph_at(x, y);
1802 if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) {
1803 boolean chesttrap = trapped_chest_at(tt, x, y);
1805 if (chesttrap || trapped_door_at(tt, x, y)) {
1806 pline("That is a trapped %s.", chesttrap ? "chest" : "door");
1807 return 0; /* trap ID'd, but no time elapses */
1811 for (trap = ftrap; trap; trap = trap->ntrap)
1812 if (trap->tx == x && trap->ty == y) {
1817 if (u.dz < 0 ? is_hole(tt) : tt == ROCKTRAP)
1820 tt = what_trap(tt, rn2_on_display_rng);
1822 pline("That is %s%s%s.",
1823 an(defsyms[trap_to_defsym(tt)].explanation),
1828 /* trap doors & spiked pits can't be made by
1829 player, and should be considered at least
1830 as much "set" as "dug" anyway */
1831 : (tt == HOLE || tt == PIT)
1834 !trap->madeby_u ? "" : " by you");
1836 pline("
\82»
\82ê
\82Í%s%s
\82¾
\81D",
1840 ? "
\82 \82È
\82½
\82ª
\92£
\82Á
\82½"
1841 : (tt == HOLE || tt == PIT)
1842 ? "
\82 \82È
\82½
\82ª
\8c@
\82Á
\82½"
1843 : "
\82 \82È
\82½
\82ª
\8ed
\8a|
\82¯
\82½",
1844 defsyms[trap_to_defsym(tt)].explanation);
1849 pline("I can't see a trap there.");
1851 pline("
\82»
\82±
\82É
\82Íã©
\82Í
\82Ý
\82 \82½
\82ç
\82È
\82¢
\81D");
1856 Implements a rudimentary if/elif/else/endif interpretor and use
1857 conditionals in dat/cmdhelp to describe what command each keystroke
1858 currently invokes, so that there isn't a lot of "(debug mode only)"
1859 and "(if number_pad is off)" cluttering the feedback that the user
1860 sees. (The conditionals add quite a bit of clutter to the raw data
1861 but users don't see that. number_pad produces a lot of conditional
1862 commands: basic letters vs digits, 'g' vs 'G' for '5', phone
1863 keypad vs normal layout of digits, and QWERTZ keyboard swap between
1864 y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.)
1866 The interpretor understands
1868 '&? option' for 'if' (also '&? !option'
1869 or '&? option=value[,value2,...]'
1870 or '&? !option=value[,value2,...]'),
1871 '&: option' for 'elif' (with argument variations same as 'if';
1872 any number of instances for each 'if'),
1873 '&:' for 'else' (also '&: #comment';
1874 0 or 1 instance for a given 'if'), and
1875 '&.' for 'endif' (also '&. #comment'; required for each 'if').
1877 The option handling is a bit of a mess, with no generality for
1878 which options to deal with and only a comma separated list of
1879 integer values for the '=value' part. number_pad is the only
1880 supported option that has a value; the few others (wizard/debug,
1881 rest_on_space, #if SHELL, #if SUSPEND) are booleans.
1888 char *p, buf[BUFSZ];
1889 winid tmpwin = create_nhwindow(NHW_TEXT);
1891 fp = dlb_fopen(KEYHELP, "r");
1894 pline("Cannot open \"%s\" data file!", KEYHELP);
1896 pline("
\83f
\81[
\83^
\83t
\83@
\83C
\83\8b\"%s\"
\82ð
\8aJ
\82¯
\82È
\82¢
\81I", KEYHELP);
1897 display_nhwindow(WIN_MESSAGE, TRUE);
1900 while (dlb_fgets(buf, (int) sizeof buf, fp)) {
1903 for (p = buf; *p; p++)
1904 if (*p != ' ' && *p != '\t')
1906 putstr(tmpwin, 0, p);
1908 (void) dlb_fclose(fp);
1909 display_nhwindow(tmpwin, TRUE);
1910 destroy_nhwindow(tmpwin);
1914 #define WD_STACKLIMIT 5
1915 struct wd_stack_frame {
1916 Bitfield(active, 1);
1917 Bitfield(been_true, 1);
1918 Bitfield(else_seen, 1);
1921 STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
1925 whatdoes_cond(buf, stack, depth, lnum)
1927 struct wd_stack_frame *stack;
1930 const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
1931 boolean newcond, neg, gotopt;
1932 char *p, *q, act = buf[1];
1935 newcond = (act == '?' || !stack[*depth].been_true);
1938 if (act == '#' || *buf == '#' || !*buf || !newcond) {
1939 gotopt = (*buf && *buf != '#');
1941 neg = FALSE; /* lint suppression */
1945 if ((neg = (*buf == '!')) != 0)
1948 p = index(buf, '='), q = index(buf, ':');
1949 if (!p || (q && q < p))
1951 if (p) { /* we have a value specified */
1952 /* handle a space before or after (or both) '=' (or ':') */
1953 if (p > buf && p[-1] == ' ')
1954 p[-1] = '\0'; /* end of keyword in buf[] */
1955 *p++ = '\0'; /* terminate keyword, advance to start of value */
1960 if (*buf && (act == '?' || act == ':')) {
1961 if (!strcmpi(buf, "number_pad")) {
1963 newcond = iflags.num_pad;
1965 /* convert internal encoding (separate yes/no and 0..3)
1966 back to user-visible one (-1..4) */
1967 np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
1968 : (-1 * iflags.num_pad_mode); /* -1..0 */
1974 if (atoi(p) == np) {
1980 } else if (!strcmpi(buf, "rest_on_space")) {
1981 newcond = flags.rest_on_space;
1982 } else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
1983 newcond = flags.debug; /* == wizard */
1984 } else if (!strcmpi(buf, "shell")) {
1986 /* should we also check sysopt.shellers? */
1991 } else if (!strcmpi(buf, "suspend")) {
1993 /* sysopt.shellers is also used for dosuspend()... */
2000 "cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
2004 /* this works for number_pad too: &? !number_pad:-1,0
2005 would be true for 1..4 after negation */
2011 case '#': /* comment */
2013 case '.': /* endif */
2015 impossible(badstackfmt, '.', lnum);
2019 case ':': /* else or elif */
2020 if (*depth == 0 || stack[*depth].else_seen) {
2021 impossible(badstackfmt, ':', lnum);
2022 *depth = 1; /* so that stack[*depth - 1] is a valid access */
2024 if (stack[*depth].active || stack[*depth].been_true
2025 || !stack[*depth - 1].active)
2026 stack[*depth].active = 0;
2028 stack[*depth].active = stack[*depth].been_true = 1;
2030 stack[*depth].else_seen = 1;
2033 if (++*depth >= WD_STACKLIMIT) {
2034 impossible(badstackfmt, '?', lnum);
2035 *depth = WD_STACKLIMIT - 1;
2037 stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
2038 stack[*depth].been_true = stack[*depth].active;
2039 stack[*depth].else_seen = 0;
2042 return stack[*depth].active ? TRUE : FALSE;
2047 dowhatdoes_core(q, cbuf)
2054 struct wd_stack_frame stack[WD_STACKLIMIT];
2056 int ctrl, meta, depth = 0, lnum = 0;
2058 const char *ec_desc;
2060 if ((ec_desc = key2extcmddesc(q)) != NULL) {
2061 char keybuf[QBUFSZ];
2063 Sprintf(buf, "%-8s%s.", key2txt(q, keybuf), ec_desc);
2069 fp = dlb_fopen(CMDHELPFILE, "r");
2071 pline("Cannot open \"%s\" data file!", CMDHELPFILE);
2075 meta = (0x80 & (uchar) q) != 0;
2078 ctrl = (0x1f & (uchar) q) == (uchar) q;
2080 q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
2084 (void) memset((genericptr_t) stack, 0, sizeof stack);
2085 cond = stack[0].active = 1;
2086 while (dlb_fgets(buf, sizeof buf, fp)) {
2088 if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
2089 cond = whatdoes_cond(buf, stack, &depth, lnum);
2094 if (meta ? (buf[0] == 'M' && buf[1] == '-'
2095 && (ctrl ? buf[2] == '^' && highc(buf[3]) == q
2097 : (ctrl ? buf[0] == '^' && highc(buf[1]) == q
2099 (void) strip_newline(buf);
2100 if (index(buf, '\t'))
2101 (void) tabexpand(buf);
2102 if (meta && ctrl && buf[4] == ' ') {
2103 (void) strncpy(buf, "M-^? ", 8);
2105 } else if (meta && buf[3] == ' ') {
2106 (void) strncpy(buf, "M-? ", 8);
2108 } else if (ctrl && buf[2] == ' ') {
2109 (void) strncpy(buf, "^? ", 8);
2111 } else if (buf[1] == ' ') {
2112 (void) strncpy(buf, "? ", 8);
2115 (void) dlb_fclose(fp);
2120 (void) dlb_fclose(fp);
2122 impossible("cmdhelp: mismatched &? &: &. conditionals.");
2130 static boolean once = FALSE;
2135 pline("Ask about '&' or '?' to get more info.%s",
2137 iflags.altmeta ? " (For ESC, type it twice.)" :
2142 #if defined(UNIX) || defined(VMS)
2143 introff(); /* disables ^C but not ^\ */
2146 q = yn_function("What command?", (char *) 0, '\0');
2148 q = yn_function("
\82Ç
\82¤
\82¢
\82¤
\83R
\83}
\83\93\83h
\81H", (char *) 0, '\0');
2150 if (q == '\033' && iflags.altmeta) {
2151 /* in an ideal world, we would know whether another keystroke
2152 was already pending, but this is not an ideal world...
2153 if user typed ESC, we'll essentially hang until another
2154 character is typed */
2155 q = yn_function("]", (char *) 0, '\0');
2157 q = (char) ((uchar) q | 0200);
2160 #if defined(UNIX) || defined(VMS)
2161 intron(); /* reenables ^C */
2163 reslt = dowhatdoes_core(q, bufr);
2165 if (q == '&' || q == '?')
2170 pline("No such command '%s', char code %d (0%03o or 0x%02x).",
2171 visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2173 pline("
\82»
\82ñ
\82È
\83R
\83}
\83\93\83h'%s'
\81C
\95¶
\8e\9a\83R
\81[
\83h%d(0%03o
\82Ü
\82½
\82Í 0x%02x)
\82Í
\82È
\82¢
\81D",
2174 visctrl(q), (uchar) q, (uchar) q, (uchar) q);
2181 docontact(VOID_ARGS)
2183 winid cwin = create_nhwindow(NHW_TEXT);
2186 if (sysopt.support) {
2187 /*XXX overflow possibilities*/
2188 Sprintf(buf, "To contact local support, %s", sysopt.support);
2189 putstr(cwin, 0, buf);
2190 putstr(cwin, 0, "");
2191 } else if (sysopt.fmtd_wizard_list) { /* formatted SYSCF WIZARDS */
2192 Sprintf(buf, "To contact local support, contact %s.",
2193 sysopt.fmtd_wizard_list);
2194 putstr(cwin, 0, buf);
2195 putstr(cwin, 0, "");
2197 putstr(cwin, 0, "To contact the NetHack development team directly,");
2198 /*XXX overflow possibilities*/
2199 Sprintf(buf, "see the 'Contact' form on our website or email <%s>.",
2201 putstr(cwin, 0, buf);
2202 putstr(cwin, 0, "");
2203 putstr(cwin, 0, "For more information on NetHack, or to report a bug,");
2204 Sprintf(buf, "visit our website \"%s\".", DEVTEAM_URL);
2205 putstr(cwin, 0, buf);
2206 display_nhwindow(cwin, FALSE);
2207 destroy_nhwindow(cwin);
2211 dispfile_help(VOID_ARGS)
2213 display_file(HELP, TRUE);
2217 dispfile_shelp(VOID_ARGS)
2219 display_file(SHELP, TRUE);
2223 dispfile_optionfile(VOID_ARGS)
2225 display_file(OPTIONFILE, TRUE);
2229 dispfile_license(VOID_ARGS)
2231 display_file(LICENSE, TRUE);
2235 dispfile_debughelp(VOID_ARGS)
2237 display_file(DEBUGHELP, TRUE);
2241 hmenu_doextversion(VOID_ARGS)
2243 (void) doextversion();
2247 hmenu_dohistory(VOID_ARGS)
2253 hmenu_dowhatis(VOID_ARGS)
2259 hmenu_dowhatdoes(VOID_ARGS)
2261 (void) dowhatdoes();
2265 hmenu_doextlist(VOID_ARGS)
2271 domenucontrols(VOID_ARGS)
2273 winid cwin = create_nhwindow(NHW_TEXT);
2274 show_menu_controls(cwin, FALSE);
2275 display_nhwindow(cwin, FALSE);
2276 destroy_nhwindow(cwin);
2279 /* data for dohelp() */
2283 } help_menu_items[] = {
2285 { hmenu_doextversion, "About NetHack (version information)." },
2287 { hmenu_doextversion, "NetHack
\82É
\82Â
\82¢
\82Ä(
\83o
\81[
\83W
\83\87\83\93\8fî
\95ñ)" },
2289 { dispfile_help, "Long description of the game and commands." },
2291 { dispfile_help, "
\83Q
\81[
\83\80\82¨
\82æ
\82Ñ
\83R
\83}
\83\93\83h
\82Ì
\89ð
\90à(
\92·
\95¶)" },
2293 { dispfile_shelp, "List of game commands." },
2295 { dispfile_shelp, "
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2297 { hmenu_dohistory, "Concise history of NetHack." },
2299 { hmenu_dohistory, "NetHack
\82Ì
\8aÈ
\92P
\82È
\97ð
\8ej" },
2301 { hmenu_dowhatis, "Info on a character in the game display." },
2303 { hmenu_dowhatis, "
\89æ
\96Ê
\82É
\95\
\8e¦
\82³
\82ê
\82é
\95¶
\8e\9a\82Ì
\90à
\96¾" },
2305 { hmenu_dowhatdoes, "Info on what a given key does." },
2307 { hmenu_dowhatdoes, "
\82±
\82Ì
\83L
\81[
\82ª
\89½
\82ð
\88Ó
\96¡
\82·
\82é
\82©
\82Ì
\90à
\96¾" },
2309 { option_help, "List of game options." },
2311 { option_help, "
\83Q
\81[
\83\80\82Ì
\83I
\83v
\83V
\83\87\83\93\88ê
\97\97" },
2313 { dispfile_optionfile, "Longer explanation of game options." },
2315 { dispfile_optionfile, "
\83Q
\81[
\83\80\82Ì
\83I
\83v
\83V
\83\87\83\93\88ê
\97\97(
\92·
\95¶)" },
2317 { dokeylist, "Full list of keyboard commands" },
2319 { dokeylist, "
\83L
\81[
\83{
\81[
\83h
\83R
\83}
\83\93\83h
\82Ì
\8a®
\91S
\82È
\88ê
\97\97" },
2321 { hmenu_doextlist, "List of extended commands." },
2323 { hmenu_doextlist, "
\8ag
\92£
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2325 { domenucontrols, "List menu control keys" },
2327 { domenucontrols, "
\83\81\83j
\83\85\81[
\90§
\8cä
\83L
\81[
\88ê
\97\97s" },
2329 { dispfile_license, "The NetHack license." },
2331 { dispfile_license, "NetHack
\82Ì
\83\89\83C
\83Z
\83\93\83X" },
2333 { docontact, "Support information." },
2335 { docontact, "
\83T
\83|
\81[
\83g
\8fî
\95ñ" },
2338 { port_help, "%s-specific help and commands." },
2340 { port_help, "%s
\82É
\93Á
\97L
\82Ì
\83w
\83\8b\83v
\82Æ
\83R
\83}
\83\93\83h" },
2343 { dispfile_debughelp, "List of wizard-mode commands." },
2345 { dispfile_debughelp, "
\83E
\83B
\83U
\81[
\83h
\83\82\81[
\83h
\82Ì
\83R
\83}
\83\93\83h
\88ê
\97\97" },
2346 { (void NDECL((*))) 0, (char *) 0 }
2349 /* the '?' command */
2353 winid tmpwin = create_nhwindow(NHW_MENU);
2354 char helpbuf[QBUFSZ];
2356 menu_item *selected;
2360 any = zeroany; /* zero all bits */
2363 for (i = 0; help_menu_items[i].text; i++) {
2364 if (!wizard && help_menu_items[i].f == dispfile_debughelp)
2366 if (help_menu_items[i].text[0] == '%') {
2367 Sprintf(helpbuf, help_menu_items[i].text, PORT_ID);
2369 Strcpy(helpbuf, help_menu_items[i].text);
2372 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
2373 helpbuf, MENU_UNSELECTED);
2376 end_menu(tmpwin, "Select one item:");
2378 end_menu(tmpwin, "
\91I
\82ñ
\82Å
\82
\82¾
\82³
\82¢
\81F");
2379 n = select_menu(tmpwin, PICK_ONE, &selected);
2380 destroy_nhwindow(tmpwin);
2382 sel = selected[0].item.a_int - 1;
2383 free((genericptr_t) selected);
2384 (void) (*help_menu_items[sel].f)();
2389 /* the 'V' command; also a choice for '?' */
2393 display_file(HISTORY, TRUE);