diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 8c414e498..eef8ccc6a 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -3352,6 +3352,15 @@ gives you the row and column of your review cursor and the PC cursor. These co-ordinates are often useful in giving players a better sense of the overall location of items on the screen. .pg +NetHack can also be compiled with support for sending the game messages +to an external program, such as a text-to-speech synthesizer. If the #version +extended command shows "external program as a message handler", your NetHack +has been compiled with the capability. When compiling NetHack from source +on Linux and other POSIX systems, define MSGHANDLER to enable it. To use +the capability, set the environment variable NETHACK_MSGHANDLER to an +executable, which will be executed with the game message as the program's +only parameter. +.pg While it is not difficult for experienced users to edit the \fBdefaults.nh\fP file to accomplish this, novices may find this task somewhat daunting. Included within the ``symbols'' file of all official distributions of NetHack @@ -3369,10 +3378,20 @@ Load a symbol set for the rogue level that is appropriate for use by blind players. .lp menustyle:traditional This will assist in the interface to speech synthesizers. +.lp nomenu_overlay +Show menus on a cleared screen and aligned to the left edge. .lp number_pad A lot of speech access programs use the number-pad to review the screen. If this is the case, disable the number_pad option and use the traditional Rogue-like commands. +.lp autodescribe +Automatically describe the terrain under the cursor when targeting. +.lp mention_walls +Give feedback messages when walking towards a wall or when travel command +was interrupted. +.lp whatis_coord:compass +When targeting with cursor, describe the cursor position with coordinates +relative to your character. .hn 2 Global Configuration for System Administrators .pg diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index bb0e4a021..98218165e 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -3995,6 +3995,15 @@ gives you the row and column of your review cursor and the PC cursor. These co-ordinates are often useful in giving players a better sense of the overall location of items on the screen. %.pg +NetHack can also be compiled with support for sending the game messages +to an external program, such as a text-to-speech synthesizer. If the #version +extended command shows "external program as a message handler", your NetHack +has been compiled with the capability. When compiling NetHack from source +on Linux and other POSIX systems, define {\it MSGHANDLER\/} to enable it. To use +the capability, set the environment variable {\it NETHACK\_MSGHANDLER\/} to an +executable, which will be executed with the game message as the program's +only parameter. +%.pg While it is not difficult for experienced users to edit the {\it defaults.nh\/} file to accomplish this, novices may find this task somewhat daunting. Included within the symbol file of all official distributions of NetHack @@ -4017,10 +4026,24 @@ use by blind players. \item[\ib{menustyle:traditional}] This will assist in the interface to speech synthesizers. %.lp +\item[\ib{nomenu\verb+_+overlay}] +Show menus on a cleared screen and aligned to the left edge. +%.lp \item[\ib{number\verb+_+pad}] A lot of speech access programs use the number-pad to review the screen. If this is the case, disable the number\verb+_+pad option and use the traditional Rogue-like commands. +%.lp +\item[\ib{autodescribe}] +Automatically describe the terrain under the cursor when targeting. +%.lp +\item[\ib{mention\verb+_+walls}] +Give feedback messages when walking towards a wall or when travel command +was interrupted. +%.lp +\item[\ib{whatis\verb+_+coord:compass}] +When targeting with cursor, describe the cursor position with coordinates +relative to your character. \elist %.hn2 diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 332e05c63..71425d6e8 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -336,6 +336,9 @@ if user supplied a specific monster name when asked to choose a monster class, S_quadruped due to being preceded by "titanothere" in mons[]) change ing_suffix() to not double final 'w' when adding 'ing' ('t=' yielded "You mime throwwing something.") +using 'D' to drop when not carrying anything finished (after doing nothing) + without giving any feedback for menustyles "full" and "partial" +"you hear a distant squeak" might actually be nearby Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository @@ -483,6 +486,8 @@ undead #turning takes less time at higher experience level peacefuls may react when you attack other peacefuls prevent diagonal jumping through open doorways different liquids when hallucinating +when moving a cursor for travel target, show if there is no known travel + path to that location, if "autodescribe" is on Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 12e709e45..b3a8316b0 100644 --- a/include/extern.h +++ b/include/extern.h @@ -796,6 +796,7 @@ E void NDECL(drinksink); /* ### hack.c ### */ +E boolean FDECL(is_valid_travelpt, (int,int)); E anything *FDECL(uint_to_any, (unsigned)); E anything *FDECL(long_to_any, (long)); E anything *FDECL(monst_to_any, (struct monst *)); diff --git a/include/flag.h b/include/flag.h index 55a544471..1f79f07dd 100644 --- a/include/flag.h +++ b/include/flag.h @@ -192,6 +192,7 @@ struct instance_flags { #define TER_OBJ 0x04 #define TER_MON 0x08 #define TER_DETECT 0x10 /* detect_foo magic rather than #terrain */ + boolean getloc_travelmode; coord travelcc; /* coordinates for travel_cache */ boolean window_inited; /* true if init_nhwindows() completed */ boolean vision_inited; /* true if vision is ready */ diff --git a/src/cmd.c b/src/cmd.c index 13086a9c2..441a6938a 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -4323,11 +4323,14 @@ dotravel(VOID_ARGS) cc.x = u.ux; cc.y = u.uy; } + iflags.getloc_travelmode = TRUE; pline("Where do you want to travel to?"); if (getpos(&cc, TRUE, "the desired destination") < 0) { /* user pressed ESC */ + iflags.getloc_travelmode = FALSE; return 0; } + iflags.getloc_travelmode = FALSE; iflags.travelcc.x = u.tx = cc.x; iflags.travelcc.y = u.ty = cc.y; cmd[0] = CMD_TRAVEL; diff --git a/src/do.c b/src/do.c index 1cc797817..6f09b5bd2 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do.c $NHDT-Date: 1464487100 2016/05/29 01:58:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.156 $ */ +/* NetHack 3.6 do.c $NHDT-Date: 1472809073 2016/09/02 09:37:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.158 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -34,7 +34,8 @@ dodrop() result = drop(getobj(&drop_types[i], "drop")); if (*u.ushops) sellobj_state(SELL_NORMAL); - reset_occupations(); + if (result) + reset_occupations(); return result; } @@ -739,6 +740,10 @@ doddrop() { int result = 0; + if (!invent) { + You("have nothing to drop."); + return 0; + } add_valid_menu_class(0); /* clear any classes already there */ if (*u.ushops) sellobj_state(SELL_DELIBERATE); @@ -747,7 +752,8 @@ doddrop() result = menu_drop(result); if (*u.ushops) sellobj_state(SELL_NORMAL); - reset_occupations(); + if (result) + reset_occupations(); return result; } @@ -785,6 +791,7 @@ int retry; free((genericptr_t) pick_list); } else if (flags.menu_style == MENU_COMBINATION) { unsigned ggoresults = 0; + all_categories = FALSE; /* Gather valid classes via traditional NetHack method */ i = ggetobj("drop", drop, 0, TRUE, &ggoresults); diff --git a/src/do_name.c b/src/do_name.c index 316282f76..594cab44d 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -316,7 +316,9 @@ int cx, cy; cc.y = cy; if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) { (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords); - pline("%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf); + pline("%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf, + (iflags.getloc_travelmode && !is_valid_travelpt(cx,cy)) + ? " (no travel path)" : ""); curs(WIN_MAP, cx, cy); flush_screen(0); } diff --git a/src/eat.c b/src/eat.c index ff5390496..f827d71c0 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1675,20 +1675,18 @@ struct obj *otmp; if (!strncmpi(pmxnam, "the ", 4)) pmxnam += 4; - pline("%s%s %s!", + pline("%s%s %s %s%c", type_is_pname(&mons[mnum]) - ? "" : the_unique_pm(&mons[mnum]) ? "The " : "This ", + ? "" : the_unique_pm(&mons[mnum]) ? "The " : "This ", pmxnam, + Hallucination ? "is" : "tastes", /* tiger reference is to TV ads for "Frosted Flakes", breakfast cereal targeted at kids by "Tony the tiger" */ Hallucination - ? (yummy ? ((u.umonnum == PM_TIGER) ? "is gr-r-reat" - : "is gnarly") - : palatable ? "is copacetic" - : "is grody") - : (yummy ? "tastes delicious" - : palatable ? "tastes okay" - : "tastes terrible")); + ? (yummy ? ((u.umonnum == PM_TIGER) ? "gr-r-reat" : "gnarly") + : palatable ? "copacetic" : "grody") + : (yummy ? "delicious" : palatable ? "okay" : "terrible"), + (yummy || !palatable) ? '!' : '.'); } return retcode; diff --git a/src/hack.c b/src/hack.c index f9f9cee3f..1c7e44804 100644 --- a/src/hack.c +++ b/src/hack.c @@ -10,7 +10,7 @@ STATIC_DCL void NDECL(maybe_wail); STATIC_DCL int NDECL(moverock); STATIC_DCL int FDECL(still_chewing, (XCHAR_P, XCHAR_P)); STATIC_DCL void NDECL(dosinkfall); -STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P)); +STATIC_DCL boolean FDECL(findtravelpath, (int)); STATIC_DCL boolean FDECL(trapmove, (int, int, struct trap *)); STATIC_DCL void NDECL(switch_terrain); STATIC_DCL struct monst *FDECL(monstinroom, (struct permonst *, int)); @@ -19,6 +19,11 @@ STATIC_DCL void FDECL(move_update, (BOOLEAN_P)); #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE) +/* mode values for findtravelpath() */ +#define TRAVP_TRAVEL 0 +#define TRAVP_GUESS 1 +#define TRAVP_VALID 2 + static anything tmp_anything; anything * @@ -887,21 +892,25 @@ int wiz_debug_cmd_traveldisplay() * Returns TRUE if a path was found. */ STATIC_OVL boolean -findtravelpath(guess) -boolean guess; +findtravelpath(mode) +int mode; { /* if travel to adjacent, reachable location, use normal movement rules */ - if (!guess && context.travel1 && distmin(u.ux, u.uy, u.tx, u.ty) == 1 + if ((mode == TRAVP_TRAVEL || mode == TRAVP_VALID) && context.travel1 + && distmin(u.ux, u.uy, u.tx, u.ty) == 1 && !(u.ux != u.tx && u.uy != u.ty && NODIAG(u.umonnum))) { context.run = 0; if (test_move(u.ux, u.uy, u.tx - u.ux, u.ty - u.uy, TEST_MOVE)) { - u.dx = u.tx - u.ux; - u.dy = u.ty - u.uy; - nomul(0); - iflags.travelcc.x = iflags.travelcc.y = -1; + if (mode == TRAVP_TRAVEL) { + u.dx = u.tx - u.ux; + u.dy = u.ty - u.uy; + nomul(0); + iflags.travelcc.x = iflags.travelcc.y = -1; + } return TRUE; } - context.run = 8; + if (mode == TRAVP_TRAVEL) + context.run = 8; } if (u.tx != u.ux || u.ty != u.uy) { xchar travel[COLNO][ROWNO]; @@ -917,7 +926,7 @@ boolean guess; * goal is the position the player knows of, or might figure out * (couldsee) that is closest to the target on a straight path. */ - if (guess) { + if (mode == TRAVP_GUESS || mode == TRAVP_VALID) { tx = u.ux; ty = u.uy; ux = u.tx; @@ -987,7 +996,8 @@ boolean guess; * example above is never included in it, preventing * the cycle. */ - if (!isok(nx, ny) || (guess && !couldsee(nx, ny))) + if (!isok(nx, ny) + || ((mode == TRAVP_GUESS) && !couldsee(nx, ny))) continue; if ((!Passes_walls && !can_ooze(&youmonst) && closed_door(x, y)) || sobj_at(BOULDER, x, y) @@ -1009,10 +1019,11 @@ boolean guess; && (levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) { if (nx == ux && ny == uy) { - if (!guess) { + if (mode == TRAVP_TRAVEL || mode == TRAVP_VALID) { u.dx = x - ux; u.dy = y - uy; - if (x == u.tx && y == u.ty) { + if (mode == TRAVP_TRAVEL + && x == u.tx && y == u.ty) { nomul(0); /* reset run so domove run checks work */ context.run = 8; @@ -1052,7 +1063,7 @@ boolean guess; } /* if guessing, find best location in travel matrix and go there */ - if (guess) { + if (mode == TRAVP_GUESS) { int px = tx, py = ty; /* pick location */ int dist, nxtdist, d2, nd2; @@ -1107,7 +1118,7 @@ boolean guess; uy = u.uy; set = 0; n = radius = 1; - guess = FALSE; + mode = TRAVP_TRAVEL; goto noguess; } return FALSE; @@ -1120,6 +1131,27 @@ found: return FALSE; } +boolean +is_valid_travelpt(x,y) +int x,y; +{ + int tx = u.tx; + int ty = u.ty; + boolean ret; + int g = glyph_at(x,y); + if (x == u.ux && y == u.uy) + return TRUE; + if (isok(x,y) && glyph_is_cmap(g) && S_stone == glyph_to_cmap(g) + && !levl[x][y].seenv) + return FALSE; + u.tx = x; + u.ty = y; + ret = findtravelpath(TRAVP_VALID); + u.tx = tx; + u.ty = ty; + return ret; +} + /* try to escape being stuck in a trapped state by walking out of it; return true iff moving should continue to intended destination (all failures and most successful escapes leave hero at original spot) */ @@ -1381,6 +1413,16 @@ domove() || (Blind && !Levitation && !Flying && !is_clinger(youmonst.data) && is_pool_or_lava(x, y) && levl[x][y].seenv)) { if (context.run >= 2) { + if (iflags.mention_walls) { + if (trap && trap->tseen) { + int tt = what_trap(trap->ttyp); + You("stop in front of %s.", + an(defsyms[trap_to_defsym(tt)].explanation)); + } else if (is_pool_or_lava(x,y) && levl[x][y].seenv) { + You("stop at the edge of the %s.", + hliquid(is_pool(x,y) ? "water" : "lava")); + } + } nomul(0); context.move = 0; return; @@ -2484,7 +2526,8 @@ lookaround() /* Grid bugs stop if trying to move diagonal, even if blind. Maybe */ /* they polymorphed while in the middle of a long move. */ - if (u.umonnum == PM_GRID_BUG && u.dx && u.dy) { + if (NODIAG(u.umonnum) && u.dx && u.dy) { + You("cannot move diagonally."); nomul(0); return; } @@ -2504,8 +2547,11 @@ lookaround() && (!mtmp->minvis || See_invisible) && !mtmp->mundetected) { if ((context.run != 1 && !mtmp->mtame) || (x == u.ux + u.dx && y == u.uy + u.dy - && !context.travel)) + && !context.travel)) { + if (iflags.mention_walls) + pline("%s blocks your path.", upstart(a_monnam(mtmp))); goto stop; + } } if (levl[x][y].typ == STONE) @@ -2519,8 +2565,11 @@ lookaround() } else if (closed_door(x, y) || (mtmp && is_door_mappear(mtmp))) { if (x != u.ux && y != u.uy) continue; - if (context.run != 1) + if (context.run != 1) { + if (iflags.mention_walls) + You("stop in front of the door."); goto stop; + } goto bcorr; } else if (levl[x][y].typ == CORR) { bcorr: @@ -2545,20 +2594,30 @@ lookaround() } else if ((trap = t_at(x, y)) && trap->tseen) { if (context.run == 1) goto bcorr; /* if you must */ - if (x == u.ux + u.dx && y == u.uy + u.dy) + if (x == u.ux + u.dx && y == u.uy + u.dy) { + if (iflags.mention_walls) { + int tt = what_trap(trap->ttyp); + You("stop in front of %s.", + an(defsyms[trap_to_defsym(tt)].explanation)); + } goto stop; + } continue; } else if (is_pool_or_lava(x, y)) { /* water and lava only stop you if directly in front, and stop * you even if you are running */ if (!Levitation && !Flying && !is_clinger(youmonst.data) - && x == u.ux + u.dx && y == u.uy + u.dy) + && x == u.ux + u.dx && y == u.uy + u.dy) { /* No Wwalking check; otherwise they'd be able * to test boots by trying to SHIFT-direction * into a pool and seeing if the game allowed it */ + if (iflags.mention_walls) + You("stop at the edge of the %s.", + hliquid(is_pool(x,y) ? "water" : "lava")); goto stop; + } continue; } else { /* e.g. objects or trap or stairs */ if (context.run == 1) @@ -2576,8 +2635,11 @@ lookaround() return; } /* end for loops */ - if (corrct > 1 && context.run == 2) + if (corrct > 1 && context.run == 2) { + if (iflags.mention_walls) + pline_The("corridor widens here."); goto stop; + } if ((context.run == 1 || context.run == 3 || context.run == 8) && !noturn && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1))) { /* make sure that we do not turn too far */ diff --git a/src/invent.c b/src/invent.c index 5aa99ce6c..fa478b516 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1461967848 2016/04/29 22:10:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.208 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1472809075 2016/09/02 09:37:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.210 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1573,13 +1573,15 @@ unsigned *resultflags; char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */ char buf[BUFSZ], qbuf[QBUFSZ]; + if (!invent) { + You("have nothing to %s.", word); + if (resultflags) + *resultflags = ALL_FINISHED; + return 0; + } if (resultflags) *resultflags = 0; takeoff = ident = allflag = m_seen = FALSE; - if (!invent) { - You("have nothing to %s.", word); - return 0; - } add_valid_menu_class(0); /* reset */ if (taking_off(word)) { takeoff = TRUE; diff --git a/src/mhitm.c b/src/mhitm.c index e4a5d9f39..5204e3cf0 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -987,11 +987,10 @@ register struct attack *mattk; if (resists_acid(mdef)) { if (vis) pline("%s is covered in %s, but it seems harmless.", - hliquid("acid"), - Monnam(mdef)); + Monnam(mdef), hliquid("acid")); tmp = 0; } else if (vis) { - pline("%s is covered in %s!", hliquid("acid"), Monnam(mdef)); + pline("%s is covered in %s!", Monnam(mdef), hliquid("acid")); pline("It burns %s!", mon_nam(mdef)); } if (!rn2(30)) @@ -1506,8 +1505,7 @@ int mdead; Strcpy(buf, Monnam(magr)); if (canseemon(magr)) pline("%s is splashed by %s %s!", buf, - hliquid("acid"), - s_suffix(mon_nam(mdef))); + s_suffix(mon_nam(mdef)), hliquid("acid")); if (resists_acid(magr)) { if (canseemon(magr)) pline("%s is not affected.", Monnam(magr)); diff --git a/src/mon.c b/src/mon.c index 243ffbd6f..e31ecb27b 100644 --- a/src/mon.c +++ b/src/mon.c @@ -555,8 +555,7 @@ register struct monst *mtmp; /* This can happen after a purple worm plucks you off a flying steed while you are over water. */ pline("%s sinks as %s rushes in and flushes you out.", - hliquid("water"), - Monnam(mtmp)); + Monnam(mtmp), hliquid("water")); } mondead(mtmp); if (mtmp->mhp > 0) { diff --git a/src/trap.c b/src/trap.c index 4eec29df0..9e5b2f500 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 trap.c $NHDT-Date: 1464138044 2016/05/25 01:00:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.272 $ */ +/* NetHack 3.6 trap.c $NHDT-Date: 1473665044 2016/09/12 07:24:04 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.274 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2198,8 +2198,15 @@ register struct monst *mtmp; pline("%s stops momentarily and appears to cringe.", Monnam(mtmp)); } - } else - You_hear("a distant %s squeak.", trapnote(trap, 1)); + } else { + /* same near/far threshold as mzapmsg() */ + int range = couldsee(mtmp->mx, mtmp->my) /* 9 or 5 */ + ? (BOLT_LIM + 1) : (BOLT_LIM - 3); + + You_hear("a %s squeak %s.", trapnote(trap, 1), + (distu(mtmp->mx, mtmp->my) <= range * range) + ? "nearby" : "in the distance"); + } /* wake up nearby monsters */ wake_nearto(mtmp->mx, mtmp->my, 40); break;