Merge remote-tracking branch 'origin/NetHack-3.6.0'

This commit is contained in:
keni
2016-10-09 15:56:50 -04:00
28 changed files with 2228 additions and 508 deletions

View File

@@ -34,9 +34,6 @@ boolean resuming;
monstr_init(); /* monster strengths */
objects_init();
if (wizard)
add_debug_extended_commands();
/* if a save file created in normal mode is now being restored in
explore mode, treat it as normal restore followed by 'X' command
to use up the save file and require confirmation for explore mode */

1009
src/cmd.c

File diff suppressed because it is too large Load Diff

View File

@@ -59,45 +59,90 @@ const char *goal;
putstr(tmpwin, 0, sbuf);
putstr(tmpwin, 0, "Use 'H', 'J', 'K', 'L' to move the cursor 8 units at a time.");
putstr(tmpwin, 0, "Or enter a background symbol (ex. '<').");
putstr(tmpwin, 0, "Use '@' to move the cursor on yourself.");
if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)
putstr(tmpwin, 0, "Use 'm' or 'M' to move the cursor to next monster.");
if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0)
putstr(tmpwin, 0, "Use 'o' or 'O' to move the cursor to next object.");
Sprintf(sbuf, "Use '%s' to move the cursor on yourself.",
visctrl(Cmd.spkeys[NHKF_GETPOS_SELF]));
putstr(tmpwin, 0, sbuf);
if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
Sprintf(sbuf, "Use '%s' or '%s' to move the cursor to next monster.",
visctrl(Cmd.spkeys[NHKF_GETPOS_MON_NEXT]),
visctrl(Cmd.spkeys[NHKF_GETPOS_MON_PREV]));
putstr(tmpwin, 0, sbuf);
}
if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
Sprintf(sbuf, "Use '%s' or '%s' to move the cursor to next object.",
visctrl(Cmd.spkeys[NHKF_GETPOS_OBJ_NEXT]),
visctrl(Cmd.spkeys[NHKF_GETPOS_OBJ_PREV]));
putstr(tmpwin, 0, sbuf);
}
if (!iflags.terrainmode || (iflags.terrainmode & TER_MAP) != 0) {
/* both of these are primarily useful when choosing a travel
destination for the '_' command */
putstr(tmpwin, 0,
"Use 'd' or 'D' to move the cursor to next door or doorway.");
putstr(tmpwin, 0,
"Use 'x' or 'X' to move the cursor to unexplored location.");
Sprintf(sbuf,
"Use '%s' or '%s' to move the cursor to next door or doorway.",
visctrl(Cmd.spkeys[NHKF_GETPOS_DOOR_NEXT]),
visctrl(Cmd.spkeys[NHKF_GETPOS_DOOR_PREV]));
putstr(tmpwin, 0, sbuf);
Sprintf(sbuf,
"Use '%s' or '%s' to move the cursor to unexplored location.",
visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_NEXT]),
visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_PREV]));
putstr(tmpwin, 0, sbuf);
}
Sprintf(sbuf, "Use '%s' for a menu of interesting targets in view.",
visctrl(Cmd.spkeys[NHKF_GETPOS_MENU_FOV]));
putstr(tmpwin, 0, sbuf);
Sprintf(sbuf, "Use '%s' for a menu of all interesting targets.",
visctrl(Cmd.spkeys[NHKF_GETPOS_MENU]));
putstr(tmpwin, 0, sbuf);
if (!iflags.terrainmode) {
if (getpos_hilitefunc)
putstr(tmpwin, 0, "Use '$' to display valid locations.");
putstr(tmpwin, 0, "Use '#' to toggle automatic description.");
if (iflags.cmdassist) /* assisting the '/' command, I suppose... */
putstr(tmpwin, 0,
(iflags.getpos_coords == GPCOORDS_NONE)
? "(Set 'whatis_coord' option to include coordinates with '#' text.)"
: "(Reset 'whatis_coord' option to omit coordinates from '#' text.)");
char kbuf[BUFSZ];
if (getpos_hilitefunc) {
Sprintf(sbuf, "Use '%s' to display valid locations.",
visctrl(Cmd.spkeys[NHKF_GETPOS_SHOWVALID]));
putstr(tmpwin, 0, sbuf);
}
Sprintf(sbuf, "Use '%s' to toggle automatic description.",
visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
putstr(tmpwin, 0, sbuf);
if (iflags.cmdassist) { /* assisting the '/' command, I suppose... */
Sprintf(sbuf,
(iflags.getpos_coords == GPCOORDS_NONE)
? "(Set 'whatis_coord' option to include coordinates with '%s' text.)"
: "(Reset 'whatis_coord' option to omit coordinates from '%s' text.)",
visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
}
/* disgusting hack; the alternate selection characters work for any
getpos call, but only matter for dowhatis (and doquickwhatis) */
doing_what_is = (goal == what_is_an_unknown_object);
Sprintf(sbuf, "Type a '.'%s when you are at the right place.",
doing_what_is ? " or ',' or ';' or ':'" : "");
doing_what_is = (goal == what_is_an_unknown_object);
if (doing_what_is) {
Sprintf(kbuf, "'%s' or '%s' or '%s' or '%s'",
visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]),
visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]),
visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
} else {
Sprintf(kbuf, "'%s'", visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
}
Sprintf(sbuf, "Type a %s when you are at the right place.", kbuf);
putstr(tmpwin, 0, sbuf);
if (doing_what_is) {
putstr(tmpwin, 0,
" ':' describe current spot, show 'more info', move to another spot.");
Sprintf(sbuf,
" '.' describe current spot,%s move to another spot;",
" '%s' describe current spot, show 'more info', move to another spot.",
visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
putstr(tmpwin, 0, sbuf);
Sprintf(sbuf,
" '%s' describe current spot,%s move to another spot;",
visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
flags.help ? " prompt if 'more info'," : "");
putstr(tmpwin, 0, sbuf);
putstr(tmpwin, 0,
" ',' describe current spot, move to another spot;");
putstr(tmpwin, 0,
" ';' describe current spot, stop looking at things;");
Sprintf(sbuf,
" '%s' describe current spot, move to another spot;",
visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]));
putstr(tmpwin, 0, sbuf);
Sprintf(sbuf,
" '%s' describe current spot, stop looking at things;",
visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]));
putstr(tmpwin, 0, sbuf);
}
}
if (!force)
@@ -135,7 +180,10 @@ enum gloctypes {
GLOC_DOOR,
GLOC_EXPLORE,
NUM_GLOCS
NUM_GLOCS,
GLOC_INTERESTING,
GLOC_INTERESTING_FOV
};
@@ -183,6 +231,26 @@ int x,y, gloc;
|| IS_UNEXPLORED_LOC(x - 1, y)
|| IS_UNEXPLORED_LOC(x, y + 1)
|| IS_UNEXPLORED_LOC(x, y - 1)));
case GLOC_INTERESTING_FOV:
if (!cansee(x,y))
return FALSE;
case GLOC_INTERESTING:
return gather_locs_interesting(x,y, GLOC_DOOR)
|| !(glyph_is_cmap(glyph)
&& (is_cmap_wall(glyph_to_cmap(glyph))
|| glyph_to_cmap(glyph) == S_tree
|| glyph_to_cmap(glyph) == S_bars
|| glyph_to_cmap(glyph) == S_ice
|| glyph_to_cmap(glyph) == S_air
|| glyph_to_cmap(glyph) == S_cloud
|| glyph_to_cmap(glyph) == S_lava
|| glyph_to_cmap(glyph) == S_water
|| glyph_to_cmap(glyph) == S_pool
|| glyph_to_cmap(glyph) == S_ndoor
|| glyph_to_cmap(glyph) == S_room
|| glyph_to_cmap(glyph) == S_darkroom
|| glyph_to_cmap(glyph) == S_corr
|| glyph_to_cmap(glyph) == S_litcorr));
}
/*NOTREACHED*/
return FALSE;
@@ -331,15 +399,88 @@ int cx, cy;
}
}
boolean
getpos_menu(ccp, fovonly)
coord *ccp;
boolean fovonly;
{
coord *garr = DUMMY;
int gcount = 0;
winid tmpwin;
anything any;
int i, pick_cnt;
menu_item *picks = (menu_item *) 0;
char tmpbuf[BUFSZ];
gather_locs(&garr, &gcount,
fovonly ? GLOC_INTERESTING_FOV : GLOC_INTERESTING);
if (gcount < 2) { /* gcount always includes the hero */
You("cannot %s anything interesting.", fovonly ? "see" : "detect");
return FALSE;
}
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any = zeroany;
for (i = 0; i < gcount; i++) {
char fullbuf[BUFSZ];
coord tmpcc;
const char *firstmatch = "unknown";
int sym = 0;
any.a_int = i + 1;
tmpcc.x = garr[i].x;
tmpcc.y = garr[i].y;
if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, &firstmatch)) {
(void) coord_desc(garr[i].x, garr[i].y, tmpbuf, iflags.getpos_coords);
Sprintf(fullbuf, "%s%s%s", firstmatch, (*tmpbuf ? " " : ""), tmpbuf);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, fullbuf,
MENU_UNSELECTED);
}
}
Sprintf(tmpbuf, "Pick a target%s%s",
fovonly ? " in view" : "",
iflags.getloc_travelmode ? " for travel" : "");
end_menu(tmpwin, tmpbuf);
pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
destroy_nhwindow(tmpwin);
if (pick_cnt > 0) {
ccp->x = garr[picks->item.a_int - 1].x;
ccp->y = garr[picks->item.a_int - 1].y;
free((genericptr_t) picks);
}
free((genericptr_t) garr);
return (pick_cnt > 0);
}
int
getpos(ccp, force, goal)
coord *ccp;
boolean force;
const char *goal;
{
static const char pick_chars[] = ".,;:",
mMoOdDxX[] = "mMoOdDxX";
const char *cp;
struct {
int nhkf, ret;
} const pick_chars_def[] = {
{ NHKF_GETPOS_PICK, LOOK_TRADITIONAL },
{ NHKF_GETPOS_PICK_Q, LOOK_QUICK },
{ NHKF_GETPOS_PICK_O, LOOK_ONCE },
{ NHKF_GETPOS_PICK_V, LOOK_VERBOSE }
};
const int mMoOdDxX_def[] = {
NHKF_GETPOS_MON_NEXT,
NHKF_GETPOS_MON_PREV,
NHKF_GETPOS_OBJ_NEXT,
NHKF_GETPOS_OBJ_PREV,
NHKF_GETPOS_DOOR_NEXT,
NHKF_GETPOS_DOOR_PREV,
NHKF_GETPOS_UNEX_NEXT,
NHKF_GETPOS_UNEX_PREV
};
char pick_chars[6];
char mMoOdDxX[9];
int result = 0;
int cx, cy, i, c;
int sidx, tx, ty;
@@ -350,10 +491,19 @@ const char *goal;
int gcount[NUM_GLOCS] = DUMMY;
int gidx[NUM_GLOCS] = DUMMY;
for (i = 0; i < SIZE(pick_chars_def); i++)
pick_chars[i] = Cmd.spkeys[pick_chars_def[i].nhkf];
pick_chars[SIZE(pick_chars_def)] = '\0';
for (i = 0; i < SIZE(mMoOdDxX_def); i++)
mMoOdDxX[i] = Cmd.spkeys[mMoOdDxX_def[i]];
mMoOdDxX[SIZE(mMoOdDxX_def)] = '\0';
if (!goal)
goal = "desired location";
if (flags.verbose) {
pline("(For instructions type a '?')");
pline("(For instructions type a '%s')",
visctrl(Cmd.spkeys[NHKF_GETPOS_HELP]));
msg_given = TRUE;
}
cx = ccp->x;
@@ -388,7 +538,7 @@ const char *goal;
if (iflags.autodescribe)
msg_given = FALSE;
if (c == '\033') {
if (c == Cmd.spkeys[NHKF_ESC]) {
cx = cy = -10;
msg_given = TRUE; /* force clear */
result = -1;
@@ -404,7 +554,7 @@ const char *goal;
}
if ((cp = index(pick_chars, c)) != 0) {
/* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
result = (int) (cp - pick_chars);
result = pick_chars_def[(int) (cp - pick_chars)].ret;
break;
}
for (i = 0; i < 8; i++) {
@@ -442,26 +592,23 @@ const char *goal;
goto nxtc;
}
if (c == '?' || redraw_cmd(c)) {
if (c == '?')
if (c == Cmd.spkeys[NHKF_GETPOS_HELP] || redraw_cmd(c)) {
if (c == Cmd.spkeys[NHKF_GETPOS_HELP])
getpos_help(force, goal);
else /* ^R */
docrt(); /* redraw */
/* update message window to reflect that we're still targetting */
show_goal_msg = TRUE;
msg_given = TRUE;
} else if (c == '$' && getpos_hilitefunc) {
} else if (c == Cmd.spkeys[NHKF_GETPOS_SHOWVALID]
&& getpos_hilitefunc) {
if (!hilite_state) {
(*getpos_hilitefunc)(0);
(*getpos_hilitefunc)(1);
hilite_state = TRUE;
}
goto nxtc;
} else if (c == '#') {
/* unfortunately, using '#' as a command means we can't move
cursor to sinks, iron bars, and poison clouds; perhaps
when autodescribe is already on, next '#' should try to
move to '#' rather than to toggle off? (or ask; ick...) */
} else if (c == Cmd.spkeys[NHKF_GETPOS_AUTODESC]) {
iflags.autodescribe = !iflags.autodescribe;
pline("Automatic description %sis %s.",
flags.verbose ? "of features under cursor " : "",
@@ -470,7 +617,15 @@ const char *goal;
show_goal_msg = TRUE;
msg_given = TRUE;
goto nxtc;
} else if (c == '@') { /* return to hero's spot */
} else if (c == Cmd.spkeys[NHKF_GETPOS_MENU]
|| c == Cmd.spkeys[NHKF_GETPOS_MENU_FOV]) {
coord tmpcrd;
if (getpos_menu(&tmpcrd, (c == Cmd.spkeys[NHKF_GETPOS_MENU_FOV]))) {
cx = tmpcrd.x;
cy = tmpcrd.y;
}
goto nxtc;
} else if (c == Cmd.spkeys[NHKF_GETPOS_SELF]) {
/* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
to achieve that except by manually cycling through all spots */
for (i = 0; i < NUM_GLOCS; i++)
@@ -568,9 +723,10 @@ const char *goal;
if (!force)
Strcpy(note, "aborted");
else
Sprintf(note, "use '%c', '%c', '%c', '%c' or '.'", /* hjkl */
Sprintf(note, "use '%c', '%c', '%c', '%c' or '%s'", /* hjkl */
Cmd.move_W, Cmd.move_S, Cmd.move_N,
Cmd.move_E);
Cmd.move_E,
visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
pline("Unknown direction: '%s' (%s).", visctrl((char) c),
note);
msg_given = TRUE;

View File

@@ -41,7 +41,7 @@ register struct monst *mtmp;
mtmp->meating = 0;
EDOG(mtmp)->droptime = 0;
EDOG(mtmp)->dropdist = 10000;
EDOG(mtmp)->apport = 10;
EDOG(mtmp)->apport = ACURR(A_CHA);
EDOG(mtmp)->whistletime = 0;
EDOG(mtmp)->hungrytime = 1000 + monstermoves;
EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */

View File

@@ -497,15 +497,20 @@ xchar x, y;
|| kickedobj == uchain)
return 0;
if ((trap = t_at(x, y)) != 0
&& (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls)
|| trap->ttyp == WEB)) {
if (!trap->tseen)
find_trap(trap);
You_cant("kick %s that's in a %s!", something,
Hallucination ? "tizzy" : (trap->ttyp == WEB) ? "web"
: "pit");
return 1;
if ((trap = t_at(x, y)) != 0) {
if (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls)
|| trap->ttyp == WEB) {
if (!trap->tseen)
find_trap(trap);
You_cant("kick %s that's in a %s!", something,
Hallucination ? "tizzy" :
(trap->ttyp == WEB) ? "web" : "pit");
return 1;
}
if (trap->ttyp == STATUE_TRAP) {
activate_statue_trap(trap, x,y, FALSE);
return 1;
}
}
if (Fumbling && !rn2(3)) {

View File

@@ -671,6 +671,7 @@ struct symparse loadsyms[] = {
{ SYM_PCHAR, S_explode7, "S_explode7" },
{ SYM_PCHAR, S_explode8, "S_explode8" },
{ SYM_PCHAR, S_explode9, "S_explode9" },
{ SYM_OC, ILLOBJ_CLASS + SYM_OFF_O, "S_strange_obj" },
{ SYM_OC, WEAPON_CLASS + SYM_OFF_O, "S_weapon" },
{ SYM_OC, ARMOR_CLASS + SYM_OFF_O, "S_armor" },
{ SYM_OC, ARMOR_CLASS + SYM_OFF_O, "S_armour" },

View File

@@ -93,6 +93,12 @@ register struct obj *obj;
&& (youmonst.data != &mons[PM_RUST_MONSTER] || is_rustprone(obj)))
return TRUE;
/* Ghouls only eat non-veggy corpses or eggs (see dogfood()) */
if (u.umonnum == PM_GHOUL)
return (boolean)((obj->otyp == CORPSE
&& !vegan(&mons[obj->corpsenm]))
|| (obj->otyp == EGG));
if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj)
/* [g.cubes can eat containers and retain all contents
as engulfed items, but poly'd player can't do that] */
@@ -1622,7 +1628,7 @@ struct obj *otmp;
pline("Ecch - that must have been poisonous!");
if (!Poison_resistance) {
losestr(rnd(4));
losehp(rnd(15), !glob ? "poisonous corpse" : "posionous glob",
losehp(rnd(15), !glob ? "poisonous corpse" : "poisonous glob",
KILLED_BY_AN);
} else
You("seem unaffected by the poison.");

View File

@@ -2152,6 +2152,10 @@ int src;
parseoptions(bufp, TRUE, TRUE);
} else if (match_varname(buf, "AUTOPICKUP_EXCEPTION", 5)) {
add_autopickup_exception(bufp);
} else if (match_varname(buf, "BINDINGS", 4)) {
parsebindings(bufp);
} else if (match_varname(buf, "AUTOCOMPLETE", 5)) {
parseautocomplete(bufp, TRUE);
} else if (match_varname(buf, "MSGTYPE", 7)) {
(void) msgtype_parse_add(bufp);
#ifdef NOCWD_ASSUMPTIONS

View File

@@ -18,6 +18,7 @@
char * ucase (char *)
char * upstart (char *)
char * mungspaces (char *)
char * trimspaces (char *)
char * strip_newline (char *)
char * eos (char *)
boolean str_end_is (const char *, const char *)
@@ -159,6 +160,22 @@ char *bp;
return bp;
}
/* remove leading and trailing whitespace, in place */
char*
trimspaces(txt)
char* txt;
{
char* end;
while (*txt == ' ' || *txt == '\t')
txt++;
end = eos(txt);
while (--end >= txt && (*end == ' ' || *end == '\t'))
*end = '\0';
return txt;
}
/* remove \n from end of line; remove \r too if one is there */
char *
strip_newline(str)
@@ -385,13 +402,17 @@ char *sbuf;
return strcpy(sbuf, buf);
}
#define VISCTRL_NBUF 5
/* make a displayable string from a character */
char *
visctrl(c)
char c;
{
Static char ccc[5];
Static char visctrl_bufs[VISCTRL_NBUF][5];
static int nbuf = 0;
register int i = 0;
char *ccc = visctrl_bufs[nbuf];
nbuf = (nbuf + 1) % VISCTRL_NBUF;
if ((uchar) c & 0200) {
ccc[i++] = 'M';

View File

@@ -269,6 +269,58 @@ register struct monst *mtmp;
} else if (mm == PM_NINJA) { /* extra quest villains */
(void) mongets(mtmp, rn2(4) ? SHURIKEN : DART);
(void) mongets(mtmp, rn2(4) ? SHORT_SWORD : AXE);
} else if (ptr->msound == MS_GUARDIAN) {
/* quest "guardians" */
switch (mm) {
case PM_STUDENT:
case PM_ATTENDANT:
case PM_ABBOT:
case PM_ACOLYTE:
case PM_GUIDE:
case PM_APPRENTICE:
if (rn2(2))
(void) mongets(mtmp, rn2(3) ? DAGGER : KNIFE);
if (rn2(5))
(void) mongets(mtmp, rn2(3) ? LEATHER_JACKET : LEATHER_CLOAK);
if (rn2(3))
(void) mongets(mtmp, rn2(3) ? LOW_BOOTS : HIGH_BOOTS);
if (rn2(3))
(void) mongets(mtmp, POT_HEALING);
break;
case PM_CHIEFTAIN:
case PM_PAGE:
case PM_ROSHI:
case PM_WARRIOR:
(void) mongets(mtmp, rn2(3) ? LONG_SWORD : SHORT_SWORD);
(void) mongets(mtmp, rn2(3) ? CHAIN_MAIL : LEATHER_ARMOR);
if (rn2(2))
(void) mongets(mtmp, rn2(2) ? LOW_BOOTS : HIGH_BOOTS);
if (!rn2(3))
(void) mongets(mtmp, LEATHER_CLOAK);
if (!rn2(3)) {
(void) mongets(mtmp, BOW);
m_initthrow(mtmp, ARROW, 12);
}
break;
case PM_HUNTER:
(void) mongets(mtmp, rn2(3) ? SHORT_SWORD : DAGGER);
if (rn2(2))
(void) mongets(mtmp, rn2(2) ? LEATHER_JACKET : LEATHER_ARMOR);
(void) mongets(mtmp, BOW);
m_initthrow(mtmp, ARROW, 12);
break;
case PM_THUG:
(void) mongets(mtmp, CLUB);
(void) mongets(mtmp, rn2(3) ? DAGGER : KNIFE);
if (rn2(2))
(void) mongets(mtmp, LEATHER_GLOVES);
(void) mongets(mtmp, rn2(2) ? LEATHER_JACKET : LEATHER_ARMOR);
break;
case PM_NEANDERTHAL:
(void) mongets(mtmp, CLUB);
(void) mongets(mtmp, LEATHER_ARMOR);
break;
}
}
break;

View File

@@ -237,7 +237,7 @@ int dir;
mz_move(x, y, dir);
mz_move(x, y, dir);
if (x < 3 || y < 3 || x > x_maze_max || y > y_maze_max
|| levl[x][y].typ != 0)
|| levl[x][y].typ != STONE)
return FALSE;
return TRUE;
}

View File

@@ -469,21 +469,21 @@ static char def_inv_order[MAXOCLASSES] = {
typedef struct {
const char *name;
char cmd;
const char *desc;
} menu_cmd_t;
#define NUM_MENU_CMDS 11
static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
/* 0*/ { "menu_first_page", MENU_FIRST_PAGE },
{ "menu_last_page", MENU_LAST_PAGE },
{ "menu_next_page", MENU_NEXT_PAGE },
{ "menu_previous_page", MENU_PREVIOUS_PAGE },
{ "menu_select_all", MENU_SELECT_ALL },
/* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL },
{ "menu_invert_all", MENU_INVERT_ALL },
{ "menu_select_page", MENU_SELECT_PAGE },
{ "menu_deselect_page", MENU_UNSELECT_PAGE },
{ "menu_invert_page", MENU_INVERT_PAGE },
/*10*/ { "menu_search", MENU_SEARCH },
static const menu_cmd_t default_menu_cmd_info[] = {
{ "menu_first_page", MENU_FIRST_PAGE, "Go to first page" },
{ "menu_last_page", MENU_LAST_PAGE, "Go to last page" },
{ "menu_next_page", MENU_NEXT_PAGE, "Go to next page" },
{ "menu_previous_page", MENU_PREVIOUS_PAGE, "Go to previous page" },
{ "menu_select_all", MENU_SELECT_ALL, "Select all items" },
{ "menu_deselect_all", MENU_UNSELECT_ALL, "Unselect all items" },
{ "menu_invert_all", MENU_INVERT_ALL, "Insert selection" },
{ "menu_select_page", MENU_SELECT_PAGE, "Select items in current page" },
{ "menu_deselect_page", MENU_UNSELECT_PAGE, "Unselect items in current page" },
{ "menu_invert_page", MENU_INVERT_PAGE, "Invert current page selection" },
{ "menu_search", MENU_SEARCH, "Search and toggle matching items" },
};
/*
@@ -833,6 +833,10 @@ int maxlen;
* has the effect of 'meta'-ing the value which follows (so that the
* alternate character set will be enabled).
*
* X normal key X
* ^X control-X
* \mX meta-X
*
* For 3.4.3 and earlier, input ending with "\M", backslash, or caret
* prior to terminating '\0' would pull that '\0' into the output and then
* keep processing past it, potentially overflowing the output buffer.
@@ -3233,7 +3237,7 @@ boolean tinitial, tfrom_file;
}
/* check for menu command mapping */
for (i = 0; i < NUM_MENU_CMDS; i++) {
for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
fullname = default_menu_cmd_info[i].name;
if (duplicate)
complain_about_duplicate(opts, 1);
@@ -3241,7 +3245,6 @@ boolean tinitial, tfrom_file;
if (negated) {
bad_negation(fullname, FALSE);
} else if ((op = string_for_opt(opts, FALSE)) != 0) {
int j;
char c, op_buf[BUFSZ];
escapes(op, op_buf);
@@ -3475,6 +3478,56 @@ boolean tinitial, tfrom_file;
badoption(opts);
}
/* parse key:command */
void
parsebindings(bindings)
char* bindings;
{
char *bind;
char key;
int i;
/* break off first binding from the rest; parse the rest */
if ((bind = index(bindings, ',')) != 0) {
*bind++ = 0;
parsebindings(bind);
}
/* parse a single binding: first split around : */
if (! (bind = index(bindings, ':'))) return; /* it's not a binding */
*bind++ = 0;
/* read the key to be bound */
key = txt2key(bindings);
if (!key) {
raw_printf("Bad binding %s.", bindings);
wait_synch();
return;
}
bind = trimspaces(bind);
/* is it a special key? */
if (bind_specialkey(key, bind))
return;
/* is it a menu command? */
for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
if (!strcmp(default_menu_cmd_info[i].name, bind)) {
if (illegal_menu_cmd_key(key)) {
char tmp[BUFSZ];
Sprintf(tmp, "Bad menu key %s:%s", visctrl(key), bind);
badoption(tmp);
} else
add_menu_cmd_alias(key, default_menu_cmd_info[i].cmd);
return;
}
}
/* extended command? */
bind_key(key, bind);
}
static NEARDATA const char *menutype[] = { "traditional", "combination",
"full", "partial" };
@@ -3525,6 +3578,18 @@ char from_ch, to_ch;
}
}
char
get_menu_cmd_key(ch)
char ch;
{
char *found = index(mapped_menu_op, ch);
if (found) {
int idx = (int) (found - mapped_menu_op);
ch = mapped_menu_cmds[idx];
}
return ch;
}
/*
* Map the given character to its corresponding menu command. If it
* doesn't match anything, just return the original.
@@ -3541,6 +3606,57 @@ char ch;
return ch;
}
void
show_menu_controls(win, dolist)
winid win;
boolean dolist;
{
char buf[BUFSZ];
putstr(win, 0, "Menu control keys:");
if (dolist) {
int i;
for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
Sprintf(buf, "%-8s %s",
visctrl(get_menu_cmd_key(default_menu_cmd_info[i].cmd)),
default_menu_cmd_info[i].desc);
putstr(win, 0, buf);
}
} else {
putstr(win, 0, "");
putstr(win, 0, " Page All items");
Sprintf(buf, " Select %s %s",
visctrl(get_menu_cmd_key(MENU_SELECT_PAGE)),
visctrl(get_menu_cmd_key(MENU_SELECT_ALL)));
putstr(win, 0, buf);
Sprintf(buf, "Deselect %s %s",
visctrl(get_menu_cmd_key(MENU_UNSELECT_PAGE)),
visctrl(get_menu_cmd_key(MENU_UNSELECT_ALL)));
putstr(win, 0, buf);
Sprintf(buf, " Invert %s %s",
visctrl(get_menu_cmd_key(MENU_INVERT_PAGE)),
visctrl(get_menu_cmd_key(MENU_INVERT_ALL)));
putstr(win, 0, buf);
putstr(win, 0, "");
Sprintf(buf, " Go to %s Next page",
visctrl(get_menu_cmd_key(MENU_NEXT_PAGE)));
putstr(win, 0, buf);
Sprintf(buf, " %s Previous page",
visctrl(get_menu_cmd_key(MENU_PREVIOUS_PAGE)));
putstr(win, 0, buf);
Sprintf(buf, " %s First page",
visctrl(get_menu_cmd_key(MENU_FIRST_PAGE)));
putstr(win, 0, buf);
Sprintf(buf, " %s Last page",
visctrl(get_menu_cmd_key(MENU_LAST_PAGE)));
putstr(win, 0, buf);
putstr(win, 0, "");
Sprintf(buf, " %s Search and toggle matching entries",
visctrl(get_menu_cmd_key(MENU_SEARCH)));
putstr(win, 0, buf);
}
}
#if defined(MICRO) || defined(MAC) || defined(WIN32)
#define OPTIONS_HEADING "OPTIONS"
#else

View File

@@ -1371,6 +1371,7 @@ whatdoes_help()
destroy_nhwindow(tmpwin);
}
#if 0
#define WD_STACKLIMIT 5
struct wd_stack_frame {
Bitfield(active, 1);
@@ -1501,18 +1502,31 @@ int *depth, lnum;
}
return stack[*depth].active ? TRUE : FALSE;
}
#endif /* 0 */
char *
dowhatdoes_core(q, cbuf)
char q;
char *cbuf;
{
dlb *fp;
char buf[BUFSZ];
#if 0
dlb *fp;
struct wd_stack_frame stack[WD_STACKLIMIT];
boolean cond;
int ctrl, meta, depth = 0, lnum = 0;
#endif /* 0 */
const char *ec_desc;
if ((ec_desc = key2extcmddesc(q)) != NULL) {
char keybuf[QBUFSZ];
Sprintf(buf, "%-8s%s.", key2txt(q, keybuf), ec_desc);
Strcpy(cbuf, buf);
return cbuf;
}
return 0;
#if 0
fp = dlb_fopen(CMDHELPFILE, "r");
if (!fp) {
pline("Cannot open \"%s\" data file!", CMDHELPFILE);
@@ -1568,6 +1582,7 @@ char *cbuf;
if (depth != 0)
impossible("cmdhelp: mismatched &? &: &. conditionals.");
return (char *) 0;
#endif /* 0 */
}
int
@@ -1705,6 +1720,15 @@ hmenu_doextlist()
(void) doextlist();
}
void
domenucontrols()
{
winid cwin = create_nhwindow(NHW_TEXT);
show_menu_controls(cwin, FALSE);
display_nhwindow(cwin, FALSE);
destroy_nhwindow(cwin);
}
/* data for dohelp() */
static struct {
void (*f)();
@@ -1718,7 +1742,9 @@ static struct {
{ hmenu_dowhatdoes, "Info on what a given key does." },
{ option_help, "List of game options." },
{ dispfile_optionfile, "Longer explanation of game options." },
{ dokeylist, "Full list of keyboard commands" },
{ hmenu_doextlist, "List of extended commands." },
{ domenucontrols, "List menu control keys" },
{ dispfile_license, "The NetHack license." },
{ docontact, "Support information." },
#ifdef PORT_HELP

View File

@@ -814,7 +814,7 @@ nextpos:
else
ny += dy;
while ((typ = (crm = &levl[nx][ny])->typ) != 0) {
while ((typ = (crm = &levl[nx][ny])->typ) != STONE) {
/* in view of the above we must have IS_WALL(typ) or typ == POOL */
/* must be a wall here */
if (isok(nx + nx - x, ny + ny - y) && !IS_POOL(typ)