diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index e2f534dfc..1a194ea54 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -5495,7 +5495,7 @@ maintained the port of {\it NetHack\/} 3.6 for Microsoft Windows. %.pg \medskip {\it Pat Rankin} attempted to keep the VMS port running for NetHack 3.6.1, -hindered by limited access. {it Kevin Smolkowski} has updated and tested it +hindered by limited access. {\it Kevin Smolkowski} has updated and tested it for the most recent version of OpenVMS (V8.4 as of this writing) on Alpha and Integrity (aka Itanium aka IA64) but not VAX. diff --git a/doc/fixes36.2 b/doc/fixes36.2 index f8e4c8b11..323d911df 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -151,7 +151,7 @@ wizard mode ^T shouldn't have been diminishing player power but it was fix missing space in "would flyif you weren't levitating" a wand of polymorph lost its magical ability for the turn just because the player using it to engrave happened to be blind, which didn't make - a much sense + much sense floating eye is classified as a flyer but flying is blocked while levitating, so don't set intrinsic flying if hero is polymorphed into one being trapped (bear trap, web, molten or solidified lava, chained to buried @@ -176,6 +176,15 @@ prayer result which enhanced strength (fix weakness from hunger) didn't give a message if a change in encumbrance occurred; it came on next move add current location within the dungeon to the Background section of ^X and final disclosure (it's not background but doesn't fit anywhere else) +death from something other than loss of hit points could leave hero with + non-zero HP at end of game (during "really die?" prompt, disclosure) +added several special cases for genocide and/or wishing prompt: (cookie, + pie, genie, watchmen) +lightning strike from Mjollnir did not make any noise +with menustyle:Full, picking 'A - autoselect all' when putting items into a + container actually took everything out of that container +add missing 'A - autoselect all' choice for menustyle:Full when taking items + out while looting a container Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -189,6 +198,8 @@ make long extended commands list be more navigable simplify #wizidentify; don't rely on having bold menu entries ensure tmp_at() structures are initialized for all code paths when swallowed trapped-vs-levitation/flying change broke Sting releasing hero from web +life-saving while poly'd and Unchanging wasn't restoring u.mh (HP as monster) +change in searching stopped finding unseen monsters except hiders and eels tty: turn off an optimization that is the suspected cause of Windows reported partial status lines following level changes tty: ensure that current status fields are always copied to prior status @@ -199,6 +210,7 @@ tty: fix leftover display artifact when the last field on the row got placed to its left, getting shorter X11: its use of genl_status_update exposed a negative index use that could lead to a segfault +X11: rollback disabling of keystroke input for PICK_NONE menus (for scrolling) Platform- and/or Interface-Specific Fixes @@ -248,6 +260,7 @@ X11: handle X errors via panic X11: don't reuse perm_invent window for picking an object X11: obey mouse_support and allow toggling it in game X11: obey menu movement keys +X11: enable menu [cancel] button for PICK_NONE menus General New Features @@ -270,6 +283,12 @@ make mine town "orctown" variation a multiple level feature of the mines replace #monpolycontrol command with monpolycontrol boolean option replace #wizdebug_traveldisplay command with travel_debug boolean option rename #wizdebug_bury command to #wizbury +life-saving now makes swallower or grabber release hero +for ^X and enlightenment, display the information in a menu rather than a + plain text popup, so that player can go back within the text via + '<' (menu_previous_page) and '^' (menu_first_page) menu keys; + needed for interfaces (tty) without text popup scrollbar support; + end of game disclosure of attributes remains single-forward-pass Code Cleanup and Reorganization diff --git a/include/extern.h b/include/extern.h index 4a3e1b610..8887994bb 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1535812936 2018/09/01 14:42:16 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.636 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1541145514 2018/11/02 07:58:34 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.645 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -721,6 +721,7 @@ E void FDECL(make_grave, (int, int, const char *)); /* ### exper.c ### */ +E long FDECL(newuexp, (int)); E int NDECL(newpw); E int FDECL(experience, (struct monst *, int)); E void FDECL(more_experienced, (int, int)); @@ -2724,6 +2725,9 @@ E int NDECL(abon); E int NDECL(dbon); E void FDECL(wet_a_towel, (struct obj *, int, BOOLEAN_P)); E void FDECL(dry_a_towel, (struct obj *, int, BOOLEAN_P)); +E char *FDECL(skill_level_name, (int, char *)); +E const char *FDECL(skill_name, (int)); +E boolean FDECL(can_advance, (int, BOOLEAN_P)); E int NDECL(enhance_weapon_skill); E void FDECL(unrestrict_weapon_skill, (int)); E void FDECL(use_skill, (int, int)); diff --git a/src/artifact.c b/src/artifact.c index 2ef7dfa7c..87cbf3b61 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -1215,6 +1215,8 @@ int dieroll; /* needed for Magicbane and vorpal blades */ pline_The("massive hammer hits%s %s%c", !spec_dbon_applies ? "" : "! Lightning strikes", hittee, !spec_dbon_applies ? '.' : '!'); + if (spec_dbon_applies) + wake_nearto(mdef->mx, mdef->my, 4 * 4); if (!rn2(5)) (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC); if (!rn2(5)) diff --git a/src/cmd.c b/src/cmd.c index f88247ec7..9b4579857 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1523306904 2018/04/09 20:48:24 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.281 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1541235664 2018/11/03 09:01:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.298 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -182,6 +182,7 @@ STATIC_DCL int NDECL(wiz_port_debug); STATIC_PTR int NDECL(wiz_rumor_check); STATIC_PTR int NDECL(doattributes); +STATIC_DCL void FDECL(enlght_out, (const char *)); STATIC_DCL void FDECL(enlght_line, (const char *, const char *, const char *, const char *)); STATIC_DCL char *FDECL(enlght_combatinc, (const char *, int, int, char *)); @@ -190,6 +191,7 @@ STATIC_DCL boolean NDECL(walking_on_water); STATIC_DCL boolean FDECL(cause_known, (int)); STATIC_DCL char *FDECL(attrval, (int, int, char *)); STATIC_DCL void FDECL(background_enlightenment, (int, int)); +STATIC_DCL void FDECL(basics_enlightenment, (int, int)); STATIC_DCL void FDECL(characteristics_enlightenment, (int, int)); STATIC_DCL void FDECL(one_characteristic, (int, int, int)); STATIC_DCL void FDECL(status_enlightenment, (int, int)); @@ -1533,6 +1535,7 @@ doterrain(VOID_ARGS) /* -enlightenment and conduct- */ static winid en_win = WIN_ERR; +static boolean en_via_menu = FALSE; static const char You_[] = "You ", are[] = "are ", were[] = "were ", have[] = "have ", had[] = "had ", can[] = "can ", could[] = "could "; @@ -1550,6 +1553,19 @@ static const char have_been[] = "have been ", have_never[] = "have never ", #define you_have_X(something) \ enl_msg(You_, have, (const char *) "", something, "") +static void +enlght_out(buf) +const char *buf; +{ + if (en_via_menu) { + anything any; + + any = zeroany; + add_menu(en_win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); + } else + putstr(en_win, 0, buf); +} + static void enlght_line(start, middle, end, ps) const char *start, *middle, *end, *ps; @@ -1557,7 +1573,7 @@ const char *start, *middle, *end, *ps; char buf[BUFSZ]; Sprintf(buf, " %s%s%s%s.", start, middle, end, ps); - putstr(en_win, 0, buf); + enlght_out(buf); } /* format increased chance to hit or damage or defense (Protection) */ @@ -1679,6 +1695,11 @@ int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */ { char buf[BUFSZ], tmpbuf[BUFSZ]; + en_win = create_nhwindow(NHW_MENU); + en_via_menu = !final; + if (en_via_menu) + start_menu(en_win); + Strcpy(tmpbuf, plname); *tmpbuf = highc(*tmpbuf); /* same adjustment as bottom line */ /* as in background_enlightenment, when poly'd we need to use the saved @@ -1688,13 +1709,14 @@ int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */ ? urole.name.f : urole.name.m); - en_win = create_nhwindow(NHW_MENU); /* title */ - putstr(en_win, 0, buf); /* "Conan the Archeologist's attributes:" */ + enlght_out(buf); /* "Conan the Archeologist's attributes:" */ /* background and characteristics; ^X or end-of-game disclosure */ if (mode & BASICENLIGHTENMENT) { - /* role, race, alignment, deities */ + /* role, race, alignment, deities, dungeon level, time, experience */ background_enlightenment(mode, final); + /* hit points, energy points, armor class, gold */ + basics_enlightenment(mode, final); /* strength, dexterity, &c */ characteristics_enlightenment(mode, final); } @@ -1710,7 +1732,17 @@ int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */ /* intrinsics and other traditional enlightenment feedback */ attributes_enlightenment(mode, final); } - display_nhwindow(en_win, TRUE); + + if (!en_via_menu) { + display_nhwindow(en_win, TRUE); + } else { + menu_item *selected = 0; + + end_menu(en_win, (char *) 0); + if (select_menu(en_win, PICK_NONE, &selected) > 0) + free((genericptr_t) selected); + en_via_menu = FALSE; + } destroy_nhwindow(en_win); en_win = WIN_ERR; } @@ -1732,8 +1764,8 @@ int final; role_titl = (innategend && urole.name.f) ? urole.name.f : urole.name.m; rank_titl = rank_of(u.ulevel, Role_switch, innategend); - putstr(en_win, 0, ""); /* separator after title */ - putstr(en_win, 0, "Background:"); + enlght_out(""); /* separator after title */ + enlght_out("Background:"); /* if polymorphed, report current shape before underlying role; will be repeated as first status: "you are transformed" and also @@ -1795,7 +1827,7 @@ int final; /* lastly, normal case */ : "", u_gname()); - putstr(en_win, 0, buf); + enlght_out(buf); /* show the rest of this game's pantheon (finishes previous sentence) [appending "also Moloch" at the end would allow for straightforward trailing "and" on all three aligned entries but looks too verbose] */ @@ -1811,7 +1843,7 @@ int final; Sprintf(eos(buf), " %s (%s)", align_gname(A_CHAOTIC), align_str(A_CHAOTIC)); Strcat(buf, "."); /* terminate sentence */ - putstr(en_win, 0, buf); + enlght_out(buf); /* show original alignment,gender,race,role if any have been changed; giving separate message for temporary alignment change bypasses need @@ -1831,7 +1863,7 @@ int final; difgend ? genders[flags.initgend].adj : "", (difgend && difalgn) ? " and " : "", difalgn ? align_str(u.ualignbase[A_ORIGINAL]) : ""); - putstr(en_win, 0, buf); + enlght_out(buf); } /* 3.6.2: dungeon level, so that ^X really has all status info as @@ -1868,36 +1900,78 @@ int final; Sprintf(buf, "in %s, on %s", dgnbuf, tmpbuf); } you_are(buf, ""); + + /* this is shown even if the 'time' option is off */ + if (moves == 1L) { + you_have("just started your adventure", ""); + } else { + /* 'turns' grates on the nerves in this context... */ + Sprintf(buf, "the dungeon %ld turn%s ago", moves, plur(moves)); + /* same phrasing for current and final: "entered" is unconditional */ + enlght_line(You_, "entered ", buf, ""); + } + if (!Upolyd) { + /* flags.showexp does not matter */ + /* experience level is already shown above */ + Sprintf(buf, "%-1ld experience point%s", u.uexp, plur(u.uexp)); + if (wizard) { + if (u.ulevel < 30) { + int ulvl = (int) u.ulevel; + long nxtlvl = newuexp(ulvl); + /* long oldlvl = (ulvl > 1) ? newuexp(ulvl - 1) : 0; */ + + Sprintf(eos(buf), ", %ld %s%sneeded to attain level %d", + (nxtlvl - u.uexp), (u.uexp > 0) ? "more " : "", + !final ? "" : "were ", (ulvl + 1)); + } + } + you_have(buf, ""); + } +#ifdef SCORE_ON_BOTL + if (flags.showscore) { + /* describes what's shown on status line, which is an approximation; + only show it here if player has the 'showscore' option enabled */ + Sprintf(buf, "%ld%s", botl_score(), + !final ? "" : " before end-of-game adjustments"); + enl_msg("Your score ", "is ", "was ", buf, ""); + } +#endif } -/* characteristics: expanded version of bottom line strength, dexterity, &c; - [3.6.1: now includes all status info (except things already shown in the - 'background' section), primarily so that blind players can suppress the - status line(s) altogether and use ^X feedback on demand to view HP, &c] */ +/* hit points, energy points, armor class -- essential information which + doesn't fit very well in other categories */ +/*ARGSUSED*/ STATIC_OVL void -characteristics_enlightenment(mode, final) -int mode; +basics_enlightenment(mode, final) +int mode UNUSED; int final; { + static char Power[] = "energy points (spell power)"; char buf[BUFSZ]; - int hp = Upolyd ? u.mh : u.uhp; - int hpmax = Upolyd ? u.mhmax : u.uhpmax; + int pw = u.uen, hp = (Upolyd ? u.mh : u.uhp), + pwmax = u.uenmax, hpmax = (Upolyd ? u.mhmax : u.uhpmax); - putstr(en_win, 0, ""); /* separator after background */ - putstr(en_win, 0, - final ? "Final Characteristics:" : "Current Characteristics:"); + enlght_out(""); /* separator after background */ + enlght_out("Basics:"); if (hp < 0) hp = 0; - Sprintf(buf, "%d hit points (max:%d)", hp, hpmax); + /* "1 out of 1" rather than "all" if max is only 1; should never happen */ + if (hp == hpmax && hpmax > 1) + Sprintf(buf, "all %d hit points", hpmax); + else + Sprintf(buf, "%d out of %d hit point%s", hp, hpmax, plur(hpmax)); you_have(buf, ""); - Sprintf(buf, "%d magic power (max:%d)", u.uen, u.uenmax); + /* low max energy is feasible, so handle couple of extra special cases */ + if (pwmax == 0 || (pw == pwmax && pwmax == 2)) /* both: "all 2" is silly */ + Sprintf(buf, "%s %s", !pwmax ? "no" : "both", Power); + else if (pw == pwmax && pwmax > 2) + Sprintf(buf, "all %d %s", pwmax, Power); + else + Sprintf(buf, "%d out of %d %s", pw, pwmax, Power); you_have(buf, ""); - Sprintf(buf, "%d", u.uac); - enl_msg("Your armor class ", "is ", "was ", buf, ""); - if (Upolyd) { switch (mons[u.umonnum].mlevel) { case 0: @@ -1911,28 +1985,38 @@ int final; Sprintf(buf, "%d hit dice", mons[u.umonnum].mlevel); break; } - } else { - /* flags.showexp does not matter */ - /* experience level is already shown in the Background section */ - Sprintf(buf, "%-1ld experience point%s", - u.uexp, plur(u.uexp)); + you_have(buf, ""); } - you_have(buf, ""); - /* this is shown even if the 'time' option is off */ - Sprintf(buf, "the dungeon %ld turn%s ago", moves, plur(moves)); - /* same phrasing at end of game: "entered" is unconditional */ - enlght_line(You_, "entered ", buf, ""); + Sprintf(buf, "%d", u.uac); + enl_msg("Your armor class ", "is ", "was ", buf, ""); -#ifdef SCORE_ON_BOTL - if (flags.showscore) { - /* describes what's shown on status line, which is an approximation; - only show it here if player has the 'showscore' option enabled */ - Sprintf(buf, "%ld%s", botl_score(), - !final ? "" : " before end-of-game adjustments"); - enl_msg("Your score ", "is ", "was ", buf, ""); + /* gold; similar to doprgold(#seegold) but without shop billing info; + same amount as shown on status line which ignores container contents */ + { + static const char Your_wallet[] = "Your wallet "; + long umoney = money_cnt(invent); + + if (!umoney) { + enl_msg(Your_wallet, "is ", "was ", "empty", ""); + } else { + Sprintf(buf, "%ld %s", umoney, currency(umoney)); + enl_msg(Your_wallet, "contains ", "contained ", buf, ""); + } } -#endif +} + +/* characteristics: expanded version of bottom line strength, dexterity, &c */ +STATIC_OVL void +characteristics_enlightenment(mode, final) +int mode; +int final; +{ + char buf[BUFSZ]; + + enlght_out(""); + Sprintf(buf, "%s Characteristics:", !final ? "Current" : "Final"); + enlght_out(buf); /* bottom line order */ one_characteristic(mode, final, A_STR); /* strength */ @@ -2045,7 +2129,7 @@ int mode; int final; { boolean magic = (mode & MAGICENLIGHTENMENT) ? TRUE : FALSE; - int cap; + int cap, wtype; char buf[BUFSZ], youtoo[BUFSZ]; boolean Riding = (u.usteed /* if hero dies while dismounting, u.usteed will still @@ -2063,8 +2147,8 @@ int final; * Status (many are abbreviated on bottom line; others are or * should be discernible to the hero hence to the player) \*/ - putstr(en_win, 0, ""); /* separator after title or characteristics */ - putstr(en_win, 0, final ? "Final Status:" : "Current Status:"); + enlght_out(""); /* separator after title or characteristics */ + enlght_out(final ? "Final Status:" : "Current Status:"); Strcpy(youtoo, You_); /* not a traditional status but inherently obvious to player; more @@ -2286,6 +2370,7 @@ int final; still useful though) */ you_are("unencumbered", ""); } + /* report being weaponless; distinguish whether gloves are worn */ if (!uwep) { you_are(uarmg ? "empty handed" /* gloves imply hands */ @@ -2295,7 +2380,8 @@ int final; /* alternate phrasing for paws or lack of hands */ : "not wielding anything", ""); - /* two-weaponing implies a weapon (not other odd stuff) in each hand */ + /* two-weaponing implies hands (can't be polymorphed) and + a weapon or wep-tool (not other odd stuff) in each hand */ } else if (u.twoweap) { you_are("wielding two weapons at once", ""); /* report most weapons by their skill class (so a katana will be @@ -2312,6 +2398,33 @@ int final; (uwep->quan == 1L) ? an(what) : makeplural(what)); you_are(buf, ""); } + /* + * Skill with current weapon. Might help players who've never + * noticed #enhance or decided that it was pointless. + * + * TODO? Maybe merge wielding line and skill line into one sentence. + */ + if ((wtype = uwep_skill_type()) != P_NONE) { + char sklvlbuf[20]; + int sklvl = P_SKILL(wtype); + boolean hav = (sklvl != P_UNSKILLED && sklvl != P_SKILLED); + + if (sklvl == P_ISRESTRICTED) + Strcpy(sklvlbuf, "no"); + else + (void) lcase(skill_level_name(wtype, sklvlbuf)); + /* "you have no/basic/expert/master/grand-master skill with " + or "you are unskilled/skilled in " */ + Sprintf(buf, "%s %s %s", sklvlbuf, + hav ? "skill with" : "in", skill_name(wtype)); + if (can_advance(wtype, FALSE)) + Sprintf(eos(buf), " and %s that", + !final ? "can enhance" : "could have enhanced"); + if (hav) + you_have(buf, ""); + else + you_are(buf, ""); + } /* report 'nudity' */ if (!uarm && !uarmu && !uarmc && !uarmg && !uarmf && !uarmh) { if (u.uroleplay.nudist) @@ -2335,8 +2448,8 @@ int final; /*\ * Attributes \*/ - putstr(en_win, 0, ""); - putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:"); + enlght_out(""); + enlght_out(final ? "Final Attributes:" : "Current Attributes:"); if (u.uevent.uhand_of_elbereth) { static const char *const hofe_titles[3] = { "the Hand of Elbereth", diff --git a/src/detect.c b/src/detect.c index 80a985096..ca6eda709 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 detect.c $NHDT-Date: 1539908137 2018/10/19 00:15:37 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.83 $ */ +/* NetHack 3.6 detect.c $NHDT-Date: 1541144458 2018/11/02 07:40:58 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.85 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1548,14 +1548,16 @@ boolean via_warning; if (mtmp->m_ap_type) { seemimic(mtmp); found_something = TRUE; - } else if (mtmp->mundetected - && (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) { - if (via_warning) { - Your("warning senses cause you to take a second %s.", - Blind ? "to check nearby" : "look close by"); - display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */ + } else if (!canspotmon(mtmp)) { + if (mtmp->mundetected + && (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) { + if (via_warning) { + Your("warning senses cause you to take a second %s.", + Blind ? "to check nearby" : "look close by"); + display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */ + } + mtmp->mundetected = 0; } - mtmp->mundetected = 0; newsym(x, y); found_something = TRUE; } diff --git a/src/end.c b/src/end.c index 93216c76c..c423fbcde 100644 --- a/src/end.c +++ b/src/end.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 end.c $NHDT-Date: 1539804880 2018/10/17 19:34:40 $ $NHDT-Branch: keni-makedefsm $:$NHDT-Revision: 1.146 $ */ +/* NetHack 3.6 end.c $NHDT-Date: 1540767809 2018/10/28 23:03:29 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.148 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -851,7 +851,8 @@ int how; if (u.uhpmax < uhpmin) u.uhpmax = uhpmin; u.uhp = u.uhpmax; - u.uswldtim = 0; + if (Upolyd) /* Unchanging, or death which bypasses losing hit points */ + u.mh = u.mhmax; if (u.uhunger < 500) { u.uhunger = 500; newuhs(FALSE); @@ -877,6 +878,16 @@ int how; curs_on_u(); if (!context.mon_moving) endmultishot(FALSE); + if (u.uswallow) { + /* might drop hero onto a trap that kills her all over again */ + expels(u.ustuck, u.ustuck->data, TRUE); + } else if (u.ustuck) { + if (Upolyd && sticks(youmonst.data)) + You("release %s.", mon_nam(u.ustuck)); + else + pline("%s releases you.", Monnam(u.ustuck)); + unstuck(u.ustuck); + } } /* @@ -1006,13 +1017,16 @@ void done(how) int how; { + boolean survive = FALSE; + if (how == TRICKED) { if (killer.name[0]) { paniclog("trickery", killer.name); - killer.name[0] = 0; + killer.name[0] = '\0'; } if (wizard) { You("are a very tricky wizard, it seems."); + killer.format = KILLED_BY_AN; /* reset to 0 */ return; } } @@ -1037,8 +1051,17 @@ int how; if (!killer.name[0] || how >= PANICKED) Strcpy(killer.name, deaths[how]); - if (how < PANICKED) + if (how < PANICKED) { u.umortality++; + /* in case caller hasn't already done this */ + if (u.uhp > 0 || (Upolyd && u.mh > 0)) { + /* for deaths not triggered by loss of hit points, force + current HP to zero (0 HP when turning into green slime + is iffy but we don't have much choice--that is fatal) */ + u.uhp = u.mh = 0; + context.botl = 1; + } + } if (Lifesaved && (how <= GENOCIDED)) { pline("But wait..."); makeknown(AMULET_OF_LIFE_SAVING); @@ -1055,20 +1078,24 @@ int how; if (how == GENOCIDED) { pline("Unfortunately you are still genocided..."); } else { - killer.name[0] = 0; - killer.format = 0; - return; + survive = TRUE; } } - if ((wizard || discover) && (how <= GENOCIDED) + /* explore and wizard modes offer player the option to keep playing */ + if (!survive && (wizard || discover) && how <= GENOCIDED && !paranoid_query(ParanoidDie, "Die?")) { pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die"); savelife(how); - killer.name[0] = 0; - killer.format = 0; + survive = TRUE; + } + + if (survive) { + killer.name[0] = '\0'; + killer.format = KILLED_BY_AN; /* reset to 0 */ return; } really_done(how); + /*NOTREACHED*/ } /* separated from done() in order to specify the __noreturn__ attribute */ diff --git a/src/exper.c b/src/exper.c index a9b3eed77..5bca20e46 100644 --- a/src/exper.c +++ b/src/exper.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 exper.c $NHDT-Date: 1446975467 2015/11/08 09:37:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ +/* NetHack 3.6 exper.c $NHDT-Date: 1541145516 2018/11/02 07:58:36 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2007. */ /* NetHack may be freely redistributed. See license for details. */ @@ -6,10 +6,9 @@ #include "hack.h" #include -STATIC_DCL long FDECL(newuexp, (int)); STATIC_DCL int FDECL(enermod, (int)); -STATIC_OVL long +long newuexp(lev) int lev; { diff --git a/src/invent.c b/src/invent.c index 34b784475..2a52cda32 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1519672703 2018/02/26 19:18:23 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.225 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1541145517 2018/11/02 07:58:37 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.241 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3605,6 +3605,7 @@ doprgold() /* the messages used to refer to "carrying gold", but that didn't take containers into account */ long umoney = money_cnt(invent); + if (!umoney) Your("wallet is empty."); else diff --git a/src/mhitu.c b/src/mhitu.c index f3fecbd92..85293d57b 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhitu.c $NHDT-Date: 1513297347 2017/12/15 00:22:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.149 $ */ +/* NetHack 3.6 mhitu.c $NHDT-Date: 1540767817 2018/10/28 23:03:37 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.159 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1956,11 +1956,17 @@ struct attack *mattk; if (tmp) stop_occupation(); - if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) { + if (!u.uswallow) { + ; /* life-saving has already expelled swallowed hero */ + } else if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) { pline("%s very hurriedly %s you!", Monnam(mtmp), is_animal(mtmp->data) ? "regurgitates" : "expels"); expels(mtmp, mtmp->data, FALSE); } else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) { + /* 3.6.2: u.uswldtim used to be set to 0 by life-saving but it + expels now so the !u.uswldtim case is no longer possible; + however, polymorphing into a huge form while already + swallowed is still possible */ You("get %s!", is_animal(mtmp->data) ? "regurgitated" : "expelled"); if (flags.verbose && (is_animal(mtmp->data) diff --git a/src/mondata.c b/src/mondata.c index 312448466..74814bd3d 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -762,6 +762,7 @@ const char *in_str; { "lurkers above", PM_LURKER_ABOVE }, { "cavemen", PM_CAVEMAN }, { "cavewomen", PM_CAVEWOMAN }, + { "watchmen", PM_WATCHMAN }, { "djinn", PM_DJINNI }, { "mumakil", PM_MUMAK }, { "erinyes", PM_ERINYS }, diff --git a/src/pickup.c b/src/pickup.c index fae1e2f03..319f1f031 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pickup.c $NHDT-Date: 1516581051 2018/01/22 00:30:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.194 $ */ +/* NetHack 3.6 pickup.c $NHDT-Date: 1541312259 2018/11/04 06:17:39 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.201 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2720,9 +2720,7 @@ boolean put_in; } else if (flags.menu_style == MENU_FULL) { all_categories = FALSE; Sprintf(buf, "%s what type of objects?", action); - mflags = (ALL_TYPES | UNPAID_TYPES | BUCX_TYPES); - if (put_in) - mflags |= CHOOSE_ALL; + mflags = (ALL_TYPES | UNPAID_TYPES | BUCX_TYPES | CHOOSE_ALL); n = query_category(buf, put_in ? invent : current_container->cobj, mflags, &pick_list, PICK_ANY); if (!n) @@ -2739,12 +2737,23 @@ boolean put_in; } if (loot_everything) { - current_container->cknown = 1; - for (otmp = current_container->cobj; otmp; otmp = otmp2) { - otmp2 = otmp->nobj; - res = out_container(otmp); - if (res < 0) - break; + if (!put_in) { + current_container->cknown = 1; + for (otmp = current_container->cobj; otmp; otmp = otmp2) { + otmp2 = otmp->nobj; + res = out_container(otmp); + if (res < 0) + break; + n_looted += res; + } + } else { + for (otmp = invent; otmp && current_container; otmp = otmp2) { + otmp2 = otmp->nobj; + res = in_container(otmp); + if (res < 0) + break; + n_looted += res; + } } } else { mflags = INVORDER_SORT; diff --git a/src/weapon.c b/src/weapon.c index b680f864c..a590366bb 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 weapon.c $NHDT-Date: 1454660575 2016/02/05 08:22:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.57 $ */ +/* NetHack 3.6 weapon.c $NHDT-Date: 1541145518 2018/11/02 07:58:38 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.60 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,6 +10,12 @@ */ #include "hack.h" +STATIC_DCL void FDECL(give_may_advance_msg, (int)); +STATIC_DCL boolean FDECL(could_advance, (int)); +STATIC_DCL boolean FDECL(peaked_skill, (int)); +STATIC_DCL int FDECL(slots_required, (int)); +STATIC_DCL void FDECL(skill_advance, (int)); + /* Categories whose names don't come from OBJ_NAME(objects[type]) */ #define PN_BARE_HANDED (-1) /* includes martial arts */ @@ -27,8 +33,6 @@ #define PN_ESCAPE_SPELL (-13) #define PN_MATTER_SPELL (-14) -STATIC_DCL void FDECL(give_may_advance_msg, (int)); - STATIC_VAR NEARDATA const short skill_names_indices[P_NUM_SKILLS] = { 0, DAGGER, KNIFE, AXE, PICK_AXE, SHORT_SWORD, BROADSWORD, LONG_SWORD, TWO_HANDED_SWORD, SCIMITAR, PN_SABER, CLUB, MACE, MORNING_STAR, FLAIL, @@ -51,25 +55,6 @@ STATIC_VAR NEARDATA const char *const barehands_or_martial[] = { "bare handed combat", "martial arts" }; -STATIC_OVL void -give_may_advance_msg(skill) -int skill; -{ - You_feel("more confident in your %sskills.", - skill == P_NONE ? "" : skill <= P_LAST_WEAPON - ? "weapon " - : skill <= P_LAST_SPELL - ? "spell casting " - : "fighting "); -} - -STATIC_DCL boolean FDECL(can_advance, (int, BOOLEAN_P)); -STATIC_DCL boolean FDECL(could_advance, (int)); -STATIC_DCL boolean FDECL(peaked_skill, (int)); -STATIC_DCL int FDECL(slots_required, (int)); -STATIC_DCL char *FDECL(skill_level_name, (int, char *)); -STATIC_DCL void FDECL(skill_advance, (int)); - #define P_NAME(type) \ ((skill_names_indices[type] > 0) \ ? OBJ_NAME(objects[skill_names_indices[type]]) \ @@ -80,6 +65,17 @@ STATIC_DCL void FDECL(skill_advance, (int)); static NEARDATA const char kebabable[] = { S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0' }; +STATIC_OVL void +give_may_advance_msg(skill) +int skill; +{ + You_feel("more confident in your %sskills.", + (skill == P_NONE) ? "" + : (skill <= P_LAST_WEAPON) ? "weapon " + : (skill <= P_LAST_SPELL) ? "spell casting " + : "fighting "); +} + /* weapon's skill category name for use as generalized description of weapon; mostly used to shorten "you drop your " messages when slippery fingers or polymorph causes hero to involuntarily drop wielded weapon(s) */ @@ -871,7 +867,7 @@ boolean verbose; } /* copy the skill level name into the given buffer */ -STATIC_OVL char * +char * skill_level_name(skill, buf) int skill; char *buf; @@ -906,6 +902,13 @@ char *buf; return buf; } +const char * +skill_name(skill) +int skill; +{ + return P_NAME(skill); +} + /* return the # of slots required to advance the skill */ STATIC_OVL int slots_required(skill) @@ -932,8 +935,7 @@ int skill; } /* return true if this skill can be advanced */ -/*ARGSUSED*/ -STATIC_OVL boolean +boolean can_advance(skill, speedy) int skill; boolean speedy; diff --git a/win/X11/winX.c b/win/X11/winX.c index 0c1016da9..7337e6f04 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -202,6 +202,9 @@ boolean init; static int numlines = 0; struct xwindow *wp = &window_list[WIN_MESSAGE]; + if (init) + curr = (struct line_element *) 0; + if (!curr) { curr = wp->mesg_information->head; numlines = 0; @@ -1920,35 +1923,38 @@ char *input; /* Display file ----------------------------------------------------------- */ +/* uses a menu (with no selectors specified) rather than a text window + to allow previous_page and first_menu actions to move backwards */ void X11_display_file(str, complain) const char *str; boolean complain; { dlb *fp; + winid newwin; + struct xwindow *wp; + anything any; + menu_item *menu_list; #define LLEN 128 char line[LLEN]; /* Use the port-independent file opener to see if the file exists. */ fp = dlb_fopen(str, RDTMODE); - if (!fp) { if (complain) pline("Cannot open %s. Sorry.", str); return; /* it doesn't exist, ignore */ } - winid newwin = X11_create_nhwindow(NHW_MENU); - struct xwindow *wp = &window_list[newwin]; - anything any = zeroany; - menu_item *menu_list; - + newwin = X11_create_nhwindow(NHW_MENU); + wp = &window_list[newwin]; X11_start_menu(newwin); + any = zeroany; while (dlb_fgets(line, LLEN, fp)) { - X11_add_menu(newwin, NO_GLYPH, &any, 0, 0, ATR_NONE, line, MENU_UNSELECTED); + X11_add_menu(newwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + line, MENU_UNSELECTED); } - (void) dlb_fclose(fp); /* show file name as the window title */ diff --git a/win/X11/winmenu.c b/win/X11/winmenu.c index 05f0bba36..eaba350d4 100644 --- a/win/X11/winmenu.c +++ b/win/X11/winmenu.c @@ -254,7 +254,8 @@ Cardinal *num_params; return; } - if (menu_info->is_active && menu_info->how != PICK_NONE) { /* waiting for input */ + /* don't exclude PICK_NONE menus; doing so disables scrolling via keys */ + if (menu_info->is_active) { /* waiting for input */ /* first check for an explicit selector match, so that it won't be overridden if it happens to duplicate a mapped menu command (':' to look inside a container vs ':' to select via search string) */ @@ -324,12 +325,14 @@ Cardinal *num_params; } else if (ch == MENU_FIRST_PAGE || ch == MENU_LAST_PAGE) { Widget hbar = (Widget) 0, vbar = (Widget) 0; float top = (ch == MENU_FIRST_PAGE) ? 0.0 : 1.0; + find_scrollbars(wp->w, &hbar, &vbar); if (vbar) XtCallCallbacks(vbar, XtNjumpProc, &top); return; } else if (ch == MENU_NEXT_PAGE || ch == MENU_PREVIOUS_PAGE) { Widget hbar = (Widget) 0, vbar = (Widget) 0; + find_scrollbars(wp->w, &hbar, &vbar); if (vbar) { float shown, top; @@ -1029,7 +1032,9 @@ Widget form,under; num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), ok); num_args++; +#if 0 /* [cancel] is a viable choice even for PICK_NONE */ XtSetArg(args[num_args], nhStr(XtNsensitive), how != PICK_NONE); num_args++; +#endif XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; diff --git a/win/tty/topl.c b/win/tty/topl.c index 8aed570e7..97919a3d9 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 topl.c $NHDT-Date: 1490908468 2017/03/30 21:14:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.36 $ */ +/* NetHack 3.6 topl.c $NHDT-Date: 1540934784 2018/10/30 21:26:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.38 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -637,7 +637,7 @@ boolean init; * * It's also called by the quest pager code when a block message * has a one-line summary specified. We put that line directly - * message history for ^P recall without having displayed it. + * into message history for ^P recall without having displayed it. */ void tty_putmsghistory(msg, restoring_msghist)