2089 lines
54 KiB
C
2089 lines
54 KiB
C
/* SCCS Id: @(#)cmd.c 3.3 2000/05/05 */
|
|
/* 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 */
|
|
|
|
/*
|
|
* 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
|
|
|
|
#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 void 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(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 */
|
|
|
|
#ifdef OVL1
|
|
static int NDECL((*timed_occ_fn));
|
|
#endif /* OVL1 */
|
|
|
|
STATIC_PTR int NDECL(doprev_message);
|
|
STATIC_PTR int NDECL(timed_occupation);
|
|
STATIC_PTR int NDECL(doextcmd);
|
|
STATIC_PTR int NDECL(domonability);
|
|
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_level_tele);
|
|
STATIC_PTR int NDECL(wiz_show_seenv);
|
|
STATIC_PTR int NDECL(wiz_show_vision);
|
|
STATIC_PTR int NDECL(wiz_mon_polycontrol);
|
|
STATIC_PTR int NDECL(wiz_show_wmodes);
|
|
#if defined(__BORLANDC__) && !defined(_WIN32)
|
|
extern void FDECL(show_borlandc_stats, (winid));
|
|
#endif
|
|
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);
|
|
# endif
|
|
STATIC_PTR int NDECL(enter_explore_mode);
|
|
STATIC_PTR int NDECL(doattributes);
|
|
STATIC_PTR int NDECL(doconduct); /**/
|
|
STATIC_PTR void NDECL(minimal_enlightenment);
|
|
|
|
#ifdef OVLB
|
|
STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *));
|
|
#ifdef UNIX
|
|
static void NDECL(end_of_input);
|
|
#endif
|
|
#endif /* OVLB */
|
|
|
|
static const char* readchar_queue="";
|
|
|
|
STATIC_DCL char *NDECL(parse);
|
|
|
|
#ifdef OVL1
|
|
|
|
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 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 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 */
|
|
|
|
#endif /* OVL1 */
|
|
#ifdef OVLB
|
|
|
|
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, " %-14s - %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
|
|
|
|
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 (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 WIZARD
|
|
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 '^W'.");
|
|
return 0;
|
|
}
|
|
|
|
STATIC_PTR int
|
|
wiz_identify()
|
|
{
|
|
if (wizard) identify_pack(0);
|
|
else pline("Unavailable command '^I'.");
|
|
return 0;
|
|
}
|
|
|
|
/* reveal the level map and any traps on it */
|
|
STATIC_PTR int
|
|
wiz_map()
|
|
{
|
|
if (wizard) {
|
|
struct trap *t;
|
|
|
|
for (t = ftrap; t != 0; t = t->ntrap) {
|
|
t->tseen = 1;
|
|
map_trap(t, TRUE);
|
|
}
|
|
do_mapping();
|
|
} else
|
|
pline("Unavailable command '^F'.");
|
|
return 0;
|
|
}
|
|
|
|
STATIC_PTR int
|
|
wiz_genesis()
|
|
{
|
|
if (wizard) (void) create_particular();
|
|
else pline("Unavailable command '^G'.");
|
|
return 0;
|
|
}
|
|
|
|
STATIC_PTR int
|
|
wiz_where()
|
|
{
|
|
if (wizard) print_dungeon();
|
|
else pline("Unavailable command '^O'.");
|
|
return 0;
|
|
}
|
|
|
|
STATIC_PTR int
|
|
wiz_detect()
|
|
{
|
|
if(wizard) (void) findit();
|
|
else pline("Unavailable command '^E'.");
|
|
return 0;
|
|
}
|
|
|
|
STATIC_PTR int
|
|
wiz_level_tele()
|
|
{
|
|
if (wizard) level_tele();
|
|
else pline("Unavailable command '^V'.");
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
STATIC_PTR int
|
|
wiz_show_wmodes()
|
|
{
|
|
winid win;
|
|
int x,y;
|
|
char row[COLNO+1];
|
|
struct rm *lev;
|
|
|
|
win = create_nhwindow(NHW_TEXT);
|
|
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';
|
|
putstr(win, 0, row);
|
|
}
|
|
display_nhwindow(win, TRUE);
|
|
destroy_nhwindow(win);
|
|
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) \
|
|
enlght_line(prefix, final ? past : present, suffix)
|
|
#define you_are(attr) enl_msg(You_,are,were,attr)
|
|
#define you_have(attr) enl_msg(You_,have,had,attr)
|
|
#define you_can(attr) enl_msg(You_,can,could,attr)
|
|
#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)
|
|
const char *start, *middle, *end;
|
|
{
|
|
char buf[BUFSZ];
|
|
|
|
Sprintf(buf, "%s%s%s.", start, middle, end);
|
|
putstr(en_win, 0, buf);
|
|
}
|
|
|
|
void
|
|
enlightenment(final)
|
|
int final; /* 0 => still in progress; 1 => over, survived; 2 => dead */
|
|
{
|
|
int ltmp;
|
|
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 *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");
|
|
if (Cold_resistance) you_are("cold resistant");
|
|
if (Sleep_resistance) you_are("sleep resistant");
|
|
if (Disint_resistance) you_are("disintegration-resistant");
|
|
if (Shock_resistance) you_are("shock resistant");
|
|
if (Poison_resistance) you_are("poison resistant");
|
|
if (Drain_resistance) you_are("level-drain resistant");
|
|
if (Sick_resistance) you_are("immune to sickness");
|
|
if (Antimagic) you_are("magic-protected");
|
|
if (Acid_resistance) you_are("acid resistant");
|
|
if (Stone_resistance)
|
|
you_are("petrification resistant");
|
|
if (Invulnerable) you_are("invulnerable");
|
|
if (u.uedibility) you_can("recognize detrimental food");
|
|
|
|
/*** Troubles ***/
|
|
if (Halluc_resistance)
|
|
enl_msg("You resist", "", "ed", " hallucinations");
|
|
if (final) {
|
|
if (Hallucination) you_are("hallucinating");
|
|
if (Stunned) you_are("stunned");
|
|
if (Confusion) you_are("confused");
|
|
if (Blinded) you_are("blinded");
|
|
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", "");
|
|
if (Wounded_legs
|
|
#ifdef STEED
|
|
&& !u.usteed
|
|
#endif
|
|
) {
|
|
Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
|
|
you_have(buf);
|
|
}
|
|
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");
|
|
if (Blind_telepat) you_are("telepathic");
|
|
if (Warning) you_are("warned");
|
|
if (Warn_of_mon && flags.warntype) {
|
|
Sprintf(buf, "aware of the presence of %s",
|
|
(flags.warntype & M2_ORC) ? "orcs" :
|
|
(flags.warntype & M2_DEMON) ? "demons" :
|
|
something);
|
|
you_are(buf);
|
|
}
|
|
if (Undead_warning) you_are("warned of undead");
|
|
if (Searching) you_have("automatic searching");
|
|
if (Clairvoyant) you_are("clairvoyant");
|
|
if (Infravision) you_have("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) you_are("adorned");
|
|
if (Invisible) you_are("invisible");
|
|
else if (Invis) you_are("invisible to others");
|
|
/* 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");
|
|
if (Stealth) you_are("stealthy");
|
|
if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters");
|
|
if (Conflict) enl_msg("You cause", "", "d", " conflict");
|
|
|
|
/*** Transportation ***/
|
|
if (Jumping) you_can("jump");
|
|
if (Teleportation) you_can("teleport");
|
|
if (Teleport_control) you_have("teleport control");
|
|
if (Lev_at_will) you_are("levitating, at will");
|
|
else if (Levitation) you_are("levitating"); /* without control */
|
|
else if (Flying) you_can("fly");
|
|
if (Wwalking) you_can("walk on water");
|
|
if (Swimming) you_can("swim");
|
|
if (Breathless) you_can("survive without air");
|
|
else if (Amphibious) you_can("breathe water");
|
|
if (Passes_walls) you_can("walk through walls");
|
|
#ifdef STEED
|
|
if (u.usteed) {
|
|
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 (Slow_digestion) you_have("slower digestion");
|
|
if (Regeneration) enl_msg("You regenerate", "", "d", "");
|
|
if (u.uspellprot || Protection) you_are("protected");
|
|
if (Protection_from_shape_changers)
|
|
you_are("protected from shape changers");
|
|
if (Polymorph) you_are("polymorphing");
|
|
if (Polymorph_control) you_have("polymorph control");
|
|
if (u.ulycn >= LOW_PM) {
|
|
Strcpy(buf, an(mons[u.ulycn].mname));
|
|
you_are(buf);
|
|
}
|
|
if (Upolyd) {
|
|
if (u.ulycn >= LOW_PM) 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");
|
|
if (Reflecting) you_have("reflection");
|
|
if (Free_action) you_have("free action");
|
|
if (Fixed_abil) you_have("fixed abilities");
|
|
if (Lifesaved)
|
|
enl_msg("Your life ", "will be", "would have been", " saved");
|
|
if (u.twoweap) you_are("wielding two weapons at once");
|
|
|
|
/*** 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(FALSE);
|
|
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.
|
|
*/
|
|
STATIC_OVL void
|
|
minimal_enlightenment()
|
|
{
|
|
winid tmpwin;
|
|
menu_item *selected;
|
|
anything any;
|
|
char buf[BUFSZ], buf2[BUFSZ];
|
|
static char fmtstr[] = "%-15s: %-12s";
|
|
|
|
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, ATR_BOLD, "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, ATR_BOLD, "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);
|
|
}
|
|
Sprintf(buf, fmtstr, "gender", genders[poly_gender()].adj);
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
|
|
|
|
if (Upolyd) {
|
|
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, ATR_BOLD, "Deities", FALSE);
|
|
Sprintf(buf2, "%-17s%s", 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 deity", buf2);
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
|
|
|
|
Sprintf(buf2, "%-17s%s", 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 deity", buf2);
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
|
|
|
|
Sprintf(buf2, "%-17s%s", 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 deity", buf2);
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
|
|
|
|
end_menu(tmpwin, "Base Attributes");
|
|
(void) select_menu(tmpwin, PICK_NONE, &selected);
|
|
destroy_nhwindow(tmpwin);
|
|
}
|
|
|
|
STATIC_PTR int
|
|
doattributes()
|
|
{
|
|
minimal_enlightenment();
|
|
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);
|
|
}
|
|
|
|
#endif /* OVLB */
|
|
#ifdef OVL1
|
|
|
|
#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 */
|
|
#ifdef WIZARD
|
|
{C('o'), TRUE, wiz_where},
|
|
#endif
|
|
{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},
|
|
{"chat", "talk to someone", dotalk, TRUE}, /* converse? */
|
|
{"conduct", "list which challenges you have adhered to", doconduct, TRUE},
|
|
{"dip", "dip an object into something", dodip, FALSE},
|
|
{"enhance", "advance or check weapons 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},
|
|
{"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", dorub, FALSE},
|
|
{"sit", "sit down", dosit, 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},
|
|
{(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},
|
|
#endif
|
|
{(char *)0, (char *)0, donull, TRUE} /* sentinel */
|
|
};
|
|
|
|
#if defined(WIZARD)
|
|
static const struct ext_func_tab debug_extcmdlist[] = {
|
|
{"light sources", "show mobile light sources", wiz_light_sources, TRUE},
|
|
{"monpoly_control", "control monster polymorphs", wiz_mon_polycontrol, TRUE},
|
|
{"seenv", "show seen vectors", wiz_show_seenv, TRUE},
|
|
{"stats", "show memory statistics", wiz_show_stats, TRUE},
|
|
{"timeout", "look at timeout queue", wiz_timeout_queue, TRUE},
|
|
{"vision", "show vision array", wiz_show_vision, TRUE},
|
|
#ifdef DEBUG
|
|
{"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE},
|
|
#endif
|
|
{"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 */
|
|
}
|
|
}
|
|
|
|
|
|
static const char *template = "%-18s %4ld %6ld";
|
|
static const char *count_str = " count bytes";
|
|
static const char *separator = "------------------ ----- ------";
|
|
|
|
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 += sizeof(struct obj) + obj->oxlth + obj->onamelth;
|
|
}
|
|
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 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 += sizeof(struct monst) + mon->mxlth + mon->mnamelth;
|
|
}
|
|
*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();
|
|
}
|
|
|
|
#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);
|
|
|
|
if (firsttime) {
|
|
flags.nopick = 0;
|
|
cmd = parse();
|
|
}
|
|
if (*cmd == '\033') {
|
|
flags.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();
|
|
flags.move = FALSE;
|
|
return; /* probably we just had an interrupt */
|
|
}
|
|
|
|
/* handle most movement commands */
|
|
do_walk = do_rush = prefix_seen = FALSE;
|
|
flags.travel = 0;
|
|
switch (*cmd) {
|
|
case 'g': if (movecmd(cmd[1])) {
|
|
flags.run = 2;
|
|
do_rush = TRUE;
|
|
} else
|
|
prefix_seen = TRUE;
|
|
break;
|
|
case '5': if (!iflags.num_pad) break; /* else FALLTHRU */
|
|
case 'G': if (movecmd(lowc(cmd[1]))) {
|
|
flags.run = 3;
|
|
do_rush = TRUE;
|
|
} else
|
|
prefix_seen = TRUE;
|
|
break;
|
|
case '-': if (!iflags.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])) {
|
|
flags.forcefight = 1;
|
|
do_walk = TRUE;
|
|
} else
|
|
prefix_seen = TRUE;
|
|
break;
|
|
case 'm': if (movecmd(cmd[1]) || u.dz) {
|
|
flags.run = 0;
|
|
flags.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]))) {
|
|
flags.run = 1;
|
|
flags.nopick = 1;
|
|
do_rush = TRUE;
|
|
} else
|
|
prefix_seen = TRUE;
|
|
break;
|
|
case '0': if (!iflags.num_pad) break;
|
|
(void)ddoinv(); /* a convenience borrowed from the PC */
|
|
flags.move = FALSE;
|
|
multi = 0;
|
|
return;
|
|
case CMD_TRAVEL:
|
|
flags.travel = 1;
|
|
flags.run = 8;
|
|
flags.nopick = 1;
|
|
do_rush = TRUE;
|
|
break;
|
|
default: if (movecmd(*cmd)) { /* ordinary movement */
|
|
do_walk = TRUE;
|
|
} else if (movecmd(iflags.num_pad ?
|
|
unmeta(*cmd) : lowc(*cmd))) {
|
|
flags.run = 1;
|
|
do_rush = TRUE;
|
|
} else if (movecmd(unctrl(*cmd))) {
|
|
flags.run = 3;
|
|
do_rush = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
if (do_walk) {
|
|
if (multi) flags.mv = TRUE;
|
|
domove();
|
|
flags.forcefight = 0;
|
|
return;
|
|
} else if (do_rush) {
|
|
if (firsttime) {
|
|
if (!multi) multi = max(COLNO,ROWNO);
|
|
u.last_str_turn = 0;
|
|
}
|
|
flags.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));
|
|
|
|
for (tlist = cmdlist; tlist->f_char; tlist++) {
|
|
if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue;
|
|
|
|
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) {
|
|
flags.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 *cp = expcmd;
|
|
|
|
while (*cmd && (int)(cp - expcmd) < (int)(sizeof expcmd - 3)) {
|
|
if (*cmd >= 040 && *cmd < 0177) {
|
|
*cp++ = *cmd++;
|
|
} else if (*cmd & 0200) {
|
|
*cp++ = 'M';
|
|
*cp++ = '-';
|
|
*cp++ = *cmd++ &= ~0200;
|
|
} else {
|
|
*cp++ = '^';
|
|
*cp++ = *cmd++ ^ 0100;
|
|
}
|
|
}
|
|
*cp = '\0';
|
|
Norep("Unknown command '%s'.", expcmd);
|
|
}
|
|
/* didn't move */
|
|
flags.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;
|
|
register const char *sdp;
|
|
if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */
|
|
|
|
u.dz = 0;
|
|
if(!(dp = index(sdp, sym))) return 0;
|
|
u.dx = xdir[dp-sdp];
|
|
u.dy = ydir[dp-sdp];
|
|
u.dz = zdir[dp-sdp];
|
|
if (u.dx && u.dy && u.umonnum == PM_GRID_BUG) {
|
|
u.dx = u.dy = 0;
|
|
return 0;
|
|
}
|
|
return !u.dz;
|
|
}
|
|
|
|
int
|
|
getdir(s)
|
|
const char *s;
|
|
{
|
|
char dirsym;
|
|
|
|
#ifdef REDO
|
|
if(in_doagain || *readchar_queue)
|
|
dirsym = readchar();
|
|
else
|
|
#endif
|
|
dirsym = yn_function (s ? s : "In what direction?",
|
|
(char *)0, '\0');
|
|
#ifdef REDO
|
|
savech(dirsym);
|
|
#endif
|
|
if(dirsym == '.' || dirsym == 's')
|
|
u.dx = u.dy = u.dz = 0;
|
|
else if(!movecmd(dirsym) && !u.dz) {
|
|
if(!index(quitchars, dirsym))
|
|
pline("What a strange direction!");
|
|
return 0;
|
|
}
|
|
if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir();
|
|
return 1;
|
|
}
|
|
|
|
#endif /* OVL1 */
|
|
#ifdef OVLB
|
|
|
|
void
|
|
confdir()
|
|
{
|
|
register int x = (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) : rn2(8);
|
|
u.dx = xdir[x];
|
|
u.dy = ydir[x];
|
|
return;
|
|
}
|
|
|
|
#endif /* OVLB */
|
|
#ifdef OVL0
|
|
|
|
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;
|
|
|
|
x -= u.ux;
|
|
y -= u.uy;
|
|
|
|
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, 1)) {
|
|
cmd[1] = (iflags.num_pad ? ndir[dir] : sdir[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;
|
|
}
|
|
}
|
|
|
|
/* move, attack, etc. */
|
|
cmd[1] = 0;
|
|
if(mod == CLICK_1) {
|
|
cmd[0] = (iflags.num_pad ? ndir[dir] : sdir[dir]);
|
|
} else {
|
|
cmd[0] = (iflags.num_pad ? M(ndir[dir]) :
|
|
(sdir[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;
|
|
flags.move = 1;
|
|
flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
|
|
|
|
if (!iflags.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' || (iflags.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);
|
|
}
|
|
|
|
#endif /* OVL0 */
|
|
#ifdef OVLB
|
|
|
|
#ifdef UNIX
|
|
static
|
|
void
|
|
end_of_input()
|
|
{
|
|
exit_nhwindows("End of input?");
|
|
#ifndef NOSAVEONHANGUP
|
|
if (!program_state.done_hup++)
|
|
(void) dosave0();
|
|
#endif
|
|
clearlocks();
|
|
terminate(EXIT_SUCCESS);
|
|
}
|
|
#endif
|
|
|
|
#endif /* OVLB */
|
|
#ifdef OVL0
|
|
|
|
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)
|
|
end_of_input();
|
|
#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;
|
|
cmd[1]=0;
|
|
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;
|
|
}
|
|
u.tx = cc.x;
|
|
u.ty = cc.y;
|
|
cmd[0] = CMD_TRAVEL;
|
|
readchar_queue = cmd;
|
|
return 0;
|
|
}
|
|
|
|
#endif /* OVL0 */
|
|
|
|
/*cmd.c*/
|