diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 605268883..aef6c5289 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -312,6 +312,16 @@ when #tip's terse object drop format got interrupted by a regular message, seems hopeless; leaving it is better than always using verbose format) for #tip inside shop, credit was incorrectly given for spilled gold if that gold's stale location coordinates didn't happen to be inside the shop +when confused scroll of light summoned lights, player would be asked what to + call the scroll even if scroll of light was already identified +if a visible monster becomes invisible, mark its spot with the 'remembered, + unseen monster' glyph ('I' character or '?' tile) +monsters can throw cockatrice eggs at hero, but there was no handling for eggs + when the missile hit an intervening monster +clarify that shape-shifted vampires revert to vampire form when petrified or + digested; when back in 'V' form, they're vulnerable to such damage +when poly'd into an engulfer which does digestion damage, a kill resulting in + a level gain gave "welcome to level N+1" before "you digest " Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/src/attrib.c b/src/attrib.c index 1eb709d22..5c80c5ed2 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -245,7 +245,8 @@ boolean thrown_weapon; /* thrown weapons are less deadly */ boolean plural = (reason[strlen(reason) - 1] == 's') ? 1 : 0; /* avoid "The" Orcus's sting was poisoned... */ - pline("%s%s %s poisoned!", isupper(*reason) ? "" : "The ", reason, + pline("%s%s %s poisoned!", + isupper((uchar) *reason) ? "" : "The ", reason, plural ? "were" : "was"); } if (Poison_resistance) { diff --git a/src/mcastu.c b/src/mcastu.c index addcc1575..e2fdfad66 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -443,6 +443,8 @@ int spellnum; pline("%s suddenly %s!", Monnam(mtmp), !See_invisible ? "disappears" : "becomes transparent"); mon_set_minvis(mtmp); + if (cansee(mtmp->mx, mtmp->my) && !canspotmon(mtmp)) + map_invisible(mtmp->mx, mtmp->my); dmg = 0; } else impossible("no reason for monster to cast disappear spell?"); diff --git a/src/mhitm.c b/src/mhitm.c index 7ab6fe763..273fecf09 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -675,12 +675,26 @@ register struct attack *mattk; return MM_MISS; if (vis) { + /* [this two-part formatting dates back to when only one x_monnam + result could be included in an expression because the next one + would overwrite first's result -- that's no longer the case] */ Sprintf(buf, "%s swallows", Monnam(magr)); pline("%s %s.", buf, mon_nam(mdef)); } for (obj = mdef->minvent; obj; obj = obj->nobj) (void) snuff_lit(obj); + if (is_vampshifter(mdef) + && newcham(mdef, &mons[mdef->cham], FALSE, FALSE)) { + if (vis) { + /* 'it' -- previous form is no longer available and + using that would be excessively verbose */ + pline("%s expels it.", Monnam(magr)); + pline("It turns into %s.", a_monnam(mdef)); + } + return MM_HIT; /* bypass mdamagem() */ + } + /* * All of this manipulation is needed to keep the display correct. * There is a flush at the next pline(). diff --git a/src/mon.c b/src/mon.c index 457313246..243ffbd6f 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2043,6 +2043,9 @@ struct monst *mdef; xchar x = mdef->mx, y = mdef->my; boolean wasinside = FALSE; + if (!vamp_stone(mdef)) /* vampshifter reverts to vampire */ + return; + /* we have to make the statue before calling mondead, to be able to * put inventory in it, and we have to check for lifesaving before * making the statue.... @@ -2402,9 +2405,8 @@ struct monst *mtmp; /* construct a format string before transformation */ Sprintf(buf, "The lapidifying %s %s %s", x_monnam(mtmp, ARTICLE_NONE, (char *) 0, - SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION - | SUPPRESS_INVISIBLE | SUPPRESS_IT, - FALSE), + (SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION + | SUPPRESS_INVISIBLE | SUPPRESS_IT), FALSE), amorphous(mtmp->data) ? "coalesces on the" : is_flyer(mtmp->data) ? "drops to the" : "writhes on the", @@ -2434,8 +2436,8 @@ struct monst *mtmp; else mtmp->cham = mndx; if (canspotmon(mtmp)) { - pline("%s rises from the %s with renewed agility!", - Amonnam(mtmp), surface(mtmp->mx, mtmp->my)); + pline("%s rises from the %s with renewed agility!", + Amonnam(mtmp), surface(mtmp->mx, mtmp->my)); } newsym(mtmp->mx, mtmp->my); return FALSE; /* didn't petrify */ diff --git a/src/mthrowu.c b/src/mthrowu.c index a448ba8e6..c36c0fe75 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -338,10 +338,15 @@ boolean verbose; /* give message(s) even when you can't see what happened */ if (ismimic) seemimic(mtmp); mtmp->msleeping = 0; - if (vis) - hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage)); - else if (verbose && !target) - pline("%s is hit%s", Monnam(mtmp), exclam(damage)); + if (vis) { + if (otmp->otyp == EGG) + pline("Splat! %s is hit with %s egg!", Monnam(mtmp), + otmp->known ? an(mons[otmp->corpsenm].mname) : "an"); + else + hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage)); + } else if (verbose && !target) + pline("%s%s is hit%s", (otmp->otyp == EGG) ? "Splat! " : "", + Monnam(mtmp), exclam(damage)); if (otmp->opoisoned && is_poisonable(otmp)) { if (resists_poison(mtmp)) { @@ -369,7 +374,6 @@ boolean verbose; /* give message(s) even when you can't see what happened */ if (resists_acid(mtmp)) { if (vis || (verbose && !target)) pline("%s is unaffected.", Monnam(mtmp)); - damage = 0; } else { if (vis) pline_The("%s burns %s!", hliquid("acid"), mon_nam(mtmp)); @@ -377,24 +381,36 @@ boolean verbose; /* give message(s) even when you can't see what happened */ pline("It is burned!"); } } - mtmp->mhp -= damage; - if (mtmp->mhp < 1) { - if (vis || (verbose && !target)) - pline("%s is %s!", Monnam(mtmp), - (nonliving(mtmp->data) || is_vampshifter(mtmp) - || !canspotmon(mtmp)) ? "destroyed" : "killed"); - /* don't blame hero for unknown rolling boulder trap */ - if (!context.mon_moving - && (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped)) - xkilled(mtmp, XKILL_NOMSG); - else - mondied(mtmp); + if (otmp->otyp == EGG && touch_petrifies(&mons[otmp->corpsenm])) { + if (!munstone(mtmp, TRUE)) + minstapetrify(mtmp, TRUE); + if (resists_ston(mtmp)) + damage = 0; } - if (can_blnd((struct monst *) 0, mtmp, - (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT - : AT_WEAP), - otmp)) { + if (mtmp->mhp > 0) { /* might already be dead (if petrified) */ + mtmp->mhp -= damage; + if (mtmp->mhp < 1) { + if (vis || (verbose && !target)) + pline("%s is %s!", Monnam(mtmp), + (nonliving(mtmp->data) || is_vampshifter(mtmp) + || !canspotmon(mtmp)) ? "destroyed" : "killed"); + /* don't blame hero for unknown rolling boulder trap */ + if (!context.mon_moving && (otmp->otyp != BOULDER + || range >= 0 || otmp->otrapped)) + xkilled(mtmp, XKILL_NOMSG); + else + mondied(mtmp); + } + } + + /* blinding venom and cream pie do 0 damage, but verify + that the target is still alive anyway */ + if (mtmp->mhp > 0 + && can_blnd((struct monst *) 0, mtmp, + (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT + : AT_WEAP), + otmp)) { if (vis && mtmp->mcansee) pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp))); mtmp->mcansee = 0; diff --git a/src/muse.c b/src/muse.c index 0b8c3ded1..7b5129003 100644 --- a/src/muse.c +++ b/src/muse.c @@ -1207,8 +1207,8 @@ register struct monst *mtmp; register struct obj *otmp; { int tmp; - boolean reveal_invis = FALSE; + if (mtmp != &youmonst) { mtmp->msleeping = 0; if (mtmp->m_ap_type) @@ -1819,12 +1819,15 @@ struct monst *mtmp; Strcpy(nambuf, mon_nam(mtmp)); mon_set_minvis(mtmp); if (vismon && mtmp->minvis) { /* was seen, now invisible */ - if (canspotmon(mtmp)) + if (canspotmon(mtmp)) { pline("%s body takes on a %s transparency.", upstart(s_suffix(nambuf)), Hallucination ? "normal" : "strange"); - else + } else { pline("Suddenly you cannot see %s.", nambuf); + if (vis) + map_invisible(mtmp->mx, mtmp->my); + } if (oseen) makeknown(otmp->otyp); } diff --git a/src/potion.c b/src/potion.c index 2e7ceb15f..aebbc75ee 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1379,10 +1379,15 @@ boolean your_fault; if (!resist(mon, POTION_CLASS, 0, NOTELL)) mon->mconf = TRUE; break; - case POT_INVISIBILITY: + case POT_INVISIBILITY: { + boolean sawit = canspotmon(mon); + angermon = FALSE; mon_set_minvis(mon); + if (sawit && !canspotmon(mon) && cansee(mon->mx, mon->my)) + map_invisible(mon->mx, mon->my); break; + } case POT_SLEEPING: /* wakeup() doesn't rouse victims of temporary sleep */ if (sleep_monst(mon, rnd(12), POTION_CLASS)) { diff --git a/src/read.c b/src/read.c index fbf9f8201..12e3cc002 100644 --- a/src/read.c +++ b/src/read.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 read.c $NHDT-Date: 1457660917 2016/03/11 01:48:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.136 $ */ +/* NetHack 3.6 read.c $NHDT-Date: 1467718299 2016/07/05 11:31:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.140 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1414,8 +1414,6 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ (void) create_critters(1, !scursed ? &mons[PM_YELLOW_LIGHT] : &mons[PM_BLACK_LIGHT], TRUE); - if (!objects[sobj->otyp].oc_uname) - docall(sobj); } break; case SCR_TELEPORTATION: diff --git a/src/teleport.c b/src/teleport.c index 289d6a351..f45abfb5e 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -956,11 +956,9 @@ struct monst *mtmp; * * Pulls a monster from its current position and places a monster at * a new x and y. If oldx is 0, then the monster was not in the - * levels.monsters - * array. However, if oldx is 0, oldy may still have a value because mtmp is - * a - * migrating_mon. Worm tails are always placed randomly around the head of - * the worm. + * levels.monsters array. However, if oldx is 0, oldy may still have + * a value because mtmp is a migrating_mon. Worm tails are always + * placed randomly around the head of the worm. */ void rloc_to(mtmp, x, y) @@ -974,15 +972,15 @@ register int x, y; return; if (oldx) { /* "pick up" monster */ - if (mtmp->wormno) + if (mtmp->wormno) { remove_worm(mtmp); - else { + } else { remove_monster(oldx, oldy); newsym(oldx, oldy); /* update old location */ } } - memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack)); + memset(mtmp->mtrack, 0, sizeof mtmp->mtrack); place_monster(mtmp, x, y); /* put monster down */ update_monster_region(mtmp); diff --git a/src/uhitm.c b/src/uhitm.c index 7c9bf3f5f..1217b5b48 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1894,6 +1894,18 @@ register struct attack *mattk; for (otmp = mdef->minvent; otmp; otmp = otmp->nobj) (void) snuff_lit(otmp); + /* force vampire in bat, cloud, or wolf form to revert back to + vampire form now instead of dealing with that when it dies */ + if (is_vampshifter(mdef) + && newcham(mdef, &mons[mdef->cham], FALSE, FALSE)) { + You("engulf it, then expel it."); + if (canspotmon(mdef)) + pline("It turns into %s.", a_monnam(mdef)); + else + map_invisible(mdef->mx, mdef->my); + return 1; + } + /* engulfing a cockatrice or digesting a Rider or Medusa */ fatal_gulp = (touch_petrifies(pd) && !Stone_resistance) || (mattk->adtyp == AD_DGST @@ -1937,7 +1949,13 @@ register struct attack *mattk; m_useup(mdef, otmp); newuhs(FALSE); - xkilled(mdef, XKILL_NOMSG | XKILL_NOCORPSE); + /* start_engulf() issues "you engulf " above; this + used to specify XKILL_NOMSG but we need "you kill " + in case we're also going to get "welcome to level N+1"; + "you totally digest " will be coming soon (after + several turns) but the level-gain message seems out of + order if the kill message is left implicit */ + xkilled(mdef, XKILL_GIVEMSG | XKILL_NOCORPSE); if (mdef->mhp > 0) { /* monster lifesaved */ You("hurriedly regurgitate the sizzling in your %s.", body_part(STOMACH)); diff --git a/src/zap.c b/src/zap.c index dfd1ee72b..ea246aabb 100644 --- a/src/zap.c +++ b/src/zap.c @@ -280,6 +280,7 @@ struct obj *otmp; mon_set_minvis(mtmp); if (!oldinvis && knowninvisible(mtmp)) { pline("%s turns transparent!", nambuf); + reveal_invis = TRUE; learn_it = TRUE; } break; diff --git a/sys/share/pcsys.c b/sys/share/pcsys.c index 47f74a717..085956c76 100644 --- a/sys/share/pcsys.c +++ b/sys/share/pcsys.c @@ -299,7 +299,7 @@ int start; * whitespace, do not change the value of SAVEF. */ for (bp = buf; *bp; bp++) - if (!isspace(*bp)) { + if (!isspace((uchar) *bp)) { strncpy(SAVEF, bp, PATHLEN); break; } diff --git a/sys/winnt/nh340key.c b/sys/winnt/nh340key.c index 7d64b3843..8d512142e 100644 --- a/sys/winnt/nh340key.c +++ b/sys/winnt/nh340key.c @@ -153,7 +153,7 @@ int portdebug; if (vk == 0xBF) ch = M('?'); else - ch = M(tolower(keycode)); + ch = M(tolower((uchar) keycode)); } if (ch == '\r') ch = '\n'; diff --git a/sys/winnt/nhdefkey.c b/sys/winnt/nhdefkey.c index 258874e54..5f7390955 100644 --- a/sys/winnt/nhdefkey.c +++ b/sys/winnt/nhdefkey.c @@ -167,7 +167,7 @@ int portdebug; if (vk == 0xBF) ch = M('?'); else - ch = M(tolower(keycode)); + ch = M(tolower((uchar) keycode)); } /* Attempt to work better with international keyboards. */ else { diff --git a/sys/winnt/nhraykey.c b/sys/winnt/nhraykey.c index cae80ccd8..3b0a6ef04 100644 --- a/sys/winnt/nhraykey.c +++ b/sys/winnt/nhraykey.c @@ -352,7 +352,7 @@ int portdebug; if (vk == 0xBF) ch = M('?'); else - ch = M(tolower(keycode)); + ch = M(tolower((uchar) keycode)); } else if (ch < 32 && !isnumkeypad(scan)) { /* Control code; ReadConsole seems to filter some of these, * including ESC */ diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index e95fe4f1d..892744432 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -119,7 +119,7 @@ char *str; char *ptr; char drive; if ((ptr = index(str, ':')) != (char *) 0) { - drive = toupper(*(ptr - 1)); + drive = toupper((uchar) *(ptr - 1)); _chdrive((drive - 'A') + 1); } } diff --git a/util/makedefs.c b/util/makedefs.c index 45a2bb6c2..e571e3783 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -666,7 +666,7 @@ const char *id; { struct grep_var *rv; - while (*id && isspace(*id)) + while (*id && isspace((uchar) *id)) id++; if (!*id) { Fprintf(stderr, "missing identifier in line %d", grep_lineno); @@ -713,10 +713,10 @@ char *buf; int isif = 1; char *buf0 = buf; #if 1 - if (isspace(buf[0])) + if (isspace((uchar) buf[0])) return &buf[-1]; /* XXX see docs above */ #else - while (buf[0] && isspace(buf[0])) + while (buf[0] && isspace((uchar) buf[0])) buf++; #endif switch (buf[0]) { @@ -768,7 +768,7 @@ char *buf; default: { char str[10]; - if (isprint(buf[0])) { + if (isprint((uchar) buf[0])) { str[0] = buf[0]; str[1] = '\0'; } else { diff --git a/win/share/tiletext.c b/win/share/tiletext.c index 8d913f897..f2ee7bf03 100644 --- a/win/share/tiletext.c +++ b/win/share/tiletext.c @@ -181,7 +181,7 @@ pixel (*pixels)[TILE_X]; /* DICE again... it doesn't seem to eat whitespace after the } like * it should, so we have to do so manually. */ - while ((*c = fgetc(txtfile)) != EOF && isspace(*c)) + while ((*c = fgetc(txtfile)) != EOF && isspace((uchar) *c)) ; ungetc(*c, txtfile); #endif diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 74cee9880..6c07b5081 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -1412,7 +1412,7 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) } } - if (isdigit(ch)) { + if (isdigit((uchar) ch)) { int count; i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if (i >= 0) { diff --git a/win/win32/mhmsgwnd.c b/win/win32/mhmsgwnd.c index e30a099b3..40b4791ef 100644 --- a/win/win32/mhmsgwnd.c +++ b/win/win32/mhmsgwnd.c @@ -310,7 +310,7 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) /* check if the string is empty */ for (p = data->window_text[MSG_LINES - 1].text; - *p && isspace(*p); p++) + *p && isspace((uchar) *p); p++) ; if (*p) { diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index b51488332..7247dbbb3 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1583,7 +1583,7 @@ mswin_yn_function(const char *question, const char *choices, CHAR_P def) (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret); /* display selection in the message window */ - if (isprint(ch) && ch != '#') { + if (isprint((uchar) ch) && ch != '#') { res_ch[0] = ch; res_ch[1] = '\x0'; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1); @@ -2019,7 +2019,7 @@ mswin_getmsghistory(BOOLEAN_P init) if (next_message) next_message++; if (p) - while (p >= retval && isspace(*p)) + while (p >= retval && isspace((uchar) *p)) *p-- = (char) 0; /* delete trailing whitespace */ return retval; } @@ -2539,23 +2539,32 @@ mswin_color_from_string(char *colorstring, HBRUSH *brushptr, if (strlen(++colorstring) != 6) return; - red_value = (int) (index(hexadecimals, tolower(*colorstring++)) + red_value = (int) (index(hexadecimals, tolower((uchar) *colorstring)) - hexadecimals); + ++colorstring; red_value *= 16; - red_value += (int) (index(hexadecimals, tolower(*colorstring++)) + red_value += (int) (index(hexadecimals, tolower((uchar) *colorstring)) - hexadecimals); + ++colorstring; - green_value = (int) (index(hexadecimals, tolower(*colorstring++)) + green_value = (int) (index(hexadecimals, + tolower((uchar) *colorstring)) - hexadecimals); + ++colorstring; green_value *= 16; - green_value += (int) (index(hexadecimals, tolower(*colorstring++)) + green_value += (int) (index(hexadecimals, + tolower((uchar) *colorstring)) - hexadecimals); + ++colorstring; - blue_value = (int) (index(hexadecimals, tolower(*colorstring++)) + blue_value = (int) (index(hexadecimals, tolower((uchar) *colorstring)) - hexadecimals); + ++colorstring; blue_value *= 16; - blue_value += (int) (index(hexadecimals, tolower(*colorstring++)) + blue_value += (int) (index(hexadecimals, + tolower((uchar) *colorstring)) - hexadecimals); + ++colorstring; *colorptr = RGB(red_value, green_value, blue_value); } else {