From d8591be858cefceef4db2c159dba14efe9d4c28f Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 17:57:39 -0800 Subject: [PATCH 01/26] fix #4138 - 'text bug' for freezing moat Freezing a moat--unlike other types of water--substitutes the type of water (because that isn't "moat" for Medusa's level) in the freeze message but was doing so after changing the affected terrain to ICE, yielding "The ice is bridged with ice." --- doc/fixes36.1 | 1 + src/zap.c | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 2602460c0..12386fc24 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -97,6 +97,7 @@ make vault guard accept names starting with number fix weight of containers in special levels make the raven medusa level shortsighted fix possible segfault in lev_comp when map was too tall +fix "the ice is bridged with ice" when freezing castle's moat or Medusa's sea Platform- and/or Interface-Specific Fixes diff --git a/src/zap.c b/src/zap.c index 0749c8dbf..6a695fbac 100644 --- a/src/zap.c +++ b/src/zap.c @@ -4234,8 +4234,8 @@ short exploding_wand_typ; case ZT_COLD: if (is_pool(x, y) || is_lava(x, y)) { - boolean lava = is_lava(x, y); - boolean moat = is_moat(x, y); + boolean lava = is_lava(x, y), + moat = is_moat(x, y); if (lev->typ == WATER) { /* For now, don't let WATER freeze. */ @@ -4245,23 +4245,25 @@ short exploding_wand_typ; You_hear("a soft crackling."); rangemod -= 1000; /* stop */ } else { + char buf[BUFSZ]; + + Strcpy(buf, waterbody_name(x, y)); /* for MOAT */ rangemod -= 3; if (lev->typ == DRAWBRIDGE_UP) { lev->drawbridgemask &= ~DB_UNDER; /* clear lava */ lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE); } else { if (!lava) - lev->icedpool = - (lev->typ == POOL ? ICED_POOL : ICED_MOAT); - lev->typ = (lava ? ROOM : ICE); + lev->icedpool = (lev->typ == POOL) ? ICED_POOL + : ICED_MOAT; + lev->typ = lava ? ROOM : ICE; } bury_objs(x, y); if (see_it) { if (lava) Norep("The lava cools and solidifies."); else if (moat) - Norep("The %s is bridged with ice!", - waterbody_name(x, y)); + Norep("The %s is bridged with ice!", buf); else Norep("The water freezes."); newsym(x, y); From b48673425eb3c5a954a59f62f3b6de690f476bee Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 6 Jan 2016 21:04:05 -0500 Subject: [PATCH 02/26] vault Deaf bits --- src/vault.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vault.c b/src/vault.c index 365f06cc9..18c1d9a16 100644 --- a/src/vault.c +++ b/src/vault.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vault.c $NHDT-Date: 1451962301 2016/01/05 02:51:41 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.40 $ */ +/* NetHack 3.6 vault.c $NHDT-Date: 1452132199 2016/01/07 02:03:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -377,7 +377,7 @@ invault() } trycount = 5; do { - getlin(Deaf ? "You are required to sign in with your name. -" : + getlin(Deaf ? "You are required to supply your name. -" : "\"Hello stranger, who are you?\" -", buf); (void) mungspaces(buf); } while (!buf[0] && --trycount > 0); From 9fae6217786305dd4c5fdd7961c9f4674fdac625 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 7 Jan 2016 01:53:06 -0800 Subject: [PATCH 03/26] fix #H4181 - strange death messages "Petrified by , while getting stoned." -- multi_reason "while getting stoned" explains why no last-second recovery could be made, but doesn't explain how the petrification happened, so suppress it. "Died of starvation, while fainted from lack of food." -- nethack does not display this; presumeably the IRC death notices for NAO are generated from xlogfile entries. Change 'while fainted from lack of food' to 'while fainted' at time of death if reason for death is starvation. The longer version is accurate but sounds fairly silly. When starvation is set in motion, set it up before checking whether the initial faint triggers falling on a wielded cockatrice corpse, so that fainting isn't applied after recovery in case of life-saving. --- doc/fixes36.1 | 1 + src/eat.c | 4 ++-- src/end.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 12386fc24..b2c3197ca 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -88,6 +88,7 @@ make mimics mimicing walls or trees also block light stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact fix death reason when eating tainted glob of (not corpse) +fix death reason when petrified (avoid redundant 'while getting stoned') use appropriate place name for drum of earthquake shakes fix unmapped branch stairs on sokoban level redraw map when hilite_pile is toggled to display the highlighting diff --git a/src/eat.c b/src/eat.c index 7591b9cc3..13a394405 100644 --- a/src/eat.c +++ b/src/eat.c @@ -2838,14 +2838,14 @@ boolean incr; /* stop what you're doing, then faint */ stop_occupation(); You("faint from lack of food."); - if (!Levitation) - selftouch("Falling, you"); incr_itimeout(&HDeaf, duration); nomul(-duration); multi_reason = "fainted from lack of food"; nomovemsg = "You regain consciousness."; afternmv = unfaint; newhs = FAINTED; + if (!Levitation) + selftouch("Falling, you"); } } else if (u.uhunger < -(int) (200 + 20 * ACURR(A_CON))) { u.uhs = STARVED; diff --git a/src/end.c b/src/end.c index 5e5231856..7e53467e7 100644 --- a/src/end.c +++ b/src/end.c @@ -503,6 +503,42 @@ int how; return; } +/* some special cases for overriding while-helpless reason */ +static const struct { + int why, unmulti; + const char *exclude, *include; +} death_fixups[] = { + /* "petrified by , while getting stoned" -- "while getting stoned" + prevented any last-second recovery, but it was not the cause of + "petrified by " */ + { STONING, 1, "getting stoned", (char *) 0 }, + /* "died of starvation, while fainted from lack of food" is accurate + but sounds a fairly silly (and doesn't actually appear unless you + splice together death and while-helpless from xlogfile) */ + { STARVING, 0, "fainted from lack of food", "fainted" }, +}; + +/* clear away while-helpless when the cause of death caused that + helplessness (ie, "petrified by while getting stoned") */ +STATIC_DCL void +fixup_death(how) +int how; +{ + int i; + + for (i = 0; i < SIZE(death_fixups); ++i) + if (death_fixups[i].why == how + && !strcmp(death_fixups[i].exclude, multi_reason)) { + if (death_fixups[i].include) /* substitute an alternate reason */ + multi_reason = death_fixups[i].include; + else /* remove the helplessness reason */ + multi_reason = (char *) 0; + if (death_fixups[i].unmulti) /* possibly hide helplessness */ + multi = 0L; + break; + } +} + #if defined(WIN32) && !defined(SYSCF) #define NOTIFY_NETHACK_BUGS #endif @@ -1002,6 +1038,8 @@ int how; if (how == ESCAPED || how == PANICKED) killer.format = NO_KILLER_PREFIX; + fixup_death(how); /* actually, fixup multi_reason */ + if (how != PANICKED) { /* these affect score and/or bones, but avoid them during panic */ taken = paybill((how == ESCAPED) ? -1 : (how != QUIT)); From 8aa0d9e2cc04ca2730156a1ca903ad94e328c3a4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 7 Jan 2016 07:46:20 -0500 Subject: [PATCH 04/26] typo spotted --- doc/fixes36.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index b2c3197ca..a56b969b1 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -107,7 +107,7 @@ tty: M-N gave "Unknown command 'M-" with "'." finishing the sentence on the line below it, leaving bogus '.' displayed on the top row of the map tty: specifying all four of role, race, gender, and alignment still prompted for confirmation with "Is this ok?" before starting play -tty: responding with or duing role, race, &c selection +tty: responding with or during role, race, &c selection behaved same as to quit; now it will pick [random] instead unix/X11: in top level Makefile, some commented out definitions of VARDATND misspelled pilemark.xbm (as pilemark.xpm) From 0f5809c9248dce94fb598effaa48c2825245595a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 7 Jan 2016 22:38:33 +0200 Subject: [PATCH 05/26] Add some new database entries --- dat/data.base | 35 ++++++++++++++++++++++++++++++++--- doc/fixes36.1 | 2 ++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/dat/data.base b/dat/data.base index 960932c18..ed7674819 100644 --- a/dat/data.base +++ b/dat/data.base @@ -890,6 +890,12 @@ tiamat extremely vain. citrine* A pale yellow variety of crystalline quartz resembling topaz. +cleaver + Hither came Conan, the Cimmerian, black-haired, sullen-eyed, + sword in hand, a thief, a reaver, a slayer, with gigantic + melancholies and gigantic mirth, to tread the jeweled + thrones of the Earth under his sandalled feet. + [ The Phoenix on the Sword, by Robert E. Howard ] ~elven cloak ~oilskin cloak *cloak* @@ -1645,9 +1651,16 @@ fire trap _anywhere_?' [ The Last Hero, by Terry Pratchett ] f* brand - One of a pair of legendary swords that possess the powers - of elemental flame and ice, and will grant these to whoever - is fortunate enough to wield them. + Some say the world will end in fire, + Some say in ice. + From what I’ve tasted of desire + I hold with those who favor fire. + But if it had to perish twice, + I think I know enough of hate + To say that for destruction ice + Is also great + And would suffice. + [ Fire and Ice, by Robert Frost ] flesh golem With an anxiety that almost amounted to agony, I collected the instruments of life around me, that I might infuse a spark @@ -3920,6 +3933,17 @@ user Might just kill you. [ It's a Jungle Out There, by Randy Newman ] # [ theme song from "Monk" ] +polymorph trap + One morning, as Gregor Samsa was waking up from anxious dreams, + he discovered that in bed he had been changed into a monstrous + verminous bug. He lay on his armour-hard back and saw, as he + lifted his head up a little, his brown, arched abdomen divided + up into rigid bow-like sections. From this height the blanket, + just about ready to slide off completely, could hardly stay in + place. His numerous legs, pitifully thin in comparison to the + rest of his circumference, flickered helplessly before his eyes. + [ The Metamorphosis, by Franz Kafka, + translated by Ian Johnston ] pony Hey! now! Come hoy now! Whither do you wander? Up, down, near or far, here, there or yonder? @@ -4853,6 +4877,11 @@ straw golem figure was raised above the stalks of corn by means of the pole stuck up its back. [ The Wonderful Wizard of Oz, by L. Frank Baum ] +sunsword + What you seek is a blade of light, + a weapon for vengeance. + [ Expedition to Castle Ravenloft, + by Bruce Cordell and James Wyatt ] susano*o The Shinto chthonic and weather god and brother of the sun goddess Amaterasu, he was born from the nose of the diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a56b969b1..7e29a0101 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -144,6 +144,8 @@ wizard mode #wizintrinsic command additional tribute passages for The Colour of Magic, The Light Fantastic, Equal Rites, Snuff, and Raising Steam compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use +database entries for Cleaver, Sunsword, Frost and Fire brands, and + polymorph trap Platform- and/or Interface-Specific New Features From f16e9a88903c76d731030f93703b0dc2802468f6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 8 Jan 2016 07:55:56 +0200 Subject: [PATCH 06/26] Use plain ASCII for the database --- dat/data.base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dat/data.base b/dat/data.base index ed7674819..50152f2c1 100644 --- a/dat/data.base +++ b/dat/data.base @@ -1653,7 +1653,7 @@ fire trap f* brand Some say the world will end in fire, Some say in ice. - From what I’ve tasted of desire + From what I've tasted of desire I hold with those who favor fire. But if it had to perish twice, I think I know enough of hate From db234f743d99a770443174f2f7e74074305b9327 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 8 Jan 2016 00:38:34 -0800 Subject: [PATCH 07/26] integrate 'msgtype' option and Norep() Allow 'msgtype=show' for messages that nethack uses Norep() for. I don't know whether anyone will ever want to do that, but if felt strange to have two different message suppression mechanisms that were completely disconnected from each other. For a user with no msgtype filter, there'll be no difference in behavior. --- include/extern.h | 2 +- src/options.c | 5 +++-- src/pline.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/extern.h b/include/extern.h index 3e58ee565..70ce04b31 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1662,7 +1662,7 @@ E boolean FDECL(add_menu_coloring, (char *)); E boolean FDECL(get_menu_coloring, (char *, int *, int *)); E void NDECL(free_menu_coloring); E boolean FDECL(msgtype_parse_add, (char *)); -E int FDECL(msgtype_type, (const char *)); +E int FDECL(msgtype_type, (const char *, BOOLEAN_P)); E void NDECL(msgtype_free); /* ### pager.c ### */ diff --git a/src/options.c b/src/options.c index 11a26c074..f706d2c0a 100644 --- a/src/options.c +++ b/src/options.c @@ -1455,8 +1455,9 @@ int idx; /* 0 .. */ } int -msgtype_type(msg) +msgtype_type(msg, norepeat) const char *msg; +boolean norepeat; /* called from Norep(via pline) */ { struct plinemsg_type *tmp = plinemsg_types; @@ -1465,7 +1466,7 @@ const char *msg; return tmp->msgtype; tmp = tmp->next; } - return MSGTYP_NORMAL; + return norepeat ? MSGTYP_NOREP : MSGTYP_NORMAL; } int diff --git a/src/pline.c b/src/pline.c index ce4b60702..4ada9bff7 100644 --- a/src/pline.c +++ b/src/pline.c @@ -83,22 +83,22 @@ VA_DECL(const char *, line) iflags.last_msg = PLNMSG_UNKNOWN; return; } -#ifndef MAC - if (no_repeat && !strcmp(line, toplines)) + + msgtyp = msgtype_type(line, no_repeat); + if (msgtyp == MSGTYP_NOSHOW + || (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg))) return; -#endif /* MAC */ if (vision_full_recalc) vision_recalc(0); if (u.ux) flush_screen(1); /* %% */ - msgtyp = msgtype_type(line); - if (msgtyp == MSGTYP_NOSHOW) return; - if (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg)) return; + putstr(WIN_MESSAGE, 0, line); /* this gets cleared after every pline message */ iflags.last_msg = PLNMSG_UNKNOWN; - strncpy(prevmsg, line, BUFSZ); - if (msgtyp == MSGTYP_STOP) display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */ + strncpy(prevmsg, line, BUFSZ), prevmsg[BUFSZ - 1] = '\0'; + if (msgtyp == MSGTYP_STOP) + display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */ #if !(defined(USE_STDARG) || defined(USE_VARARGS)) /* provide closing brace for the nested block From befc6a65b50068b46e44f2f1139d71d8e7c81d67 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 8 Jan 2016 22:17:37 +0200 Subject: [PATCH 08/26] TTY: Add menu_overlay option This was a request from a blind player. It's hard to find the left edge of the menu when it's drawn on the map, so clear the screen and align menus to the left edge of the screen when this option is turned off. Originally this was called the window edge patch. --- dat/opthelp | 1 + doc/Guidebook.mn | 4 ++++ doc/Guidebook.tex | 4 ++++ doc/fixes36.1 | 1 + include/flag.h | 1 + src/options.c | 5 +++++ win/tty/wintty.c | 8 +++++--- 7 files changed, 21 insertions(+), 3 deletions(-) diff --git a/dat/opthelp b/dat/opthelp index c378e618c..60531aae5 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -22,6 +22,7 @@ implicit_uncursed omit "uncursed" from inventory, if possible [TRUE] legacy print introductory message [TRUE] lit_corridor show a dark corridor as lit if in sight [FALSE] lootabc use a/b/c rather than o/i/b when looting [FALSE] +menu_overlay overlay menus on the screen and align to right [TRUE] mail enable the mail daemon [TRUE] null allow nulls to be sent to your terminal [TRUE] try turning this option off (forcing NetHack to use its own diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 2efd8bbf2..aa06e40c4 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -2218,6 +2218,10 @@ Default '>'. .lp menu_objsyms Show object symbols in menu headings in menus where the object symbols act as menu accelerators (default off). +.lp menu_overlay +Do not clear the screen before drawing menus, and align +menus to the right edge of the screen. Only for the tty port. +(default on) .lp menu_previous_page Menu character accelerator to goto the previous menu page. Implemented by the Amiga, Gem and tty ports. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index cbb63f7a0..849476ef2 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -2664,6 +2664,10 @@ Default `\verb+>+'. \item[\ib{menu\verb+_+objsyms}] Show object symbols in menu headings in menus where the object symbols act as menu accelerators (default off). +\item[\ib{menu\verb+_+overlay}] +Do not clear the screen before drawing menus, and align +menus to the right edge of the screen. Only for the tty port. +(default on) \item[\ib{menu\verb+_+previous\verb+_+page}] Menu character accelerator to goto the previous menu page. Implemented by the Amiga, Gem and tty ports. diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 7e29a0101..a58c4c95e 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -150,6 +150,7 @@ database entries for Cleaver, Sunsword, Frost and Fire brands, and Platform- and/or Interface-Specific New Features ------------------------------------------------ +tty: menu_overlay -option to clear screen and align menus to left NetHack Community Patches (or Variation) Included diff --git a/include/flag.h b/include/flag.h index bd6d2b2fc..a55591a13 100644 --- a/include/flag.h +++ b/include/flag.h @@ -199,6 +199,7 @@ struct instance_flags { boolean mention_walls; /* give feedback when bumping walls */ boolean menu_tab_sep; /* Use tabs to separate option menu fields */ boolean menu_head_objsym; /* Show obj symbol in menu headings */ + boolean menu_overlay; /* Draw menus over the map */ boolean menu_requested; /* Flag for overloaded use of 'm' prefix * on some non-move commands */ boolean renameallowed; /* can change hero name during role selection */ diff --git a/src/options.c b/src/options.c index f706d2c0a..0e5332038 100644 --- a/src/options.c +++ b/src/options.c @@ -149,6 +149,11 @@ static struct Bool_Opt { /* for menu debugging only*/ { "menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_WIZGAME }, { "menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME }, +#ifdef TTY_GRAPHICS + { "menu_overlay", &iflags.menu_overlay, TRUE, SET_IN_GAME }, +#else + { "menu_overlay", (boolean *) 0, FALSE, SET_IN_FILE }, +#endif { "mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME }, /*WC*/ #ifdef NEWS { "news", &iflags.news, TRUE, DISP_IN_GAME }, diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 58dee65a3..0690f8e24 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -2108,13 +2108,15 @@ boolean blocking; /* with ttys, all windows are blocking */ if (ttyDisplay->toplin == 1) tty_display_nhwindow(WIN_MESSAGE, TRUE); #ifdef H2344_BROKEN - if (cw->maxrow >= (int) ttyDisplay->rows) + if (cw->maxrow >= (int) ttyDisplay->rows + || !iflags.menu_overlay) #else - if (cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows) + if (cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows + || !iflags.menu_overlay) #endif { cw->offx = 0; - if (cw->offy) { + if (cw->offy || iflags.menu_overlay) { tty_curs(window, 1, 0); cl_eos(); } else From a2a1027be17b9af94899f4be58da3f31a15e4d12 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 9 Jan 2016 02:19:29 +0200 Subject: [PATCH 09/26] Fix bz62: Pets walk into poison clouds Makes monsters who would be damaged by the poison cloud not walk into it --- doc/fixes36.1 | 1 + src/mon.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a58c4c95e..936bce369 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -99,6 +99,7 @@ fix weight of containers in special levels make the raven medusa level shortsighted fix possible segfault in lev_comp when map was too tall fix "the ice is bridged with ice" when freezing castle's moat or Medusa's sea +make monsters and pets avoid poison gas clouds if it would damage them Platform- and/or Interface-Specific Fixes diff --git a/src/mon.c b/src/mon.c index 08333c250..5978f1c20 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1172,6 +1172,9 @@ long flag; boolean wantpool, poolok, lavaok, nodiag; boolean rockok = FALSE, treeok = FALSE, thrudoor; int maxx, maxy; + boolean poisongas_ok, in_poisongas; + NhRegion *gas_reg; + int gas_glyph = cmap_to_glyph(S_poisoncloud); x = mon->mx; y = mon->my; @@ -1183,6 +1186,11 @@ long flag; || (is_swimmer(mdat) && !wantpool)); lavaok = (is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat)); thrudoor = ((flag & (ALLOW_WALL | BUSTDOOR)) != 0L); + poisongas_ok = ((nonliving(mdat) || is_vampshifter(mon) + || breathless(mdat)) || resists_poison(mon)); + in_poisongas = ((gas_reg = visible_region_at(x,y)) != 0 + && gas_reg->glyph == gas_glyph); + if (flag & ALLOW_DIG) { struct obj *mw_tmp; @@ -1231,6 +1239,11 @@ nexttry: /* eels prefer the water, but if there is no water nearby, || ((levl[nx][ny].doormask & D_LOCKED) && !(flag & UNLOCKDOOR))) && !thrudoor) continue; + /* avoid poison gas? */ + if (!poisongas_ok && !in_poisongas + && (gas_reg = visible_region_at(nx,ny)) != 0 + && gas_reg->glyph == gas_glyph) + continue; /* first diagonal checks (tight squeezes handled below) */ if (nx != x && ny != y && (nodiag From ff4a59ef23c7462b190fca1c1ff952edd65aa11e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 9 Jan 2016 12:06:50 +0200 Subject: [PATCH 10/26] Fix bz258: Covetous monsters malfunction when there are no upstairs Make the monsters pick downstairs/ladders if the branch builds up (like Sokoban), otherwise try upstairs/ladders. --- src/wizard.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/wizard.c b/src/wizard.c index facacc799..830aa0a60 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -306,11 +306,49 @@ register struct monst *mtmp; return dstrat; } +void +choose_stairs(sx, sy) +xchar *sx; +xchar *sy; +{ + xchar x = 0, y = 0; + + if (builds_up(&u.uz)) { + if (xdnstair) { + x = xdnstair; + y = ydnstair; + } else if (xdnladder) { + x = xdnladder; + y = ydnladder; + } + } else { + if (xupstair) { + x = xupstair; + y = yupstair; + } else if (xupladder) { + x = xupladder; + y = yupladder; + } + } + + if (!x && sstairs.sx) { + x = sstairs.sx; + y = sstairs.sy; + } + + if (x && y) { + *sx = x; + *sy = y; + } + +} + int tactics(mtmp) register struct monst *mtmp; { unsigned long strat = strategy(mtmp); + xchar sx, sy; mtmp->mstrategy = (mtmp->mstrategy & (STRAT_WAITMASK | STRAT_APPEARMSG)) | strat; @@ -318,15 +356,14 @@ register struct monst *mtmp; switch (strat) { case STRAT_HEAL: /* hide and recover */ /* if wounded, hole up on or near the stairs (to block them) */ - /* unless, of course, there are no stairs (e.g. endlevel) */ + choose_stairs(&sx, &sy); mtmp->mavenge = 1; /* covetous monsters attack while fleeing */ if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) - || (mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) { + || (mtmp->iswiz && !sx && !mon_has_amulet(mtmp))) { if (!rn2(3 + mtmp->mhp / 10)) (void) rloc(mtmp, TRUE); - } else if (xupstair - && (mtmp->mx != xupstair || mtmp->my != yupstair)) { - (void) mnearto(mtmp, xupstair, yupstair, TRUE); + } else if (sx && (mtmp->mx != sx || mtmp->my != sy)) { + (void) mnearto(mtmp, sx, sy, TRUE); } /* if you're not around, cast healing spells */ if (distu(mtmp->mx, mtmp->my) > (BOLT_LIM * BOLT_LIM)) From 7e4e9f263a4e5d182553ee96668311b391fdeb8d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 9 Jan 2016 13:16:43 +0200 Subject: [PATCH 11/26] Update fixes --- doc/fixes36.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 936bce369..9149325ef 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -100,6 +100,7 @@ make the raven medusa level shortsighted fix possible segfault in lev_comp when map was too tall fix "the ice is bridged with ice" when freezing castle's moat or Medusa's sea make monsters and pets avoid poison gas clouds if it would damage them +covetous monsters may choose to teleport to downstairs or ladders Platform- and/or Interface-Specific Fixes From 1e1557ed46466bbcad5f1b1e1dde48f4c5be9fcd Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 9 Jan 2016 13:39:45 +0200 Subject: [PATCH 12/26] Add extended command #kick I've seen some complaints about not being able to kick with ^d so add kick as an extended command. Also add the missing #exploremode command to the Guidebook. --- doc/Guidebook.mn | 4 ++++ doc/Guidebook.tex | 6 ++++++ src/cmd.c | 1 + 3 files changed, 11 insertions(+) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index aa06e40c4..2d73781f5 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -860,12 +860,16 @@ See the section below entitled ``Conduct'' for details. Dip an object into something. .lp #enhance Advance or check weapon and spell skills. +.lp #exploremode +Enter the explore mode. .lp #force Force a lock. .lp #invoke Invoke an object's special powers. .lp #jump Jump to another location. +.lp #kick +Kick something. .lp #loot Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 849476ef2..53716a2a9 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -1042,6 +1042,9 @@ Dip an object into something. \item[\tb{\#enhance}] Advance or check weapon and spell skills. %.lp +\item[\tb{\#exploremode}] +Enter the explore mode. +%.lp \item[\tb{\#force}] Force a lock. %.lp @@ -1051,6 +1054,9 @@ Invoke an object's special powers. \item[\tb{\#jump}] Jump to another location. %.lp +\item[\tb{\#kick}] +Kick something. +%.lp \item[\tb{\#loot}] Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. diff --git a/src/cmd.c b/src/cmd.c index 162234a76..1b389f722 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -2777,6 +2777,7 @@ struct ext_func_tab extcmdlist[] = { { "force", "force a lock", doforce, FALSE }, { "invoke", "invoke an object's powers", doinvoke, TRUE }, { "jump", "jump to a location", dojump, FALSE }, + { "kick", "kick something", dokick, FALSE }, { "loot", "loot a box on the floor", doloot, FALSE }, { "monster", "use a monster's special ability", domonability, TRUE }, { "name", "name a monster or an object", docallcmd, TRUE }, From 7e3f82ed3ca07ec8a2d56068eb01b330ca9b857f Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 9 Jan 2016 13:57:15 -0800 Subject: [PATCH 13/26] fix #H4187 - doppelgangers posing as Riders... ... never transform and can leave Rider corpses Riders can't be polymorphed, and the code to prevent that was also preventing doppelgangers in Rider form from changing shape. Using ring of protection from shape changers effectively turned such doppelgangers into actual Riders which would leave self-reviving corpses. That didn't prevent Riders from appearing on the Astral Plane though. --- doc/fixes36.1 | 3 +++ src/mon.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 9149325ef..49dc28c48 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -101,6 +101,9 @@ fix possible segfault in lev_comp when map was too tall fix "the ice is bridged with ice" when freezing castle's moat or Medusa's sea make monsters and pets avoid poison gas clouds if it would damage them covetous monsters may choose to teleport to downstairs or ladders +doppelganger posing as Rider would never change shape +since doppelganger posing as Rider could never revert to innate form, + protection from shape changers turned it into genuine Rider Platform- and/or Interface-Specific Fixes diff --git a/src/mon.c b/src/mon.c index 5978f1c20..802d20bff 100644 --- a/src/mon.c +++ b/src/mon.c @@ -3157,8 +3157,9 @@ boolean msg; /* "The oldmon turns into a newmon!" */ struct permonst *olddata = mtmp->data; char oldname[BUFSZ], l_oldname[BUFSZ], newname[BUFSZ]; - /* Riders are immune to polymorph and green slime */ - if (is_rider(mtmp->data)) + /* Riders are immune to polymorph and green slime + (but apparent Rider might actually be a doppelganger) */ + if (is_rider(mtmp->data) && mtmp->cham == NON_PM) return 0; if (msg) { From 3a8ce3ff981bca3e60135c0fe94e33b9175dda3c Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 9 Jan 2016 15:28:25 -0800 Subject: [PATCH 14/26] fix #H4083 - globs preID'd as "uncursed" I think there was also a report about this during beta testing. Killing an ooze, slime, or pudding left a glob of same which had its bknown flag pre-set so was immediately shown as "uncursed" even to non-priests. Use another way to maximize glob mergability: allow globs to merge even when one has bknown set and the other doesn't. --- doc/fixes36.1 | 4 ++++ src/invent.c | 35 +++++++++++++++++++++++++++-------- src/mkobj.c | 8 +++----- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 49dc28c48..174c21b95 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -104,6 +104,10 @@ covetous monsters may choose to teleport to downstairs or ladders doppelganger posing as Rider would never change shape since doppelganger posing as Rider could never revert to innate form, protection from shape changers turned it into genuine Rider +don't create globs of ooze/slime/pudding with bknown flag set so pre-known to + be "uncursed" +do allow globs with same curse/bless state to merge even when that state is + known for one and unknown for the other; result will have bknown clear Platform- and/or Interface-Specific Fixes diff --git a/src/invent.c b/src/invent.c index a79c7d46b..94ae77d7c 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2880,24 +2880,46 @@ mergable(otmp, obj) register struct obj *otmp, *obj; { int objnamelth = 0, otmpnamelth = 0; + if (obj == otmp) return FALSE; /* already the same object */ if (obj->otyp != otmp->otyp) + return FALSE; /* different types */ + if (obj->nomerge) /* explicitly marked to prevent merge */ return FALSE; + /* coins of the same kind will always merge */ if (obj->oclass == COIN_CLASS) return TRUE; + if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe || obj->dknown != otmp->dknown - || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit - || obj->greased != otmp->greased || obj->oeroded != otmp->oeroded - || obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass) + || obj->bypass != otmp->bypass) return FALSE; - if (obj->nomerge) /* explicitly marked to prevent merge */ + if (obj->oclass == FOOD_CLASS + && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten)) + return FALSE; + + if (obj->globby) { + /* globs won't merge if they have different bless/curse + state, but will merge non-bknown with bknown */ + if (obj->bknown != otmp->bknown) + obj->bknown = otmp->bknown = 0; + if (obj->rknown != otmp->rknown) + obj->rknown = otmp->rknown = 0; + if (obj->greased != otmp->greased) + obj->greased = otmp->greased = 0; + /* checks beyond this point aren't applicable to globs */ + return TRUE; + } + + if ((obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) + || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2 + || obj->greased != otmp->greased) return FALSE; if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS) @@ -2905,10 +2927,6 @@ register struct obj *otmp, *obj; || obj->rknown != otmp->rknown)) return FALSE; - if (obj->oclass == FOOD_CLASS - && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten)) - return FALSE; - if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) { if (obj->corpsenm != otmp->corpsenm) return FALSE; @@ -3413,6 +3431,7 @@ doorganize() /* inventory organizer by Del Lamb */ names, strip off the name of the one being moved */ if (olth && !obj->oartifact && !mergable(otmp, obj)) { char *holdname = ONAME(obj); + ONAME(obj) = (char *) 0; /* restore name iff merging is still not possible */ if (!mergable(otmp, obj)) { diff --git a/src/mkobj.c b/src/mkobj.c index 9a1023117..a6f8bfd29 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -819,11 +819,9 @@ boolean artif; } if (Is_pudding(otmp)) { otmp->globby = 1; - otmp->known = otmp->bknown = otmp->rknown = otmp->dknown = 1; - otmp->corpsenm = - PM_GRAY_OOZE + (otmp->otyp - GLOB_OF_GRAY_OOZE); - /* this ensures that they don't fail merging because of - * BUC status or other irrelevancies */ + otmp->known = otmp->dknown = 1; + otmp->corpsenm = PM_GRAY_OOZE + + (otmp->otyp - GLOB_OF_GRAY_OOZE); } else { if (otmp->otyp != CORPSE && otmp->otyp != MEAT_RING && otmp->otyp != KELP_FROND && !rn2(6)) { From e1f8deb63fe93adad16df8e04dac6acd64899b27 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 9 Jan 2016 18:17:15 -0800 Subject: [PATCH 15/26] tribute: Mort --- dat/tribute | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 262 insertions(+), 6 deletions(-) diff --git a/dat/tribute b/dat/tribute index 53cfbd985..462e4743e 100644 --- a/dat/tribute +++ b/dat/tribute @@ -800,11 +800,260 @@ shelves, but not to prevent them being stolen.... # # # -%title Mort (1) +%title Mort (11) +# p. 136 (Signet edition; passage is a footnote; +# Vetinari doesn't show up as recurring Patrician until /Sourcery/) %passage 1 -Ankh-Morpork had dallied with many forms of government and hand ended up - with that form of democracy known as One Man, One Vote. The Patrician was -the Man; he had the Vote. +Ankh-Morpork had dallied with many forms of government and had ended up +with that form of democracy known as One Man, One Vote. The Patrician was +the Man; he had the Vote. + + [Mort, by Terry Pratchett] +%e passage +# p. 11 +%passage 2 +Mort was getting interested in the rock. It had curly shells in it, relics +of the early days of the world when the Creator had made creatures out of +stone, no-one knew why. + +Mort was interested in lots of things. Why people's teeth fitted together +so neatly, for example. He'd given that one a lot of thought. Then there +was the puzzle of why the sun came out during the day, instead of at night +when the light would come in useful. He knew the standard explanation, +which somehow didn't seem satisfying. + +In short, Mort is one of those people who are more dangerous than a bag +full of rattlesnakes. He was determined to discover the underlying logic +behind the universe. + +Which was going to be hard, because there wasn't one. The Creator had a +lot of remarkably good ideas when he put the world together, but making it +understandable hadn't been one of them. + + [Mort, by Terry Pratchett] +%e passage +# p. 18 +%passage 3 +"But you're Death," said Mort. "You go around killing people!" + +I? KILL? said Death, obviously offended. CERTAINLY NOT. PEOPLE /GET/ +KILLED, BUT THAT'S THEIR BUSINESS. I JUST TAKE OVER FROM THEN ON. AFTER +ALL, IT'D BE A BLOODY STUPID WORLD IF PEOPLE GOT KILLED WITHOUT DYING, +WOULDN'T IT? + + [Mort, by Terry Pratchett] +%e passage +# p. 25 +%passage 4 +"Is it magic?" said Mort. + +WHAT DO YOU THINK? said Death. AM I REALLY HERE, BOY? + +"Yes," said Mort slowly. "I... I've watched people. They look at you but +the don't see you, I think. You do something to their minds." + +Death shook his head. + +THEY DO IT ALL THEMSELVES, he said. THERE'S NO MAGIC. PEOPLE CAN'T SEE ME, +THEY SIMPLY WON'T ALLOW THEMSELVES TO DO IT. UNTIL IT'S TIME, OF COURSE. +WIZARDS CAN SEE ME, AND CATS. BUT YOUR AVERAGE HUMAN... NO, NEVER. He blew +a smoke ring at the sky, and added, STRANGE BUT TRUE. + + [Mort, by Terry Pratchett] +%e passage +# pp. 48-49 (Binky is Death's white horse, who was left 'parked' on a +# castle's roof; Mort is Death's novice apprentice) +%passage 5 +They were on the roof before he spoke again. + +YOU TRIED TO WARN HIM, he said, removing Binky's nosebag. + +"Yes, sir. Sorry." + +YOU CANNOT INTERFERE WITH FATE. WHO ARE YOU TO JUDGE WHO SHOULD LIVE AND +WHO SHOULD DIE? + +Death watched Mort's expression carefully. + +ONLY THE GODS ARE ALLOWED TO DO THAT, he added. TO TINKER WITH THE FATE OF +EVEN ONE INDIVIDUAL COULD DESTROY THE WHOLE WORLD. DO YOU UNDERSTAND? + +Mort nodded miserably. + +"Are you going to send me home?" he said. + +Death reached down and swung him up behind the saddle. + +BECAUSE YOU SHOWED COMPASSION? NO. I MIGHT HAVE DONE IF YOU HAD SHOWN +PLEASURE. BUT YOU MUST LEARN THE COMPASSION PROPER TO YOUR TRADE. + +"What's that?" + +A /SHARP/ EDGE. + + [Mort, by Terry Pratchett] +%e passage +# pp. 59-61 (in Ankh-Morpork, Mort has accidentally walked through a wall +# into an immigrant Klatchian family's dining room; 'the creature +# who was not there' refers to Death during an earlier event) +%passage 6 +"I'm no demon! I'm a human!" he said, and stopped in shock as his words +emerged in perfect Klatch. + +"You're a thief?" said the father. "A murderer? To creep in thus, are you +a /tax-gatherer/?" His hand slipped under the table and came up holding a +meat cleaver honed to paper thinness. His wife screamed and dropped the +plate and clutched the youngest children to her. + +Mort watched the blade weave through the air, and gave in. + +"I bring you greetings from the uttermost circles of hell," he hazarded. + +The change was remarkable. The cleaver was lowered and the family broke +into broad smiles. + +"There is much luck to us if a demon visits," beamed the father. "What is +your wish, O foul spawn of Offler's loins?" + +"Sorry?" said Mort. + +"A demon brings blessing and good fortune on the man that helps it," said +the man. "How may we be of assistance, O evil dogsbreath of the nether +pit?" + +"Well, I'm not very hungry," said Mort, "but if you know where I can get a +fast horse, I could be in Sto Lat before sunset." + +The man beamed and bowed. "I know the very place, noxious extrusion of the +bowels, if you would be so good as to follow me." + +Mort hurried out after him. The ancient ancestor watched them go with a +critical expression, its jowls rhymically chewing. + +"That was what they call a demon around here?" it said. "Offler rot this +country of dampness, even their demons are third-rate, not a patch on the +demons we had in the Old Country." + +The wife placed a small bowl of rice in the folded middle pair of hands of +the Offler statue (it would be gone in the morning) and stood back. + +"Husband did say that last month at the /Curry Gardens/ he served a creature +who was not there," she said. "He was impressed." + +Ten minutes later the man returned and, in solemn silence, placed a small +heap of gold coins on the table. They represented enough wealth to +purchase quite a large part of the city. + +"He had a bag of them," he said. + +The family stared at the money for some time. The wife sighed. + +"Riches bring many problems," she said. "What are we to do?" + +"We return to Klatch," said the husband firmly, "where our children can grow +up in a proper country, true to the glorious traditions of our ancient race +and men do not need to work as waiters for wicked masters but can stand tall +and proud. And we must leave right now, fragrant blossom of the date palm." + +"Why so soon, O hard-working son of the desert?" + +"Because," said the man, "I have just sold the Patrician's champion +racehorse." + + [Mort, by Terry Pratchett] +%e passage +# p. 139-140 (passage ends mid-sentence) +%passage 7 +"You don't know much about monarchy, do you?" said Keli. + +"Um, no?" + +"She means better to be a dead queen in your own castle than a live +commoner somewhere else," said Cutwell, [...] + + [Mort, by Terry Pratchett] +%e passage +# p. 158 +%passage 8 +"You mean you won't help?" said Mort. "Not even if you can?" + +"Give the boy a prize," growled Albert. "And it's no good thinking you can +appeal to my better nature under this here crusty exterior," he added, +"'cos my interior's pretty damn crusty too." + + [Mort, by Terry Pratchett] +%e passage +# p. 159-160 (Death has come to an employment agency--a new concept in +# Ankh-Morpork--looking for a job) +%passage 9 +"And what was your previous position?" + +I BEG YOUR PARDON? + +"What did you do for a living?" said the thin young man behind the desk. + +I USHERED SOULS INTO THE NEXT WORLD. I WAS THE GRAVE OF ALL HOPE. I WAS +THE ULTIMATE REALITY. I WAS THE ASSASSIN AGAINST WHOM NO LOCK WOULD HOLD. + +"Yes, point taken, but do you have any particular skills?" + +I SUPPOSE A CERTAIN AMOUNT OF EXPERTISE WITH AGRICULTURAL IMPLEMENTS? he +ventured after a while. + +The young man shook his head firmly. + +NO? + + [Mort, by Terry Pratchett] +%e passage +# p. 205 +%passage 10 +Death raised his skull and sniffed the air. + +The sound cut through all the other noises in the hall and forced them +into silence. + +It is the kind of noise that is heard on the twilight edges of dreams, +the sort that you wake from in the cold sweat of mortal horror. It was +the snuffling under the door of dread. It was like the snuffling of a +hedgehog, but if so then it was the kind of hedgehog that crashes out of +the verges and flattens lorries. It was the kind of noise you wouldn't +want to hear twice; you wouldn't want to hear it /once/. + + [Mort, by Terry Pratchett] +%e passage +# p. 207 +%passage 11 +"Well, that was a lesson to all of us," the bursar continued, brushing dust +and candle wax off his robe. He looked up, expecting to see the statue of +Alberto Malich back on its pedestal. + +"Clearly even statues have feelings," he said. "I myself recall, when I +was but a first-year student, writing my name on his... well, never mind. +The point is, I propose here and now we replace the statue." + +Dead silence greeted this suggestion. + +"With, say, an exact likeness cast in gold. Suitably embellished with +jewels, as befits our great founder," he went on brightly. + +"And to make sure no students deface it in any way I suggest we then erect +it in the deepest cellar," he continued. + +"And then lock the door," he added. Several wizards began to cheer up. + +"And throw away the key?" said Rincewind. + +"And /weld/ the door," the bursar said. He had just remembered about The +Mended Drum. He thought for a while and remembered about the physical +fitness regime as well. + +"And then brick up the doorway," he said. There was a round of applause. + +"And throw away the brick layer!" chortled Rincewind, who felt he was +getting the hang of this. + +The bursar scowled at him. "No need to get carried away," he said. [Mort, by Terry Pratchett] %e passage @@ -6390,7 +6639,7 @@ IF YOU ASK ME, said Death, NOBODY COULD DO ANY BETTER THAN THAT... # Used for interaction with Death. # %section Death -%title Death Quotes (17) +%title Death Quotes (19) %passage 1 WHERE THE FIRST PRIMAL CELL WAS, THERE WAS I ALSO. WHERE MAN IS, THERE AM I. WHEN THE LAST LIFE CRAWLS UNDER FREEZING STARS, THERE WILL I BE. %e passage @@ -6443,7 +6692,8 @@ I HAVE COME FOR THEE. # including them here wouldn't fit with the rest) %passage 14 DARK IN HERE, ISN'T IT? -# p. 14 (Equal Rites; 2nd sentence continues 'said the deep, heavy voice...') +# Equal Rites, p. 14 (Signet edition; second sentence continues +# 'said the deep, heavy voice...') %passage 15 THERE IS NO GOING BACK. THERE IS NO GOING BACK. # p. 15 (contradicts later descriptions of Death as existing outside of time; @@ -6453,6 +6703,12 @@ I HAVEN'T GOT ALL DAY, YOU KNOW. # p. 15 (same page) %passage 17 LIFE IS FOR THE LIVING. +# Mort, p. 148 (Signet edition) +%passage 18 +NO-ONE EVER WANTED TO TALK TO ME BEFORE. +# p. 149 +%passage 19 +I HAVEN'T GOT A SINGLE FRIEND. EVEN CATS FIND ME AMUSING. %e title %e section # From 653f75edc1ee8a6cafd43f7f0a4c131d24bc54c7 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 10:09:56 +0200 Subject: [PATCH 16/26] Add missing variable init --- src/wizard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wizard.c b/src/wizard.c index 830aa0a60..57d4d6cbe 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -348,7 +348,7 @@ tactics(mtmp) register struct monst *mtmp; { unsigned long strat = strategy(mtmp); - xchar sx, sy; + xchar sx = 0, sy = 0; mtmp->mstrategy = (mtmp->mstrategy & (STRAT_WAITMASK | STRAT_APPEARMSG)) | strat; From e7d65a44cd93384bb526e2c3f448407ba62fd8de Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 10:35:27 +0200 Subject: [PATCH 17/26] TTY: Add compile-time option for tile data hinting Several people have asked if 3.6.0 supports playing with tiles on a public server. Because there's no way for the user's end to know what that white @ is, this adds special console escape codes for tile hinting. The idea was originally a patch called TelnetTiles by Justin Hiltscher, but this expanded version comes via NAO, where it's been in use for years. This is basically an interim hack, which should go away when/if we support actual client-server model. --- doc/fixes36.1 | 1 + include/config.h | 33 +++++++++++++++++++++++ include/flag.h | 3 +++ src/options.c | 5 ++++ util/makedefs.c | 3 +++ win/tty/wintty.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 174c21b95..a14453683 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -160,6 +160,7 @@ database entries for Cleaver, Sunsword, Frost and Fire brands, and Platform- and/or Interface-Specific New Features ------------------------------------------------ tty: menu_overlay -option to clear screen and align menus to left +tty: compile-time option to output escape codes for tile data hints NetHack Community Patches (or Variation) Included diff --git a/include/config.h b/include/config.h index 3392e6407..72f87fb11 100644 --- a/include/config.h +++ b/include/config.h @@ -439,6 +439,33 @@ typedef unsigned char uchar; * bugs left here. */ +/* TTY_TILES_ESCCODES: Enable output of special console escape codes + * which act as hints for external programs such as EbonHack. + * + * Only for TTY_GRAPHICS. + * + * All of the escape codes are in the format ESC [ N z, where N can be + * one or more positive integer values, separated by semicolons. + * For example ESC [ 1 ; 0 ; 120 z + * + * Possible codes are: + * ESC [ 1 ; 0 ; n ; m z Start a glyph (aka a tile) number n, with flags m + * ESC [ 1 ; 1 z End a glyph. + * ESC [ 1 ; 2 ; n z Select a window n to output to. + * ESC [ 1 ; 3 z End of data. NetHack has finished sending data, + * and is waiting for input. + * + * Whenever NetHack outputs anything, it will first output the "select window" + * code. Whenever NetHack outputs a tile, it will first output the "start + * glyph" code, then the escape codes for color and the glyph character + * itself, and then the "end glyph" code. + * + * To compile NetHack with this, add tile.c to WINSRC and tile.o to WINOBJ + * in the hints file or Makefile. + * Set boolean option vt_tiledata in your config file to turn this on. + * Note that gnome-terminal at least doesn't work with this. */ +/* #define TTY_TILES_ESCCODES */ + /* #define STATUS_VIA_WINDOWPORT */ /* re-work of the status line updating process */ /* #define STATUS_HILITES */ /* support hilites of status fields */ @@ -459,6 +486,12 @@ typedef unsigned char uchar; /* End of Section 4 */ +#ifdef TTY_TILES_ESCCODES +# ifndef USE_TILES +# define USE_TILES +# endif +#endif + #include "global.h" /* Define everything else according to choices above */ #endif /* CONFIG_H */ diff --git a/include/flag.h b/include/flag.h index a55591a13..79da89f92 100644 --- a/include/flag.h +++ b/include/flag.h @@ -259,6 +259,9 @@ struct instance_flags { #ifdef LAN_FEATURES boolean lan_mail; /* mail is initialized */ boolean lan_mail_fetched; /* mail is awaiting display */ +#endif +#ifdef TTY_TILES_ESCCODES + boolean vt_tiledata; /* output console codes for tile support in TTY */ #endif boolean wizweight; /* display weight of everything in wizard mode */ /* diff --git a/src/options.c b/src/options.c index 0e5332038..8c47c6ae4 100644 --- a/src/options.c +++ b/src/options.c @@ -225,6 +225,11 @@ static struct Bool_Opt { { "use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME }, /*WC*/ #endif { "verbose", &flags.verbose, TRUE, SET_IN_GAME }, +#ifdef TTY_TILES_ESCCODES + { "vt_tiledata", &iflags.vt_tiledata, FALSE, SET_IN_FILE }, +#else + { "vt_tiledata", (boolean *) 0, FALSE, SET_IN_FILE }, +#endif { "wizweight", &iflags.wizweight, FALSE, SET_IN_WIZGAME }, { "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME }, #ifdef ZEROCOMP diff --git a/util/makedefs.c b/util/makedefs.c index 0e340b478..64f9b7fe5 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1323,6 +1323,9 @@ static const char *build_opts[] = { #ifdef TEXTCOLOR "color", #endif +#ifdef TTY_TILES_ESCCODES + "console escape codes for tile hinting", +#endif #ifdef COM_COMPL "command line completion", #endif diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 0690f8e24..27d53180a 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -37,6 +37,15 @@ extern void msmsg(const char *, ...); #endif #endif +#ifdef TTY_TILES_ESCCODES +extern short glyph2tile[]; +#define TILE_ANSI_COMMAND 'z' +#define AVTC_GLYPH_START 0 +#define AVTC_GLYPH_END 1 +#define AVTC_SELECT_WINDOW 2 +#define AVTC_INLINE_SYNC 3 +#endif + extern char mapped_menu_cmds[]; /* from options.c */ /* this is only needed until tty_status_* routines are written */ @@ -175,6 +184,36 @@ static const char default_menu_cmds[] = { MENU_INVERT_PAGE, MENU_SEARCH, 0 /* null terminator */ }; +#ifdef TTY_TILES_ESCCODES +static int vt_tile_current_window = -2; + +void +print_vt_code(i, c, d) +int i, c, d; +{ + if (iflags.vt_tiledata) { + if (c >= 0) { + if (i == AVTC_SELECT_WINDOW) { + if (c == vt_tile_current_window) return; + vt_tile_current_window = c; + } + if (d >= 0) + printf("\033[1;%d;%d;%d%c", i, c, d, TILE_ANSI_COMMAND); + else + printf("\033[1;%d;%d%c", i, c, TILE_ANSI_COMMAND); + } else { + printf("\033[1;%d%c", i, TILE_ANSI_COMMAND); + } + } +} +#else +# define print_vt_code(i, c, d) ; +#endif /* !TTY_TILES_ESCCODES */ +#define print_vt_code1(i) print_vt_code((i), -1, -1) +#define print_vt_code2(i,c) print_vt_code((i), (c), -1) +#define print_vt_code3(i,c,d) print_vt_code((i), (c), (d)) + + /* clean up and quit */ STATIC_OVL void bail(mesg) @@ -1427,6 +1466,8 @@ winid window; panic(winpanicstr, window); ttyDisplay->lastwin = window; + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin) { @@ -2060,6 +2101,8 @@ boolean blocking; /* with ttys, all windows are blocking */ ttyDisplay->lastwin = window; ttyDisplay->rawprint = 0; + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin == 1) { @@ -2145,6 +2188,8 @@ winid window; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin) @@ -2214,6 +2259,8 @@ register int x, y; /* not xchar: perhaps xchar is unsigned and panic(winpanicstr, window); ttyDisplay->lastwin = window; + print_vt_code2(AVTC_SELECT_WINDOW, window); + #if defined(USE_TILES) && defined(MSDOS) adjust_cursor_flags(cw); #endif @@ -2302,6 +2349,8 @@ char ch; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_STATUS: case NHW_MAP: @@ -2369,6 +2418,8 @@ const char *str; ttyDisplay->lastwin = window; + print_vt_code2(AVTC_SELECT_WINDOW, window); + switch (cw->type) { case NHW_MESSAGE: /* really do this later */ @@ -3065,9 +3116,13 @@ int bkglyph UNUSED; /* map glyph to character and color */ (void) mapglyph(glyph, &ch, &color, &special, x, y); + print_vt_code2(AVTC_SELECT_WINDOW, window); + /* Move the cursor. */ tty_curs(window, x, y); + print_vt_code3(AVTC_GLYPH_START, glyph2tile[glyph], special); + #ifndef NO_TERMS if (ul_hack && ch == '_') { /* non-destructive underscore */ (void) putchar((char) ' '); @@ -3111,6 +3166,8 @@ int bkglyph UNUSED; #endif } + print_vt_code1(AVTC_GLYPH_END); + wins[window]->curx++; /* one character over */ ttyDisplay->curx++; /* the real cursor moved too */ } @@ -3121,6 +3178,7 @@ const char *str; { if (ttyDisplay) ttyDisplay->rawprint++; + print_vt_code2(AVTC_SELECT_WINDOW, NHW_BASE); #if defined(MICRO) || defined(WIN32CON) msmsg("%s\n", str); #else @@ -3135,6 +3193,7 @@ const char *str; { if (ttyDisplay) ttyDisplay->rawprint++; + print_vt_code2(AVTC_SELECT_WINDOW, NHW_BASE); term_start_raw_bold(); #if defined(MICRO) || defined(WIN32CON) msmsg("%s", str); @@ -3153,7 +3212,7 @@ const char *str; int tty_nhgetch() { - int i; + int i, tmp; #ifdef UNIX /* kludge alert: Some Unix variants return funny values if getc() * is called, interrupted, and then called again. There @@ -3164,6 +3223,7 @@ tty_nhgetch() char nestbuf; #endif + print_vt_code1(AVTC_INLINE_SYNC); (void) fflush(stdout); /* Note: if raw_print() and wait_synch() get called to report terminal * initialization problems, then wins[] and ttyDisplay might not be @@ -3186,6 +3246,12 @@ tty_nhgetch() i = '\033'; /* same for EOF */ if (ttyDisplay && ttyDisplay->toplin == 1) ttyDisplay->toplin = 2; +#ifdef TTY_TILES_ESCCODES + /* hack to force output of the window select code */ + tmp = vt_tile_current_window; + vt_tile_current_window++; + print_vt_code2(AVTC_SELECT_WINDOW, tmp); +#endif /* TTY_TILES_ESCCODES */ return i; } From 65d780dc3d1a176d834c0b0ced197d5eaaa21428 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 13:01:46 +0200 Subject: [PATCH 18/26] Add compile-time option MSGHANDLER This was a feature request from a blind player; he wanted to play a sound whenever a pline message was given. --- doc/fixes36.1 | 1 + include/config.h | 6 ++++++ src/pline.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ util/makedefs.c | 3 +++ 4 files changed, 56 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a14453683..c3b17ca0f 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -161,6 +161,7 @@ Platform- and/or Interface-Specific New Features ------------------------------------------------ tty: menu_overlay -option to clear screen and align menus to left tty: compile-time option to output escape codes for tile data hints +unix: compile-time option MSGHANDLER to pass messages to external program NetHack Community Patches (or Variation) Included diff --git a/include/config.h b/include/config.h index 72f87fb11..121ce5407 100644 --- a/include/config.h +++ b/include/config.h @@ -466,6 +466,12 @@ typedef unsigned char uchar; * Note that gnome-terminal at least doesn't work with this. */ /* #define TTY_TILES_ESCCODES */ +/* NetHack will execute an external program whenever a new message-window + * message is shown. The program to execute is given in environment variable + * NETHACK_MSGHANDLER. It will get the message as the only parameter. + * Only available with POSIX_TYPES or GNU C */ +/* #define MSGHANDLER */ + /* #define STATUS_VIA_WINDOWPORT */ /* re-work of the status line updating process */ /* #define STATUS_HILITES */ /* support hilites of status fields */ diff --git a/src/pline.c b/src/pline.c index 4ada9bff7..141532cad 100644 --- a/src/pline.c +++ b/src/pline.c @@ -10,6 +10,9 @@ static boolean no_repeat = FALSE; static char prevmsg[BUFSZ]; static char *FDECL(You_buf, (int)); +#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) +static void FDECL(execplinehandler, (const char *)); +#endif /*VARARGS1*/ /* Note that these declarations rely on knowledge of the internals @@ -94,6 +97,11 @@ VA_DECL(const char *, line) flush_screen(1); /* %% */ putstr(WIN_MESSAGE, 0, line); + +#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) + execplinehandler(line); +#endif + /* this gets cleared after every pline message */ iflags.last_msg = PLNMSG_UNKNOWN; strncpy(prevmsg, line, BUFSZ), prevmsg[BUFSZ - 1] = '\0'; @@ -585,4 +593,42 @@ struct obj *otmp2; } } +#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) +static boolean use_pline_handler = TRUE; +static void +execplinehandler(line) +const char *line; +{ + int f; + const char *args[3]; + char *env; + + if (!use_pline_handler) + return; + + if (!(env = nh_getenv("NETHACK_MSGHANDLER"))) { + use_pline_handler = FALSE; + return; + } + + f = fork(); + if (f == 0) { /* child */ + args[0] = env; + args[1] = line; + args[2] = NULL; + (void) setgid(getgid()); + (void) setuid(getuid()); + (void) execv(args[0], (char *const *) args); + perror((char *) 0); + (void) fprintf(stderr, "Exec to message handler %s failed.\n", + env); + terminate(EXIT_FAILURE); + } else if (f == -1) { + perror((char *) 0); + use_pline_handler = FALSE; + pline("Fork to message handler failed."); + } +} +#endif /* defined(POSIX_TYPES) || defined(__GNUC__) */ + /*pline.c*/ diff --git a/util/makedefs.c b/util/makedefs.c index 64f9b7fe5..a20660c7c 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1350,6 +1350,9 @@ static const char *build_opts[] = { #ifdef HOLD_LOCKFILE_OPEN "exclusive lock on level 0 file", #endif +#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) + "external program as a message handler", +#endif #ifdef LOGFILE "log file", #endif From c6bf49f647b799a1099885a28bed46cec71d3e8e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 14:47:06 +0200 Subject: [PATCH 19/26] Small code cleanup --- src/do_name.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index da48c07dc..158189e39 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -103,6 +103,7 @@ int *cnt_p; boolean do_mons; { int x, y, pass, glyph, idx; + boolean wantedloc; *cnt_p = idx = 0; for (pass = 0; pass < 2; pass++) { @@ -118,31 +119,19 @@ boolean do_mons; for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { glyph = glyph_at(x, y); - if (do_mons) { - /* unlike '/M', this skips monsters revealed by - * warning glyphs and remembered invisible ones; - * TODO: skip worm tails - */ - if (glyph_is_monster(glyph)) { - if (!pass) { - ++*cnt_p; - } else { - (*arr_p)[idx].x = x; - (*arr_p)[idx].y = y; - ++idx; - } - } - } else { /* objects */ - /* TODO: skip boulders and rocks */ - if (glyph_is_object(glyph)) { - if (!pass) { - ++*cnt_p; - } else { - (*arr_p)[idx].x = x; - (*arr_p)[idx].y = y; - ++idx; - } - } + /* unlike '/M', this skips monsters revealed by + * warning glyphs and remembered invisible ones; + * TODO: skip worm tails, boulders and rocks + */ + wantedloc = (do_mons && glyph_is_monster(glyph) + || !do_mons && glyph_is_object(glyph)); + if (!wantedloc) continue; + if (!pass) { + ++*cnt_p; + } else { + (*arr_p)[idx].x = x; + (*arr_p)[idx].y = y; + ++idx; } } } /* pass */ From fe01018d90602a2f82ef88f14edce41cc90d1216 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 15:03:23 +0200 Subject: [PATCH 20/26] Enable TIMED_DELAY for linux hints files runmode is completely useless in TTY without this --- sys/unix/hints/linux | 1 + sys/unix/hints/linux-chroot | 1 + 2 files changed, 2 insertions(+) diff --git a/sys/unix/hints/linux b/sys/unix/hints/linux index a9b612edb..888fd9050 100644 --- a/sys/unix/hints/linux +++ b/sys/unix/hints/linux @@ -23,6 +23,7 @@ POSTINSTALL=cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INS CFLAGS=-g -O -I../include -DNOTPARMDECL $(CFLAGS1) -DDLB CFLAGS1=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE +CFLAGS+=-DTIMED_DELAY CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" LINK=$(CC) diff --git a/sys/unix/hints/linux-chroot b/sys/unix/hints/linux-chroot index d8af97580..404f4db98 100644 --- a/sys/unix/hints/linux-chroot +++ b/sys/unix/hints/linux-chroot @@ -27,6 +27,7 @@ POSTINSTALL=cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INS CFLAGS1=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" CFLAGS=-g -O -I../include -DNOTPARMDECL $(CFLAGS1) -DDLB CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE +CFLAGS+=-DTIMED_DELAY CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" CFLAGS+=-DVAR_PLAYGROUND=\"$(HACKDIR)/var\" From a8172e1208bddca281ef97dc96e8234da15c7193 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 18:24:38 +0200 Subject: [PATCH 21/26] Fix unreferenced variable --- win/tty/wintty.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 27d53180a..acd1b86ad 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3212,7 +3212,7 @@ const char *str; int tty_nhgetch() { - int i, tmp; + int i; #ifdef UNIX /* kludge alert: Some Unix variants return funny values if getc() * is called, interrupted, and then called again. There @@ -3247,10 +3247,12 @@ tty_nhgetch() if (ttyDisplay && ttyDisplay->toplin == 1) ttyDisplay->toplin = 2; #ifdef TTY_TILES_ESCCODES - /* hack to force output of the window select code */ - tmp = vt_tile_current_window; - vt_tile_current_window++; - print_vt_code2(AVTC_SELECT_WINDOW, tmp); + { + /* hack to force output of the window select code */ + int tmp = vt_tile_current_window; + vt_tile_current_window++; + print_vt_code2(AVTC_SELECT_WINDOW, tmp); + } #endif /* TTY_TILES_ESCCODES */ return i; } From 854fe40609daefc0709ef22c4c509825088eb15b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 18:27:34 +0200 Subject: [PATCH 22/26] Fix bz175: Pile mark is shown when potion is destroyed Original bug report: > When killing something that's carrying a potion, or death-drops a potion, > or stands on top of a potion, with a force bolt or a wand of striking, > "you hear something shatter" or "a potion of foo shatters" but the corpse > is inverse as if it's (still) a pile. Unfortunately the newsym() checks for already existing glyph, and the gbuf doesn't distinguish between object piles and single items, so newsym doesn't mark the location for update. This is a dirty hack to force the newsym to update the glyph. The glyph buffering should be revisited in a future version. --- include/extern.h | 1 + src/display.c | 15 +++++++++++++++ src/zap.c | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/include/extern.h b/include/extern.h index 70ce04b31..f45ca4b30 100644 --- a/include/extern.h +++ b/include/extern.h @@ -310,6 +310,7 @@ E void FDECL(map_location, (int, int, int)); E void FDECL(feel_newsym, (XCHAR_P, XCHAR_P)); E void FDECL(feel_location, (XCHAR_P, XCHAR_P)); E void FDECL(newsym, (int, int)); +E void FDECL(newsym_force, (int, int)); E void FDECL(shieldeff, (XCHAR_P, XCHAR_P)); E void FDECL(tmp_at, (int, int)); E void FDECL(swallowed, (int)); diff --git a/src/display.c b/src/display.c index 333ed4d5b..09fd943eb 100644 --- a/src/display.c +++ b/src/display.c @@ -1318,6 +1318,21 @@ static gbuf_entry gbuf[ROWNO][COLNO]; static char gbuf_start[ROWNO]; static char gbuf_stop[ROWNO]; +/* FIXME: This is a dirty hack, because newsym() doesn't distinguish + * between object piles and single objects, it doesn't mark the location + * for update. */ +void +newsym_force(x, y) +register int x, y; +{ + newsym(x,y); + gbuf[y][x].new = 1; + if (gbuf_start[y] > x) + gbuf_start[y] = x; + if (gbuf_stop[y] < x) + gbuf_stop[y] = x; +} + /* * Store the glyph in the 3rd screen for later flushing. */ diff --git a/src/zap.c b/src/zap.c index 6a695fbac..4f3dc5707 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1875,10 +1875,14 @@ struct obj *obj, *otmp; You_hear("a crumbling sound."); } } else { + int oox = obj->ox; + int ooy = obj->oy; if (context.mon_moving ? !breaks(obj, obj->ox, obj->oy) : !hero_breaks(obj, obj->ox, obj->oy, FALSE)) maybelearnit = FALSE; /* nothing broke */ + else + newsym_force(oox,ooy); res = 0; } if (maybelearnit) From c902b44b5b0c7be9b412265eb9ffbf7d1ec1c992 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 10 Jan 2016 18:54:35 +0200 Subject: [PATCH 23/26] Document fixes --- doc/fixes36.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index c3b17ca0f..0077cc71b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -108,6 +108,7 @@ don't create globs of ooze/slime/pudding with bknown flag set so pre-known to be "uncursed" do allow globs with same curse/bless state to merge even when that state is known for one and unknown for the other; result will have bknown clear +fix pile mark after killing a monster carrying a potion which is destroyed Platform- and/or Interface-Specific Fixes From 9cfc0ac5d7bf2ce9d32f188d60c921deda243231 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 10 Jan 2016 14:42:06 -0800 Subject: [PATCH 24/26] getpos() 'm','M' and 'o','O' Always include the hero's location in the set of spots for 'm',&c to cycle through. This way the set will never be empty so checks for that can be dropped, and choosing initial index becomes trivial (set to 0, then increment to reach nearest spot of interest or decrement to reach farthest). Also, it makes it easier for player to see when successive 'm's,&c have been through all the interesting locations if there are multiple monsters or objects clumped near the last one in the cycle. --- src/do_name.c | 120 +++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index 158189e39..80d2093fd 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1452064740 2016/01/06 07:19:00 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.84 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1452465671 2016/01/10 22:41:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.88 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -102,41 +102,51 @@ coord **arr_p; int *cnt_p; boolean do_mons; { - int x, y, pass, glyph, idx; - boolean wantedloc; + int x, y, pass, glyph, idx, + tail = (do_mons ? monnum_to_glyph(PM_LONG_WORM_TAIL) : 0), + boulder = (!do_mons ? objnum_to_glyph(BOULDER) : 0), + rock = (!do_mons ? objnum_to_glyph(ROCK) : 0); + /* + * We always include the hero's location even if there is no monster + * (invisible hero without see invisible) or object (usual case) + * displayed there. That way, the count will always be at least 1, + * and player has a visual indicator (cursor returns to hero's spot) + * highlighting when successive 'm's or 'o's have cycled all the way + * through all monsters or objects. + * + * Hero's spot will always sort to array[0] because it will always + * be the shortest distance (namely, 0 units) away from . + */ *cnt_p = idx = 0; for (pass = 0; pass < 2; pass++) { - if (pass) { - /* *cnt_p + 1: always allocate a non-zero amount */ - *arr_p = (coord *) alloc(sizeof (coord) * (*cnt_p + 1)); - if (!*cnt_p) { - /* needed for caller's mon[0].x,.y==u.ux,.uy check */ - (*arr_p)[0].x = (*arr_p)[0].y = 0; - break; - } - } for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { + /* TODO: if glyph is a pile glyph, convert to ordinary one + * in order to keep tail/boulder/rock check simple. + */ glyph = glyph_at(x, y); /* unlike '/M', this skips monsters revealed by - * warning glyphs and remembered invisible ones; - * TODO: skip worm tails, boulders and rocks - */ - wantedloc = (do_mons && glyph_is_monster(glyph) - || !do_mons && glyph_is_object(glyph)); - if (!wantedloc) continue; - if (!pass) { - ++*cnt_p; - } else { - (*arr_p)[idx].x = x; - (*arr_p)[idx].y = y; - ++idx; + warning glyphs and remembered invisible ones */ + if ((x == u.ux && y == u.uy) + || (do_mons ? (glyph_is_monster(glyph) && glyph != tail) + : (glyph_is_object(glyph) + && glyph != boulder && glyph != rock))) { + if (!pass) { + ++*cnt_p; + } else { + (*arr_p)[idx].x = x; + (*arr_p)[idx].y = y; + ++idx; + } } } + + if (!pass) /* end of first pass */ + *arr_p = (coord *) alloc(sizeof (coord) * *cnt_p); + else /* end of second pass */ + qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu); } /* pass */ - if (*cnt_p) - qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu); } int @@ -283,51 +293,41 @@ const char *goal; show_goal_msg = TRUE; msg_given = TRUE; goto nxtc; - } else if (c == '@') { + } else if (c == '@') { /* return to hero's spot */ + /* reset 'm','M' and 'o','O'; otherwise, there's no way for player + to achieve that except by manually cycling through all spots */ + monidx = objidx = 0; cx = u.ux; cy = u.uy; goto nxtc; - } else if (c == 'm' || c == 'M') { + } else if (c == 'm' || c == 'M') { /* nearest or farthest monster */ if (!monarr) { gather_locs(&monarr, &moncount, TRUE); - /* when hero is first element (always, unless unseen), - we want first increment to reach 1 (nearest aside - from hero) or first decrement to reach moncount-1 - (farthest); if hero is not first element, we want - first increment to end up with 0 (nearest monster), - first decrement should still choose moncount-1 */ - monidx = (monarr[0].x == u.ux && monarr[0].y == u.uy) ? 0 - : (c == 'm') ? -1 : 0; + monidx = 0; /* monarr[0] is hero's spot */ } - if (moncount) { - if (c == 'm') { - monidx = (monidx + 1) % moncount; - } else { - if (--monidx < 0) - monidx = moncount - 1; - } - cx = monarr[monidx].x; - cy = monarr[monidx].y; - goto nxtc; + if (c == 'm') { + monidx = (monidx + 1) % moncount; + } else { + if (--monidx < 0) + monidx = moncount - 1; } - } else if (c == 'o' || c == 'O') { + cx = monarr[monidx].x; + cy = monarr[monidx].y; + goto nxtc; + } else if (c == 'o' || c == 'O') { /* nearest or farthest object */ if (!objarr) { gather_locs(&objarr, &objcount, FALSE); - /* ready for first increment to change to zero - or first decrement to change to objcount-1 */ - objidx = (c == 'o') ? -1 : 0; + objidx = 0; /* objarr[0] is hero's spot */ } - if (objcount) { - if (c == 'o') { - objidx = (objidx + 1) % objcount; - } else { - if (--objidx < 0) - objidx = objcount - 1; - } - cx = objarr[objidx].x; - cy = objarr[objidx].y; - goto nxtc; + if (c == 'o') { + objidx = (objidx + 1) % objcount; + } else { + if (--objidx < 0) + objidx = objcount - 1; } + cx = objarr[objidx].x; + cy = objarr[objidx].y; + goto nxtc; } else { if (!index(quitchars, c)) { char matching[MAXPCHARS]; From 0ee5d8ce4763dd2e5039295e4ec8fdad1da9f473 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 11 Jan 2016 21:07:33 +0200 Subject: [PATCH 25/26] Add getpos_coord option Allows showing the coordinate when picking a position on the map with '/' and autodescribe is on. This is another blind player request --- doc/Guidebook.mn | 5 +++++ doc/Guidebook.tex | 6 ++++++ include/flag.h | 6 ++++++ src/do_name.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/options.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 2d73781f5..44dc33b29 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -2125,6 +2125,11 @@ The default is to randomly pick an appropriate gender. If you prefix a `!' or ``no'' to the value, you can exclude that gender from being picked randomly. Cannot be set with the `O' command. Persistent. +.lp getpos_coord +When using the `/' command to look around on the map with +``autodescribe'' on, display coordinates after the description. +The value specified should be the first letter of one of the following: +absolute, cartesian, or none. Default is none. .lp "help " If more information is available for an object looked at with the `/' command, ask if you want to see it (default on). Turning help diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 53716a2a9..88a9d8eb6 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -2559,6 +2559,12 @@ If you prefix `{\tt !}' or ``{\tt no}'' to the value, you can exclude that gender from being picked randomly. Cannot be set with the `{\tt O}' command. Persistent. %.lp +\item[\ib{getpos\verb+_+coord}] +When using the `{\tt /}' command to look around on the map with +``{\tt autodescribe}'' on, display coordinates after the description. +The value specified should be the first letter of one of the following: +absolute, cartesian, or none. Default is none. +%.lp \item[\ib{help}] If more information is available for an object looked at with the `{\tt /}' command, ask if you want to see it (default on). diff --git a/include/flag.h b/include/flag.h index 79da89f92..298825660 100644 --- a/include/flag.h +++ b/include/flag.h @@ -167,6 +167,11 @@ struct sysflag { * */ +/* values for iflags.getpos_coords */ +#define GPCOORDS_NONE 'n' +#define GPCOORDS_ABSOLUTE 'a' +#define GPCOORDS_CARTESIAN 'c' + struct instance_flags { /* stuff that really isn't option or platform related. They are * set and cleared during the game to control the internal @@ -185,6 +190,7 @@ struct instance_flags { boolean mon_polycontrol; /* debug: control monster polymorphs */ /* stuff that is related to options and/or user or platform preferences */ unsigned msg_history; /* hint: # of top lines to save */ + int getpos_coords; /* show coordinates when getting cursor position */ int menu_headings; /* ATR for menu headings */ int *opt_booldup; /* for duplication of boolean opts in config file */ int *opt_compdup; /* for duplication of compound opts in config file */ diff --git a/src/do_name.c b/src/do_name.c index 80d2093fd..3c86589c2 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -149,6 +149,34 @@ boolean do_mons; } /* pass */ } +char * +dxdy_to_dist_descr(dx,dy) +int dx,dy; +{ + static char buf[QBUFSZ]; + int d; + if (!dx && !dy) + Sprintf(buf, "here"); + else if ((d = xytod(dx,dy)) != -1) + Sprintf(buf, "%s", directionname(d)); + else { + char tmp[QBUFSZ]; + buf[0] = '\0'; + if (dy) { + Sprintf(tmp, "%i%c", abs(dy), (dy > 0) ? 's' : 'n'); + Strcat(buf, tmp); + } + if (dy && dx) + Strcat(buf, ","); + if (dx) { + Sprintf(tmp, "%i%c", abs(dx), (dx > 0) ? 'e' : 'w'); + Strcat(buf, tmp); + } + } + return buf; +} + + int getpos(ccp, force, goal) coord *ccp; @@ -192,12 +220,27 @@ const char *goal; coord cc; int sym = 0; char tmpbuf[BUFSZ]; + char outbuf[BUFSZ]; const char *firstmatch = NULL; + int dx,dy; cc.x = cx; cc.y = cy; if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) { - pline1(firstmatch); + outbuf[0] = '\0'; + switch (iflags.getpos_coords) { + default: + break; + case GPCOORDS_CARTESIAN: + dx = cc.x - u.ux; + dy = cc.y - u.uy; + Sprintf(outbuf, " (%s)", dxdy_to_dist_descr(dx,dy)); + break; + case GPCOORDS_ABSOLUTE: + Sprintf(outbuf, " (%d,%d)", cc.x,cc.y); + break; + } + pline("%s%s", firstmatch, outbuf); curs(WIN_MAP, cx, cy); flush_screen(0); } diff --git a/src/options.c b/src/options.c index 8c47c6ae4..6ba023a3c 100644 --- a/src/options.c +++ b/src/options.c @@ -294,6 +294,7 @@ static struct Comp_Opt { DISP_IN_GAME }, /*WC*/ { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ, SET_IN_GAME }, { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME }, + { "getpos_coord", "show coordinates when getting cursor position", 1, SET_IN_GAME }, { "horsename", "the name of your (first) horse (e.g., horsename:Silver)", PL_PSIZ, DISP_IN_GAME }, { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/ @@ -685,6 +686,7 @@ initoptions_init() iflags.prevmsg_window = 's'; #endif iflags.menu_headings = ATR_INVERSE; + iflags.getpos_coords = GPCOORDS_NONE; /* hero's role, race, &c haven't been chosen yet */ flags.initrole = flags.initrace = flags.initgend = flags.initalign = @@ -2332,6 +2334,24 @@ boolean tinitial, tfrom_file; return; } + fullname = "getpos_coord"; + if (match_optname(opts, fullname, 6, TRUE)) { + if (duplicate) + complain_about_duplicate(opts, 1); + if (negated) { + iflags.getpos_coords = GPCOORDS_NONE; + return; + } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { + if (tolower(*op) == GPCOORDS_NONE + || tolower(*op) == GPCOORDS_CARTESIAN + || tolower(*op) == GPCOORDS_ABSOLUTE) { + iflags.getpos_coords = tolower(*op); + } else + badoption(opts); + } + return; + } + fullname = "warnings"; if (match_optname(opts, fullname, 5, TRUE)) { if (duplicate) @@ -4008,6 +4028,27 @@ boolean setinitial, setfromfile; free((genericptr_t) mode_pick); } destroy_nhwindow(tmpwin); + } else if (!strcmp("getpos_coord", optname)) { + menu_item *window_pick = (menu_item *) 0; + + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + any = zeroany; + any.a_char = GPCOORDS_ABSOLUTE; + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_ABSOLUTE, + 0, ATR_NONE, "absolute", MENU_UNSELECTED); + any.a_char = GPCOORDS_CARTESIAN; + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_CARTESIAN, + 0, ATR_NONE, "cartesian", MENU_UNSELECTED); + any.a_char = GPCOORDS_NONE; + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_NONE, + 0, ATR_NONE, "none", MENU_UNSELECTED); + end_menu(tmpwin, "Select coordinate display when picking a position:"); + if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) { + iflags.getpos_coords = window_pick->item.a_char; + free((genericptr_t) window_pick); + } + destroy_nhwindow(tmpwin); } else if (!strcmp("msg_window", optname)) { #ifdef TTY_GRAPHICS /* by Christian W. Cooper */ @@ -4755,6 +4796,11 @@ char *buf; Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m)); } else if (!strcmp(optname, "runmode")) { Sprintf(buf, "%s", runmodes[flags.runmode]); + } else if (!strcmp(optname, "getpos_coord")) { + Sprintf(buf, "%s", + (iflags.getpos_coords == GPCOORDS_ABSOLUTE) ? "absolute" + : (iflags.getpos_coords == GPCOORDS_CARTESIAN) ? "cartesian" + : "none"); } else if (!strcmp(optname, "scores")) { Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around, flags.end_own ? "/own" : ""); From 6dd6584e21b29282bf16ddaef62647e8d4830364 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 11 Jan 2016 21:12:52 +0200 Subject: [PATCH 26/26] Add getpos_coord to fixes file --- doc/fixes36.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 0077cc71b..96c0ee768 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -156,6 +156,8 @@ additional tribute passages for The Colour of Magic, The Light Fantastic, compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use database entries for Cleaver, Sunsword, Frost and Fire brands, and polymorph trap +allow showing coordinates when picking a position on the map and + autodescribe option is on Platform- and/or Interface-Specific New Features