Files
nethack/src/cmd.c
nethack.allison ac49eb5b84 build warning
a recent patch triggered a new warning:
cmd.c(995) : warning C4101: 'numbuf' : unreferenced local variable
2006-05-30 05:07:16 +00:00

2971 lines
82 KiB
C

/* SCCS Id: @(#)cmd.c 3.5 2006/04/14 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "func_tab.h"
/* #define DEBUG */ /* uncomment for debugging */
struct cmd Cmd = { 0 }; /* flag.h */
/*
* Some systems may have getchar() return EOF for various reasons, and
* we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
*/
#if defined(SYSV) || defined(DGUX) || defined(HPUX)
#define NR_OF_EOFS 20
#endif
#define CMD_TRAVEL (char)0x90
#define CMD_CLICKLOOK (char)0x8F
#define NODIAG(monnum) ((monnum) == PM_GRID_BUG)
#ifdef DEBUG
/*
* only one "wiz_debug_cmd" routine should be available (in whatever
* module you are trying to debug) or things are going to get rather
* hard to link :-)
*/
extern int NDECL(wiz_debug_cmd);
#endif
#ifdef DUMB /* stuff commented out in extern.h, but needed here */
extern int NDECL(doapply); /**/
extern int NDECL(dorub); /**/
extern int NDECL(dojump); /**/
extern int NDECL(doextlist); /**/
extern int NDECL(dodrop); /**/
extern int NDECL(doddrop); /**/
extern int NDECL(dodown); /**/
extern int NDECL(doup); /**/
extern int NDECL(donull); /**/
extern int NDECL(dowipe); /**/
extern int NDECL(do_mname); /**/
extern int NDECL(ddocall); /**/
extern int NDECL(dotakeoff); /**/
extern int NDECL(doremring); /**/
extern int NDECL(dowear); /**/
extern int NDECL(doputon); /**/
extern int NDECL(doddoremarm); /**/
extern int NDECL(dokick); /**/
extern int NDECL(dofire); /**/
extern int NDECL(dothrow); /**/
extern int NDECL(doeat); /**/
extern int NDECL(done2); /**/
extern int NDECL(doengrave); /**/
extern int NDECL(dopickup); /**/
extern int NDECL(ddoinv); /**/
extern int NDECL(dotypeinv); /**/
extern int NDECL(dolook); /**/
extern int NDECL(doprgold); /**/
extern int NDECL(doprwep); /**/
extern int NDECL(doprarm); /**/
extern int NDECL(doprring); /**/
extern int NDECL(dopramulet); /**/
extern int NDECL(doprtool); /**/
extern int NDECL(dosuspend); /**/
extern int NDECL(doforce); /**/
extern int NDECL(doopen); /**/
extern int NDECL(doclose); /**/
extern int NDECL(dosh); /**/
extern int NDECL(dodiscovered); /**/
extern int NDECL(doset); /**/
extern int NDECL(dotogglepickup); /**/
extern int NDECL(dowhatis); /**/
extern int NDECL(doquickwhatis); /**/
extern int NDECL(dowhatdoes); /**/
extern int NDECL(dohelp); /**/
extern int NDECL(dohistory); /**/
extern int NDECL(doloot); /**/
extern int NDECL(dodrink); /**/
extern int NDECL(dodip); /**/
extern int NDECL(dosacrifice); /**/
extern int NDECL(dopray); /**/
extern int NDECL(dotip); /**/
extern int NDECL(doturn); /**/
extern int NDECL(doredraw); /**/
extern int NDECL(doread); /**/
extern int NDECL(dosave); /**/
extern int NDECL(dosearch); /**/
extern int NDECL(doidtrap); /**/
extern int NDECL(dopay); /**/
extern int NDECL(dosit); /**/
extern int NDECL(dotalk); /**/
extern int NDECL(docast); /**/
extern int NDECL(dovspell); /**/
extern int NDECL(dotele); /**/
extern int NDECL(dountrap); /**/
extern int NDECL(doversion); /**/
extern int NDECL(doextversion); /**/
extern int NDECL(doswapweapon); /**/
extern int NDECL(dowield); /**/
extern int NDECL(dowieldquiver); /**/
extern int NDECL(dozap); /**/
extern int NDECL(doorganize); /**/
#endif /* DUMB */
static int NDECL((*timed_occ_fn));
STATIC_PTR int NDECL(doprev_message);
STATIC_PTR int NDECL(timed_occupation);
STATIC_PTR int NDECL(doextcmd);
STATIC_PTR int NDECL(domonability);
#ifdef DUNGEON_OVERVIEW
STATIC_PTR int NDECL(dooverview_or_wiz_where);
#endif /* DUNGEON_OVERVIEW */
STATIC_PTR int NDECL(dotravel);
# ifdef WIZARD
STATIC_PTR int NDECL(wiz_wish);
STATIC_PTR int NDECL(wiz_identify);
STATIC_PTR int NDECL(wiz_map);
STATIC_PTR int NDECL(wiz_genesis);
STATIC_PTR int NDECL(wiz_where);
STATIC_PTR int NDECL(wiz_detect);
STATIC_PTR int NDECL(wiz_panic);
STATIC_PTR int NDECL(wiz_polyself);
STATIC_PTR int NDECL(wiz_level_tele);
STATIC_PTR int NDECL(wiz_level_change);
STATIC_PTR int NDECL(wiz_show_seenv);
STATIC_PTR int NDECL(wiz_show_vision);
STATIC_PTR int NDECL(wiz_smell);
STATIC_PTR int NDECL(wiz_mon_polycontrol);
STATIC_PTR int NDECL(wiz_show_wmodes);
STATIC_PTR int NDECL(wiz_map_terrain);
#if defined(__BORLANDC__) && !defined(_WIN32)
extern void FDECL(show_borlandc_stats, (winid));
#endif
#ifdef DEBUG_MIGRATING_MONS
STATIC_PTR int NDECL(wiz_migrate_mons);
#endif
STATIC_DCL int FDECL(size_monst, (struct monst *));
STATIC_DCL int FDECL(size_obj, (struct obj *));
STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P));
STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *));
STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *));
STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *));
STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *));
STATIC_PTR int NDECL(wiz_show_stats);
# ifdef PORT_DEBUG
STATIC_DCL int NDECL(wiz_port_debug);
# endif
STATIC_PTR int NDECL(wiz_rumor_check);
# endif
STATIC_PTR int NDECL(enter_explore_mode);
STATIC_PTR int NDECL(doattributes);
STATIC_PTR int NDECL(doconduct); /**/
STATIC_PTR boolean NDECL(minimal_enlightenment);
STATIC_DCL char FDECL(cmd_from_func, (int NDECL((*))));
STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *,char *));
STATIC_DCL char *FDECL(enlght_combatinc, (const char *,int,int,char *));
#if defined(UNIX) || defined(SAFERHANGUP)
static void NDECL(end_of_input);
#endif
static const char* readchar_queue="";
static coord clicklook_cc;
STATIC_DCL char *NDECL(parse);
STATIC_DCL boolean FDECL(help_dir, (CHAR_P,const char *));
STATIC_PTR int
doprev_message()
{
return nh_doprev_message();
}
/* Count down by decrementing multi */
STATIC_PTR int
timed_occupation()
{
(*timed_occ_fn)();
if (multi > 0)
multi--;
return multi > 0;
}
/* If you have moved since initially setting some occupations, they
* now shouldn't be able to restart.
*
* The basic rule is that if you are carrying it, you can continue
* since it is with you. If you are acting on something at a distance,
* your orientation to it must have changed when you moved.
*
* The exception to this is taking off items, since they can be taken
* off in a number of ways in the intervening time, screwing up ordering.
*
* Currently: Take off all armor.
* Picking Locks / Forcing Chests.
* Setting traps.
*/
void
reset_occupations()
{
reset_remarm();
reset_pick();
reset_trapset();
}
/* If a time is given, use it to timeout this function, otherwise the
* function times out by its own means.
*/
void
set_occupation(fn, txt, xtime)
int NDECL((*fn));
const char *txt;
int xtime;
{
if (xtime) {
occupation = timed_occupation;
timed_occ_fn = fn;
} else
occupation = fn;
occtxt = txt;
occtime = 0;
return;
}
#ifdef REDO
STATIC_DCL char NDECL(popch);
/* Provide a means to redo the last command. The flag `in_doagain' is set
* to true while redoing the command. This flag is tested in commands that
* require additional input (like `throw' which requires a thing and a
* direction), and the input prompt is not shown. Also, while in_doagain is
* TRUE, no keystrokes can be saved into the saveq.
*/
#define BSIZE 20
static char pushq[BSIZE], saveq[BSIZE];
static NEARDATA int phead, ptail, shead, stail;
STATIC_OVL char
popch() {
/* If occupied, return '\0', letting tgetch know a character should
* be read from the keyboard. If the character read is not the
* ABORT character (as checked in pcmain.c), that character will be
* pushed back on the pushq.
*/
if (occupation) return '\0';
if (in_doagain) return(char)((shead != stail) ? saveq[stail++] : '\0');
else return(char)((phead != ptail) ? pushq[ptail++] : '\0');
}
char
pgetchar() { /* curtesy of aeb@cwi.nl */
register int ch;
if(!(ch = popch()))
ch = nhgetch();
return((char)ch);
}
/* A ch == 0 resets the pushq */
void
pushch(ch)
char ch;
{
if (!ch)
phead = ptail = 0;
if (phead < BSIZE)
pushq[phead++] = ch;
return;
}
/* A ch == 0 resets the saveq. Only save keystrokes when not
* replaying a previous command.
*/
void
savech(ch)
char ch;
{
if (!in_doagain) {
if (!ch)
phead = ptail = shead = stail = 0;
else if (shead < BSIZE)
saveq[shead++] = ch;
}
return;
}
#endif /* REDO */
STATIC_PTR int
doextcmd() /* here after # - now read a full-word command */
{
int idx, retval;
/* keep repeating until we don't run help or quit */
do {
idx = get_ext_cmd();
if (idx < 0) return 0; /* quit */
retval = (*extcmdlist[idx].ef_funct)();
} while (extcmdlist[idx].ef_funct == doextlist);
return retval;
}
int
doextlist() /* here after #? - now list all full-word commands */
{
register const struct ext_func_tab *efp;
char buf[BUFSZ];
winid datawin;
datawin = create_nhwindow(NHW_TEXT);
putstr(datawin, 0, "");
putstr(datawin, 0, " Extended Commands List");
putstr(datawin, 0, "");
putstr(datawin, 0, " Press '#', then type:");
putstr(datawin, 0, "");
for(efp = extcmdlist; efp->ef_txt; efp++) {
Sprintf(buf, " %-15s - %s.", efp->ef_txt, efp->ef_desc);
putstr(datawin, 0, buf);
}
display_nhwindow(datawin, FALSE);
destroy_nhwindow(datawin);
return 0;
}
#ifdef TTY_GRAPHICS
#define MAX_EXT_CMD 40 /* Change if we ever have > 40 ext cmds */
/*
* This is currently used only by the tty port and is
* controlled via runtime option 'extmenu'
*/
int
extcmd_via_menu() /* here after # - now show pick-list of possible commands */
{
const struct ext_func_tab *efp;
menu_item *pick_list = (menu_item *)0;
winid win;
anything any;
const struct ext_func_tab *choices[MAX_EXT_CMD];
char buf[BUFSZ];
char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20];
int i, n, nchoices, acount;
int ret, biggest;
int accelerator, prevaccelerator;
int matchlevel = 0;
ret = 0;
cbuf[0] = '\0';
biggest = 0;
while (!ret) {
i = n = 0;
accelerator = 0;
any.a_void = 0;
/* populate choices */
for(efp = extcmdlist; efp->ef_txt; efp++) {
if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) {
choices[i++] = efp;
if ((int)strlen(efp->ef_desc) > biggest) {
biggest = strlen(efp->ef_desc);
Sprintf(fmtstr,"%%-%ds", biggest + 15);
}
#ifdef DEBUG
if (i >= MAX_EXT_CMD - 2) {
impossible("Exceeded %d extended commands in doextcmd() menu",
MAX_EXT_CMD - 2);
return 0;
}
#endif
}
}
choices[i] = (struct ext_func_tab *)0;
nchoices = i;
/* if we're down to one, we have our selection so get out of here */
if (nchoices == 1) {
for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) {
ret = i;
break;
}
break;
}
/* otherwise... */
win = create_nhwindow(NHW_MENU);
start_menu(win);
prevaccelerator = 0;
acount = 0;
for(i = 0; choices[i]; ++i) {
accelerator = choices[i]->ef_txt[matchlevel];
if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) {
if (acount) {
/* flush the extended commands for that letter already in buf */
Sprintf(buf, fmtstr, prompt);
any.a_char = prevaccelerator;
add_menu(win, NO_GLYPH, &any, any.a_char, 0,
ATR_NONE, buf, FALSE);
acount = 0;
}
}
prevaccelerator = accelerator;
if (!acount || nchoices < (ROWNO - 3)) {
Sprintf(prompt, "%s [%s]", choices[i]->ef_txt,
choices[i]->ef_desc);
} else if (acount == 1) {
Sprintf(prompt, "%s or %s", choices[i-1]->ef_txt,
choices[i]->ef_txt);
} else {
Strcat(prompt," or ");
Strcat(prompt, choices[i]->ef_txt);
}
++acount;
}
if (acount) {
/* flush buf */
Sprintf(buf, fmtstr, prompt);
any.a_char = prevaccelerator;
add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE);
}
Sprintf(prompt, "Extended Command: %s", cbuf);
end_menu(win, prompt);
n = select_menu(win, PICK_ONE, &pick_list);
destroy_nhwindow(win);
if (n==1) {
if (matchlevel > (QBUFSZ - 2)) {
free((genericptr_t)pick_list);
#ifdef DEBUG
impossible("Too many characters (%d) entered in extcmd_via_menu()",
matchlevel);
#endif
ret = -1;
} else {
cbuf[matchlevel++] = pick_list[0].item.a_char;
cbuf[matchlevel] = '\0';
free((genericptr_t)pick_list);
}
} else {
if (matchlevel) {
ret = 0;
matchlevel = 0;
} else
ret = -1;
}
}
return ret;
}
#endif
/* #monster command - use special monster ability while polymorphed */
STATIC_PTR int
domonability()
{
if (can_breathe(youmonst.data)) return dobreathe();
else if (attacktype(youmonst.data, AT_SPIT)) return dospit();
else if (youmonst.data->mlet == S_NYMPH) return doremove();
else if (attacktype(youmonst.data, AT_GAZE)) return dogaze();
else if (is_were(youmonst.data)) return dosummon();
else if (webmaker(youmonst.data)) return dospinweb();
else if (is_hider(youmonst.data)) return dohide();
else if (is_mind_flayer(youmonst.data)) return domindblast();
else if (u.umonnum == PM_GREMLIN) {
if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
if (split_mon(&youmonst, (struct monst *)0))
dryup(u.ux, u.uy, TRUE);
} else There("is no fountain here.");
} else if (is_unicorn(youmonst.data)) {
use_unicorn_horn((struct obj *)0);
return 1;
} else if (youmonst.data->msound == MS_SHRIEK) {
You("shriek.");
if(u.uburied)
pline("Unfortunately sound does not carry well through rock.");
else aggravate();
} else if (youmonst.data->mlet == S_VAMPIRE) return dopoly();
else if (Upolyd)
pline("Any special ability you may have is purely reflexive.");
else You("don't have a special ability in your normal form!");
return 0;
}
STATIC_PTR int
enter_explore_mode()
{
if(!discover && !wizard) {
pline("Beware! From explore mode there will be no return to normal game.");
if (yn("Do you want to enter explore mode?") == 'y') {
clear_nhwindow(WIN_MESSAGE);
You("are now in non-scoring explore mode.");
discover = TRUE;
}
else {
clear_nhwindow(WIN_MESSAGE);
pline("Resuming normal game.");
}
}
return 0;
}
#ifdef DUNGEON_OVERVIEW
STATIC_PTR int
dooverview_or_wiz_where()
{
#ifdef WIZARD
if (wizard) return wiz_where();
else
#endif
dooverview();
return 0;
}
#endif /* DUNGEON_OVERVIEW */
#ifdef WIZARD
/* ^W command - wish for something */
STATIC_PTR int
wiz_wish() /* Unlimited wishes for debug mode by Paul Polderman */
{
if (wizard) {
boolean save_verbose = flags.verbose;
flags.verbose = FALSE;
makewish();
flags.verbose = save_verbose;
(void) encumber_msg();
} else
pline("Unavailable command '%s'.",
visctrl((int)cmd_from_func(wiz_wish)));
return 0;
}
/* ^I command - reveal and optionally identify hero's inventory */
STATIC_PTR int
wiz_identify()
{
if (wizard) {
iflags.override_ID = (int)cmd_from_func(wiz_identify);
if (display_inventory((char *)0, TRUE) == -1)
identify_pack(0, FALSE);
iflags.override_ID = 0;
} else pline("Unavailable command '%s'.",
visctrl((int)cmd_from_func(wiz_identify)));
return 0;
}
/* ^F command - reveal the level map and any traps on it */
STATIC_PTR int
wiz_map()
{
if (wizard) {
struct trap *t;
long save_Hconf = HConfusion,
save_Hhallu = HHallucination;
HConfusion = HHallucination = 0L;
for (t = ftrap; t != 0; t = t->ntrap) {
t->tseen = 1;
map_trap(t, TRUE);
}
do_mapping();
HConfusion = save_Hconf;
HHallucination = save_Hhallu;
} else
pline("Unavailable command '%s'.",
visctrl((int)cmd_from_func(wiz_map)));
return 0;
}
/* ^G command - generate monster(s); a count prefix will be honored */
STATIC_PTR int
wiz_genesis()
{
if (wizard) (void) create_particular();
else pline("Unavailable command '%s'.",
visctrl((int)cmd_from_func(wiz_genesis)));
return 0;
}
/* ^O command - display dungeon layout */
STATIC_PTR int
wiz_where()
{
if (wizard) (void) print_dungeon(FALSE, (schar *)0, (xchar *)0);
else pline("Unavailable command '%s'.",
visctrl((int)cmd_from_func(wiz_where)));
return 0;
}
/* ^E command - detect unseen (secret doors, traps, hidden monsters) */
STATIC_PTR int
wiz_detect()
{
if(wizard) (void) findit();
else pline("Unavailable command '%s'.",
visctrl((int)cmd_from_func(wiz_detect)));
return 0;
}
/* ^V command - level teleport */
STATIC_PTR int
wiz_level_tele()
{
if (wizard) level_tele();
else pline("Unavailable command '%s'.",
visctrl((int)cmd_from_func(wiz_level_tele)));
return 0;
}
/* #monpolycontrol command - choose new form for shapechangers, polymorphees */
STATIC_PTR int
wiz_mon_polycontrol()
{
iflags.mon_polycontrol = !iflags.mon_polycontrol;
pline("Monster polymorph control is %s.",
iflags.mon_polycontrol ? "on" : "off");
return 0;
}
/* #levelchange command - adjust hero's experience level */
STATIC_PTR int
wiz_level_change()
{
char buf[BUFSZ];
int newlevel;
int ret;
getlin("To what experience level do you want to be set?", buf);
(void)mungspaces(buf);
if (buf[0] == '\033' || buf[0] == '\0') ret = 0;
else ret = sscanf(buf, "%d", &newlevel);
if (ret != 1) {
pline(Never_mind);
return 0;
}
if (newlevel == u.ulevel) {
You("are already that experienced.");
} else if (newlevel < u.ulevel) {
if (u.ulevel == 1) {
You("are already as inexperienced as you can get.");
return 0;
}
if (newlevel < 1) newlevel = 1;
while (u.ulevel > newlevel)
losexp("#levelchange");
} else {
if (u.ulevel >= MAXULEV) {
You("are already as experienced as you can get.");
return 0;
}
if (newlevel > MAXULEV) newlevel = MAXULEV;
while (u.ulevel < newlevel)
pluslvl(FALSE);
}
u.ulevelmax = u.ulevel;
return 0;
}
/* #panic command - test program's panic handling */
STATIC_PTR int
wiz_panic()
{
if (yn("Do you want to call panic() and end your game?") == 'y')
panic("crash test.");
return 0;
}
/* #polyself command - change hero's form */
STATIC_PTR int
wiz_polyself()
{
polyself(1);
return 0;
}
/* #seenv command */
STATIC_PTR int
wiz_show_seenv()
{
winid win;
int x, y, v, startx, stopx, curx;
char row[COLNO+1];
win = create_nhwindow(NHW_TEXT);
/*
* Each seenv description takes up 2 characters, so center
* the seenv display around the hero.
*/
startx = max(1, u.ux-(COLNO/4));
stopx = min(startx+(COLNO/2), COLNO);
/* can't have a line exactly 80 chars long */
if (stopx - startx == COLNO/2) startx++;
for (y = 0; y < ROWNO; y++) {
for (x = startx, curx = 0; x < stopx; x++, curx += 2) {
if (x == u.ux && y == u.uy) {
row[curx] = row[curx+1] = '@';
} else {
v = levl[x][y].seenv & 0xff;
if (v == 0)
row[curx] = row[curx+1] = ' ';
else
Sprintf(&row[curx], "%02x", v);
}
}
/* remove trailing spaces */
for (x = curx-1; x >= 0; x--)
if (row[x] != ' ') break;
row[x+1] = '\0';
putstr(win, 0, row);
}
display_nhwindow(win, TRUE);
destroy_nhwindow(win);
return 0;
}
/* #vision command */
STATIC_PTR int
wiz_show_vision()
{
winid win;
int x, y, v;
char row[COLNO+1];
win = create_nhwindow(NHW_TEXT);
Sprintf(row, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit",
COULD_SEE, IN_SIGHT, TEMP_LIT);
putstr(win, 0, row);
putstr(win, 0, "");
for (y = 0; y < ROWNO; y++) {
for (x = 1; x < COLNO; x++) {
if (x == u.ux && y == u.uy)
row[x] = '@';
else {
v = viz_array[y][x]; /* data access should be hidden */
if (v == 0)
row[x] = ' ';
else
row[x] = '0' + viz_array[y][x];
}
}
/* remove trailing spaces */
for (x = COLNO-1; x >= 1; x--)
if (row[x] != ' ') break;
row[x+1] = '\0';
putstr(win, 0, &row[1]);
}
display_nhwindow(win, TRUE);
destroy_nhwindow(win);
return 0;
}
/* #wmode command */
STATIC_PTR int
wiz_show_wmodes()
{
winid win;
int x,y;
char row[COLNO+1];
struct rm *lev;
boolean istty = !strcmp(windowprocs.name, "tty");
win = create_nhwindow(NHW_TEXT);
if (istty) putstr(win, 0, ""); /* tty only: blank top line */
for (y = 0; y < ROWNO; y++) {
for (x = 0; x < COLNO; x++) {
lev = &levl[x][y];
if (x == u.ux && y == u.uy)
row[x] = '@';
else if (IS_WALL(lev->typ) || lev->typ == SDOOR)
row[x] = '0' + (lev->wall_info & WM_MASK);
else if (lev->typ == CORR)
row[x] = '#';
else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ))
row[x] = '.';
else
row[x] = 'x';
}
row[COLNO] = '\0';
/* map column 0, levl[0][], is off the left edge of the screen */
putstr(win, 0, &row[1]);
}
display_nhwindow(win, TRUE);
destroy_nhwindow(win);
return 0;
}
/* #terrain command */
STATIC_PTR int
wiz_map_terrain()
{
winid win;
int x, y, terrain;
char row[COLNO+1];
boolean istty = !strcmp(windowprocs.name, "tty");
win = create_nhwindow(NHW_TEXT);
/* map row 0, levl[][0], is drawn on the second line of tty screen */
if (istty) putstr(win, 0, ""); /* tty only: blank top line */
for (y = 0; y < ROWNO; y++) {
/* map column 0, levl[0][], is off the left edge of the screen;
it should always have terrain type "undiggable stone" */
for (x = 1; x < COLNO; x++) {
terrain = levl[x][y].typ;
/* assumes there aren't more than 10+26+26 terrain types */
row[x-1] = (char)((terrain == 0 && !may_dig(x, y)) ? '*' :
(terrain < 10) ? '0' + terrain :
(terrain < 36) ? 'a' + terrain - 10 :
'A' + terrain - 36);
}
if (levl[0][y].typ != 0 || may_dig(0, y)) row[x++] = '!';
row[x] = '\0';
putstr(win, 0, row);
}
{
char dsc[BUFSZ];
s_level *slev = Is_special(&u.uz);
Sprintf(dsc, "D:%d,L:%d", u.uz.dnum, u.uz.dlevel);
/* [dungeon branch features currently omitted] */
/* special level features */
if (slev) {
Sprintf(eos(dsc), " \"%s\"", slev->proto);
/* special level flags (note: dungeon.def doesn't set `maze'
or `hell' for any specific levels so those never show up) */
if (slev->flags.maze_like) Strcat(dsc, " mazelike");
if (slev->flags.hellish) Strcat(dsc, " hellish");
if (slev->flags.town) Strcat(dsc, " town");
if (slev->flags.rogue_like) Strcat(dsc, " roguelike");
/* alignment currently omitted to save space */
}
/* level features */
if (level.flags.nfountains) Sprintf(eos(dsc), " %c:%d",
defsyms[S_fountain].sym,
(int)level.flags.nfountains);
#ifdef SINKS
if (level.flags.nsinks) Sprintf(eos(dsc), " %c:%d",
defsyms[S_sink].sym,
(int)level.flags.nsinks);
#endif
if (level.flags.has_vault) Strcat(dsc, " vault");
if (level.flags.has_shop) Strcat(dsc, " shop");
if (level.flags.has_temple) Strcat(dsc, " temple");
if (level.flags.has_court) Strcat(dsc, " throne");
if (level.flags.has_zoo) Strcat(dsc, " zoo");
if (level.flags.has_morgue) Strcat(dsc, " morgue");
if (level.flags.has_barracks) Strcat(dsc, " barracks");
if (level.flags.has_beehive) Strcat(dsc, " hive");
if (level.flags.has_swamp) Strcat(dsc, " swamp");
/* level flags */
if (level.flags.noteleport) Strcat(dsc, " noTport");
if (level.flags.hardfloor) Strcat(dsc, " noDig");
if (level.flags.nommap) Strcat(dsc, " noMMap");
if (!level.flags.hero_memory) Strcat(dsc, " noMem");
if (level.flags.shortsighted) Strcat(dsc, " shortsight");
if (level.flags.graveyard) Strcat(dsc, " graveyard");
if (level.flags.is_maze_lev) Strcat(dsc, " maze");
if (level.flags.is_cavernous_lev) Strcat(dsc, " cave");
if (level.flags.arboreal) Strcat(dsc, " tree");
/* non-flag info; probably should include dungeon branching
checks (extra stairs and magic portals) here */
if (Invocation_lev(&u.uz)) Strcat(dsc, " invoke");
if (On_W_tower_level(&u.uz)) Strcat(dsc, " tower");
/* append a branch identifier for completeness' sake */
if (u.uz.dnum == 0) Strcat(dsc, " dungeon");
else if (u.uz.dnum == mines_dnum) Strcat(dsc, " mines");
else if (In_sokoban(&u.uz)) Strcat(dsc, " sokoban");
else if (u.uz.dnum == quest_dnum) Strcat(dsc, " quest");
else if (Is_knox(&u.uz)) Strcat(dsc, " ludios");
else if (u.uz.dnum == 1) Strcat(dsc, " gehennom");
else if (u.uz.dnum == tower_dnum) Strcat(dsc, " vlad");
else if (In_endgame(&u.uz)) Strcat(dsc, " endgame");
else {
/* somebody's added a dungeon branch we're not expecting */
const char *brname = dungeons[u.uz.dnum].dname;
if (!brname || !*brname) brname = "unknown";
if (!strncmpi(brname, "the ", 4)) brname += 4;
Sprintf(eos(dsc), " %s", brname);
}
/* limit the line length to map width */
if (strlen(dsc) >= COLNO) dsc[COLNO-1] = '\0'; /* truncate */
putstr(win, 0, dsc);
}
display_nhwindow(win, TRUE);
/* TODO? create legend of levl[][].typ codes and allow switching
back and forth between it and coded map display */
destroy_nhwindow(win);
return 0;
}
/* #wizsmell command - test usmellmon(). */
STATIC_PTR int
wiz_smell()
{
char out_str[BUFSZ];
struct permonst *pm = 0;
int ans = 0;
int mndx; /* monster index */
int found; /* count of matching mndxs found */
coord cc; /* screen pos of unknown glyph */
int glyph; /* glyph at selected position */
cc.x = u.ux;
cc.y = u.uy;
mndx = 0; /* gcc -Wall lint */
if (!olfaction(youmonst.data)) {
You("are incapable of detecting odors in your present form.");
return 0;
}
pline("You can move the cursor to a monster that you want to smell.");
do {
/* Reset some variables. */
pm = (struct permonst *)0;
found = 0;
out_str[0] = '\0';
pline("Pick a monster to smell.");
ans = getpos(&cc, TRUE, "a monster");
if (ans < 0 || cc.x < 0) {
return 0; /* done */
}
/* Convert the glyph at the selected position to a mndxbol. */
glyph = glyph_at(cc.x,cc.y);
if (glyph_is_monster(glyph))
mndx = glyph_to_mon(glyph);
else
mndx = 0;
/* Is it a monster? */
if (mndx) {
if (!usmellmon(&mons[mndx]))
pline("That monster seems to give off no smell.");
} else pline("That is not a monster.");
} while (TRUE);
return 0;
}
/* #wizrumorcheck command - verify each rumor access */
STATIC_PTR int
wiz_rumor_check()
{
rumor_check();
return 0;
}
#endif /* WIZARD */
/* -enlightenment and conduct- */
static winid en_win;
static const char
You_[] = "You ",
are[] = "are ", were[] = "were ",
have[] = "have ", had[] = "had ",
can[] = "can ", could[] = "could ";
static const char
have_been[] = "have been ",
have_never[] = "have never ", never[] = "never ";
#define enl_msg(prefix,present,past,suffix,ps) \
enlght_line(prefix, final ? past : present, suffix, ps)
#define you_are(attr,ps) enl_msg(You_,are,were,attr,ps)
#define you_have(attr,ps) enl_msg(You_,have,had,attr,ps)
#define you_can(attr,ps) enl_msg(You_,can,could,attr,ps)
#define you_have_been(goodthing) enl_msg(You_,have_been,were,goodthing,"")
#define you_have_never(badthing) enl_msg(You_,have_never,never,badthing,"")
#define you_have_X(something) enl_msg(You_,have,(const char *)"",something,"")
static void
enlght_line(start, middle, end, ps)
const char *start, *middle, *end;
char *ps;
{
char buf[BUFSZ];
Sprintf(buf, "%s%s%s%s.", start, middle, end, ps);
putstr(en_win, 0, buf);
}
/* format increased chance to hit or damage or defense (Protection) */
static char *
enlght_combatinc(inctyp, incamt, final, outbuf)
const char *inctyp;
int incamt, final;
char *outbuf;
{
const char *modif, *bonus;
boolean invrt;
int absamt;
absamt = abs(incamt);
/* Protection amount is typically larger than damage or to-hit;
reduce magnitude by a third in order to stretch modifier ranges
(small:1..5, moderate:6..10, large:11..19, huge:20+) */
if (!strcmp(inctyp, "defense")) absamt = (absamt * 2) / 3;
if (absamt <= 3) modif = "small";
else if (absamt <= 6) modif = "moderate";
else if (absamt <= 12) modif = "large";
else modif = "huge";
modif = !incamt ? "no" : an(modif); /* ("no" case shouldn't happen) */
bonus = (incamt >= 0) ? "bonus" : "penalty";
/* "bonus <foo>" (to hit) vs "<bar> bonus" (damage, defense) */
invrt = strcmp(inctyp, "to hit") ? TRUE : FALSE;
Sprintf(outbuf, "%s %s %s", modif,
invrt ? inctyp : bonus, invrt ? bonus : inctyp);
if (final || wizard)
Sprintf(eos(outbuf), " (%s%d)",
(incamt > 0) ? "+" : "", incamt);
return outbuf;
}
void
enlightenment(final)
int final; /* 0 => still in progress; 1 => over, survived; 2 => dead */
{
int ltmp, armpro;
char buf[BUFSZ];
en_win = create_nhwindow(NHW_MENU);
putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:");
putstr(en_win, 0, "");
#ifdef ELBERETH
if (u.uevent.uhand_of_elbereth) {
static const char * const hofe_titles[3] = {
"the Hand of Elbereth",
"the Envoy of Balance",
"the Glory of Arioch"
};
you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1],"");
}
#endif
/* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
if (u.ualign.record >= 20) you_are("piously aligned","");
else if (u.ualign.record > 13) you_are("devoutly aligned","");
else if (u.ualign.record > 8) you_are("fervently aligned","");
else if (u.ualign.record > 3) you_are("stridently aligned","");
else if (u.ualign.record == 3) you_are("aligned","");
else if (u.ualign.record > 0) you_are("haltingly aligned","");
else if (u.ualign.record == 0) you_are("nominally aligned","");
else if (u.ualign.record >= -3) you_have("strayed","");
else if (u.ualign.record >= -8) you_have("sinned","");
else you_have("transgressed","");
#ifdef WIZARD
if (wizard) {
Sprintf(buf, " %d", u.ualign.record);
enl_msg("Your alignment ", "is", "was", buf, "");
}
#endif
/*** Resistances to troubles ***/
if (Fire_resistance) you_are("fire resistant",from_what(FIRE_RES));
if (Cold_resistance) you_are("cold resistant",from_what(COLD_RES));
if (Sleep_resistance) you_are("sleep resistant",from_what(SLEEP_RES));
if (Disint_resistance)
you_are("disintegration-resistant",from_what(DISINT_RES));
if (Shock_resistance) you_are("shock resistant",from_what(SHOCK_RES));
if (Poison_resistance) you_are("poison resistant",from_what(POISON_RES));
if (Drain_resistance)
you_are("level-drain resistant",from_what(DRAIN_RES));
if (Sick_resistance) you_are("immune to sickness",from_what(SICK_RES));
if (Antimagic) you_are("magic-protected",from_what(ANTIMAGIC));
if (Acid_resistance) you_are("acid resistant",from_what(ACID_RES));
if (Stone_resistance)
you_are("petrification resistant",from_what(STONE_RES));
if (Invulnerable) you_are("invulnerable",from_what(INVULNERABLE));
if (u.uedibility) you_can("recognize detrimental food","");
/*** Troubles ***/
if (Halluc_resistance)
enl_msg("You resist", "", "ed", " hallucinations",
from_what(HALLUC_RES));
if (final) {
if (Hallucination) you_are("hallucinating","");
if (Stunned) you_are("stunned","");
if (Confusion) you_are("confused","");
if (Blinded) you_are("blinded",from_what(BLINDED));
if (Deaf) you_are("deaf",from_what(DEAF));
if (Sick) {
if (u.usick_type & SICK_VOMITABLE)
you_are("sick from food poisoning","");
if (u.usick_type & SICK_NONVOMITABLE)
you_are("sick from illness","");
}
}
if (Stoned) you_are("turning to stone","");
if (Slimed) you_are("turning into slime","");
if (Strangled) you_are((u.uburied) ? "buried" : "being strangled","");
if (Glib) {
Sprintf(buf, "slippery %s", makeplural(body_part(FINGER)));
you_have(buf,"");
}
if (Fumbling) enl_msg("You fumble", "", "d", "",from_what(FUMBLING));
if (Wounded_legs
#ifdef STEED
&& !u.usteed
#endif
) {
Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
you_have(buf,"");
}
#if defined(WIZARD) && defined(STEED)
if (Wounded_legs && u.usteed && wizard) {
Strcpy(buf, x_monnam(u.usteed, ARTICLE_YOUR, (char *)0,
SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION, FALSE));
*buf = highc(*buf);
enl_msg(buf, " has", " had", " wounded legs", "");
}
#endif
if (Sleeping) enl_msg("You ", "fall", "fell", " asleep", "");
if (Hunger) enl_msg("You hunger", "", "ed", " rapidly", "");
/*** Vision and senses ***/
if (See_invisible) enl_msg(You_, "see", "saw", " invisible",
from_what(SEE_INVIS));
if (Blind_telepat) you_are("telepathic",from_what(TELEPAT));
if (Warning) you_are("warned", from_what(WARNING));
if (Warn_of_mon && context.warntype.obj) {
Sprintf(buf, "aware of the presence of %s",
(context.warntype.obj & M2_ORC) ? "orcs" :
(context.warntype.obj & M2_DEMON) ? "demons" :
something);
you_are(buf,from_what(WARN_OF_MON));
}
if (Warn_of_mon && context.warntype.polyd) {
Sprintf(buf, "aware of the presence of %s",
((context.warntype.polyd &
(M2_HUMAN|M2_ELF))==(M2_HUMAN|M2_ELF)) ? "humans and elves" :
(context.warntype.polyd & M2_HUMAN) ? "humans" :
(context.warntype.polyd & M2_ELF) ? "elves" :
(context.warntype.polyd & M2_ORC) ? "orcs" :
(context.warntype.polyd & M2_DEMON) ? "demons" :
"certain monsters");
you_are(buf,"");
}
if (Warn_of_mon && context.warntype.speciesidx) {
Sprintf(buf, "aware of the presence of %s",
makeplural(mons[context.warntype.speciesidx].mname));
you_are(buf,from_what(WARN_OF_MON));
}
if (Undead_warning) you_are("warned of undead",from_what(WARN_UNDEAD));
if (Searching) you_have("automatic searching",from_what(SEARCHING));
if (Clairvoyant) you_are("clairvoyant",from_what(CLAIRVOYANT));
if (Infravision) you_have("infravision",from_what(INFRAVISION));
if (Detect_monsters)
you_are("sensing the presence of monsters", "");
if (u.umconf) you_are("going to confuse monsters","");
/*** Appearance and behavior ***/
if (Adornment) {
int adorn = 0;
if(uleft && uleft->otyp == RIN_ADORNMENT) adorn += uleft->spe;
if(uright && uright->otyp == RIN_ADORNMENT) adorn += uright->spe;
if (adorn < 0)
you_are("poorly adorned","");
else
you_are("adorned","");
}
if (Invisible) you_are("invisible",from_what(INVIS));
else if (Invis) you_are("invisible to others",from_what(INVIS));
/* ordinarily "visible" is redundant; this is a special case for
the situation when invisibility would be an expected attribute */
else if ((HInvis || EInvis || pm_invisible(youmonst.data)) && BInvis)
you_are("visible","");
if (Displaced) you_are("displaced",from_what(DISPLACED));
if (Stealth) you_are("stealthy",from_what(STEALTH));
if (Aggravate_monster)
enl_msg("You aggravate", "", "d",
" monsters",from_what(AGGRAVATE_MONSTER));
if (Conflict) enl_msg("You cause", "", "d", " conflict",from_what(CONFLICT));
/*** Transportation ***/
if (Jumping) you_can("jump",from_what(JUMPING));
if (Teleportation) you_can("teleport",from_what(TELEPORT));
if (Teleport_control)
you_have("teleport control",from_what(TELEPORT_CONTROL));
if (Lev_at_will) you_are("levitating, at will", "");
else if (Levitation)
you_are("levitating",from_what(LEVITATION)); /* without control */
else if (Flying) you_can("fly",from_what(FLYING));
if (Wwalking) you_can("walk on water",from_what(WWALKING));
if (Swimming) you_can("swim",from_what(SWIMMING));
if (Breathless) you_can("survive without air",from_what(MAGICAL_BREATHING));
else if (Amphibious) you_can("breathe water",from_what(MAGICAL_BREATHING));
if (Passes_walls) you_can("walk through walls",from_what(PASSES_WALLS));
#ifdef STEED
/* If you die while dismounting, u.usteed is still set. Since several
* places in the done() sequence depend on u.usteed, just detect this
* special case. */
if (u.usteed && (final < 2 || strcmp(killer.name, "riding accident"))) {
Sprintf(buf, "riding %s", y_monnam(u.usteed));
you_are(buf,"");
}
#endif
if (u.uswallow) {
Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck));
#ifdef WIZARD
if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim);
#endif
you_are(buf,"");
} else if (u.ustuck) {
Sprintf(buf, "%s %s",
(Upolyd && sticks(youmonst.data)) ? "holding" : "held by",
a_monnam(u.ustuck));
you_are(buf,"");
}
/*** Physical attributes ***/
if (Regeneration)
enl_msg("You regenerate", "", "d", "",from_what(REGENERATION));
if (Slow_digestion)
you_have("slower digestion",from_what(SLOW_DIGESTION));
if (u.uhitinc)
you_have(enlght_combatinc("to hit", u.uhitinc, final, buf),"");
if (u.udaminc)
you_have(enlght_combatinc("damage", u.udaminc, final, buf),"");
if (u.uspellprot || Protection) {
int prot = 0;
if(uleft && uleft->otyp == RIN_PROTECTION) prot += uleft->spe;
if(uright && uright->otyp == RIN_PROTECTION) prot += uright->spe;
if (HProtection & INTRINSIC) prot += u.ublessed;
prot += u.uspellprot;
if (prot)
you_have(enlght_combatinc("defense", prot, final, buf), "");
}
if ((armpro = magic_negation(&youmonst)) > 0) {
/* magic cancellation factor, conferred by worn armor */
static const char * const mc_types[] = {
"" /*ordinary*/, "warded", "guarded", "protected",
};
/* sanity check */
if (armpro >= SIZE(mc_types)) armpro = SIZE(mc_types) - 1;
you_are(mc_types[armpro],"");
}
if (Protection_from_shape_changers)
you_are("protected from shape changers","");
if (Polymorph) you_are("polymorphing","");
if (Polymorph_control)
you_have("polymorph control",from_what(POLYMORPH_CONTROL));
if (u.ulycn >= LOW_PM) {
Strcpy(buf, an(mons[u.ulycn].mname));
you_are(buf,"");
}
if (Upolyd) {
if (u.umonnum == u.ulycn) Strcpy(buf, "in beast form");
else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname));
#ifdef WIZARD
if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone);
#endif
you_are(buf,"");
}
if (Unchanging) you_can("not change from your current form","");
if (Fast) you_are(Very_fast ? "very fast" : "fast",from_what(FAST));
if (Reflecting) you_have("reflection",from_what(REFLECTING));
if (Free_action) you_have("free action",from_what(FREE_ACTION));
if (Fixed_abil) you_have("fixed abilities",from_what(FIXED_ABIL));
if (Lifesaved)
enl_msg("Your life ", "will be", "would have been", " saved","");
if (u.twoweap) you_are("wielding two weapons at once","");
if (u.utraptype == TT_BURIEDBALL) you_are("fastened to a buried ball","");
/*** Miscellany ***/
if (Luck) {
ltmp = abs((int)Luck);
Sprintf(buf, "%s%slucky",
ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
Luck < 0 ? "un" : "");
#ifdef WIZARD
if (wizard) Sprintf(eos(buf), " (%d)", Luck);
#endif
you_are(buf,"");
}
#ifdef WIZARD
else if (wizard) enl_msg("Your luck ", "is", "was", " zero","");
#endif
if (u.moreluck > 0) you_have("extra luck","");
else if (u.moreluck < 0) you_have("reduced luck","");
if (carrying(LUCKSTONE) || stone_luck(TRUE)) {
ltmp = stone_luck(0);
if (ltmp <= 0)
enl_msg("Bad luck ", "does", "did", " not time out for you","");
if (ltmp >= 0)
enl_msg("Good luck ", "does", "did", " not time out for you","");
}
if (u.ugangr) {
Sprintf(buf, " %sangry with you",
u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : "");
#ifdef WIZARD
if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr);
#endif
enl_msg(u_gname(), " is", " was", buf,"");
} else
/*
* We need to suppress this when the game is over, because death
* can change the value calculated by can_pray(), potentially
* resulting in a false claim that you could have prayed safely.
*/
if (!final) {
#if 0
/* "can [not] safely pray" vs "could [not] have safely prayed" */
Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ",
final ? "have " : "", final ? "ed" : "");
#else
Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not ");
#endif
#ifdef WIZARD
if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt);
#endif
you_can(buf,"");
}
{
const char *p;
buf[0] = '\0';
if (final < 2) { /* still in progress, or quit/escaped/ascended */
p = "survived after being killed ";
switch (u.umortality) {
case 0: p = !final ? (char *)0 : "survived"; break;
case 1: Strcpy(buf, "once"); break;
case 2: Strcpy(buf, "twice"); break;
case 3: Strcpy(buf, "thrice"); break;
default: Sprintf(buf, "%d times", u.umortality);
break;
}
} else { /* game ended in character's death */
p = "are dead";
switch (u.umortality) {
case 0: impossible("dead without dying?");
case 1: break; /* just "are dead" */
default: Sprintf(buf, " (%d%s time!)", u.umortality,
ordin(u.umortality));
break;
}
}
if (p) enl_msg(You_, "have been killed ", p, buf, "");
}
display_nhwindow(en_win, TRUE);
destroy_nhwindow(en_win);
return;
}
/*
* Courtesy function for non-debug, non-explorer mode players
* to help refresh them about who/what they are.
* Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise.
*/
STATIC_OVL boolean
minimal_enlightenment()
{
winid tmpwin;
menu_item *selected;
anything any;
int genidx, n;
char buf[BUFSZ], buf2[BUFSZ];
static const char untabbed_fmtstr[] = "%-15s: %-12s";
static const char untabbed_deity_fmtstr[] = "%-17s%s";
static const char tabbed_fmtstr[] = "%s:\t%-12s";
static const char tabbed_deity_fmtstr[] = "%s\t%s";
static const char *fmtstr;
static const char *deity_fmtstr;
fmtstr = iflags.menu_tab_sep ? tabbed_fmtstr : untabbed_fmtstr;
deity_fmtstr = iflags.menu_tab_sep ?
tabbed_deity_fmtstr : untabbed_deity_fmtstr;
any.a_void = 0;
buf[0] = buf2[0] = '\0';
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Starting", FALSE);
/* Starting name, race, role, gender */
Sprintf(buf, fmtstr, "name", plname);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
Sprintf(buf, fmtstr, "race", urace.noun);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
Sprintf(buf, fmtstr, "role",
(flags.initgend && urole.name.f) ? urole.name.f : urole.name.m);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
/* Starting alignment */
Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL]));
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
/* Current name, race, role, gender */
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Current", FALSE);
Sprintf(buf, fmtstr, "race", Upolyd ? youmonst.data->mname : urace.noun);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
if (Upolyd) {
Sprintf(buf, fmtstr, "role (base)",
(u.mfemale && urole.name.f) ? urole.name.f : urole.name.m);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
} else {
Sprintf(buf, fmtstr, "role",
(flags.female && urole.name.f) ? urole.name.f : urole.name.m);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
}
/* don't want poly_gender() here; it forces `2' for non-humanoids */
genidx = is_neuter(youmonst.data) ? 2 : flags.female;
Sprintf(buf, fmtstr, "gender", genders[genidx].adj);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
if (Upolyd && (int)u.mfemale != genidx) {
Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
}
/* Current alignment */
Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type));
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
/* Deity list */
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Deities", FALSE);
Sprintf(buf2, deity_fmtstr, align_gname(A_CHAOTIC),
(u.ualignbase[A_ORIGINAL] == u.ualign.type
&& u.ualign.type == A_CHAOTIC) ? " (s,c)" :
(u.ualignbase[A_ORIGINAL] == A_CHAOTIC) ? " (s)" :
(u.ualign.type == A_CHAOTIC) ? " (c)" : "");
Sprintf(buf, fmtstr, "Chaotic", buf2);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
Sprintf(buf2, deity_fmtstr, align_gname(A_NEUTRAL),
(u.ualignbase[A_ORIGINAL] == u.ualign.type
&& u.ualign.type == A_NEUTRAL) ? " (s,c)" :
(u.ualignbase[A_ORIGINAL] == A_NEUTRAL) ? " (s)" :
(u.ualign.type == A_NEUTRAL) ? " (c)" : "");
Sprintf(buf, fmtstr, "Neutral", buf2);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
Sprintf(buf2, deity_fmtstr, align_gname(A_LAWFUL),
(u.ualignbase[A_ORIGINAL] == u.ualign.type &&
u.ualign.type == A_LAWFUL) ? " (s,c)" :
(u.ualignbase[A_ORIGINAL] == A_LAWFUL) ? " (s)" :
(u.ualign.type == A_LAWFUL) ? " (c)" : "");
Sprintf(buf, fmtstr, "Lawful", buf2);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
end_menu(tmpwin, "Base Attributes");
n = select_menu(tmpwin, PICK_NONE, &selected);
destroy_nhwindow(tmpwin);
return (n != -1);
}
/* ^X command */
STATIC_PTR int
doattributes()
{
if (!minimal_enlightenment())
return 0;
if (wizard || discover)
enlightenment(0);
return 0;
}
/* KMH, #conduct
* (shares enlightenment's tense handling)
*/
STATIC_PTR int
doconduct()
{
show_conduct(0);
return 0;
}
void
show_conduct(final)
int final;
{
char buf[BUFSZ];
int ngenocided;
/* Create the conduct window */
en_win = create_nhwindow(NHW_MENU);
putstr(en_win, 0, "Voluntary challenges:");
putstr(en_win, 0, "");
if (!u.uconduct.food)
enl_msg(You_, "have gone", "went", " without food", "");
/* But beverages are okay */
else if (!u.uconduct.unvegan)
you_have_X("followed a strict vegan diet");
else if (!u.uconduct.unvegetarian)
you_have_been("vegetarian");
if (!u.uconduct.gnostic)
you_have_been("an atheist");
if (!u.uconduct.weaphit)
you_have_never("hit with a wielded weapon");
#ifdef WIZARD
else if (wizard) {
Sprintf(buf, "used a wielded weapon %ld time%s",
u.uconduct.weaphit, plur(u.uconduct.weaphit));
you_have_X(buf);
}
#endif
if (!u.uconduct.killer)
you_have_been("a pacifist");
if (!u.uconduct.literate)
you_have_been("illiterate");
#ifdef WIZARD
else if (wizard) {
Sprintf(buf, "read items or engraved %ld time%s",
u.uconduct.literate, plur(u.uconduct.literate));
you_have_X(buf);
}
#endif
ngenocided = num_genocides();
if (ngenocided == 0) {
you_have_never("genocided any monsters");
} else {
Sprintf(buf, "genocided %d type%s of monster%s",
ngenocided, plur(ngenocided), plur(ngenocided));
you_have_X(buf);
}
if (!u.uconduct.polypiles)
you_have_never("polymorphed an object");
#ifdef WIZARD
else if (wizard) {
Sprintf(buf, "polymorphed %ld item%s",
u.uconduct.polypiles, plur(u.uconduct.polypiles));
you_have_X(buf);
}
#endif
if (!u.uconduct.polyselfs)
you_have_never("changed form");
#ifdef WIZARD
else if (wizard) {
Sprintf(buf, "changed form %ld time%s",
u.uconduct.polyselfs, plur(u.uconduct.polyselfs));
you_have_X(buf);
}
#endif
if (!u.uconduct.wishes)
you_have_X("used no wishes");
else {
Sprintf(buf, "used %ld wish%s",
u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : "");
you_have_X(buf);
if (!u.uconduct.wisharti)
enl_msg(You_, "have not wished", "did not wish",
" for any artifacts", "");
}
/* Pop up the window and wait for a key */
display_nhwindow(en_win, TRUE);
destroy_nhwindow(en_win);
}
#ifndef M
# ifndef NHSTDC
# define M(c) (0x80 | (c))
# else
# define M(c) ((c) - 128)
# endif /* NHSTDC */
#endif
#ifndef C
#define C(c) (0x1f & (c))
#endif
static const struct func_tab cmdlist[] = {
{C('d'), FALSE, dokick}, /* "D" is for door!...? Msg is in dokick.c */
#ifdef WIZARD
{C('e'), TRUE, wiz_detect},
{C('f'), TRUE, wiz_map},
{C('g'), TRUE, wiz_genesis},
{C('i'), TRUE, wiz_identify},
#endif
{C('l'), TRUE, doredraw}, /* if number_pad is set */
#ifndef DUNGEON_OVERVIEW
#ifdef WIZARD
{C('o'), TRUE, wiz_where},
#endif
#else
{C('n'), TRUE, donamelevel}, /* if number_pad is set */
{C('o'), TRUE, dooverview_or_wiz_where}, /* depending on wizard status */
#endif /* DUNGEON_OVERVIEW */
{C('p'), TRUE, doprev_message},
{C('r'), TRUE, doredraw},
{C('t'), TRUE, dotele},
#ifdef WIZARD
{C('v'), TRUE, wiz_level_tele},
{C('w'), TRUE, wiz_wish},
#endif
{C('x'), TRUE, doattributes},
#ifdef SUSPEND
{C('z'), TRUE, dosuspend},
#endif
{'a', FALSE, doapply},
{'A', FALSE, doddoremarm},
{M('a'), TRUE, doorganize},
/* 'b', 'B' : go sw */
{'c', FALSE, doclose},
{'C', TRUE, do_mname},
{M('c'), TRUE, dotalk},
{'d', FALSE, dodrop},
{'D', FALSE, doddrop},
{M('d'), FALSE, dodip},
{'e', FALSE, doeat},
{'E', FALSE, doengrave},
{M('e'), TRUE, enhance_weapon_skill},
{'f', FALSE, dofire},
/* 'F' : fight (one time) */
{M('f'), FALSE, doforce},
/* 'g', 'G' : multiple go */
/* 'h', 'H' : go west */
{'h', TRUE, dohelp}, /* if number_pad is set */
{'i', TRUE, ddoinv},
{'I', TRUE, dotypeinv}, /* Robert Viduya */
{M('i'), TRUE, doinvoke},
/* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
{'j', FALSE, dojump}, /* if number_pad is on */
{M('j'), FALSE, dojump},
{'k', FALSE, dokick}, /* if number_pad is on */
{'l', FALSE, doloot}, /* if number_pad is on */
{M('l'), FALSE, doloot},
/* 'n' prefixes a count if number_pad is on */
{M('m'), TRUE, domonability},
{'N', TRUE, ddocall}, /* if number_pad is on */
{M('n'), TRUE, ddocall},
{M('N'), TRUE, ddocall},
{'o', FALSE, doopen},
{'O', TRUE, doset},
{M('o'), FALSE, dosacrifice},
{'p', FALSE, dopay},
{'P', FALSE, doputon},
{M('p'), TRUE, dopray},
{'q', FALSE, dodrink},
{'Q', FALSE, dowieldquiver},
{M('q'), TRUE, done2},
{'r', FALSE, doread},
{'R', FALSE, doremring},
{M('r'), FALSE, dorub},
{'s', TRUE, dosearch, "searching"},
{'S', TRUE, dosave},
{M('s'), FALSE, dosit},
{'t', FALSE, dothrow},
{'T', FALSE, dotakeoff},
{M('t'), TRUE, doturn},
/* 'u', 'U' : go ne */
{'u', FALSE, dountrap}, /* if number_pad is on */
{M('u'), FALSE, dountrap},
{'v', TRUE, doversion},
{'V', TRUE, dohistory},
{M('v'), TRUE, doextversion},
{'w', FALSE, dowield},
{'W', FALSE, dowear},
{M('w'), FALSE, dowipe},
{'x', FALSE, doswapweapon},
{'X', TRUE, enter_explore_mode},
/* 'y', 'Y' : go nw */
{'z', FALSE, dozap},
{'Z', TRUE, docast},
{'<', FALSE, doup},
{'>', FALSE, dodown},
{'/', TRUE, dowhatis},
{'&', TRUE, dowhatdoes},
{'?', TRUE, dohelp},
{M('?'), TRUE, doextlist},
#ifdef SHELL
{'!', TRUE, dosh},
#endif
{'.', TRUE, donull, "waiting"},
{' ', TRUE, donull, "waiting"},
{',', FALSE, dopickup},
{':', TRUE, dolook},
{';', TRUE, doquickwhatis},
{'^', TRUE, doidtrap},
{'\\', TRUE, dodiscovered}, /* Robert Viduya */
{'@', TRUE, dotogglepickup},
{M('2'), FALSE, dotwoweapon},
{WEAPON_SYM, TRUE, doprwep},
{ARMOR_SYM, TRUE, doprarm},
{RING_SYM, TRUE, doprring},
{AMULET_SYM, TRUE, dopramulet},
{TOOL_SYM, TRUE, doprtool},
{'*', TRUE, doprinuse}, /* inventory of all equipment in use */
{GOLD_SYM, TRUE, doprgold},
{SPBOOK_SYM, TRUE, dovspell}, /* Mike Stephenson */
{'#', TRUE, doextcmd},
{'_', TRUE, dotravel},
{0,0,0,0}
};
struct ext_func_tab extcmdlist[] = {
{"adjust", "adjust inventory letters", doorganize, TRUE},
#ifdef DUNGEON_OVERVIEW
{"annotate", "name current level", donamelevel, TRUE},
#endif /* DUNGEON_OVERVIEW */
{"chat", "talk to someone", dotalk, TRUE}, /* converse? */
{"conduct", "list voluntary challenges you have maintained",
doconduct, TRUE},
{"dip", "dip an object into something", dodip, FALSE},
{"enhance", "advance or check weapon and spell skills",
enhance_weapon_skill, TRUE},
{"force", "force a lock", doforce, FALSE},
{"invoke", "invoke an object's powers", doinvoke, TRUE},
{"jump", "jump to a location", dojump, FALSE},
{"loot", "loot a box on the floor", doloot, FALSE},
{"monster", "use a monster's special ability", domonability, TRUE},
{"name", "name an item or type of object", ddocall, TRUE},
{"offer", "offer a sacrifice to the gods", dosacrifice, FALSE},
#ifdef DUNGEON_OVERVIEW
{"overview", "show an overview of the dungeon", dooverview, TRUE},
#endif /* DUNGEON_OVERVIEW */
{"pray", "pray to the gods for help", dopray, TRUE},
{"quit", "exit without saving current game", done2, TRUE},
#ifdef STEED
{"ride", "ride (or stop riding) a monster", doride, FALSE},
#endif
{"rub", "rub a lamp or a stone", dorub, FALSE},
{"sit", "sit down", dosit, FALSE},
{"tip", "empty a container", dotip, FALSE},
{"turn", "turn undead", doturn, TRUE},
{"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE},
{"untrap", "untrap something", dountrap, FALSE},
{"version", "list compile time options for this version of NetHack",
doextversion, TRUE},
{"wipe", "wipe off your face", dowipe, FALSE},
{"?", "get this list of extended commands", doextlist, TRUE},
#if defined(WIZARD)
/*
* There must be a blank entry here for every entry in the table
* below.
*/
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
#ifdef DEBUG_MIGRATING_MONS
{(char *)0, (char *)0, donull, TRUE},
#endif
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
#ifdef PORT_DEBUG
{(char *)0, (char *)0, donull, TRUE},
#endif
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
#ifdef DEBUG
{(char *)0, (char *)0, donull, TRUE},
#endif
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
#endif
{(char *)0, (char *)0, donull, TRUE} /* sentinel */
};
#if defined(WIZARD)
static const struct ext_func_tab debug_extcmdlist[] = {
{"levelchange", "change experience level", wiz_level_change, TRUE},
{"lightsources", "show mobile light sources", wiz_light_sources, TRUE},
#ifdef DEBUG_MIGRATING_MONS
{"migratemons", "migrate n random monsters", wiz_migrate_mons, TRUE},
#endif
{"monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol, TRUE},
{"panic", "test panic routine (fatal to game)", wiz_panic, TRUE},
{"polyself", "polymorph self", wiz_polyself, TRUE},
#ifdef PORT_DEBUG
{"portdebug", "wizard port debug command", wiz_port_debug, TRUE},
#endif
{"seenv", "show seen vectors", wiz_show_seenv, TRUE},
{"stats", "show memory statistics", wiz_show_stats, TRUE},
{"terrain", "show map topology", wiz_map_terrain, TRUE},
{"timeout", "look at timeout queue", wiz_timeout_queue, TRUE},
{"vision", "show vision array", wiz_show_vision, TRUE},
{"wizsmell", "smell monster", wiz_smell, TRUE},
#ifdef DEBUG
{"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE},
#endif
{"wizrumorcheck", "verify rumor boundaries", wiz_rumor_check, TRUE},
{"wmode", "show wall modes", wiz_show_wmodes, TRUE},
{(char *)0, (char *)0, donull, TRUE}
};
/*
* Insert debug commands into the extended command list. This function
* assumes that the last entry will be the help entry.
*
* You must add entries in ext_func_tab every time you add one to the
* debug_extcmdlist().
*/
void
add_debug_extended_commands()
{
int i, j, k, n;
/* count the # of help entries */
for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++)
;
for (i = 0; debug_extcmdlist[i].ef_txt; i++) {
for (j = 0; j < n; j++)
if (strcmp(debug_extcmdlist[i].ef_txt, extcmdlist[j].ef_txt) < 0) break;
/* insert i'th debug entry into extcmdlist[j], pushing down */
for (k = n; k >= j; --k)
extcmdlist[k+1] = extcmdlist[k];
extcmdlist[j] = debug_extcmdlist[i];
n++; /* now an extra entry */
}
}
/* called at startup and after number_pad is twiddled */
void
reset_commands(initial)
boolean initial;
{
static const char
sdir[] = "hykulnjb><", sdir_swap_yz[] = "hzkulnjb><",
ndir[] = "47896321><", ndir_phone_layout[] = "41236987><";
static const int ylist[] = { 'y', 'Y', C('y'), M('y'), M('Y'), M(C('y')) };
const struct func_tab *cmdtmp;
boolean flagtemp;
int c, i, updated = 0;
if (initial) {
updated = 1;
for (i = 0; i < SIZE(cmdlist); i++) {
c = cmdlist[i].f_char & 0xff;
Cmd.commands[c] = &cmdlist[i];
}
Cmd.num_pad = FALSE;
Cmd.pcHack_compat = Cmd.phone_layout = Cmd.swap_yz = FALSE;
} else {
/* basic num_pad */
flagtemp = iflags.num_pad;
if (flagtemp != Cmd.num_pad) {
Cmd.num_pad = flagtemp;
++updated;
}
/* swap_yz mode (only applicable for !num_pad) */
flagtemp = (iflags.num_pad_mode & 1) ? !Cmd.num_pad : FALSE;
if (flagtemp != Cmd.swap_yz) {
Cmd.swap_yz = flagtemp;
++updated;
/* Cmd.swap_yz has been toggled;
perform the swap (or reverse previous one) */
for (i = 0; i < SIZE(ylist); i++) {
c = ylist[i] & 0xff;
cmdtmp = Cmd.commands[c]; /* tmp = [y] */
Cmd.commands[c] = Cmd.commands[c + 1]; /* [y] = [z] */
Cmd.commands[c + 1] = cmdtmp; /* [z] = tmp */
}
}
/* MSDOS compatibility mode (only applicable for num_pad) */
flagtemp = (iflags.num_pad_mode & 1) ? Cmd.num_pad : FALSE;
if (flagtemp != Cmd.pcHack_compat) {
Cmd.pcHack_compat = flagtemp;
++updated;
/* pcHack_compat has been toggled */
c = M('5') & 0xff;
cmdtmp = Cmd.commands['5'];
Cmd.commands['5'] = Cmd.commands[c];
Cmd.commands[c] = cmdtmp;
c = M('0') & 0xff;
Cmd.commands[c] = Cmd.pcHack_compat ? Cmd.commands['I'] : 0;
}
/* phone keypad layout (only applicable for num_pad) */
flagtemp = (iflags.num_pad_mode & 2) ? Cmd.num_pad : FALSE;
if (flagtemp != Cmd.phone_layout) {
Cmd.phone_layout = flagtemp;
++updated;
/* phone_layout has been toggled */
for (i = 0; i < 3; i++) {
c = '1' + i; /* 1,2,3 <-> 7,8,9 */
cmdtmp = Cmd.commands[c]; /* tmp = [1] */
Cmd.commands[c] = Cmd.commands[c + 6]; /* [1] = [7] */
Cmd.commands[c + 6] = cmdtmp; /* [7] = tmp */
c = (M('1') & 0xff) + i; /* M-1,M-2,M-3 <-> M-7,M-8,M-9 */
cmdtmp = Cmd.commands[c]; /* tmp = [M-1] */
Cmd.commands[c] = Cmd.commands[c + 6]; /* [M-1] = [M-7] */
Cmd.commands[c + 6] = cmdtmp; /* [M-7] = tmp */
}
}
} /*?initial*/
if (updated) Cmd.serialno++;
Cmd.dirchars = !Cmd.num_pad ? (!Cmd.swap_yz ? sdir : sdir_swap_yz) :
(!Cmd.phone_layout ? ndir : ndir_phone_layout);
Cmd.alphadirchars = !Cmd.num_pad ? Cmd.dirchars : sdir;
Cmd.move_W = Cmd.dirchars[0];
Cmd.move_NW = Cmd.dirchars[1];
Cmd.move_N = Cmd.dirchars[2];
Cmd.move_NE = Cmd.dirchars[3];
Cmd.move_E = Cmd.dirchars[4];
Cmd.move_SE = Cmd.dirchars[5];
Cmd.move_S = Cmd.dirchars[6];
Cmd.move_SW = Cmd.dirchars[7];
}
STATIC_OVL char
cmd_from_func(fn)
int NDECL((*fn));
{
int i;
for (i = 0; i < SIZE(cmdlist); ++i)
if (cmdlist[i].f_funct == fn)
return cmdlist[i].f_char;
return 0;
}
/* decide whether a character (user input keystroke) requests screen repaint */
boolean
redraw_cmd(c)
char c;
{
return (c == C('r') || (Cmd.num_pad && c == C('l')));
}
static const char template[] = "%-18s %4ld %6ld";
static const char count_str[] = " count bytes";
static const char separator[] = "------------------ ----- ------";
STATIC_OVL int
size_obj(otmp)
struct obj *otmp;
{
int sz = (int)sizeof (struct obj);
if (otmp->oextra) {
if (ONAME(otmp)) sz += (int)strlen(ONAME(otmp)) + 1;
if (OMONST(otmp)) sz += (int)sizeof (struct monst);
if (OMID(otmp)) sz += (int)sizeof (unsigned);
if (OLONG(otmp)) sz += (int)sizeof (long);
if (OMAILCMD(otmp)) sz += (int)strlen(OMAILCMD(otmp)) + 1;
}
return sz;
}
STATIC_OVL void
count_obj(chain, total_count, total_size, top, recurse)
struct obj *chain;
long *total_count;
long *total_size;
boolean top;
boolean recurse;
{
long count, size;
struct obj *obj;
for (count = size = 0, obj = chain; obj; obj = obj->nobj) {
if (top) {
count++;
size += size_obj(obj);
}
if (recurse && obj->cobj)
count_obj(obj->cobj, total_count, total_size, TRUE, TRUE);
}
*total_count += count;
*total_size += size;
}
STATIC_OVL void
obj_chain(win, src, chain, total_count, total_size)
winid win;
const char *src;
struct obj *chain;
long *total_count;
long *total_size;
{
char buf[BUFSZ];
long count = 0, size = 0;
count_obj(chain, &count, &size, TRUE, FALSE);
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
}
STATIC_OVL void
mon_invent_chain(win, src, chain, total_count, total_size)
winid win;
const char *src;
struct monst *chain;
long *total_count;
long *total_size;
{
char buf[BUFSZ];
long count = 0, size = 0;
struct monst *mon;
for (mon = chain; mon; mon = mon->nmon)
count_obj(mon->minvent, &count, &size, TRUE, FALSE);
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
}
STATIC_OVL void
contained(win, src, total_count, total_size)
winid win;
const char *src;
long *total_count;
long *total_size;
{
char buf[BUFSZ];
long count = 0, size = 0;
struct monst *mon;
count_obj(invent, &count, &size, FALSE, TRUE);
count_obj(fobj, &count, &size, FALSE, TRUE);
count_obj(level.buriedobjlist, &count, &size, FALSE, TRUE);
count_obj(migrating_objs, &count, &size, FALSE, TRUE);
/* DEADMONSTER check not required in this loop since they have no inventory */
for (mon = fmon; mon; mon = mon->nmon)
count_obj(mon->minvent, &count, &size, FALSE, TRUE);
for (mon = migrating_mons; mon; mon = mon->nmon)
count_obj(mon->minvent, &count, &size, FALSE, TRUE);
*total_count += count; *total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
}
STATIC_OVL int
size_monst(mtmp)
struct monst *mtmp;
{
int sz = (int)sizeof (struct monst);
if (mtmp->mextra) {
if (MNAME(mtmp)) sz += (int)strlen(MNAME(mtmp)) + 1;
if (EGD(mtmp)) sz += (int)sizeof (struct egd);
if (EPRI(mtmp)) sz += (int)sizeof (struct epri);
if (ESHK(mtmp)) sz += (int)sizeof (struct eshk);
if (EMIN(mtmp)) sz += (int)sizeof (struct emin);
if (EDOG(mtmp)) sz += (int)sizeof (struct edog);
}
return sz;
}
STATIC_OVL void
mon_chain(win, src, chain, total_count, total_size)
winid win;
const char *src;
struct monst *chain;
long *total_count;
long *total_size;
{
char buf[BUFSZ];
long count, size;
struct monst *mon;
for (count = size = 0, mon = chain; mon; mon = mon->nmon) {
count++;
size += size_monst(mon);
}
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
}
/*
* Display memory usage of all monsters and objects on the level.
*/
static int
wiz_show_stats()
{
char buf[BUFSZ];
winid win;
long total_obj_size = 0, total_obj_count = 0;
long total_mon_size = 0, total_mon_count = 0;
win = create_nhwindow(NHW_TEXT);
putstr(win, 0, "Current memory statistics:");
putstr(win, 0, "");
Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj));
putstr(win, 0, buf);
putstr(win, 0, "");
putstr(win, 0, count_str);
obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size);
obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size);
obj_chain(win, "buried", level.buriedobjlist,
&total_obj_count, &total_obj_size);
obj_chain(win, "migrating obj", migrating_objs,
&total_obj_count, &total_obj_size);
mon_invent_chain(win, "minvent", fmon,
&total_obj_count,&total_obj_size);
mon_invent_chain(win, "migrating minvent", migrating_mons,
&total_obj_count, &total_obj_size);
contained(win, "contained",
&total_obj_count, &total_obj_size);
putstr(win, 0, separator);
Sprintf(buf, template, "Total", total_obj_count, total_obj_size);
putstr(win, 0, buf);
putstr(win, 0, "");
putstr(win, 0, "");
Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst));
putstr(win, 0, buf);
putstr(win, 0, "");
mon_chain(win, "fmon", fmon,
&total_mon_count, &total_mon_size);
mon_chain(win, "migrating", migrating_mons,
&total_mon_count, &total_mon_size);
putstr(win, 0, separator);
Sprintf(buf, template, "Total", total_mon_count, total_mon_size);
putstr(win, 0, buf);
#if defined(__BORLANDC__) && !defined(_WIN32)
show_borlandc_stats(win);
#endif
display_nhwindow(win, FALSE);
destroy_nhwindow(win);
return 0;
}
void
sanity_check()
{
obj_sanity_check();
timer_sanity_check();
}
#ifdef DEBUG_MIGRATING_MONS
static int
wiz_migrate_mons()
{
int mcount = 0;
char inbuf[BUFSZ];
struct permonst *ptr;
struct monst *mtmp;
d_level tolevel;
getlin("How many random monsters to migrate? [0]", inbuf);
if (*inbuf == '\033') return 0;
mcount = atoi(inbuf);
if (mcount < 0 || mcount > (COLNO * ROWNO) || Is_botlevel(&u.uz))
return 0;
while (mcount > 0) {
if (Is_stronghold(&u.uz))
assign_level(&tolevel, &valley_level);
else
get_level(&tolevel, depth(&u.uz) + 1);
ptr = rndmonst();
mtmp = makemon(ptr, 0, 0, NO_MM_FLAGS);
if (mtmp) migrate_to_level(mtmp, ledger_no(&tolevel),
MIGR_RANDOM, (coord *)0);
mcount--;
}
return 0;
}
#endif
#endif /* WIZARD */
#define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
#define unmeta(c) (0x7f & (c))
void
rhack(cmd)
register char *cmd;
{
boolean do_walk, do_rush, prefix_seen, bad_command,
firsttime = (cmd == 0);
iflags.menu_requested = FALSE;
#ifdef SAFERHANGUP
if (program_state.done_hup) end_of_input();
#endif
if (firsttime) {
context.nopick = 0;
cmd = parse();
}
if (*cmd == '\033') {
context.move = FALSE;
return;
}
#ifdef REDO
if (*cmd == DOAGAIN && !in_doagain && saveq[0]) {
in_doagain = TRUE;
stail = 0;
rhack((char *)0); /* read and execute command */
in_doagain = FALSE;
return;
}
/* Special case of *cmd == ' ' handled better below */
if(!*cmd || *cmd == (char)0377)
#else
if(!*cmd || *cmd == (char)0377 || (!flags.rest_on_space && *cmd == ' '))
#endif
{
nhbell();
context.move = FALSE;
return; /* probably we just had an interrupt */
}
if (Cmd.pcHack_compat) {
/* This handles very old inconsistent DOS/Windows behaviour
* in a new way: earlier, the keyboard handler mapped these,
* which caused counts to be strange when entered from the
* number pad. Now do not map them until here.
*/
switch (*cmd) {
case '5': *cmd = 'g'; break;
case M('5'): *cmd = 'G'; break;
case M('0'): *cmd = 'I'; break;
}
}
/* handle most movement commands */
do_walk = do_rush = prefix_seen = FALSE;
context.travel = context.travel1 = 0;
switch (*cmd) {
case 'g': if (movecmd(cmd[1])) {
context.run = 2;
do_rush = TRUE;
} else
prefix_seen = TRUE;
break;
case '5': if (!Cmd.num_pad) break; /* else FALLTHRU */
case 'G': if (movecmd(lowc(cmd[1]))) {
context.run = 3;
do_rush = TRUE;
} else
prefix_seen = TRUE;
break;
case '-': if (!Cmd.num_pad) break; /* else FALLTHRU */
/* Effects of movement commands and invisible monsters:
* m: always move onto space (even if 'I' remembered)
* F: always attack space (even if 'I' not remembered)
* normal movement: attack if 'I', move otherwise
*/
case 'F': if (movecmd(cmd[1])) {
context.forcefight = 1;
do_walk = TRUE;
} else
prefix_seen = TRUE;
break;
case 'm': if (movecmd(cmd[1]) || u.dz) {
context.run = 0;
context.nopick = 1;
if (!u.dz) do_walk = TRUE;
else cmd[0] = cmd[1]; /* "m<" or "m>" */
} else
prefix_seen = TRUE;
break;
case 'M': if (movecmd(lowc(cmd[1]))) {
context.run = 1;
context.nopick = 1;
do_rush = TRUE;
} else
prefix_seen = TRUE;
break;
case '0': if (!Cmd.num_pad) break;
(void)ddoinv(); /* a convenience borrowed from the PC */
context.move = FALSE;
multi = 0;
return;
case CMD_CLICKLOOK:
if (iflags.clicklook) {
context.move = FALSE;
do_look(2, &clicklook_cc);
}
return;
case CMD_TRAVEL:
if (flags.travelcmd) {
context.travel = 1;
context.travel1 = 1;
context.run = 8;
context.nopick = 1;
do_rush = TRUE;
break;
}
/*FALLTHRU*/
default: if (movecmd(*cmd)) { /* ordinary movement */
context.run = 0; /* only matters here if it was 8 */
do_walk = TRUE;
} else if (movecmd(Cmd.num_pad ?
unmeta(*cmd) : lowc(*cmd))) {
context.run = 1;
do_rush = TRUE;
} else if (movecmd(unctrl(*cmd))) {
context.run = 3;
do_rush = TRUE;
}
break;
}
/* some special prefix handling */
/* overload 'm' prefix for ',' to mean "request a menu" */
if (prefix_seen && cmd[1] == ',') {
iflags.menu_requested = TRUE;
++cmd;
}
if (do_walk) {
if (multi) context.mv = TRUE;
domove();
context.forcefight = 0;
return;
} else if (do_rush) {
if (firsttime) {
if (!multi) multi = max(COLNO,ROWNO);
u.last_str_turn = 0;
}
context.mv = TRUE;
domove();
return;
} else if (prefix_seen && cmd[1] == '\033') { /* <prefix><escape> */
/* don't report "unknown command" for change of heart... */
bad_command = FALSE;
} else if (*cmd == ' ' && !flags.rest_on_space) {
bad_command = TRUE; /* skip cmdlist[] loop */
/* handle all other commands */
} else {
register const struct func_tab *tlist;
int res, NDECL((*func));
#if 0
for (tlist = cmdlist; tlist->f_char; tlist++) {
if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue;
#else
if ((tlist = Cmd.commands[*cmd & 0xff]) != 0) {
#endif
if (u.uburied && !tlist->can_if_buried) {
You_cant("do that while you are buried!");
res = 0;
} else {
/* we discard 'const' because some compilers seem to have
trouble with the pointer passed to set_occupation() */
func = ((struct func_tab *)tlist)->f_funct;
if (tlist->f_text && !occupation && multi)
set_occupation(func, tlist->f_text, multi);
res = (*func)(); /* perform the command */
}
if (!res) {
context.move = FALSE;
multi = 0;
}
return;
}
/* if we reach here, cmd wasn't found in cmdlist[] */
bad_command = TRUE;
}
if (bad_command) {
char expcmd[10];
register char c, *cp = expcmd;
while ((c = *cmd++) != '\0' &&
(int)(cp - expcmd) < (int)(sizeof expcmd - 3)) {
if (c >= 040 && c < 0177) {
*cp++ = c;
} else if (c & 0200) {
*cp++ = 'M';
*cp++ = '-';
*cp++ = c & ~0200;
} else {
*cp++ = '^';
*cp++ = c ^ 0100;
}
}
*cp = '\0';
if (!prefix_seen || !iflags.cmdassist ||
!help_dir(0, "Invalid direction key!"))
Norep("Unknown command '%s'.", expcmd);
}
/* didn't move */
context.move = FALSE;
multi = 0;
return;
}
int
xytod(x, y) /* convert an x,y pair into a direction code */
schar x, y;
{
register int dd;
for(dd = 0; dd < 8; dd++)
if(x == xdir[dd] && y == ydir[dd]) return dd;
return -1;
}
void
dtoxy(cc,dd) /* convert a direction code into an x,y pair */
coord *cc;
register int dd;
{
cc->x = xdir[dd];
cc->y = ydir[dd];
return;
}
int
movecmd(sym) /* also sets u.dz, but returns false for <> */
char sym;
{
register const char *dp = index(Cmd.dirchars, sym);
u.dz = 0;
if (!dp) return 0;
u.dx = xdir[dp - Cmd.dirchars];
u.dy = ydir[dp - Cmd.dirchars];
u.dz = zdir[dp - Cmd.dirchars];
if (u.dx && u.dy && NODIAG(u.umonnum)) {
u.dx = u.dy = 0;
return 0;
}
return !u.dz;
}
/*
* uses getdir() but unlike getdir() it specifically
* produces coordinates using the direction from getdir()
* and verifies that those coordinates are ok.
*
* If the call to getdir() returns 0, Never_mind is displayed.
* If the resulting coordinates are not okay, emsg is displayed.
*
* Returns non-zero if coordinates in cc are valid.
*/
int get_adjacent_loc(prompt,emsg,x,y,cc)
const char *prompt, *emsg;
xchar x,y;
coord *cc;
{
xchar new_x, new_y;
if (!getdir(prompt)) {
pline(Never_mind);
return 0;
}
new_x = x + u.dx;
new_y = y + u.dy;
if (cc && isok(new_x,new_y)) {
cc->x = new_x;
cc->y = new_y;
} else {
if (emsg) pline(emsg);
return 0;
}
return 1;
}
int
getdir(s)
const char *s;
{
char dirsym;
retry:
#ifdef REDO
if (in_doagain || *readchar_queue)
dirsym = readchar();
else
#endif
dirsym = yn_function((s && *s != '^') ? s : "In what direction?",
(char *)0, '\0');
/* remove the prompt string so caller won't have to */
clear_nhwindow(WIN_MESSAGE);
if (redraw_cmd(dirsym)) { /* ^R */
docrt(); /* redraw */
goto retry;
}
#ifdef REDO
savech(dirsym);
#endif
if (dirsym == '.' || dirsym == 's') {
u.dx = u.dy = u.dz = 0;
} else if (!movecmd(dirsym) && !u.dz) {
boolean did_help = FALSE, help_requested;
if (!index(quitchars, dirsym)) {
help_requested = (dirsym == '?');
if (help_requested || iflags.cmdassist) {
did_help = help_dir((s && *s == '^') ? dirsym : 0,
help_requested ? (const char *)0 :
"Invalid direction key!");
if (help_requested) goto retry;
}
if (!did_help) pline("What a strange direction!");
}
return 0;
}
if (!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir();
return 1;
}
STATIC_OVL boolean
help_dir(sym, msg)
char sym;
const char *msg;
{
char ctrl;
winid win;
static const char wiz_only_list[] = "EFGIOVW";
char buf[BUFSZ], buf2[BUFSZ], *explain;
win = create_nhwindow(NHW_TEXT);
if (!win) return FALSE;
if (msg) {
Sprintf(buf, "cmdassist: %s", msg);
putstr(win, 0, buf);
putstr(win, 0, "");
}
if (letter(sym)) {
sym = highc(sym);
ctrl = (sym - 'A') + 1;
if ((explain = dowhatdoes_core(ctrl, buf2))
&& (!index(wiz_only_list, sym)
#ifdef WIZARD
|| wizard
#endif
)) {
Sprintf(buf, "Are you trying to use ^%c%s?", sym,
index(wiz_only_list, sym) ? "" :
" as specified in the Guidebook");
putstr(win, 0, buf);
putstr(win, 0, "");
putstr(win, 0, explain);
putstr(win, 0, "");
putstr(win, 0, "To use that command, you press");
Sprintf(buf,
"the <Ctrl> key, and the <%c> key at the same time.", sym);
putstr(win, 0, buf);
putstr(win, 0, "");
}
}
if (NODIAG(u.umonnum)) {
putstr(win, 0, "Valid direction keys in your current form are:");
Sprintf(buf, " %c ", Cmd.move_N);
putstr(win, 0, buf);
putstr(win, 0, " | ");
Sprintf(buf, " %c- . -%c", Cmd.move_W, Cmd.move_E);
putstr(win, 0, buf);
putstr(win, 0, " | ");
Sprintf(buf, " %c ", Cmd.move_S);
putstr(win, 0, buf);
} else {
putstr(win, 0, "Valid direction keys are:");
Sprintf(buf, " %c %c %c",
Cmd.move_NW, Cmd.move_N, Cmd.move_NE);
putstr(win, 0, buf);
putstr(win, 0, " \\ | / ");
Sprintf(buf, " %c- . -%c", Cmd.move_W, Cmd.move_E);
putstr(win, 0, buf);
putstr(win, 0, " / | \\ ");
Sprintf(buf, " %c %c %c",
Cmd.move_SW, Cmd.move_S, Cmd.move_SE);
putstr(win, 0, buf);
};
putstr(win, 0, "");
putstr(win, 0, " < up");
putstr(win, 0, " > down");
putstr(win, 0, " . direct at yourself");
if (msg) {
/* non-null msg means that this wasn't an explicit user request */
putstr(win, 0, "");
putstr(win, 0,
"(Suppress this message with !cmdassist in config file.)");
}
display_nhwindow(win, FALSE);
destroy_nhwindow(win);
return TRUE;
}
void
confdir()
{
register int x = NODIAG(u.umonnum) ? 2*rn2(4) : rn2(8);
u.dx = xdir[x];
u.dy = ydir[x];
return;
}
int
isok(x,y)
register int x, y;
{
/* x corresponds to curx, so x==1 is the first column. Ach. %% */
return x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1;
}
static NEARDATA int last_multi;
/*
* convert a MAP window position into a movecmd
*/
const char *
click_to_cmd(x, y, mod)
int x, y, mod;
{
int dir;
static char cmd[4];
cmd[1]=0;
if (iflags.clicklook && mod == CLICK_2) {
clicklook_cc.x = x;
clicklook_cc.y = y;
cmd[0] = CMD_CLICKLOOK;
return cmd;
}
x -= u.ux;
y -= u.uy;
if (flags.travelcmd) {
if (abs(x) <= 1 && abs(y) <= 1 ) {
x = sgn(x), y = sgn(y);
} else {
u.tx = u.ux+x;
u.ty = u.uy+y;
cmd[0] = CMD_TRAVEL;
return cmd;
}
if(x == 0 && y == 0) {
/* here */
if(IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) {
cmd[0]=mod == CLICK_1 ? 'q' : M('d');
return cmd;
} else if(IS_THRONE(levl[u.ux][u.uy].typ)) {
cmd[0]=M('s');
return cmd;
} else if((u.ux == xupstair && u.uy == yupstair)
|| (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up)
|| (u.ux == xupladder && u.uy == yupladder)) {
return "<";
} else if((u.ux == xdnstair && u.uy == ydnstair)
|| (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)
|| (u.ux == xdnladder && u.uy == ydnladder)) {
return ">";
} else if(OBJ_AT(u.ux, u.uy)) {
cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ',';
return cmd;
} else {
return "."; /* just rest */
}
}
/* directional commands */
dir = xytod(x, y);
if (!m_at(u.ux+x, u.uy+y) && !test_move(u.ux, u.uy, x, y, TEST_MOVE)) {
cmd[1] = Cmd.dirchars[dir];
cmd[2] = '\0';
if (IS_DOOR(levl[u.ux+x][u.uy+y].typ)) {
/* slight assistance to the player: choose kick/open for them */
if (levl[u.ux+x][u.uy+y].doormask & D_LOCKED) {
cmd[0] = C('d');
return cmd;
}
if (levl[u.ux+x][u.uy+y].doormask & D_CLOSED) {
cmd[0] = 'o';
return cmd;
}
}
if (levl[u.ux+x][u.uy+y].typ <= SCORR) {
cmd[0] = 's';
cmd[1] = 0;
return cmd;
}
}
} else {
/* convert without using floating point, allowing sloppy clicking */
if(x > 2*abs(y))
x = 1, y = 0;
else if(y > 2*abs(x))
x = 0, y = 1;
else if(x < -2*abs(y))
x = -1, y = 0;
else if(y < -2*abs(x))
x = 0, y = -1;
else
x = sgn(x), y = sgn(y);
if(x == 0 && y == 0) /* map click on player to "rest" command */
return ".";
dir = xytod(x, y);
}
/* move, attack, etc. */
cmd[1] = 0;
if(mod == CLICK_1) {
cmd[0] = Cmd.dirchars[dir];
} else {
cmd[0] = (Cmd.num_pad ? M(Cmd.dirchars[dir]) :
(Cmd.dirchars[dir] - 'a' + 'A')); /* run command */
}
return cmd;
}
STATIC_OVL char *
parse()
{
#ifdef LINT /* static char in_line[COLNO]; */
char in_line[COLNO];
#else
static char in_line[COLNO];
#endif
register int foo;
boolean prezero = FALSE;
multi = 0;
context.move = 1;
flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
if (!Cmd.num_pad || (foo = readchar()) == 'n')
for (;;) {
foo = readchar();
if (foo >= '0' && foo <= '9') {
multi = 10 * multi + foo - '0';
if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT;
if (multi > 9) {
clear_nhwindow(WIN_MESSAGE);
Sprintf(in_line, "Count: %d", multi);
pline(in_line);
mark_synch();
}
last_multi = multi;
if (!multi && foo == '0') prezero = TRUE;
} else break; /* not a digit */
}
if (foo == '\033') { /* esc cancels count (TH) */
clear_nhwindow(WIN_MESSAGE);
multi = last_multi = 0;
# ifdef REDO
} else if (foo == DOAGAIN || in_doagain) {
multi = last_multi;
} else {
last_multi = multi;
savech(0); /* reset input queue */
savech((char)foo);
# endif
}
if (multi) {
multi--;
save_cm = in_line;
} else {
save_cm = (char *)0;
}
in_line[0] = foo;
in_line[1] = '\0';
if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' ||
foo == 'F' || (Cmd.num_pad && (foo == '5' || foo == '-'))) {
foo = readchar();
#ifdef REDO
savech((char)foo);
#endif
in_line[1] = foo;
in_line[2] = 0;
}
clear_nhwindow(WIN_MESSAGE);
if (prezero) in_line[0] = '\033';
return(in_line);
}
#if defined(UNIX) || defined(SAFERHANGUP)
static
void
end_of_input()
{
#ifndef NOSAVEONHANGUP
# ifndef SAFERHANGUP
if (!program_state.done_hup++)
#endif
if (program_state.something_worth_saving) (void) dosave0();
#endif
exit_nhwindows((char *)0);
clearlocks();
terminate(EXIT_SUCCESS);
}
#endif
char
readchar()
{
register int sym;
int x = u.ux, y = u.uy, mod = 0;
if ( *readchar_queue )
sym = *readchar_queue++;
else
#ifdef REDO
sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod);
#else
sym = Getchar();
#endif
#ifdef UNIX
# ifdef NR_OF_EOFS
if (sym == EOF) {
register int cnt = NR_OF_EOFS;
/*
* Some SYSV systems seem to return EOFs for various reasons
* (?like when one hits break or for interrupted systemcalls?),
* and we must see several before we quit.
*/
do {
clearerr(stdin); /* omit if clearerr is undefined */
sym = Getchar();
} while (--cnt && sym == EOF);
}
# endif /* NR_OF_EOFS */
if (sym == EOF) {
# ifndef SAFERHANGUP
end_of_input();
# else
program_state.done_hup++;
sym = '\033';
# endif
}
#endif /* UNIX */
if(sym == 0) {
/* click event */
readchar_queue = click_to_cmd(x, y, mod);
sym = *readchar_queue++;
}
return((char) sym);
}
STATIC_PTR int
dotravel()
{
/* Keyboard travel command */
static char cmd[2];
coord cc;
if (!flags.travelcmd) return 0;
cmd[1]=0;
cc.x = iflags.travelcc.x;
cc.y = iflags.travelcc.y;
if (cc.x == -1 && cc.y == -1) {
/* No cached destination, start attempt from current position */
cc.x = u.ux;
cc.y = u.uy;
}
pline("Where do you want to travel to?");
if (getpos(&cc, TRUE, "the desired destination") < 0) {
/* user pressed ESC */
return 0;
}
iflags.travelcc.x = u.tx = cc.x;
iflags.travelcc.y = u.ty = cc.y;
cmd[0] = CMD_TRAVEL;
readchar_queue = cmd;
return 0;
}
#ifdef PORT_DEBUG
# ifdef WIN32CON
extern void NDECL(win32con_debug_keystrokes);
extern void NDECL(win32con_handler_info);
# endif
int
wiz_port_debug()
{
int n, k;
winid win;
anything any;
int item = 'a';
int num_menu_selections;
struct menu_selection_struct {
char *menutext;
void NDECL((*fn));
} menu_selections[] = {
#ifdef WIN32CON
{"test win32 keystrokes", win32con_debug_keystrokes},
{"show keystroke handler information", win32con_handler_info},
#endif
{(char *)0, (void NDECL((*)))0} /* array terminator */
};
num_menu_selections = SIZE(menu_selections) - 1;
if (num_menu_selections > 0) {
menu_item *pick_list;
win = create_nhwindow(NHW_MENU);
start_menu(win);
for (k=0; k < num_menu_selections; ++k) {
any.a_int = k+1;
add_menu(win, NO_GLYPH, &any, item++, 0, ATR_NONE,
menu_selections[k].menutext, MENU_UNSELECTED);
}
end_menu(win, "Which port debugging feature?");
n = select_menu(win, PICK_ONE, &pick_list);
destroy_nhwindow(win);
if (n > 0) {
n = pick_list[0].item.a_int - 1;
free((genericptr_t) pick_list);
/* execute the function */
(*menu_selections[n].fn)();
}
} else
pline("No port-specific debug capability defined.");
return 0;
}
# endif /*PORT_DEBUG*/
/*
* Parameter validator for generic yes/no function to prevent
* the core from sending too long a prompt string to the
* window port causing a buffer overflow there.
*/
char
yn_function(query,resp, def)
const char *query,*resp;
char def;
{
char qbuf[QBUFSZ];
unsigned truncspot, reduction = sizeof(" [N] ?") + 1;
if (resp) reduction += strlen(resp) + sizeof(" () ");
if (strlen(query) < (QBUFSZ - reduction))
return (*windowprocs.win_yn_function)(query, resp, def);
paniclog("Query truncated: ", query);
reduction += sizeof("...");
truncspot = QBUFSZ - reduction;
(void) strncpy(qbuf, query, (int)truncspot);
qbuf[truncspot] = '\0';
Strcat(qbuf,"...");
return (*windowprocs.win_yn_function)(qbuf, resp, def);
}
/*cmd.c*/