diff --git a/include/extern.h b/include/extern.h index ce0b42008..afbf4e498 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1514769568 2018/01/01 01:19:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.622 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1517128658 2018/01/28 08:37:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.624 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2473,13 +2473,14 @@ E void NDECL(u_init); E void FDECL(erode_armor, (struct monst *, int)); E boolean FDECL(attack_checks, (struct monst *, struct obj *)); E void FDECL(check_caitiff, (struct monst *)); -E int FDECL(find_roll_to_hit, - (struct monst *, UCHAR_P, struct obj *, int *, int *)); +E int FDECL(find_roll_to_hit, (struct monst *, UCHAR_P, struct obj *, + int *, int *)); E boolean FDECL(attack, (struct monst *)); E boolean FDECL(hmon, (struct monst *, struct obj *, int, int)); E int FDECL(damageum, (struct monst *, struct attack *)); E void FDECL(missum, (struct monst *, struct attack *, BOOLEAN_P)); -E int FDECL(passive, (struct monst *, BOOLEAN_P, int, UCHAR_P, BOOLEAN_P)); +E int FDECL(passive, (struct monst *, struct obj *, BOOLEAN_P, int, + UCHAR_P, BOOLEAN_P)); E void FDECL(passive_obj, (struct monst *, struct obj *, struct attack *)); E void FDECL(stumble_onto_mimic, (struct monst *)); E int FDECL(flash_hits_mon, (struct monst *, struct obj *)); diff --git a/src/dokick.c b/src/dokick.c index 7aa8e2baa..c1976dbc8 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dokick.c $NHDT-Date: 1446955295 2015/11/08 04:01:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.104 $ */ +/* NetHack 3.6 dokick.c $NHDT-Date: 1517128663 2018/01/28 08:37:43 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.113 $ */ /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -116,7 +116,7 @@ register boolean clumsy; } } - (void) passive(mon, TRUE, mon->mhp > 0, AT_KICK, FALSE); + (void) passive(mon, uarmf, TRUE, mon->mhp > 0, AT_KICK, FALSE); if (mon->mhp <= 0 && !trapkilled) killed(mon); @@ -162,7 +162,7 @@ xchar x, y; && !is_flyer(mon->data)) { pline("Floating in the air, you miss wildly!"); exercise(A_DEX, FALSE); - (void) passive(mon, FALSE, 1, AT_KICK, FALSE); + (void) passive(mon, uarmf, FALSE, 1, AT_KICK, FALSE); return; } @@ -213,13 +213,13 @@ xchar x, y; } else if (tmp > (kickdieroll = rnd(20))) { You("kick %s.", mon_nam(mon)); sum = damageum(mon, uattk); - (void) passive(mon, (boolean) (sum > 0), (sum != 2), AT_KICK, - FALSE); + (void) passive(mon, uarmf, (boolean) (sum > 0), + (sum != 2), AT_KICK, FALSE); if (sum == 2) break; /* Defender died */ } else { missum(mon, uattk, (tmp + armorpenalty > kickdieroll)); - (void) passive(mon, FALSE, 1, AT_KICK, FALSE); + (void) passive(mon, uarmf, FALSE, 1, AT_KICK, FALSE); } } return; @@ -233,7 +233,7 @@ xchar x, y; if (martial() && !rn2(2)) goto doit; Your("clumsy kick does no damage."); - (void) passive(mon, FALSE, 1, AT_KICK, FALSE); + (void) passive(mon, uarmf, FALSE, 1, AT_KICK, FALSE); return; } if (i < j / 10) @@ -257,7 +257,7 @@ doit: if (!nohands(mon->data) && !rn2(martial() ? 5 : 3)) { pline("%s blocks your %skick.", Monnam(mon), clumsy ? "clumsy " : ""); - (void) passive(mon, FALSE, 1, AT_KICK, FALSE); + (void) passive(mon, uarmf, FALSE, 1, AT_KICK, FALSE); return; } else { maybe_mnexto(mon); @@ -274,7 +274,7 @@ doit: ? "slides" : "jumps", clumsy ? "easily" : "nimbly", clumsy ? "clumsy " : ""); - (void) passive(mon, FALSE, 1, AT_KICK, FALSE); + (void) passive(mon, uarmf, FALSE, 1, AT_KICK, FALSE); return; } } diff --git a/src/uhitm.c b/src/uhitm.c index df0645b96..daa069cc4 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 uhitm.c $NHDT-Date: 1513297347 2017/12/15 00:22:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.172 $ */ +/* NetHack 3.6 uhitm.c $NHDT-Date: 1517128664 2018/01/28 08:37:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.173 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -392,11 +392,10 @@ register struct monst *mtmp; unweapon = FALSE; if (flags.verbose) { if (uwep) - You("begin bashing monsters with %s.", - yobjnam(uwep, (char *) 0)); + You("begin bashing monsters with %s.", yname(uwep)); else if (!cantwield(youmonst.data)) - You("begin %sing monsters with your %s %s.", - Role_if(PM_MONK) ? "strik" : "bash", + You("begin %s monsters with your %s %s.", + ing_suffix(Role_if(PM_MONK) ? "strike" : "bash"), uarmg ? "gloved" : "bare", /* Del Lamb */ makeplural(body_part(HAND))); } @@ -541,7 +540,7 @@ struct attack *uattk; mhit = (tmp > dieroll); result = known_hitum(mtmp, uwep, &mhit, tmp, armorpenalty, uattk, dieroll); - (void) passive(mtmp, mhit, DEADMONSTER(mtmp), AT_WEAP, !uwep); + (void) passive(mtmp, uwep, mhit, DEADMONSTER(mtmp), AT_WEAP, !uwep); if (mon == mtmp) malive = result; } @@ -570,6 +569,10 @@ struct attack *uattk; if (tmp > dieroll) exercise(A_DEX, TRUE); malive = known_hitum(mon, uwep, &mhit, tmp, armorpenalty, uattk, dieroll); + if (wepbefore && !uwep) + wep_was_destroyed = TRUE; + (void) passive(mon, uwep, mhit, malive, AT_WEAP, wep_was_destroyed); + /* second attack for two-weapon combat; won't occur if Stormbringer overrode confirmation (assumes Stormbringer is primary weapon) or if the monster was killed or knocked to different location */ @@ -580,10 +583,10 @@ struct attack *uattk; mhit = (tmp > dieroll || u.uswallow); malive = known_hitum(mon, uswapwep, &mhit, tmp, armorpenalty, uattk, dieroll); + /* second passive counter-attack only occurs if second attack hits */ + if (mhit) + (void) passive(mon, uswapwep, mhit, malive, AT_WEAP, !uswapwep); } - if (wepbefore && !uwep) - wep_was_destroyed = TRUE; - (void) passive(mon, mhit, malive, AT_WEAP, wep_was_destroyed); return malive; } @@ -1157,8 +1160,9 @@ int dieroll; if ((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING]) /* pudding is alive and healthy enough to split */ && mon->mhp > 1 && !mon->mcan - /* iron weapon using melee or polearm hit [3.6.1: metal weapon too] */ - && obj && obj == uwep + /* iron weapon using melee or polearm hit [3.6.1: metal weapon too; + also allow either or both weapons to cause split when twoweap] */ + && obj && (obj == uwep || (u.twoweap && obj == uswapwep)) && ((objects[obj->otyp].oc_material == IRON /* allow scalpel and tsurugi to split puddings */ || objects[obj->otyp].oc_material == METAL) @@ -1166,7 +1170,12 @@ int dieroll; && !(is_ammo(obj) || is_missile(obj))) && hand_to_hand) { if (clone_mon(mon, 0, 0)) { - pline("%s divides as you hit it!", Monnam(mon)); + char withwhat[BUFSZ]; + + withwhat[0] = '\0'; + if (u.twoweap && flags.verbose) + Sprintf(withwhat, " with %s", yname(obj)); + pline("%s divides as you hit it%s!", Monnam(mon), withwhat); hittxt = TRUE; } } @@ -2186,7 +2195,7 @@ hmonas(mon) register struct monst *mon; { struct attack *mattk, alt_attk; - struct obj *weapon; + struct obj *weapon, **originalweapon; boolean altwep = FALSE, weapon_used = FALSE; int i, tmp, armorpenalty, sum[NATTK], nsum = 0, dhit = 0, attknum = 0; int dieroll; @@ -2194,6 +2203,7 @@ register struct monst *mon; for (i = 0; i < NATTK; i++) { sum[i] = 0; mattk = getmattk(&youmonst, mon, i, sum, &alt_attk); + weapon = 0; switch (mattk->aatyp) { case AT_WEAP: use_weapon: @@ -2208,20 +2218,36 @@ register struct monst *mon; * we currently allow the player to get each of these as a weapon * attack. Is this really desirable? */ - /* approximate two-weapon mode */ - weapon = (altwep && uswapwep) ? uswapwep : uwep; - altwep = !altwep; /* toggle for next attack */ + /* approximate two-weapon mode; known_hitum() -> hmon() -> &c + might destroy the weapon argument, but it might also already + 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 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 */ + altwep = !altwep; /* toggle for next attack */ + weapon = *originalweapon; + if (!weapon) /* no need to go beyond no-gloves to rings; not ...*/ + originalweapon = &uarmg; /*... subject to erosion damage */ + tmp = find_roll_to_hit(mon, AT_WEAP, weapon, &attknum, &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)) { + if (!known_hitum(mon, weapon, &dhit, tmp, + armorpenalty, mattk, dieroll)) { sum[i] = 2; break; } else sum[i] = dhit; + /* originalweapon points to an equipment slot which might + 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); @@ -2366,11 +2392,11 @@ register struct monst *mon; u.mh = -1; /* dead in the current form */ rehumanize(); } - if (sum[i] == 2) - return (boolean) passive(mon, 1, 0, mattk->aatyp, FALSE); - /* defender dead */ - else { - (void) passive(mon, sum[i], 1, mattk->aatyp, FALSE); + if (sum[i] == 2) { + /* defender dead */ + return (boolean) passive(mon, weapon, 1, 0, mattk->aatyp, FALSE); + } else { + (void) passive(mon, weapon, sum[i], 1, mattk->aatyp, FALSE); nsum |= sum[i]; } if (!Upolyd) @@ -2384,10 +2410,11 @@ register struct monst *mon; /* Special (passive) attacks on you by monsters done here. */ int -passive(mon, mhit, malive, aatyp, wep_was_destroyed) -register struct monst *mon; -register boolean mhit; -register int malive; +passive(mon, weapon, mhit, malive, aatyp, wep_was_destroyed) +struct monst *mon; +struct obj *weapon; /* uwep or uswapwep or uarmg or uarmf or Null */ +boolean mhit; +int malive; uchar aatyp; boolean wep_was_destroyed; { @@ -2412,14 +2439,14 @@ boolean wep_was_destroyed; */ switch (ptr->mattk[i].adtyp) { case AD_FIRE: - if (mhit && !mon->mcan) { + if (mhit && !mon->mcan && weapon) { if (aatyp == AT_KICK) { if (uarmf && !rn2(6)) (void) erode_obj(uarmf, xname(uarmf), ERODE_BURN, EF_GREASE | EF_VERBOSE); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) - passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i])); + passive_obj(mon, weapon, &(ptr->mattk[i])); } break; case AD_ACID: @@ -2435,14 +2462,14 @@ boolean wep_was_destroyed; if (!rn2(30)) erode_armor(&youmonst, ERODE_CORRODE); } - if (mhit) { + if (mhit && weapon) { if (aatyp == AT_KICK) { if (uarmf && !rn2(6)) (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE, EF_GREASE | EF_VERBOSE); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) - passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i])); + passive_obj(mon, weapon, &(ptr->mattk[i])); } exercise(A_STR, FALSE); break; @@ -2471,25 +2498,25 @@ boolean wep_was_destroyed; } break; case AD_RUST: - if (mhit && !mon->mcan) { + if (mhit && !mon->mcan && weapon) { if (aatyp == AT_KICK) { if (uarmf) (void) erode_obj(uarmf, xname(uarmf), ERODE_RUST, EF_GREASE | EF_VERBOSE); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) - passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i])); + passive_obj(mon, weapon, &(ptr->mattk[i])); } break; case AD_CORR: - if (mhit && !mon->mcan) { + if (mhit && !mon->mcan && weapon) { if (aatyp == AT_KICK) { if (uarmf) (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE, EF_GREASE | EF_VERBOSE); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) - passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i])); + passive_obj(mon, weapon, &(ptr->mattk[i])); } break; case AD_MAGM: @@ -2504,17 +2531,14 @@ boolean wep_was_destroyed; break; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ if (mhit) { - struct obj *obj = (struct obj *) 0; - if (aatyp == AT_KICK) { - obj = uarmf; - if (!obj) + if (!weapon) break; } else if (aatyp == AT_BITE || aatyp == AT_BUTT || (aatyp >= AT_STNG && aatyp < AT_WEAP)) { break; /* no object involved */ } - passive_obj(mon, obj, &(ptr->mattk[i])); + passive_obj(mon, weapon, &(ptr->mattk[i])); } break; default: @@ -2628,6 +2652,7 @@ struct attack *mattk; /* null means we find one internally */ struct permonst *ptr = mon->data; int i; + /* [this first bit is obsolete; we're not called with Null anymore] */ /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */ if (!obj) { obj = (u.twoweap && uswapwep && !rn2(2)) ? uswapwep : uwep;