diff --git a/doc/fixes36.1 b/doc/fixes36.1 index ddad2f371..bf5df58cb 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -378,6 +378,27 @@ levitation vs encumbrance message sequencing issues: putting on boots of levitation reported reduction of encumbrance before finish-wearing and float-up messages, taking off such boots didn't report increase of encumbrance until player took another action +removing a blindfold with 'A' took two turns, with 'R' (and 'T') only one, + and could result in a crash if the blindfold was stolen during removal +removing a blindfold and wielded weapon with 'A' could result in crash if the + weapon was destroyed by various methods +cmdassist help for movement prefix followed by invalid direction was strange + when the direction was up, down, or self disallowed for that prefix +poor message when shape-shifted vampire reverts to vampire if it has a name: + The Dracula suddenly transforms and rises as Dracula. +poor message when shape-shifted vampire reverts if cause of 'death' was + disintegration or digestion and shifted form wasn't amorphous: + The vampire bat is disintegrated. The vampire bat suddenly transforms + and rises as a vampire. (fix: switch to existing alternate phrasing + used for amorphous form, "reconstitute" rather than "transform") +poor message when named vampire shifts shape within view: + You observe a Dracula where a Dracula was. +vampire shifting into fog cloud to pass under door "oozed" rather than "flowed" +adult green dragons and the Chromatic Dragon were blinded by gas clouds +named floating eye (when hit by another monster with reflection) or named + silver weapon (when hero hits silver-hating monster) could disrupt + message formatting and conceivably trigger crash if name had '%' in it +crashes for 'A' above were downgraded to impossible "cursed without otmp" Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository @@ -418,6 +439,13 @@ humanoid pet could become hostile but still remain tame if it observed hero attacking a peaceful creature minor ^X/enlightenment bugs: grammar when poly'd into '1 hit dice' critter, missing punctuation for "You entered the dungeon N turns ago" +when configured with DUMPLOG enabled, artifacts were counted twice towards + final score +once Moloch's Sanctum (or Astral Plane via wizard mode level teleport direct + to end-game) was entered, end of game disclosure would reveal that + high priests had been incorrectly flagged as extinct +attempting to name an item as an artifact and failing via hand slip violates + illiterate conduct Platform- and/or Interface-Specific Fixes diff --git a/include/decl.h b/include/decl.h index 89533c9ae..18b37c295 100644 --- a/include/decl.h +++ b/include/decl.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 decl.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.76 $ */ +/* NetHack 3.6 decl.h $NHDT-Date: 1496531104 2017/06/03 23:05:04 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.82 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -317,6 +317,7 @@ E const char *materialnm[]; #define SUPPRESS_HALLUCINATION 0x04 #define SUPPRESS_SADDLE 0x08 #define EXACT_NAME 0x0F +#define SUPPRESS_NAME 0x10 /* Vision */ E NEARDATA boolean vision_full_recalc; /* TRUE if need vision recalc */ diff --git a/include/extern.h b/include/extern.h index 0ad6935c4..88afd012e 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1494107197 2017/05/06 21:46:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.587 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1496959470 2017/06/08 22:04:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.591 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -270,7 +270,9 @@ E void NDECL(warnreveal); E int FDECL(dosearch0, (int)); E int NDECL(dosearch); E void NDECL(sokoban_detect); +#ifdef DUMPLOG E void NDECL(dump_map); +#endif E void FDECL(reveal_terrain, (int, int)); /* ### dig.c ### */ @@ -402,6 +404,7 @@ E char *FDECL(mon_nam, (struct monst *)); E char *FDECL(noit_mon_nam, (struct monst *)); E char *FDECL(Monnam, (struct monst *)); E char *FDECL(noit_Monnam, (struct monst *)); +E char *FDECL(noname_monnam, (struct monst *, int)); E char *FDECL(m_monnam, (struct monst *)); E char *FDECL(y_monnam, (struct monst *)); E char *FDECL(Adjmonnam, (struct monst *, const char *)); @@ -433,6 +436,7 @@ E void FDECL(off_msg, (struct obj *)); E void FDECL(set_wear, (struct obj *)); E boolean FDECL(donning, (struct obj *)); E boolean FDECL(doffing, (struct obj *)); +E void FDECL(cancel_doff, (struct obj *, long)); E void NDECL(cancel_don); E int FDECL(stop_donning, (struct obj *)); E int NDECL(Armor_off); @@ -873,6 +877,7 @@ E boolean FDECL(onlyspace, (const char *)); E char *FDECL(tabexpand, (char *)); E char *FDECL(visctrl, (CHAR_P)); E char *FDECL(strsubst, (char *, const char *, const char *)); +E int FDECL(strNsubst, (char *, const char *, const char *, int)); E const char *FDECL(ordin, (int)); E char *FDECL(sitoa, (int)); E int FDECL(sgn, (int)); diff --git a/src/apply.c b/src/apply.c index e74160b9e..546d2cefd 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 apply.c $NHDT-Date: 1457397477 2016/03/08 00:37:57 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.224 $ */ +/* NetHack 3.6 apply.c $NHDT-Date: 1496619131 2017/06/04 23:32:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.232 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2060,6 +2060,7 @@ long timeout; char and_vanish[BUFSZ]; struct obj *mshelter = level.objects[mtmp->mx][mtmp->my]; + /* [m_monnam() yields accurate mon type, overriding hallucination] */ Sprintf(monnambuf, "%s", an(m_monnam(mtmp))); and_vanish[0] = '\0'; if ((mtmp->minvis && !See_invisible) diff --git a/src/cmd.c b/src/cmd.c index 048fc5bbd..fc29aaf6b 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1494034344 2017/05/06 01:32:24 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.256 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1494985492 2017/05/17 01:44:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.258 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -184,8 +184,8 @@ static const char *readchar_queue = ""; static coord clicklook_cc; STATIC_DCL char *NDECL(parse); -STATIC_DCL void FDECL(show_direction_keys, (winid, BOOLEAN_P)); -STATIC_DCL boolean FDECL(help_dir, (CHAR_P, const char *)); +STATIC_DCL void FDECL(show_direction_keys, (winid, CHAR_P, BOOLEAN_P)); +STATIC_DCL boolean FDECL(help_dir, (CHAR_P, int, const char *)); STATIC_PTR int doprev_message(VOID_ARGS) @@ -3073,7 +3073,11 @@ dokeylist(VOID_ARGS) boolean keys_used[256] = {0}; winid datawin; int i; - const struct { + static const char + run_desc[] = "Prefix: run until something very interesting is seen", + forcefight_desc[] = + "Prefix: force fight even if you don't see a monster"; + static const struct { int nhkf; const char *desc; boolean numpad; @@ -3081,22 +3085,18 @@ dokeylist(VOID_ARGS) { NHKF_ESC, "escape from the current query/action", FALSE }, { NHKF_RUSH, "Prefix: rush until something interesting is seen", FALSE }, - { NHKF_RUN, - "Prefix: run until something extremely interesting is seen", FALSE }, - { NHKF_RUN2, - "Prefix: run until something extremely interesting is seen", TRUE }, - { NHKF_FIGHT, - "Prefix: force fight even if you don't see a monster", FALSE }, - { NHKF_FIGHT2, - "Prefix: force fight even if you don't see a monster", TRUE }, + { NHKF_RUN, run_desc, FALSE }, + { NHKF_RUN2, run_desc, TRUE }, + { NHKF_FIGHT, forcefight_desc, FALSE }, + { NHKF_FIGHT2, forcefight_desc, TRUE } , { NHKF_NOPICKUP, "Prefix: move without picking up objects/fighting", FALSE }, { NHKF_RUN_NOPICKUP, "Prefix: run without picking up objects/fighting", FALSE }, - { NHKF_DOINV, "inventory (same as #inventory)", TRUE }, + { NHKF_DOINV, "view inventory", TRUE }, { NHKF_REQMENU, "Prefix: request a menu", FALSE }, #ifdef REDO - { NHKF_DOAGAIN , "redo the previous command", FALSE }, + { NHKF_DOAGAIN , "re-do: perform the previous command again", FALSE }, #endif { 0, (const char *) 0, FALSE } }; @@ -3108,7 +3108,7 @@ dokeylist(VOID_ARGS) /* directional keys */ putstr(datawin, 0, ""); putstr(datawin, 0, "Directional keys:"); - show_direction_keys(datawin, FALSE); + show_direction_keys(datawin, '.', FALSE); /* '.'==self in direction grid */ keys_used[(uchar) Cmd.move_NW] = keys_used[(uchar) Cmd.move_N] = keys_used[(uchar) Cmd.move_NE] = keys_used[(uchar) Cmd.move_W] @@ -3942,11 +3942,12 @@ int NDECL((*cmd_func)); } int -ch2spkeys(c, start,end) +ch2spkeys(c, start, end) char c; int start,end; { int i; + for (i = start; i <= end; i++) if (Cmd.spkeys[i] == c) return i; @@ -3957,6 +3958,7 @@ void rhack(cmd) register char *cmd; { + int spkey; boolean do_walk, do_rush, prefix_seen, bad_command, firsttime = (cmd == 0); @@ -3990,7 +3992,9 @@ register char *cmd; /* handle most movement commands */ do_walk = do_rush = prefix_seen = FALSE; context.travel = context.travel1 = 0; - switch (ch2spkeys(*cmd, NHKF_RUN,NHKF_CLICKLOOK)) { + spkey = ch2spkeys(*cmd, NHKF_RUN, NHKF_CLICKLOOK); + + switch (spkey) { case NHKF_RUSH: if (movecmd(cmd[1])) { context.run = 2; @@ -4161,14 +4165,13 @@ register char *cmd; if (bad_command) { char expcmd[20]; /* we expect 'cmd' to point to 1 or 2 chars */ - register char c; + char c, c1 = cmd[1]; expcmd[0] = '\0'; while ((c = *cmd++) != '\0') Strcat(expcmd, visctrl(c)); /* add 1..4 chars plus terminator */ - if (!prefix_seen || !iflags.cmdassist - || !help_dir(0, "Invalid direction key!")) + if (!prefix_seen || !help_dir(c1, spkey, "Invalid direction key!")) Norep("Unknown command '%s'.", expcmd); } /* didn't move */ @@ -4319,7 +4322,8 @@ retry: if (!index(quitchars, dirsym)) { help_requested = (dirsym == Cmd.spkeys[NHKF_GETDIR_HELP]); if (help_requested || iflags.cmdassist) { - did_help = help_dir((s && *s == '^') ? dirsym : 0, + did_help = help_dir((s && *s == '^') ? dirsym : '\0', + NHKF_ESC, help_requested ? (const char *) 0 : "Invalid direction key!"); if (help_requested) @@ -4339,61 +4343,144 @@ retry: } STATIC_OVL void -show_direction_keys(win, nodiag) -winid win; +show_direction_keys(win, centerchar, nodiag) +winid win; /* should specify a window which is using a fixed-width font... */ +char centerchar; /* '.' or '@' or ' ' */ boolean nodiag; { char buf[BUFSZ]; + if (!centerchar) + centerchar = ' '; + if (nodiag) { Sprintf(buf, " %c ", Cmd.move_N); putstr(win, 0, buf); putstr(win, 0, " | "); - Sprintf(buf, " %c- . -%c", Cmd.move_W, Cmd.move_E); + Sprintf(buf, " %c- %c -%c", + Cmd.move_W, centerchar, Cmd.move_E); putstr(win, 0, buf); putstr(win, 0, " | "); Sprintf(buf, " %c ", Cmd.move_S); putstr(win, 0, buf); } else { - Sprintf(buf, " %c %c %c", Cmd.move_NW, Cmd.move_N, - Cmd.move_NE); + Sprintf(buf, " %c %c %c", + Cmd.move_NW, Cmd.move_N, Cmd.move_NE); putstr(win, 0, buf); putstr(win, 0, " \\ | / "); - Sprintf(buf, " %c- . -%c", Cmd.move_W, Cmd.move_E); + Sprintf(buf, " %c- %c -%c", + Cmd.move_W, centerchar, Cmd.move_E); putstr(win, 0, buf); putstr(win, 0, " / | \\ "); - Sprintf(buf, " %c %c %c", Cmd.move_SW, Cmd.move_S, - Cmd.move_SE); + Sprintf(buf, " %c %c %c", + Cmd.move_SW, Cmd.move_S, Cmd.move_SE); putstr(win, 0, buf); }; } +/* explain choices if player has asked for getdir() help or has given + an invalid direction after a prefix key ('F', 'g', 'm', &c), which + might be bogus but could be up, down, or self when not applicable */ STATIC_OVL boolean -help_dir(sym, msg) +help_dir(sym, spkey, msg) char sym; +int spkey; /* NHKF_ code for prefix key, if one was used, or for ESC */ const char *msg; { static const char wiz_only_list[] = "EFGIVW"; char ctrl; winid win; char buf[BUFSZ], buf2[BUFSZ], *explain; + const char *dothat, *how; + boolean prefixhandling, viawindow; + + /* NHKF_ESC indicates that player asked for help at getdir prompt */ + viawindow = (spkey == NHKF_ESC || iflags.cmdassist); + prefixhandling = (spkey != NHKF_ESC); + /* + * Handling for prefix keys that don't want special directions. + * Delivered via pline if 'cmdassist' is off, or instead of the + * general message if it's on. + */ + dothat = "do that"; + how = " at"; /* for " at yourself"; not used for up/down */ + switch (spkey) { + case NHKF_NOPICKUP: + dothat = "move"; + break; + case NHKF_RUSH: + dothat = "rush"; + break; + case NHKF_RUN2: + if (!Cmd.num_pad) + break; /* else FALLTHRU */ + case NHKF_RUN: + case NHKF_RUN_NOPICKUP: + dothat = "run"; + break; + case NHKF_FIGHT2: + if (!Cmd.num_pad) + break; /* else FALLTHRU */ + case NHKF_FIGHT: + dothat = "fight"; + how = ""; /* avoid "fight at yourself" */ + break; + default: + prefixhandling = FALSE; + break; + } + + buf[0] = '\0'; + /* for movement prefix followed by '.' or (numpad && 's') to mean 'self'; + note: '-' for hands (inventory form of 'self') is not handled here */ + if (prefixhandling + && (sym == Cmd.spkeys[NHKF_GETDIR_SELF] + || (Cmd.num_pad && sym == Cmd.spkeys[NHKF_GETDIR_SELF2]))) { + Sprintf(buf, "You can't %s%s yourself.", dothat, how); + /* for movement prefix followed by up or down */ + } else if (prefixhandling && (sym == '<' || sym == '>')) { + Sprintf(buf, "You can't %s %s.", dothat, + /* was "upwards" and "downwards", but they're considered + to be variants of canonical "upward" and "downward" */ + (sym == '<') ? "upward" : "downward"); + } + + /* if '!cmdassist', display via pline() and we're done (note: asking + for help at getdir() prompt forces cmdassist for this operation) */ + if (!viawindow) { + if (prefixhandling) { + if (!*buf) + Sprintf(buf, "Invalid direction for '%s' prefix.", + visctrl(Cmd.spkeys[spkey])); + pline("%s", buf); + return TRUE; + } + /* when 'cmdassist' is off and caller doesn't insist, do nothing */ + return FALSE; + } win = create_nhwindow(NHW_TEXT); if (!win) return FALSE; - if (msg) { + + if (*buf) { + /* show bad-prefix message instead of general invalid-direction one */ + putstr(win, 0, buf); + putstr(win, 0, ""); + } else if (msg) { Sprintf(buf, "cmdassist: %s", msg); putstr(win, 0, buf); putstr(win, 0, ""); } - if (letter(sym) || sym == '[') { /* 'dat/cmdhelp' shows ESC as ^[ */ + + if (!prefixhandling && (letter(sym) || sym == '[')) { + /* '[': old 'cmdhelp' showed ESC as ^[ */ sym = highc(sym); /* @A-Z[ (note: letter() accepts '@') */ ctrl = (sym - 'A') + 1; /* 0-27 (note: 28-31 aren't applicable) */ if ((explain = dowhatdoes_core(ctrl, buf2)) != 0 && (!index(wiz_only_list, sym) || wizard)) { Sprintf(buf, "Are you trying to use ^%c%s?", sym, - index(wiz_only_list, sym) - ? "" + index(wiz_only_list, sym) ? "" : " as specified in the Guidebook"); putstr(win, 0, buf); putstr(win, 0, ""); @@ -4407,17 +4494,29 @@ const char *msg; } } - Sprintf(buf, "Valid direction keys %sare:", - NODIAG(u.umonnum) ? "in your current form " : ""); + Sprintf(buf, "Valid direction keys%s%s%s are:", + prefixhandling ? " to " : "", prefixhandling ? dothat : "", + NODIAG(u.umonnum) ? " in your current form" : ""); putstr(win, 0, buf); - show_direction_keys(win, NODIAG(u.umonnum)); + show_direction_keys(win, !prefixhandling ? '.' : ' ', NODIAG(u.umonnum)); + + if (!prefixhandling || spkey == NHKF_NOPICKUP) { + /* NOPICKUP: unlike the other prefix keys, 'm' allows up/down for + stair traversal; we won't get here when "m<" or "m>" has been + given but we include up and down for 'm'+invalid_direction; + self is excluded as a viable direction for every prefix */ + putstr(win, 0, ""); + putstr(win, 0, " < up"); + putstr(win, 0, " > down"); + if (!prefixhandling) { + int selfi = Cmd.num_pad ? NHKF_GETDIR_SELF2 : NHKF_GETDIR_SELF; + + Sprintf(buf, " %4s direct at yourself", + visctrl(Cmd.spkeys[selfi])); + putstr(win, 0, buf); + } + } - putstr(win, 0, ""); - putstr(win, 0, " < up"); - putstr(win, 0, " > down"); - Sprintf(buf, " %4s direct at yourself", - visctrl(Cmd.spkeys[NHKF_GETDIR_SELF])); - putstr(win, 0, buf); if (msg) { /* non-null msg means that this wasn't an explicit user request */ putstr(win, 0, ""); diff --git a/src/detect.c b/src/detect.c index def22469e..86e3159bf 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 detect.c $NHDT-Date: 1491705573 2017/04/09 02:39:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.76 $ */ +/* NetHack 3.6 detect.c $NHDT-Date: 1495346103 2017/05/21 05:55:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.77 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1799,15 +1799,28 @@ int default_glyph, which_subset; return glyph; } +#ifdef DUMPLOG void dump_map() { - int x, y, glyph; + int x, y, glyph, skippedrows; int subset = TER_MAP | TER_TRP | TER_OBJ | TER_MON; int default_glyph = cmap_to_glyph(level.flags.arboreal ? S_tree : S_stone); char buf[BUFSZ]; + boolean blankrow, toprow; + /* + * Squeeze out excess vertial space when dumping the map. + * If there are any blank map rows at the top, suppress them + * (our caller has already printed a separator). If there is + * more than one blank map row at the bottom, keep just one. + * Any blank rows within the middle of the map are kept. + * Note: putstr() with winid==0 is for dumplog. + */ + skippedrows = 0; + toprow = TRUE; for (y = 0; y < ROWNO; y++) { + blankrow = TRUE; /* assume blank until we discover otherwise */ for (x = 1; x < COLNO; x++) { int ch, color; unsigned special; @@ -1815,12 +1828,27 @@ dump_map() glyph = reveal_terrain_getglyph(x,y, FALSE, u.uswallow, default_glyph, subset); (void) mapglyph(glyph, &ch, &color, &special, x, y); - buf[x-1] = ch; + buf[x - 1] = ch; + if (ch != ' ') + blankrow = FALSE; + } + if (!blankrow) { + buf[x - 2] = '\0'; + if (toprow) { + skippedrows = 0; + toprow = FALSE; + } + for (x = 0; x < skippedrows; x++) + putstr(0, 0, ""); + putstr(0, 0, buf); /* map row #y */ + } else { + ++skippedrows; } - buf[x-2] = '\0'; - putstr(0,0, buf); } + if (skippedrows) + putstr(0, 0, ""); } +#endif /* DUMPLOG */ /* idea from crawl; show known portion of map without any monsters, objects, or traps occluding the view of the underlying terrain */ diff --git a/src/display.c b/src/display.c index d3a4e50ae..bede97c3c 100644 --- a/src/display.c +++ b/src/display.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 display.c $NHDT-Date: 1463614572 2016/05/18 23:36:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.86 $ */ +/* NetHack 3.6 display.c $NHDT-Date: 1496101037 2017/05/29 23:37:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.87 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -424,24 +424,29 @@ xchar worm_tail; /* mon is actually a worm tail */ } } - /* If the mimic is unsuccessfully mimicing something, display the monster + /* If the mimic is unsuccessfully mimicing something, display the monster. */ if (!mon_mimic || sensed) { int num; /* [ALI] Only use detected glyphs when monster wouldn't be * visible by any other means. + * + * There are no glyphs for "detected pets" so we have to + * decide whether to display such things as detected or as tame. + * If both are being highlighted in the same way, it doesn't + * matter, but if not, showing them as pets is preferrable. */ - if (sightflags == DETECTED && !mon->mtame) { - if (worm_tail) - num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); - else - num = detected_mon_to_glyph(mon); - } else if (mon->mtame && !Hallucination) { + if (mon->mtame && !Hallucination) { if (worm_tail) num = petnum_to_glyph(PM_LONG_WORM_TAIL); else num = pet_to_glyph(mon); + } else if (sightflags == DETECTED) { + if (worm_tail) + num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); + else + num = detected_mon_to_glyph(mon); } else { if (worm_tail) num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); @@ -666,7 +671,7 @@ xchar x, y; show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); } /* draw monster on top if we can sense it */ - if ((x != u.ux || y != u.uy) && (mon = m_at(x, y)) && sensemon(mon)) + if ((x != u.ux || y != u.uy) && (mon = m_at(x, y)) != 0 && sensemon(mon)) display_monster(x, y, mon, (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)) ? PHYSICALLY_SEEN diff --git a/src/do_name.c b/src/do_name.c index 34a853159..452f6c555 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1489494376 2017/03/14 12:26:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.116 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1496531112 2017/06/03 23:05:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.119 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1081,6 +1081,9 @@ register struct obj *obj; pline("While engraving, your %s slips.", body_part(HAND)); display_nhwindow(WIN_MESSAGE, FALSE); You("engrave: \"%s\".", buf); + /* violate illiteracy conduct since hero attempted to write + a valid artifact name */ + u.uconduct.literate++; } ++via_naming; /* This ought to be an argument rather than a static... */ obj = oname(obj, buf); @@ -1389,6 +1392,8 @@ rndghostname() * a_monnam: a newt it an invisible orc Fido * m_monnam: newt xan orc Fido * y_monnam: your newt your xan your invisible orc Fido + * noname_monnam(mon,article): + * article newt art xan art invisible orc art dog */ /* Bug: if the monster is a priest or shopkeeper, not every one of these @@ -1409,13 +1414,14 @@ const char *adjective; int suppress; /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE. * EXACT_NAME: combination of all the above + * SUPPRESS_NAME: omit monster's assigned name (unless uniq w/ pname). */ boolean called; { char *buf = nextmbuf(); struct permonst *mdat = mtmp->data; const char *pm_name = mdat->mname; - boolean do_hallu, do_invis, do_it, do_saddle; + boolean do_hallu, do_invis, do_it, do_saddle, do_name; boolean name_at_start, has_adjectives; char *bp; @@ -1430,6 +1436,7 @@ boolean called; && !program_state.gameover && mtmp != u.usteed && !(u.uswallow && mtmp == u.ustuck) && !(suppress & SUPPRESS_IT); do_saddle = !(suppress & SUPPRESS_SADDLE); + do_name = !(suppress & SUPPRESS_NAME) || type_is_pname(mdat); buf[0] = '\0'; @@ -1510,7 +1517,7 @@ boolean called; Strcat(buf, rname); name_at_start = bogon_is_pname(rnamecode); - } else if (has_mname(mtmp)) { + } else if (do_name && has_mname(mtmp)) { char *name = MNAME(mtmp); if (mdat == &mons[PM_GHOST]) { @@ -1605,7 +1612,7 @@ struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_THE, (char *) 0, (has_mname(mtmp)) ? (SUPPRESS_SADDLE | SUPPRESS_IT) - : SUPPRESS_IT, + : SUPPRESS_IT, FALSE); } @@ -1629,7 +1636,17 @@ struct monst *mtmp; return bp; } -/* monster's own name */ +/* return "a dog" rather than "Fido", honoring hallucination and visibility */ +char * +noname_monnam(mtmp, article) +struct monst *mtmp; +int article; +{ + return x_monnam(mtmp, article, (char *) 0, SUPPRESS_NAME, FALSE); +} + +/* monster's own name -- overrides hallucination and [in]visibility + so shouldn't be used in ordinary messages (mainly for disclosure) */ char * m_monnam(mtmp) struct monst *mtmp; diff --git a/src/do_wear.c b/src/do_wear.c index f0c1038dc..71599fd7a 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_wear.c $NHDT-Date: 1494107204 2017/05/06 21:46:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.94 $ */ +/* NetHack 3.6 do_wear.c $NHDT-Date: 1496959478 2017/06/08 22:04:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.98 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1200,37 +1200,30 @@ struct obj *obj; /* if null, do all worn items; otherwise just obj itself */ } /* check whether the target object is currently being put on (or taken off-- - also checks for doffing) */ + also checks for doffing--[why?]) */ boolean donning(otmp) struct obj *otmp; { - /* long what = (occupation == take_off) ? context.takeoff.what : 0L; */ - long what = context.takeoff.what; /* if nonzero, occupation is implied */ boolean result = FALSE; - /* 'W' and 'T' set afternmv, 'A' sets context.takeoff.what */ - if (otmp == uarm) - result = (afternmv == Armor_on || afternmv == Armor_off - || what == WORN_ARMOR); + /* 'W' (or 'P' used for armor) sets afternmv */ + if (doffing(otmp)) + result = TRUE; + else if (otmp == uarm) + result = (afternmv == Armor_on); else if (otmp == uarmu) - result = (afternmv == Shirt_on || afternmv == Shirt_off - || what == WORN_SHIRT); + result = (afternmv == Shirt_on); else if (otmp == uarmc) - result = (afternmv == Cloak_on || afternmv == Cloak_off - || what == WORN_CLOAK); + result = (afternmv == Cloak_on); else if (otmp == uarmf) - result = (afternmv == Boots_on || afternmv == Boots_off - || what == WORN_BOOTS); + result = (afternmv == Boots_on); else if (otmp == uarmh) - result = (afternmv == Helmet_on || afternmv == Helmet_off - || what == WORN_HELMET); + result = (afternmv == Helmet_on); else if (otmp == uarmg) - result = (afternmv == Gloves_on || afternmv == Gloves_off - || what == WORN_GLOVES); + result = (afternmv == Gloves_on); else if (otmp == uarms) - result = (afternmv == Shield_on || afternmv == Shield_off - || what == WORN_SHIELD); + result = (afternmv == Shield_on); return result; } @@ -1244,7 +1237,7 @@ struct obj *otmp; long what = context.takeoff.what; boolean result = FALSE; - /* 'T' (also 'W') sets afternmv, 'A' sets context.takeoff.what */ + /* 'T' (or 'R' used for armor) sets afternmv, 'A' sets takeoff.what */ if (otmp == uarm) result = (afternmv == Armor_off || what == WORN_ARMOR); else if (otmp == uarmu) @@ -1259,10 +1252,48 @@ struct obj *otmp; result = (afternmv == Gloves_off || what == WORN_GLOVES); else if (otmp == uarms) result = (afternmv == Shield_off || what == WORN_SHIELD); + /* these 1-turn items don't need 'afternmv' checks */ + else if (otmp == uamul) + result = (what == WORN_AMUL); + else if (otmp == uleft) + result = (what == LEFT_RING); + else if (otmp == uright) + result = (what == RIGHT_RING); + else if (otmp == ublindf) + result = (what == WORN_BLINDF); + else if (otmp == uwep) + result = (what == W_WEP); + else if (otmp == uswapwep) + result = (what == W_SWAPWEP); + else if (otmp == uquiver) + result = (what == W_QUIVER); return result; } +/* despite their names, cancel_don() and cancel_doff() both apply to both + donning and doffing... */ +void +cancel_doff(obj, slotmask) +struct obj *obj; +long slotmask; +{ + /* Called by setworn() for old item in specified slot or by setnotworn() + * for specified item. We don't want to call cancel_don() if we got + * here via _off() -> setworn((struct obj *)0) -> cancel_doff() + * because that would stop the 'A' command from continuing with next + * selected item. So do_takeoff() sets a flag in takeoff.mask for us. + * [For taking off an individual item with 'T'/'R'/'w-', it doesn't + * matter whether cancel_don() gets called here--the item has already + * been removed by now.] + */ + if (!(context.takeoff.mask & I_SPECIAL) && donning(obj)) + cancel_don(); /* applies to doffing too */ + context.takeoff.mask &= ~slotmask; +} + +/* despite their names, cancel_don() and cancel_doff() both apply to both + donning and doffing... */ void cancel_don() { @@ -1299,11 +1330,11 @@ struct obj *stolenobj; /* no message if stolenobj is already being doffing */ /* donning() returns True when doffing too; doffing() is more specific */ putting_on = !doffing(otmp); - /* cancel_don() looks at afternmv; it also serves as cancel_doff() */ + /* cancel_don() looks at afternmv; it can also cancel doffing */ cancel_don(); /* don't want _on() or _off() being called by unmul() since the on or off action isn't completing */ - afternmv = 0; + afternmv = (int NDECL((*))) 0; if (putting_on || otmp != stolenobj) { Sprintf(buf, "You stop %s %s.", putting_on ? "putting on" : "taking off", @@ -2293,6 +2324,7 @@ do_takeoff() struct obj *otmp = (struct obj *) 0; struct takeoff_info *doff = &context.takeoff; + context.takeoff.mask |= I_SPECIAL; /* set flag for cancel_doff() */ if (doff->what == W_WEP) { if (!cursed(uwep)) { setuwep((struct obj *) 0); @@ -2352,6 +2384,7 @@ do_takeoff() } else { impossible("do_takeoff: taking off %lx", doff->what); } + context.takeoff.mask &= ~I_SPECIAL; /* clear cancel_doff() flag */ return otmp; } @@ -2369,10 +2402,9 @@ take_off(VOID_ARGS) if (doff->delay > 0) { doff->delay--; return 1; /* still busy */ - } else { - if ((otmp = do_takeoff())) - off_msg(otmp); } + if ((otmp = do_takeoff()) != 0) + off_msg(otmp); doff->mask &= ~doff->what; doff->what = 0L; } @@ -2427,7 +2459,9 @@ take_off(VOID_ARGS) } else if (doff->what == RIGHT_RING) { doff->delay = 1; } else if (doff->what == WORN_BLINDF) { - doff->delay = 2; + /* [this used to be 2, but 'R' (and 'T') only require 1 turn to + remove a blindfold, so 'A' shouldn't have been requiring 2] */ + doff->delay = 1; } else { impossible("take_off: taking off %lx", doff->what); return 0; /* force done */ diff --git a/src/end.c b/src/end.c index 7685a8226..7cd3e4304 100644 --- a/src/end.c +++ b/src/end.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 end.c $NHDT-Date: 1489192539 2017/03/11 00:35:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.130 $ */ +/* NetHack 3.6 end.c $NHDT-Date: 1495232357 2017/05/19 22:19:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.131 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -59,7 +59,7 @@ STATIC_DCL boolean FDECL(should_query_disclose_option, (int, char *)); #ifdef DUMPLOG STATIC_DCL void NDECL(dump_plines); #endif -STATIC_DCL void FDECL(dump_everything, (int)); +STATIC_DCL void FDECL(dump_everything, (int, time_t)); STATIC_DCL int NDECL(num_extinct); #if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2) @@ -680,8 +680,7 @@ dump_plines() extern char *saved_plines[]; extern unsigned saved_pline_index; - Strcpy(buf, " "); - putstr(0, 0, ""); + Strcpy(buf, " "); /* one space for indentation */ putstr(0, 0, "Latest messages:"); for (i = 0, j = (int) saved_pline_index; i < DUMPLOG_MSG_COUNT; ++i, j = (j + 1) % DUMPLOG_MSG_COUNT) { @@ -697,27 +696,41 @@ dump_plines() } #endif +/*ARGSUSED*/ STATIC_OVL void -dump_everything(how) +dump_everything(how, when) int how; +time_t when; /* date+time at end of game */ { #ifdef DUMPLOG - struct obj *obj; - char pbuf[BUFSZ]; + char pbuf[BUFSZ], datetimebuf[24]; /* [24]: room for 64-bit bogus value */ dump_redirect(TRUE); if (!iflags.in_dumplog) return; - init_symbols(); + init_symbols(); /* revert to default symbol set */ - for (obj = invent; obj; obj = obj->nobj) { - makeknown(obj->otyp); - obj->known = obj->bknown = obj->dknown = obj->rknown = 1; - if (Is_container(obj) || obj->otyp == STATUE) - obj->cknown = obj->lknown = 1; - } + /* one line version ID, which includes build date+time; + it's conceivable that the game started with a different + build date+time or even with an older nethack version, + but we only have access to the one it finished under */ + putstr(0, 0, getversionstring(pbuf)); + putstr(0, 0, ""); + /* game start and end date+time to disambiguate version date+time */ + Strcpy(datetimebuf, yyyymmddhhmmss(ubirthday)); + Sprintf(pbuf, "Game began %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s", + &datetimebuf[0], &datetimebuf[4], &datetimebuf[6], + &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]); + Strcpy(datetimebuf, yyyymmddhhmmss(when)); + Sprintf(eos(pbuf), ", ended %4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s.", + &datetimebuf[0], &datetimebuf[4], &datetimebuf[6], + &datetimebuf[8], &datetimebuf[10], &datetimebuf[12]); + putstr(0, 0, pbuf); + putstr(0, 0, ""); + + /* character name and basic role info */ Sprintf(pbuf, "%s, %s %s %s %s", plname, aligns[1 - u.ualign.type].adj, genders[flags.female].adj, @@ -772,14 +785,7 @@ boolean taken; ask = should_query_disclose_option('i', &defquery); c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery; if (c == 'y') { - struct obj *obj; - - for (obj = invent; obj; obj = obj->nobj) { - makeknown(obj->otyp); - obj->known = obj->bknown = obj->dknown = obj->rknown = 1; - if (Is_container(obj) || obj->otyp == STATUE) - obj->cknown = obj->lknown = 1; - } + /* caller has already ID'd everything */ (void) display_inventory((char *) 0, TRUE); container_contents(invent, TRUE, TRUE, FALSE); } @@ -1166,10 +1172,26 @@ int how; if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE); - if (strcmp(flags.end_disclose, "none") && how != PANICKED) - disclose(how, taken); + if (how != PANICKED) { + struct obj *obj; - dump_everything(how); + /* + * This is needed for both inventory disclosure and dumplog. + * Both are optional, so do it once here instead of duplicating + * it in both of those places. + */ + for (obj = invent; obj; obj = obj->nobj) { + makeknown(obj->otyp); + obj->known = obj->bknown = obj->dknown = obj->rknown = 1; + if (Is_container(obj) || obj->otyp == STATUE) + obj->cknown = obj->lknown = 1; + } + + if (strcmp(flags.end_disclose, "none")) + disclose(how, taken); + + dump_everything(how, endtime); + } /* finish_paybill should be called after disclosure but before bones */ if (bones_ok && taken) @@ -1319,11 +1341,6 @@ int how; /* count the points for artifacts */ artifact_score(invent, TRUE, endwin); -#ifdef DUMPLOG - dump_redirect(TRUE); - artifact_score(invent, TRUE, endwin); - dump_redirect(FALSE); -#endif viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */ mtmp = mydogs; @@ -1418,7 +1435,7 @@ int how; plur(umoney), moves, plur(moves)); dump_forward_putstr(endwin, 0, pbuf, done_stopprint); Sprintf(pbuf, - "You were level %d with a maximum of %d hit point%s when you %s.", + "You were level %d with a maximum of %d hit point%s when you %s.", u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]); dump_forward_putstr(endwin, 0, pbuf, done_stopprint); dump_forward_putstr(endwin, 0, "", done_stopprint); diff --git a/src/explode.c b/src/explode.c index e26e58d8a..74dfcdae2 100644 --- a/src/explode.c +++ b/src/explode.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 explode.c $NHDT-Date: 1450915435 2015/12/24 00:03:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.45 $ */ +/* NetHack 3.6 explode.c $NHDT-Date: 1496103440 2017/05/30 00:17:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.49 $ */ /* Copyright (C) 1990 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -174,7 +174,7 @@ int expltype; break; } } - /* can be both you and mtmp if you're swallowed */ + /* can be both you and mtmp if you're swallowed or riding */ mtmp = m_at(i + x - 1, j + y - 1); if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy) mtmp = u.usteed; @@ -392,8 +392,7 @@ int expltype; } else { /* call resist with 0 and do damage manually so 1) we can * get out the message before doing the damage, and 2) we - * can - * call mondied, not killed, if it's not your blast + * can call mondied, not killed, if it's not your blast */ int mdam = dam; @@ -512,12 +511,10 @@ int expltype; } if (shopdamage) { - pay_for_damage(adtyp == AD_FIRE - ? "burn away" - : adtyp == AD_COLD - ? "shatter" - : adtyp == AD_DISN ? "disintegrate" - : "destroy", + pay_for_damage((adtyp == AD_FIRE) ? "burn away" + : (adtyp == AD_COLD) ? "shatter" + : (adtyp == AD_DISN) ? "disintegrate" + : "destroy", FALSE); } diff --git a/src/hack.c b/src/hack.c index a250d86de..8683fda77 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.c $NHDT-Date: 1494107206 2017/05/06 21:46:46 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.174 $ */ +/* NetHack 3.6 hack.c $NHDT-Date: 1496619131 2017/06/04 23:32:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.175 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1526,6 +1526,7 @@ domove() && !sensemon(mtmp)) stumble_onto_mimic(mtmp); else if (mtmp->mpeaceful && !Hallucination) + /* m_monnam(): "dog" or "Fido", no "invisible dog" or "it" */ pline("Pardon me, %s.", m_monnam(mtmp)); else You("move right into %s.", mon_nam(mtmp)); diff --git a/src/hacklib.c b/src/hacklib.c index 8cb76021b..1c4fe63d6 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hacklib.c $NHDT-Date: 1472006251 2016/08/24 02:37:31 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.48 $ */ +/* NetHack 3.6 hacklib.c $NHDT-Date: 1496860756 2017/06/07 18:39:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.50 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Robert Patrick Rankin, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -33,6 +33,7 @@ char * tabexpand (char *) char * visctrl (char) char * strsubst (char *, const char *, const char *) + int strNsubst (char *,const char *,const char *,int) const char * ordin (int) char * sitoa (int) int sgn (int) @@ -45,7 +46,7 @@ boolean pmatchz (const char *, const char *) int strncmpi (const char *, const char *, int) char * strstri (const char *, const char *) - boolean fuzzymatch (const char *,const char *, + boolean fuzzymatch (const char *, const char *, const char *, boolean) void setrandom (void) time_t getnow (void) @@ -442,6 +443,7 @@ const char *orig, *replacement; char *found, buf[BUFSZ]; if (bp) { + /* [this could be replaced by strNsubst(bp, orig, replacement, 1)] */ found = strstr(bp, orig); if (found) { Strcpy(buf, found + strlen(orig)); @@ -452,6 +454,52 @@ const char *orig, *replacement; return bp; } +/* substitute the Nth occurrence of a substring within a string (in place); + if N is 0, substitute all occurrences; returns the number of subsitutions; + maximum output length is BUFSZ (BUFSZ-1 chars + terminating '\0') */ +int +strNsubst(inoutbuf, orig, replacement, n) +char *inoutbuf; /* current string, and result buffer */ +const char *orig, /* old substring; if "" then insert in front of Nth char */ + *replacement; /* new substring; if "" then delete old substring */ +int n; /* which occurrence to replace; 0 => all */ +{ + char *bp, *op, workbuf[BUFSZ]; + const char *rp; + unsigned len = (unsigned) strlen(orig); + int ocount = 0, /* number of times 'orig' has been matched */ + rcount = 0; /* number of subsitutions made */ + + for (bp = inoutbuf, op = workbuf; *bp && op < &workbuf[BUFSZ - 1]; ) { + if ((!len || !strncmp(bp, orig, len)) && (++ocount == n || n == 0)) { + /* Nth match found */ + for (rp = replacement; *rp && op < &workbuf[BUFSZ - 1]; ) + *op++ = *rp++; + ++rcount; + if (len) { + bp += len; /* skip 'orig' */ + continue; + } + } + /* no match (or len==0) so retain current character */ + *op++ = *bp++; + } + if (!len && n == ocount + 1) { + /* special case: orig=="" (!len) and n==strlen(inoutbuf)+1, + insert in front of terminator (in other words, append); + [when orig=="", ocount will have been incremented once for + each input char] */ + for (rp = replacement; *rp && op < &workbuf[BUFSZ - 1]; ) + *op++ = *rp++; + ++rcount; + } + if (rcount) { + *op = '\0'; + Strcpy(inoutbuf, workbuf); + } + return rcount; +} + /* return the ordinal suffix of a number */ const char * ordin(n) diff --git a/src/makemon.c b/src/makemon.c index 9c5e4cd47..77a886b4d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 makemon.c $NHDT-Date: 1450451931 2015/12/18 15:18:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.106 $ */ +/* NetHack 3.6 makemon.c $NHDT-Date: 1495237801 2017/05/19 23:50:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.116 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -903,7 +903,7 @@ boolean ghostly; result = (((int) mvitals[mndx].born < lim) && !gone) ? TRUE : FALSE; /* if it's unique, don't ever make it again */ - if (mons[mndx].geno & G_UNIQ) + if ((mons[mndx].geno & G_UNIQ) && mndx != PM_HIGH_PRIEST) mvitals[mndx].mvflags |= G_EXTINCT; if (mvitals[mndx].born < 255 && tally diff --git a/src/mhitm.c b/src/mhitm.c index d5f1e9463..3ab02f4a4 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhitm.c $NHDT-Date: 1470819842 2016/08/10 09:04:02 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.92 $ */ +/* NetHack 3.6 mhitm.c $NHDT-Date: 1496860757 2017/06/07 18:39:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.97 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -322,11 +322,16 @@ register struct monst *magr, *mdef; mdef->mundetected = 0; newsym(mdef->mx, mdef->my); if (canseemon(mdef) && !sensemon(mdef)) { - if (Unaware) - You("dream of %s.", (mdef->data->geno & G_UNIQ) - ? a_monnam(mdef) - : makeplural(m_monnam(mdef))); - else + if (Unaware) { + boolean justone = (mdef->data->geno & G_UNIQ) != 0L; + const char *montype; + + montype = noname_monnam(mdef, justone ? ARTICLE_THE + : ARTICLE_NONE); + if (!justone) + montype = makeplural(montype); + You("dream of %s.", montype); + } else pline("Suddenly, you notice %s.", a_monnam(mdef)); } } @@ -1551,8 +1556,10 @@ int mdead; tmp = 127; if (magr->mcansee && haseyes(madat) && mdef->mcansee && (perceives(madat) || !mdef->minvis)) { - Sprintf(buf, "%s gaze is reflected by %%s %%s.", - s_suffix(Monnam(mdef))); + /* construct format string; guard against '%' in Monnam */ + Strcpy(buf, s_suffix(Monnam(mdef))); + (void) strNsubst(buf, "%", "%%", 0); + Strcat(buf, " gaze is reflected by %s %s."); if (mon_reflects(magr, canseemon(magr) ? buf : (char *) 0)) return (mdead | mhit); diff --git a/src/mhitu.c b/src/mhitu.c index 86a064f84..df5541e19 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhitu.c $NHDT-Date: 1470819843 2016/08/10 09:04:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.144 $ */ +/* NetHack 3.6 mhitu.c $NHDT-Date: 1496619132 2017/06/04 23:32:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.146 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -486,6 +486,8 @@ register struct monst *mtmp; if (obj->otyp == EGG) obj->spe = 0; } + /* note that m_monnam() overrides hallucination, which is + what we want when message is from mtmp's perspective */ if (youmonst.data->mlet == S_EEL || u.umonnum == PM_TRAPPER) pline( @@ -515,7 +517,7 @@ register struct monst *mtmp; map_invisible(mtmp->mx, mtmp->my); if (sticky && !youseeit) pline("It gets stuck on you."); - else + else /* see note about m_monnam() above */ pline("Wait, %s! That's a %s named %s!", m_monnam(mtmp), youmonst.data->mname, plname); if (sticky) @@ -536,7 +538,7 @@ register struct monst *mtmp; && youmonst.mappearance == GOLD_PIECE) ? "tries to pick you up" : "disturbs you"); - else + else /* see note about m_monnam() above */ pline("Wait, %s! That %s is really %s named %s!", m_monnam(mtmp), mimic_obj_name(&youmonst), an(mons[u.umonnum].mname), plname); diff --git a/src/mon.c b/src/mon.c index 8276d4792..33a84372e 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1492733171 2017/04/21 00:06:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.237 $ */ +/* NetHack 3.6 mon.c $NHDT-Date: 1496531114 2017/06/03 23:05:14 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.240 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -11,7 +11,7 @@ #include "mfndpos.h" #include -STATIC_VAR boolean vamp_rise_msg; +STATIC_VAR boolean vamp_rise_msg, disintegested; STATIC_DCL void FDECL(sanity_check_single_mon, (struct monst *, BOOLEAN_P, const char *)); @@ -1826,16 +1826,20 @@ register struct monst *mtmp; /* alternate message phrasing for some monster types */ spec_mon = (nonliving(mtmp->data) || noncorporeal(mtmp->data) - || amorphous(mtmp->data)); + || amorphous(mtmp->data)), + spec_death = (disintegested /* disintegrated or digested */ + || noncorporeal(mtmp->data) + || amorphous(mtmp->data)); - /* construct a format string before transformation */ - Sprintf(buf, "The %s%s suddenly %s and rises as %%s!", - spec_mon ? "" : "seemingly dead ", - x_monnam(mtmp, ARTICLE_NONE, (char *) 0, + /* construct a format string before transformation; + will be capitalized when used, expects one %s arg */ + Sprintf(buf, "%s suddenly %s and rises as %%s!", + x_monnam(mtmp, ARTICLE_THE, + spec_mon ? (char *) 0 : "seemingly dead", SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION | SUPPRESS_INVISIBLE | SUPPRESS_IT, FALSE), - spec_mon ? "reconstitutes" : "transforms"); + spec_death ? "reconstitutes" : "transforms"); mtmp->mcanmove = 1; mtmp->mfrozen = 0; if (mtmp->mhpmax <= 0) @@ -1857,7 +1861,9 @@ register struct monst *mtmp; else mtmp->cham = mndx; if (canspotmon(mtmp)) { - pline(buf, a_monnam(mtmp)); + /* was using a_monnam(mtmp) but that's weird if mtmp is named: + "Dracula suddenly transforms and rises as Dracula" */ + pline(upstart(buf), an(mtmp->data->mname)); vamp_rise_msg = TRUE; } newsym(x, y); @@ -1887,9 +1893,7 @@ register struct monst *mtmp; else if (mtmp->data == &mons[PM_WERERAT]) set_mon_data(mtmp, &mons[PM_HUMAN_WERERAT], -1); - /* if MAXMONNO monsters of a given type have died, and it - * can be done, extinguish that monster. - * + /* * mvitals[].died does double duty as total number of dead monsters * and as experience factor for the player killing more monsters. * this means that a dragon dying by other means reduces the @@ -2145,7 +2149,8 @@ int how; be_sad = (mdef->mtame != 0); /* no corpses if digested or disintegrated */ - if (how == AD_DGST || how == -AD_RBRE) + disintegested = (how == AD_DGST || how == -AD_RBRE); + if (disintegested) mondead(mdef); else mondied(mdef); @@ -2241,16 +2246,18 @@ int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */ thrownobj = 0; } - vamp_rise_msg = FALSE; /* might get set in mondead() */ + vamp_rise_msg = FALSE; /* might get set in mondead(); only checked below */ + disintegested = nocorpse; /* alternate vamp_rise message needed if true */ /* dispose of monster and make cadaver */ if (stoned) monstone(mtmp); else mondead(mtmp); + disintegested = FALSE; /* reset */ if (mtmp->mhp > 0) { /* monster lifesaved */ /* Cannot put the non-visible lifesaving message in - * lifesaved_monster() since the message appears only when you + * lifesaved_monster() since the message appears only when _you_ * kill it (as opposed to visible lifesaving which always appears). */ stoned = FALSE; @@ -3451,7 +3458,7 @@ boolean msg; /* "The oldmon turns into a newmon!" */ if (is_vampshifter(mtmp)) { Sprintf(msgtrail, " which was a shapeshifted %s", - m_monnam(mtmp)); + noname_monnam(mtmp, ARTICLE_NONE)); } else if (is_animal(mdat)) { Strcpy(msgtrail, "'s stomach"); } else { @@ -3493,16 +3500,7 @@ boolean msg; /* "The oldmon turns into a newmon!" */ newsym(mtmp->mx, mtmp->my); if (msg) { - char *save_mname = 0; - - if (has_mname(mtmp)) { - save_mname = MNAME(mtmp); - MNAME(mtmp) = (char *) 0; - } - Strcpy(newname, (mdat == &mons[PM_GREEN_SLIME]) - ? "slime" - : x_monnam(mtmp, ARTICLE_A, (char *) 0, - SUPPRESS_SADDLE, FALSE)); + Strcpy(newname, noname_monnam(mtmp, ARTICLE_A)); /* oldname was capitalized above; newname will be lower case */ if (!strcmpi(newname, "it")) { /* can't see or sense it now */ if (!!strcmpi(oldname, "it")) /* could see or sense it before */ @@ -3514,8 +3512,6 @@ boolean msg; /* "The oldmon turns into a newmon!" */ else pline("%s turns into %s!", oldname, newname); } - if (save_mname) - MNAME(mtmp) = save_mname; } /* when polymorph trap/wand/potion produces a vampire, turn in into diff --git a/src/monmove.c b/src/monmove.c index 0b60d0c15..92cdac8dd 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 monmove.c $NHDT-Date: 1463704424 2016/05/20 00:33:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.87 $ */ +/* NetHack 3.6 monmove.c $NHDT-Date: 1496534703 2017/06/04 00:05:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.91 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1250,10 +1250,12 @@ postmov: || (can_fog(mtmp) && vamp_shift(mtmp, &mons[PM_FOG_CLOUD], canspotmon(mtmp))))) { + /* update cached value for vamp_shift() case */ + ptr = mtmp->data; if (flags.verbose && canseemon(mtmp)) pline("%s %s under the door.", Monnam(mtmp), (ptr == &mons[PM_FOG_CLOUD] - || ptr == &mons[PM_YELLOW_LIGHT]) + || ptr->mlet == S_LIGHT) ? "flows" : "oozes"); } else if (here->doormask & D_LOCKED && can_unlock) { @@ -1625,13 +1627,11 @@ struct permonst *ptr; boolean domsg; { int reslt = 0; - char fmtstr[BUFSZ]; + char oldmtype[BUFSZ]; + + /* remember current monster type before shapechange */ + Strcpy(oldmtype, domsg ? noname_monnam(mon, ARTICLE_THE) : ""); - if (domsg) { - Sprintf(fmtstr, "You %s %%s where %s was.", - sensemon(mon) ? "now detect" : "observe", - an(m_monnam(mon))); - } if (mon->data == ptr) { /* already right shape */ reslt = 1; @@ -1639,9 +1639,13 @@ boolean domsg; } else if (is_vampshifter(mon)) { reslt = newcham(mon, ptr, FALSE, FALSE); } + if (reslt && domsg) { - pline(fmtstr, an(m_monnam(mon))); + pline("You %s %s where %s was.", + !canseemon(mon) ? "now detect" : "observe", + noname_monnam(mon, ARTICLE_A), oldmtype); } + return reslt; } diff --git a/src/region.c b/src/region.c index b38936c81..d91b9fa39 100644 --- a/src/region.c +++ b/src/region.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 region.c $NHDT-Date: 1446892454 2015/11/07 10:34:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.36 $ */ +/* NetHack 3.6 region.c $NHDT-Date: 1496087244 2017/05/29 19:47:24 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.40 $ */ /* Copyright (c) 1996 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -969,9 +969,15 @@ genericptr_t p2; } else { /* A monster is inside the cloud */ mtmp = (struct monst *) p2; - /* Non living and non breathing monsters are not concerned */ + /* Non living and non breathing monsters are not concerned; + adult green dragon is not affected by gas cloud, baby one is */ if (!(nonliving(mtmp->data) || is_vampshifter(mtmp)) - && !breathless(mtmp->data)) { + && !breathless(mtmp->data) + /* exclude monsters with poison gas breath attack: + adult green dragon and Chromatic Dragon (and iron golem, + but nonliving() and breathless() tests also catch that) */ + && !(attacktype_fordmg(mtmp->data, AT_BREA, AD_DRST) + || attacktype_fordmg(mtmp->data, AT_BREA, AD_RBRE))) { if (cansee(mtmp->mx, mtmp->my)) pline("%s coughs!", Monnam(mtmp)); if (heros_fault(reg)) diff --git a/src/steal.c b/src/steal.c index a973bf7a2..203bf331a 100644 --- a/src/steal.c +++ b/src/steal.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 steal.c $NHDT-Date: 1456618998 2016/02/28 00:23:18 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.67 $ */ +/* NetHack 3.6 steal.c $NHDT-Date: 1496614914 2017/06/04 22:21:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.69 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -560,18 +560,19 @@ struct monst *mtmp; /* take off outer gear if we're targetting [hypothetical] quest artifact suit, shirt, gloves, or rings */ if ((otmp == uarm || otmp == uarmu) && uarmc) - (void) Cloak_off(); + remove_worn_item(uarmc, FALSE); if (otmp == uarmu && uarm) - (void) Armor_off(); + remove_worn_item(uarm, FALSE); if ((otmp == uarmg || ((otmp == uright || otmp == uleft) && uarmg)) && uwep) { /* gloves are about to be unworn; unwield weapon(s) first */ - if (u.twoweap) - uswapwepgone(); /* will clear u.twoweap */ - uwepgone(); + if (u.twoweap) /* remove_worn_item(uswapwep) indirectly */ + remove_worn_item(uswapwep, FALSE); /* clears u.twoweap */ + remove_worn_item(uwep, FALSE); } if ((otmp == uright || otmp == uleft) && uarmg) - (void) Gloves_off(); /* handles wielded cockatrice corpse */ + /* calls Gloves_off() to handle wielded cockatrice corpse */ + remove_worn_item(uarmg, FALSE); /* finally, steal the target item */ if (otmp->owornmask) diff --git a/src/timeout.c b/src/timeout.c index e5187e93b..508fe9609 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 timeout.c $NHDT-Date: 1493510119 2017/04/29 23:55:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.70 $ */ +/* NetHack 3.6 timeout.c $NHDT-Date: 1496619133 2017/06/04 23:32:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.71 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -613,6 +613,8 @@ long timeout; boolean siblings = (hatchcount > 1), redraw = FALSE; if (cansee_hatchspot) { + /* [bug? m_monnam() yields accurate monster type + regardless of hallucination] */ Sprintf(monnambuf, "%s%s", siblings ? "some " : "", siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon))); /* we don't learn the egg type here because learning diff --git a/src/uhitm.c b/src/uhitm.c index a4a31cde0..b11cb0fd8 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 uhitm.c $NHDT-Date: 1470819843 2016/08/10 09:04:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.164 $ */ +/* NetHack 3.6 uhitm.c $NHDT-Date: 1496860757 2017/06/07 18:39:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.166 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1123,9 +1123,13 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */ else if (barehand_silver_rings == 2) fmt = "Your silver rings sear %s!"; else if (silverobj && saved_oname[0]) { - Sprintf(silverobjbuf, "Your %s%s %s %%s!", + /* guard constructed format string against '%' in + saved_oname[] from xname(via cxname()) */ + Sprintf(silverobjbuf, "Your %s%s %s", strstri(saved_oname, "silver") ? "" : "silver ", saved_oname, vtense(saved_oname, "sear")); + (void) strNsubst(silverobjbuf, "%", "%%", 0); + Strcat(silverobjbuf, " %s!"); fmt = silverobjbuf; } else fmt = "The silver sears %s!"; diff --git a/src/wield.c b/src/wield.c index 585e971c9..bd176a812 100644 --- a/src/wield.c +++ b/src/wield.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wield.c $NHDT-Date: 1461967849 2016/04/29 22:10:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.49 $ */ +/* NetHack 3.6 wield.c $NHDT-Date: 1496959480 2017/06/08 22:04:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.54 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/windows.c b/src/windows.c index 70c9feee7..55678a0b4 100644 --- a/src/windows.c +++ b/src/windows.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 windows.c $NHDT-Date: 1488075979 2017/02/26 02:26:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.39 $ */ +/* NetHack 3.6 windows.c $NHDT-Date: 1495232365 2017/05/19 22:19:25 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.41 $ */ /* Copyright (c) D. Cohrs, 1993. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1033,7 +1033,7 @@ int behavior UNUSED, under UNUSED, over UNUSED; #endif /* STATUS_VIA_WINDOWPORT */ STATIC_VAR struct window_procs dumplog_windowprocs_backup; -STATIC_PTR FILE *dumplog_file; +STATIC_VAR FILE *dumplog_file; #ifdef DUMPLOG STATIC_VAR time_t dumplog_now; @@ -1152,8 +1152,8 @@ void dump_close_log() { if (dumplog_file) { - fclose(dumplog_file); - dumplog_file = NULL; + (void) fclose(dumplog_file); + dumplog_file = (FILE *) 0; } } diff --git a/src/worn.c b/src/worn.c index a99d1336d..abc1d4c3e 100644 --- a/src/worn.c +++ b/src/worn.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 worn.c $NHDT-Date: 1493510127 2017/04/29 23:55:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.48 $ */ +/* NetHack 3.6 worn.c $NHDT-Date: 1496959481 2017/06/08 22:04:41 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.49 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -77,6 +77,9 @@ long mask; if (oobj->oartifact) set_artifact_intrinsic(oobj, 0, mask); } + /* in case wearing or removal is in progress or removal + is pending (via 'A' command for multiple items) */ + cancel_doff(oobj, wp->w_mask); } *(wp->w_obj) = obj; if (obj) { @@ -119,6 +122,10 @@ register struct obj *obj; u.twoweap = 0; for (wp = worn; wp->w_mask; wp++) if (obj == *(wp->w_obj)) { + /* in case wearing or removal is in progress or removal + is pending (via 'A' command for multiple items) */ + cancel_doff(obj, wp->w_mask); + *(wp->w_obj) = 0; p = objects[obj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;