diff --git a/doc/fixes36.2 b/doc/fixes36.2 index d796f3260..141c13584 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.230 $ $NHDT-Date: 1547680081 2019/01/16 23:08:01 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.232 $ $NHDT-Date: 1547849604 2019/01/18 22:13:24 $ This fixes36.2 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.1 in April 2018. Please note, however, @@ -337,6 +337,11 @@ entering Ft.Ludios with a lit candle lit up the entire entry room except for to prevent those wall spots from showing so soon boulder dropped or launched by a monster onto a monster trapped in a pit and killing it credited/blamed the hero and might trigger a deltrap panic +the simulation of dual weapon combat when polymorphed into a form with more + than one weapon attack allowed off-hand artifact to be used; it also + used seconary weapon even when wearing a shield, or if it was silver + even when current shape couldn't handle silver, or if it was cursed; + cursed is allowed but weapon will be dropped, just like in two-weapon Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -390,6 +395,8 @@ when in a shop and using ':' to look inside a container on shop floor, items the hero owned the container when engulfed while in a shop, dropping an item into the engulfer and then using ':' to look at current location could cause a crash +when items were on the floor just inside a shop's door where the shopkeeper + doesn't buy and sell stuff, those items showed a 'for sale' price 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 diff --git a/src/shk.c b/src/shk.c index b3c0a8dd4..154924550 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 shk.c $NHDT-Date: 1546770990 2019/01/06 10:36:30 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.152 $ */ +/* NetHack 3.6 shk.c $NHDT-Date: 1547849604 2019/01/18 22:13:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.153 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1983,6 +1983,7 @@ int *nochrg; /* alternate return value: 1: no charge, 0: shop owned, */ struct monst *shkp; struct obj *top; xchar x, y; + boolean freespot; long cost = 0L; *nochrg = -1; /* assume 'not applicable' */ @@ -1993,11 +1994,15 @@ int *nochrg; /* alternate return value: 1: no charge, 0: shop owned, */ && (shkp = shop_keeper(inside_shop(x, y))) != 0 && inhishop(shkp)) { for (top = obj; top->where == OBJ_CONTAINED; top = top->ocontainer) continue; - *nochrg = (top->where == OBJ_FLOOR && obj->no_charge); + freespot = (top->where == OBJ_FLOOR + && x == ESHK(shkp)->shk.x && y == ESHK(shkp)->shk.y); + /* no_charge is only set for floor items inside shop proper; + items on freespot are implicitly 'no charge' */ + *nochrg = (top->where == OBJ_FLOOR && (obj->no_charge || freespot)); if (carried(top) ? (int) obj->unpaid : !*nochrg) cost = obj->quan * get_cost(obj, shkp); - if (Has_contents(obj)) + if (Has_contents(obj) && !freespot) cost += contained_cost(obj, shkp, 0L, FALSE, FALSE); } return cost; diff --git a/src/uhitm.c b/src/uhitm.c index 986f9c3bd..7b4ca1a84 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 uhitm.c $NHDT-Date: 1547680084 2019/01/16 23:08:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.199 $ */ +/* NetHack 3.6 uhitm.c $NHDT-Date: 1547846557 2019/01/18 21:22:37 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.200 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2275,7 +2275,7 @@ boolean wouldhavehit; wakeup(mdef, TRUE); } -/* attack monster as a monster. */ +/* attack monster as a monster; returns True if mon survives */ STATIC_OVL boolean hmonas(mon) register struct monst *mon; @@ -2293,6 +2293,12 @@ register struct monst *mon; switch (mattk->aatyp) { case AT_WEAP: use_weapon: + /* if we've already hit with a two-handed weapon, we don't + get to make another weapon attack (note: monsters who + use weapons do not have this restriction, but they also + never have the opportunity to use two weapons) */ + if (weapon_used && sum[i - 1] && uwep && bimanual(uwep)) + continue; /* Certain monsters don't use weapons when encountered as enemies, * but players who polymorph into them have hands or claws and * thus should be able to use weapons. This shouldn't prohibit @@ -2309,11 +2315,23 @@ register struct monst *mon; be Null, and we want to track that for passive() */ originalweapon = (altwep && uswapwep) ? &uswapwep : &uwep; if (uswapwep /* set up 'altwep' flag for next iteration */ + /* only consider seconary when wielding one-handed primary */ + && uwep && !bimanual(uwep) + /* only switch if not wearing shield and not at artifact; + shield limitation is iffy since still get extra swings + if polyform has them, but it matches twoweap behavior; + twoweap also only allows primary to be an artifact, so + if alternate weapon is one, don't use it */ + && !uarms && !uswapwep->oartifact /* only switch to uswapwep if it's a weapon */ && (uswapwep->oclass == WEAPON_CLASS || is_weptool(uswapwep)) /* only switch if uswapwep is not bow, arrows, or darts */ && !(is_launcher(uswapwep) || is_ammo(uswapwep) - || is_missile(uswapwep))) /* dart, shuriken, boomerang */ + || is_missile(uswapwep)) /* dart, shuriken, boomerang */ + /* and not two-handed and not incapable of being wielded */ + && !bimanual(uswapwep) + && !(objects[uswapwep->otyp].oc_material == SILVER + && Hate_silver)) altwep = !altwep; /* toggle for next attack */ weapon = *originalweapon; if (!weapon) /* no need to go beyond no-gloves to rings; not ...*/ @@ -2323,9 +2341,9 @@ register struct monst *mon; &armorpenalty); dieroll = rnd(20); dhit = (tmp > dieroll || u.uswallow); - /* Enemy dead, before any special abilities used */ if (!known_hitum(mon, weapon, &dhit, tmp, armorpenalty, mattk, dieroll)) { + /* enemy dead, before any special abilities used */ sum[i] = 2; break; } else @@ -2334,12 +2352,13 @@ register struct monst *mon; now be empty if the weapon was destroyed during the hit; passive(,weapon,...) won't call passive_obj() in that case */ weapon = *originalweapon; /* might receive passive erosion */ - /* might be a worm that gets cut in half */ - if (m_at(u.ux + u.dx, u.uy + u.dy) != mon) - return (boolean) (nsum != 0); - /* Do not print "You hit" message, since known_hitum - * already did it. - */ + /* might be a worm that gets cut in half; if so, early return */ + if (m_at(u.ux + u.dx, u.uy + u.dy) != mon) { + i = NATTK; /* skip additional attacks */ + /* proceed with uswapwep->cursed check, then exit loop */ + goto passivedone; + } + /* Do not print "You hit" message; known_hitum already did it. */ if (dhit && mattk->adtyp != AD_SPEL && mattk->adtyp != AD_PHYS) sum[i] = damageum(mon, mattk); break; @@ -2481,17 +2500,34 @@ register struct monst *mon; } if (sum[i] == 2) { /* defender dead */ - return (boolean) passive(mon, weapon, 1, 0, mattk->aatyp, FALSE); + (void) passive(mon, weapon, 1, 0, mattk->aatyp, FALSE); + nsum = 0; /* return value below used to be 'nsum > 0' */ } else { (void) passive(mon, weapon, sum[i], 1, mattk->aatyp, FALSE); nsum |= sum[i]; } + + /* don't use sum[i] beyond this point; + 'i' will be out of bounds if we get here via 'goto' */ + passivedone: + /* when using dual weapons, cursed secondary weapon doesn't weld, + it gets dropped; do the same when multiple AT_WEAP attacks + simulate twoweap */ + if (uswapwep && weapon == uswapwep && weapon->cursed) { + drop_uswapwep(); + break; /* don't proceed with additional attacks */ + } + /* stop attacking if defender has died; + needed to defer this until after uswapwep->cursed check */ + if (DEADMONSTER(mon)) + break; if (!Upolyd) break; /* No extra attacks if no longer a monster */ if (multi < 0) break; /* If paralyzed while attacking, i.e. floating eye */ } - return (boolean) (nsum != 0); + /* return value isn't used, but make it match hitum()'s */ + return !DEADMONSTER(mon); } /* Special (passive) attacks on you by monsters done here.