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))
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;
}
* 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;
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. */
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)
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)
{