]> granicus.if.org Git - nethack/commitdiff
fix gamelog 1st kill vs 1st weapon hit sequencing
authorPatR <rankin@nethack.org>
Sat, 12 Feb 2022 00:17:17 +0000 (16:17 -0800)
committerPatR <rankin@nethack.org>
Sat, 12 Feb 2022 00:17:17 +0000 (16:17 -0800)
If the first monster the hero kills is killed by the hero's first hit
with a wielded weapon, report the hit first and kill second instead of
the other way around.  Not as hard to manage as I feared, but bound to
be more fragile than the simpler handling that produced the odd order.

Also while testing it I knocked something into a polymorph trap and it
changed form without any feedback.  Give foo-changes-into-bar message
if the hero is moving and can see it happening.  It isn't needed with
a monster moves deliberately into a polymorph trap but probably would
be useful when that's is unintentional.

The "<hero> enters the dungeon" log message had a trailing period but
other log messages don't have sentence punctuation, so take that off.

src/allmain.c
src/trap.c
src/uhitm.c

index d518b749973bf2846d827b5b0ab0d29adab9d0f6..74260e859049f412d4cf65068b354905e3a7cd4a 100644 (file)
@@ -762,7 +762,7 @@ welcome(boolean new_game) /* false => restoring an old game */
 
     l_nhcore_call(new_game ? NHCORE_START_NEW_GAME : NHCORE_RESTORE_OLD_GAME);
     if (new_game)
-        livelog_printf(LL_MINORAC, "%s the%s entered the dungeon.",
+        livelog_printf(LL_MINORAC, "%s the%s entered the dungeon",
                        g.plname, buf);
 }
 
index 720fef77882c86ac87d96f093f94a3f5f1f0df15..9e60060d3e533ab6c3899630c245a244fac880fe 100644 (file)
@@ -2129,7 +2129,12 @@ trapeffect_poly_trap(
         if (resists_magm(mtmp)) {
             shieldeff(mtmp->mx, mtmp->my);
         } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) {
-            (void) newcham(mtmp, (struct permonst *) 0, FALSE, FALSE);
+            (void) newcham(mtmp, (struct permonst *) 0, FALSE,
+                           /* if hero is moving, he probably just swapped
+                              places with a pet or perhaps used a joust
+                              attack to push mtmp into the trap; describe
+                              mtmp's transformation into another shape */
+                           (!g.context.mon_moving && in_sight));
             if (in_sight)
                 seetrap(trap);
         }
index 4638351c0b44b296ad98d7a2901ac82d4559372d..71b34b02880ccd620fdcbce40b1321c4c7aa9fa7 100644 (file)
@@ -23,6 +23,9 @@ static void end_engulf(void);
 static int gulpum(struct monst *, struct attack *);
 static boolean hmonas(struct monst *);
 static void nohandglow(struct monst *);
+static boolean mhurtle_to_doom(struct monst *, int, struct permonst **,
+                               boolean);
+static void first_weapon_hit(void);
 static boolean shade_aware(struct obj *);
 
 #define PROJECTILE(obj) ((obj) && is_ammo(obj))
@@ -568,10 +571,6 @@ known_hitum(
             if (mon->wormno && *mhit)
                 cutworm(mon, g.bhitpos.x, g.bhitpos.y, slice_or_chop);
         }
-        if (u.uconduct.weaphit && !oldweaphit)
-            livelog_printf(LL_CONDUCT,
-                                 "hit with a wielded weapon for the first time");
-
     }
     return malive;
 }
@@ -743,6 +742,11 @@ hmon_hitmon(
      * damage it did _before_ outputting a hit message, but any messages
      * associated with the damage don't come out until _after_ outputting
      * a hit message.
+     *
+     * More complications:  first_weapon_hit() should be called before
+     * xkilled() in order to have the gamelog messages in the right order.
+     * So it can't be deferred until end of known_hitum() as was originally
+     * done.  We might call it directly or indirectly via mhurtle_to_doom().
      */
     boolean hittxt = FALSE, destroyed = FALSE, already_killed = FALSE;
     boolean get_dmg_bonus = TRUE;
@@ -1300,13 +1304,8 @@ hmon_hitmon(
             useup(obj);
             obj = (struct obj *) 0;
         }
-        /* avoid migrating a dead monster */
-        if (mon->mhp > tmp) {
-            mhurtle(mon, u.dx, u.dy, 1);
-            mdat = mon->data; /* in case of a polymorph trap */
-            if (DEADMONSTER(mon))
-                already_killed = TRUE;
-        }
+        if (mhurtle_to_doom(mon, tmp, &mdat, TRUE))
+            already_killed = TRUE;
         hittxt = TRUE;
     } else if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) {
         /* VERY small chance of stunning opponent if unarmed. */
@@ -1315,19 +1314,21 @@ hmon_hitmon(
             if (canspotmon(mon))
                 pline("%s %s from your powerful strike!", Monnam(mon),
                       makeplural(stagger(mon->data, "stagger")));
-            /* avoid migrating a dead monster */
-            if (mon->mhp > tmp) {
-                mhurtle(mon, u.dx, u.dy, 1);
-                mdat = mon->data; /* in case of a polymorph trap */
-                if (DEADMONSTER(mon))
-                    already_killed = TRUE;
-            }
+            if (mhurtle_to_doom(mon, tmp, &mdat, FALSE))
+                already_killed = TRUE;
             hittxt = TRUE;
         }
     }
 
-    if (!already_killed)
+    if (!already_killed) {
+        if (obj && (obj == uwep || (obj == uswapwep && u.twoweap))
+            && (thrown == HMON_MELEE || thrown == HMON_APPLIED)
+            /* note: caller has already incremented u.uconduct.weaphit
+               so we test for 1; 0 shouldn't be able to happen here... */
+            && tmp > 0 && u.uconduct.weaphit <= 1)
+            first_weapon_hit();
         mon->mhp -= tmp;
+    }
     /* adjustments might have made tmp become less than what
        a level draining artifact has already done to max HP */
     if (mon->mhp > mon->mhpmax)
@@ -1483,6 +1484,47 @@ hmon_hitmon(
     return destroyed ? FALSE : TRUE;
 }
 
+/* joust or martial arts punch is knocking the target back; that might
+   kill 'mon' (via trap) before known_hitum() has a chance to do so;
+   return True if we kill mon, False otherwise */
+static boolean
+mhurtle_to_doom(
+    struct monst *mon,         /* target monster */
+    int tmp,                   /* amount of pending damage */
+    struct permonst **mptr,    /* caller's cached copy of mon->data */
+    boolean by_wielded_weapon) /* True: violating a potential conduct */
+{
+    /* if this hit is breaking the never-hit-with-wielded-weapon conduct
+       (handled by caller's caller...) we need to log the message about
+       that before mon is killed; without this, the log entry sequence
+        N : killed for the first time
+        N : hit with a wielded weapon for the first time
+       reported on the same turn (N) looks "suboptimal";
+       u.uconduct.weaphit has already been incremented => 1 is first hit */
+    if (by_wielded_weapon && u.uconduct.weaphit <= 1)
+        first_weapon_hit();
+
+    /* only hurtle if pending physical damage (tmp) isn't going to kill mon */
+    if (tmp < mon->mhp) {
+        mhurtle(mon, u.dx, u.dy, 1);
+        /* update caller's cached mon->data in case mon was pushed into
+           a polymorph trap or is a vampshifter whose current form has
+           been killed by a trap so that it reverted to original form */
+        *mptr = mon->data;
+        if (DEADMONSTER(mon))
+            return TRUE;
+    }
+    return FALSE; /* mon isn't dead yet */
+}
+
+/* gamelog version of "you've broken never-hit-with-wielded-weapon conduct;
+   the conduct is tracked in known_hitum(); we're called by hmon_hitmon() */
+static void
+first_weapon_hit(void)
+{
+    livelog_printf(LL_CONDUCT, "hit with a wielded weapon for the first time");
+}
+
 static boolean
 shade_aware(struct obj *obj)
 {