]> granicus.if.org Git - nethack/commitdiff
jousting
authornethack.rankin <nethack.rankin>
Thu, 5 Dec 2002 02:07:20 +0000 (02:07 +0000)
committernethack.rankin <nethack.rankin>
Thu, 5 Dec 2002 02:07:20 +0000 (02:07 +0000)
     Part I:  it's possible to use two-weapon combat while wielding a
lance (which seems odd to me); the second weapon would hit even if the
the first delivered a lance jousting blow that knocked the target away.

     Part II:  always getting the joust knockback effect when hitting
with a lance while mounted was too powerful; implement a suggestion
from the newsgroup that it be a random chance based on skill level.

     Related:  it's now possible to break your lance when hitting; when
adding that, I noticed that it was theoretically possible (didn't try
to reproduce) for a shattered boomerang or mirror to yield the stagger
bonus sometimes given for unarmed attacks.

doc/fixes34.1
src/uhitm.c
src/weapon.c

index 3ffb6eeeb11c5b44ce5415a0039b16a48138a747..0fdc838fb9700549cb315a9069cc173d69c79680 100644 (file)
@@ -316,6 +316,8 @@ don't crash teleporting out of a monster while engulfed, punished but not
        carrying the ball
 web breaking should consider steed strength and other characteristics
 various missing or inappropriate "killed by" death messages
+second attack for two-weapon combat will miss if first knocks target away
+jousting effect no longer occurs every time riding character hits with lance
 
 
 Platform- and/or Interface-Specific Fixes
index 49880d9aa76290a1335b36766ae84193fdf13011..f0dd789d06aba3424315c15413547493a91be657 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)uhitm.c    3.4     2002/11/07      */
+/*     SCCS Id: @(#)uhitm.c    3.4     2002/11/29      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -8,6 +8,10 @@ STATIC_DCL boolean FDECL(known_hitum, (struct monst *,int *,struct attack *));
 STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *));
 STATIC_DCL boolean FDECL(hitum, (struct monst *,int,struct attack *));
 STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *,struct obj *,int));
+#ifdef STEED
+STATIC_DCL int FDECL(joust, (struct monst *,struct obj *));
+#endif
+STATIC_DCL void NDECL(demonpet);
 STATIC_DCL boolean FDECL(m_slips_free, (struct monst *mtmp,struct attack *mattk));
 STATIC_DCL int FDECL(explum, (struct monst *,struct attack *));
 STATIC_DCL void FDECL(start_engulf, (struct monst *));
@@ -419,17 +423,20 @@ struct attack *uattk;
        if(!*mhit) {
            missum(mon, uattk);
        } else {
-           int oldhp = mon->mhp;
+           int oldhp = mon->mhp,
+               x = u.ux + u.dx, y = u.uy + u.dy;
 
-               /* KMH, conduct */
-               if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))
-                   u.uconduct.weaphit++;
+           /* KMH, conduct */
+           if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))
+               u.uconduct.weaphit++;
 
-           /* we hit the monster; be careful: it might die! */
-           notonhead = (mon->mx != u.ux+u.dx || mon->my != u.uy+u.dy);
+           /* we hit the monster; be careful: it might die or
+              be knocked into a different location */
+           notonhead = (mon->mx != x || mon->my != y);
            malive = hmon(mon, uwep, 0);
-           /*  This assumes that Stormbringer was uwep not uswapwep */ 
-           if (malive && u.twoweap && !override_confirmation)
+           /* this assumes that Stormbringer was uwep not uswapwep */ 
+           if (malive && u.twoweap && !override_confirmation &&
+                   m_at(x, y) == mon)
                malive = hmon(mon, uswapwep, 0);
            if (malive) {
                /* monster still alive */
@@ -453,7 +460,7 @@ struct attack *uattk;
                        --u.uconduct.weaphit;
                }
                if (mon->wormno && *mhit)
-                       cutworm(mon, u.ux+u.dx, u.uy+u.dy, uwep);
+                   cutworm(mon, x, y, uwep);
            }
        }
        return(malive);
@@ -512,10 +519,11 @@ int thrown;
        boolean get_dmg_bonus = TRUE;
        boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE;
        boolean silvermsg = FALSE;
+       boolean valid_weapon_attack = FALSE;
+       boolean unarmed = !uwep && !uarm && !uarms;
 #ifdef STEED
-       boolean jousting = FALSE;
+       int jousting = 0;
 #endif
-       boolean valid_weapon_attack = FALSE;
        int wtype;
        struct obj *monwep;
        char yourbuf[BUFSZ];
@@ -620,9 +628,12 @@ int thrown;
                                && hates_silver(mdat))
                        silvermsg = TRUE;
 #ifdef STEED
-                   if (u.usteed && !thrown &&
-                               weapon_type(obj) == P_LANCE && mon != u.ustuck)
-                       jousting = TRUE;
+                   if (u.usteed && !thrown && tmp > 0 &&
+                           weapon_type(obj) == P_LANCE && mon != u.ustuck) {
+                       jousting = joust(mon, obj);
+                       /* exercise skill even for minimal damage hits */
+                       if (jousting) valid_weapon_attack = TRUE;
+                   }
 #endif
                    if(!thrown && obj == uwep && obj->otyp == BOOMERANG &&
                       !rnl(3)) {
@@ -679,6 +690,8 @@ int thrown;
                            change_luck(-2);
                            useup(obj);
                            obj = (struct obj *) 0;
+                           unarmed = FALSE;    /* avoid obj==0 confusion */
+                           get_dmg_bonus = FALSE;
                            hittxt = TRUE;
                        }
                        tmp = 1;
@@ -908,8 +921,15 @@ int thrown;
 
 #ifdef STEED
        if (jousting) {
+           tmp += d(2, (obj == uwep) ? 10 : 2);        /* [was in dmgval()] */
            You("joust %s%s",
                         mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
+           if (jousting < 0) {
+               Your("%s shatters on impact!", doname(obj));
+               /* minor side-effect: broken lance won't split puddings */
+               useup(obj);
+               obj = 0;
+           }
            /* avoid migrating a dead monster */
            if (mon->mhp > tmp) {
                mhurtle(mon, u.dx, u.dy, 1);
@@ -920,7 +940,7 @@ int thrown;
 #endif
 
        /* VERY small chance of stunning opponent if unarmed. */
-       if (tmp > 1 && !thrown && !obj && !uwep && !uarm && !uarms && !Upolyd) {
+       if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) {
            if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) &&
                        !bigmonst(mdat) && !thick_skinned(mdat)) {
                if (canspotmon(mon))
@@ -1051,7 +1071,32 @@ struct attack *mattk;
        return FALSE;
 }
 
-STATIC_DCL void NDECL(demonpet);
+/* used when hitting a monster with a lance while mounted */
+STATIC_OVL int /* 1: joust hit; 0: ordinary hit; -1: joust but break lance */
+joust(mon, obj)
+struct monst *mon;     /* target */
+struct obj *obj;       /* weapon */
+{
+    int skill_rating, joust_dieroll;
+
+    if (Fumbling || Stunned) return 0;
+
+    /* if using two weapons, use worse of lance and two-weapon skills */
+    skill_rating = P_SKILL(weapon_type(obj));  /* lance skill */
+    if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating)
+       skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT);
+    if (skill_rating == P_ISRESTRICTED) skill_rating = P_UNSKILLED; /* 0=>1 */
+
+    /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */
+    if ((joust_dieroll = rn2(5)) < skill_rating) {
+       if (joust_dieroll == 0 && rnl(50) == (50-1) &&
+               !unsolid(mon->data) && !obj_resists(obj, 0, 100))
+           return -1;  /* hit that breaks lance */
+       return 1;       /* successful joust */
+    }
+    return 0;  /* no joust bonus; revert to ordinary attack */
+}
+
 /*
  * Send in a demon pet for the hero.  Exercise wisdom.
  *
index b3ff14ee540f1923e2dad86010ee0827df1b785f..37eca580f24f37f24b4468a0fc939a3623f97316 100644 (file)
@@ -286,13 +286,6 @@ struct monst *mon;
                otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) {
            int bonus = 0;
 
-#ifdef STEED
-               /* KMH -- Lances are especially made for riding */
-               if (otmp == uwep && u.usteed &&
-                               objects[otmp->otyp].oc_skill == P_LANCE)
-                       bonus += d(2,10);
-#endif
-
            if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
                bonus += rnd(4);
            if (is_axe(otmp) && is_wooden(ptr))