/* SCCS Id: @(#)pager.c 3.3 1999/10/10 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file contains the command routines dowhatis() and dohelp() and */ /* a few other help related facilities */ #include "hack.h" #include "dlb.h" STATIC_DCL boolean FDECL(is_swallow_sym, (int)); STATIC_DCL int FDECL(append_str, (char *, const char *)); STATIC_DCL struct permonst * FDECL(lookat, (int, int, char *, char *)); STATIC_DCL void FDECL(checkfile, (char *,struct permonst *,BOOLEAN_P,BOOLEAN_P)); STATIC_DCL int FDECL(do_look, (BOOLEAN_P)); STATIC_DCL boolean FDECL(help_menu, (int *)); #ifdef PORT_HELP extern void NDECL(port_help); #endif /* Returns "true" for characters that could represent a monster's stomach. */ STATIC_OVL boolean is_swallow_sym(c) int c; { int i; for (i = S_sw_tl; i <= S_sw_br; i++) if ((int)showsyms[i] == c) return TRUE; return FALSE; } /* * Append new_str to the end of buf if new_str doesn't already exist as * a substring of buf. Return 1 if the string was appended, 0 otherwise. * It is expected that buf is of size BUFSZ. */ STATIC_OVL int append_str(buf, new_str) char *buf; const char *new_str; { int space_left; /* space remaining in buf */ if (strstri(buf, new_str)) return 0; space_left = BUFSZ - strlen(buf) - 1; (void) strncat(buf, " or ", space_left); (void) strncat(buf, new_str, space_left - 4); return 1; } /* * Return the name of the glyph found at (x,y). * If not hallucinating and the glyph is a monster, also monster data. */ STATIC_OVL struct permonst * lookat(x, y, buf, monbuf) int x, y; char *buf, *monbuf; { register struct monst *mtmp = (struct monst *) 0; struct permonst *pm = (struct permonst *) 0; int glyph; buf[0] = monbuf[0] = 0; glyph = glyph_at(x,y); if (u.ux == x && u.uy == y && canseeself()) { char race[QBUFSZ]; /* if not polymorphed, show both the role and the race */ race[0] = 0; if (!Upolyd) { Sprintf(race, "%s ", urace.adj); } Sprintf(buf, "%s%s%s called %s", Invis ? "invisible " : "", race, mons[u.umonnum].mname, plname); #ifdef STEED if (u.usteed) { char steedbuf[BUFSZ]; Sprintf(steedbuf, ", mounted on %s", y_monnam(u.usteed)); /* assert((sizeof buf >= strlen(buf)+strlen(steedbuf)+1); */ Strcat(buf, steedbuf); } #endif } else if (u.uswallow) { /* all locations when swallowed other than the hero are the monster */ Sprintf(buf, "interior of %s", Blind ? "a monster" : a_monnam(u.ustuck)); pm = u.ustuck->data; } else if (glyph_is_monster(glyph)) { bhitpos.x = x; bhitpos.y = y; mtmp = m_at(x,y); if(mtmp != (struct monst *) 0) { register boolean hp = (mtmp->data == &mons[PM_HIGH_PRIEST]); pm = mtmp->data; Sprintf(buf, "%s%s%s", (mtmp->mx != x || mtmp->my != y) ? ((mtmp->isshk && !Hallucination) ? "tail of " : "tail of a ") : "", (!hp && mtmp->mtame && !Hallucination) ? "tame " : (!hp && mtmp->mpeaceful && !Hallucination) ? "peaceful " : "", (hp ? "high priest" : x_monnam(mtmp, ARTICLE_NONE, (char *)0, 0, TRUE))); if (u.ustuck == mtmp) Strcat(buf, (Upolyd && sticks(youmonst.data)) ? ", being held" : ", holding you"); if (mtmp->mleashed) Strcat(buf, ", leashed to you"); { int ways_seen = 0, normal = 0, xraydist; boolean useemon = (boolean) canseemon(mtmp); xraydist = (u.xray_range<0) ? -1 : u.xray_range * u.xray_range; /* normal vision */ if ((mtmp->wormno ? worm_known(mtmp) : cansee(mtmp->mx, mtmp->my)) && mon_visible(mtmp) && !mtmp->minvis) { ways_seen++; normal++; } /* see invisible */ if (useemon && mtmp->minvis) ways_seen++; /* infravision */ if ((!mtmp->minvis || See_invisible) && see_with_infrared(mtmp)) ways_seen++; /* telepathy */ if (tp_sensemon(mtmp)) ways_seen++; /* xray */ if (useemon && xraydist > 0 && distu(mtmp->mx, mtmp->my) <= xraydist) ways_seen++; if (Detect_monsters) ways_seen++; if (MATCH_WARN_OF_MON(mtmp)) ways_seen++; if (ways_seen > 1 || !normal) { if (normal) { Strcat(monbuf, "normal vision"); /* can't actually be 1 yet here */ if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (useemon && mtmp->minvis) { Strcat(monbuf, "see invisible"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if ((!mtmp->minvis || See_invisible) && see_with_infrared(mtmp)) { Strcat(monbuf, "infravision"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (tp_sensemon(mtmp)) { Strcat(monbuf, "telepathy"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (useemon && xraydist > 0 && distu(mtmp->mx, mtmp->my) <= xraydist) { /* Eyes of the Overworld */ Strcat(monbuf, "astral vision"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (Detect_monsters) { Strcat(monbuf, "monster detection"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (MATCH_WARN_OF_MON(mtmp)) { char wbuf[BUFSZ]; Sprintf(wbuf, "warned of %s", makeplural(mtmp->data->mname)); Strcat(monbuf, wbuf); if (ways_seen-- > 1) Strcat(monbuf, ", "); } } } } } else if (glyph_is_object(glyph)) { struct obj *otmp = vobj_at(x,y); if (!otmp || otmp->otyp != glyph_to_obj(glyph)) { if (glyph_to_obj(glyph) != STRANGE_OBJECT) { otmp = mksobj(glyph_to_obj(glyph), FALSE, FALSE); if (otmp->oclass == GOLD_CLASS) otmp->quan = 2L; /* to force pluralization */ else if (otmp->otyp == SLIME_MOLD) otmp->spe = current_fruit; /* give the fruit a type */ Strcpy(buf, distant_name(otmp, xname)); dealloc_obj(otmp); } } else Strcpy(buf, distant_name(otmp, xname)); if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) Strcat(buf, " embedded in stone"); else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR) Strcat(buf, " embedded in a wall"); else if (closed_door(x,y)) Strcat(buf, " embedded in a door"); else if (is_pool(x,y)) Strcat(buf, " in water"); else if (is_lava(x,y)) Strcat(buf, " in molten lava"); /* [can this ever happen?] */ } else if (glyph_is_trap(glyph)) { int tnum = what_trap(glyph_to_trap(glyph)); Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation); } else if(!glyph_is_cmap(glyph)) { Strcpy(buf,"dark part of a room"); } else switch(glyph_to_cmap(glyph)) { case S_altar: if(!In_endgame(&u.uz)) Sprintf(buf, "%s altar", align_str(Amask2align(levl[x][y].altarmask & ~AM_SHRINE))); else Sprintf(buf, "aligned altar"); break; case S_ndoor: if (is_drawbridge_wall(x, y) >= 0) Strcpy(buf,"open drawbridge portcullis"); else if ((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN) Strcpy(buf,"broken door"); else Strcpy(buf,"doorway"); break; case S_cloud: Strcpy(buf, Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud"); break; default: Strcpy(buf,defsyms[glyph_to_cmap(glyph)].explanation); break; } return ((pm && !Hallucination) ? pm : (struct permonst *) 0); } /* * Look in the "data" file for more info. Called if the user typed in the * whole name (user_typed_name == TRUE), or we've found a possible match * with a character/glyph and flags.help is TRUE. * * NOTE: when (user_typed_name == FALSE), inp is considered read-only and * must not be changed directly, e.g. via lcase(). We want to force * lcase() for data.base lookup so that we can have a clean key. * Therefore, we create a copy of inp _just_ for data.base lookup. */ STATIC_OVL void checkfile(inp, pm, user_typed_name, without_asking) char *inp; struct permonst *pm; boolean user_typed_name, without_asking; { dlb *fp; char buf[BUFSZ], newstr[BUFSZ]; char *ep, *dbase_str; long txt_offset; int chk_skip; boolean found_in_file = FALSE, skipping_entry = FALSE; fp = dlb_fopen(DATAFILE, "r"); if (!fp) { pline("Cannot open data file!"); return; } /* To prevent the need for entries in data.base like *ngel to account * for Angel and angel, make the lookup string the same for both * user_typed_name and picked name. */ if (pm != (struct permonst *) 0 && !user_typed_name) dbase_str = strcpy(newstr, pm->mname); else dbase_str = strcpy(newstr, inp); (void) lcase(dbase_str); if (!strncmp(dbase_str, "interior of ", 12)) dbase_str += 12; if (!strncmp(dbase_str, "a ", 2)) dbase_str += 2; else if (!strncmp(dbase_str, "an ", 3)) dbase_str += 3; else if (!strncmp(dbase_str, "the ", 4)) dbase_str += 4; if (!strncmp(dbase_str, "tame ", 5)) dbase_str += 5; else if (!strncmp(dbase_str, "peaceful ", 9)) dbase_str += 9; if (!strncmp(dbase_str, "invisible ", 10)) dbase_str += 10; if (!strncmp(dbase_str, "statue of ", 10)) dbase_str[6] = '\0'; else if (!strncmp(dbase_str, "figurine of ", 12)) dbase_str[8] = '\0'; /* Make sure the name is non-empty. */ if (*dbase_str) { /* adjust the input to remove "named " and convert to lower case */ char *alt = 0; /* alternate description */ if ((ep = strstri(dbase_str, " named ")) != 0) alt = ep + 7; else ep = strstri(dbase_str, " called "); if (ep) *ep = '\0'; else if ((ep = strstri(dbase_str, ", ")) != 0) *ep = '\0'; /* * If the object is named, then the name is the alternate description; * otherwise, the result of makesingular() applied to the name is. This * isn't strictly optimal, but named objects of interest to the user * will usually be found under their name, rather than under their * object type, so looking for a singular form is pointless. */ if (!alt) alt = makesingular(dbase_str); else if (user_typed_name) (void) lcase(alt); /* skip first record; read second */ txt_offset = 0L; if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) { impossible("can't read 'data' file"); (void) dlb_fclose(fp); return; } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset <= 0) goto bad_data_file; /* look for the appropriate entry */ while (dlb_fgets(buf,BUFSZ,fp)) { if (*buf == '.') break; /* we passed last entry without success */ if (digit(*buf)) { /* a number indicates the end of current entry */ skipping_entry = FALSE; } else if (!skipping_entry) { if (!(ep = index(buf, '\n'))) goto bad_data_file; *ep = 0; /* if we match a key that begins with "~", skip this entry */ chk_skip = (*buf == '~') ? 1 : 0; if (pmatch(&buf[chk_skip], dbase_str) || (alt && pmatch(&buf[chk_skip], alt))) { if (chk_skip) { skipping_entry = TRUE; continue; } else { found_in_file = TRUE; break; } } } } } if(found_in_file) { long entry_offset; int entry_count; int i; /* skip over other possible matches for the info */ do { if (!dlb_fgets(buf, BUFSZ, fp)) goto bad_data_file; } while (!digit(*buf)); if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) { bad_data_file: impossible("'data' file in wrong format"); (void) dlb_fclose(fp); return; } if (user_typed_name || without_asking || yn("More info?") == 'y') { winid datawin; if (dlb_fseek(fp, txt_offset + entry_offset, SEEK_SET) < 0) { pline("? Seek error on 'data' file!"); (void) dlb_fclose(fp); return; } datawin = create_nhwindow(NHW_MENU); for (i = 0; i < entry_count; i++) { if (!dlb_fgets(buf, BUFSZ, fp)) goto bad_data_file; if ((ep = index(buf, '\n')) != 0) *ep = 0; if (index(buf+1, '\t') != 0) (void) tabexpand(buf+1); putstr(datawin, 0, buf+1); } display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin); } } else if (user_typed_name) pline("I don't have any information on those things."); (void) dlb_fclose(fp); } /* getpos() return values */ #define LOOK_TRADITIONAL 0 /* '.' -- ask about "more info?" */ #define LOOK_QUICK 1 /* ',' -- skip "more info?" */ #define LOOK_ONCE 2 /* ';' -- skip and stop looping */ #define LOOK_VERBOSE 3 /* ':' -- show more info w/o asking */ /* also used by getpos hack in do_name.c */ const char what_is_an_unknown_object[] = "an unknown object"; STATIC_OVL int do_look(quick) boolean quick; /* use cursor && don't search for "more info" */ { char out_str[BUFSZ], look_buf[BUFSZ]; const char *x_str, *firstmatch = 0; struct permonst *pm = 0; int i, ans = 0; int sym; /* typed symbol or converted glyph */ int found; /* count of matching syms found */ coord cc; /* screen pos of unknown glyph */ boolean save_verbose; /* saved value of flags.verbose */ boolean from_screen; /* question from the screen */ boolean need_to_look; /* need to get explan. from glyph */ boolean hit_trap; /* true if found trap explanation */ int skipped_venom = 0; /* non-zero if we ignored "splash of venom" */ static const char *mon_interior = "the interior of a monster"; if (quick) { from_screen = TRUE; /* yes, we want to use the cursor */ } else { i = ynq("Specify unknown object by cursor?"); if (i == 'q') return 0; from_screen = (i == 'y'); } if (from_screen) { cc.x = u.ux; cc.y = u.uy; sym = 0; /* gcc -Wall lint */ } else { getlin("Specify what? (type the word)", out_str); if (out_str[0] == '\0' || out_str[0] == '\033') return 0; if (out_str[1]) { /* user typed in a complete string */ checkfile(out_str, pm, TRUE, TRUE); return 0; } sym = out_str[0]; } /* Save the verbose flag, we change it later. */ save_verbose = flags.verbose; flags.verbose = flags.verbose && !quick; /* * The user typed one letter, or we're identifying from the screen. */ do { /* Reset some variables. */ need_to_look = FALSE; pm = (struct permonst *)0; found = 0; out_str[0] = '\0'; if (from_screen) { int glyph; /* glyph at selected position */ if (flags.verbose) pline("Please move the cursor to %s.", what_is_an_unknown_object); else pline("Pick an object."); ans = getpos(&cc, quick, what_is_an_unknown_object); if (ans < 0 || cc.x < 0) { flags.verbose = save_verbose; return 0; /* done */ } flags.verbose = FALSE; /* only print long question once */ /* Convert the glyph at the selected position to a symbol. */ glyph = glyph_at(cc.x,cc.y); if (glyph_is_cmap(glyph)) { sym = showsyms[glyph_to_cmap(glyph)]; } else if (glyph_is_trap(glyph)) { sym = showsyms[trap_to_defsym(glyph_to_trap(glyph))]; } else if (glyph_is_object(glyph)) { sym = oc_syms[(int)objects[glyph_to_obj(glyph)].oc_class]; } else if (glyph_is_monster(glyph)) { /* takes care of pets, detected, ridden, and regular mons */ sym = monsyms[(int)mons[glyph_to_mon(glyph)].mlet]; } else if (glyph_is_swallow(glyph)) { sym = showsyms[glyph_to_swallow(glyph)+S_sw_tl]; } else if (glyph_is_invisible(glyph)) { sym = DEF_INVISIBLE; } else if (glyph_is_warning(glyph)) { sym = glyph_to_warning(glyph); sym = warnsyms[sym]; } else { impossible("do_look: bad glyph %d at (%d,%d)", glyph, (int)cc.x, (int)cc.y); sym = ' '; } } /* * Check all the possibilities, saving all explanations in a buffer. * When all have been checked then the string is printed. */ /* Check for monsters */ for (i = 0; i < MAXMCLASSES; i++) { if (sym == (from_screen ? monsyms[i] : def_monsyms[i])) { need_to_look = TRUE; if (!found) { Sprintf(out_str, "%c %s", sym, an(monexplain[i])); firstmatch = monexplain[i]; found++; } else { found += append_str(out_str, an(monexplain[i])); } } } /* handle '@' as a special case; firstmatch is guaranteed to already be set in that case */ if (!from_screen ? (sym == def_monsyms[S_HUMAN]) : (cc.x == u.ux && cc.y == u.uy && sym == monsyms[S_HUMAN])) found += append_str(out_str, "you"); /* tack on "or you" */ /* * Special case: if identifying from the screen, and we're swallowed, * and looking at something other than our own symbol, then just say * "the interior of a monster". */ if (u.uswallow && from_screen && is_swallow_sym(sym)) { if (!found) { Sprintf(out_str, "%c %s", sym, mon_interior); firstmatch = mon_interior; } else { found += append_str(out_str, mon_interior); } need_to_look = TRUE; } /* Now check for objects */ for (i = 1; i < MAXOCLASSES; i++) { if (sym == (from_screen ? oc_syms[i] : def_oc_syms[i])) { need_to_look = TRUE; if (from_screen && i == VENOM_CLASS) { skipped_venom++; continue; } if (!found) { Sprintf(out_str, "%c %s", sym, an(objexplain[i])); firstmatch = objexplain[i]; found++; } else { found += append_str(out_str, an(objexplain[i])); } } } if (sym == DEF_INVISIBLE) { if (!found) { Sprintf(out_str, "%c %s", sym, an(invisexplain)); firstmatch = invisexplain; found++; } else { found += append_str(out_str, an(invisexplain)); } } #define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap) #define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge) /* Now check for graphics symbols */ for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) { x_str = defsyms[i].explanation; if (sym == (from_screen ? showsyms[i] : defsyms[i].sym) && *x_str) { /* avoid "an air", "a water", or "a floor of a room" */ int article = (i == S_room) ? 2 : /* 2=>"the" */ !(strcmp(x_str, "air") == 0 || /* 1=>"an" */ strcmp(x_str, "water") == 0); /* 0=>(none)*/ if (!found) { if (is_cmap_trap(i)) { Sprintf(out_str, "%c a trap", sym); hit_trap = TRUE; } else { Sprintf(out_str, "%c %s", sym, article == 2 ? the(x_str) : article == 1 ? an(x_str) : x_str); } firstmatch = x_str; found++; } else if (!u.uswallow && !(hit_trap && is_cmap_trap(i)) && !(found >= 3 && is_cmap_drawbridge(i))) { found += append_str(out_str, article == 2 ? the(x_str) : article == 1 ? an(x_str) : x_str); if (is_cmap_trap(i)) hit_trap = TRUE; } if (i == S_altar || is_cmap_trap(i)) need_to_look = TRUE; } } /* Now check for warning symbols */ for (i = 0; i < WARNCOUNT; i++) { x_str = def_warnsyms[i].explanation; if (sym == (from_screen ? warnsyms[i] : def_warnsyms[i].sym)) { if (!found) { Sprintf(out_str, "%c %s", sym, def_warnsyms[i].explanation); firstmatch = def_warnsyms[i].explanation; found++; } else { found += append_str(out_str, def_warnsyms[i].explanation); } break; /* out of for loop*/ } } /* if we ignored venom and list turned out to be short, put it back */ if (skipped_venom && found < 2) { x_str = objexplain[VENOM_CLASS]; if (!found) { Sprintf(out_str, "%c %s", sym, an(x_str)); firstmatch = x_str; found++; } else { found += append_str(out_str, an(x_str)); } } /* * If we are looking at the screen, follow multiple possibilities or * an ambiguous explanation by something more detailed. */ if (from_screen) { if (found > 1 || need_to_look) { char monbuf[BUFSZ]; char temp_buf[BUFSZ], coybuf[QBUFSZ]; pm = lookat(cc.x, cc.y, look_buf, monbuf); firstmatch = look_buf; if (*firstmatch) { Sprintf(temp_buf, " (%s)", (pm == &mons[PM_COYOTE]) ? coyotename(coybuf) : firstmatch); (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1); found = 1; /* we have something to look up */ } if (monbuf[0]) { Sprintf(temp_buf, " [seen: %s]", monbuf); (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1); } } } /* Finally, print out our explanation. */ if (found) { pline("%s", out_str); /* check the data file for information about this thing */ if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE && (ans == LOOK_VERBOSE || (flags.help && !quick))) { char temp_buf[BUFSZ]; Strcpy(temp_buf, firstmatch); checkfile(temp_buf, pm, FALSE, (boolean)(ans == LOOK_VERBOSE)); } } else { pline("I've never heard of such things."); } } while (from_screen && !quick && ans != LOOK_ONCE); flags.verbose = save_verbose; return 0; } int dowhatis() { return do_look(FALSE); } int doquickwhatis() { return do_look(TRUE); } #ifdef JTP_GRAPHICS struct permonst * jtp_do_lookat(x, y, buf, monbuf) int x, y; char *buf, *monbuf; { return lookat(x, y, buf, monbuf); } #endif int doidtrap() { register struct trap *trap; int x, y, tt; if (!getdir((char *)0)) return 0; x = u.ux + u.dx; y = u.uy + u.dy; for (trap = ftrap; trap; trap = trap->ntrap) if (trap->tx == x && trap->ty == y) { if (!trap->tseen) break; tt = trap->ttyp; if (u.dz) { if (u.dz < 0 ? (tt == TRAPDOOR || tt == HOLE) : tt == ROCKTRAP) break; } tt = what_trap(tt); pline("That is %s%s%s.", an(defsyms[trap_to_defsym(tt)].explanation), !trap->madeby_u ? "" : (tt == WEB) ? " woven" : /* trap doors & spiked pits can't be made by player, and should be considered at least as much "set" as "dug" anyway */ (tt == HOLE || tt == PIT) ? " dug" : " set", !trap->madeby_u ? "" : " by you"); return 0; } pline("I can't see a trap there."); return 0; } int dowhatdoes() { dlb *fp; char bufr[BUFSZ+6]; register char *buf = &bufr[6], *ep, q, ctrl, meta; fp = dlb_fopen(CMDHELPFILE, "r"); if (!fp) { pline("Cannot open data file!"); return 0; } #if defined(UNIX) || defined(VMS) introff(); #endif q = yn_function("What command?", (char *)0, '\0'); #if defined(UNIX) || defined(VMS) intron(); #endif ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0); meta = ((0x80 & q) ? (0x7f & q) : 0); while(dlb_fgets(buf,BUFSZ,fp)) if ((ctrl && *buf=='^' && *(buf+1)==ctrl) || (meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) || *buf==q) { ep = index(buf, '\n'); if(ep) *ep = 0; if (ctrl && buf[2] == '\t'){ buf = bufr + 1; (void) strncpy(buf, "^? ", 8); buf[1] = ctrl; } else if (meta && buf[3] == '\t'){ buf = bufr + 2; (void) strncpy(buf, "M-? ", 8); buf[2] = meta; } else if(buf[1] == '\t'){ buf = bufr; buf[0] = q; (void) strncpy(buf+1, " ", 7); } pline("%s", buf); (void) dlb_fclose(fp); return 0; } pline("I've never heard of such commands."); (void) dlb_fclose(fp); return 0; } /* data for help_menu() */ static const char *help_menu_items[] = { /* 0*/ "Long description of the game and commands.", /* 1*/ "List of game commands.", /* 2*/ "Concise history of NetHack.", /* 3*/ "Info on a character in the game display.", /* 4*/ "Info on what a given key does.", /* 5*/ "List of game options.", /* 6*/ "Longer explanation of game options.", /* 7*/ "List of extended commands.", /* 8*/ "The NetHack license.", #ifdef PORT_HELP "%s-specific help and commands.", #define PORT_HELP_ID 100 #define WIZHLP_SLOT 10 #else #define WIZHLP_SLOT 9 #endif #ifdef WIZARD "List of wizard-mode commands.", #endif "", (char *)0 }; STATIC_OVL boolean help_menu(sel) int *sel; { winid tmpwin = create_nhwindow(NHW_MENU); #ifdef PORT_HELP char helpbuf[QBUFSZ]; #endif int i, n; menu_item *selected; anything any; any.a_void = 0; /* zero all bits */ start_menu(tmpwin); #ifdef WIZARD if (!wizard) help_menu_items[WIZHLP_SLOT] = "", help_menu_items[WIZHLP_SLOT+1] = (char *)0; #endif for (i = 0; help_menu_items[i]; i++) #ifdef PORT_HELP /* port-specific line has a %s in it for the PORT_ID */ if (help_menu_items[i][0] == '%') { Sprintf(helpbuf, help_menu_items[i], PORT_ID); any.a_int = PORT_HELP_ID + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, helpbuf, MENU_UNSELECTED); } else #endif { any.a_int = (*help_menu_items[i]) ? i+1 : 0; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, help_menu_items[i], MENU_UNSELECTED); } end_menu(tmpwin, "Select one item:"); n = select_menu(tmpwin, PICK_ONE, &selected); destroy_nhwindow(tmpwin); if (n > 0) { *sel = selected[0].item.a_int - 1; free((genericptr_t)selected); return TRUE; } return FALSE; } int dohelp() { int sel = 0; if (help_menu(&sel)) { switch (sel) { case 0: display_file(HELP, TRUE); break; case 1: display_file(SHELP, TRUE); break; case 2: (void) dohistory(); break; case 3: (void) dowhatis(); break; case 4: (void) dowhatdoes(); break; case 5: option_help(); break; case 6: display_file(OPTIONFILE, TRUE); break; case 7: (void) doextlist(); break; case 8: display_file(LICENSE, TRUE); break; #ifdef WIZARD /* handle slot 9 or 10 */ default: display_file(DEBUGHELP, TRUE); break; #endif #ifdef PORT_HELP case PORT_HELP_ID: port_help(); break; #endif } } return 0; } int dohistory() { display_file(HISTORY, TRUE); return 0; } /*pager.c*/