diff --git a/src/allmain.c b/src/allmain.c index d518b7499..74260e859 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -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); } diff --git a/src/trap.c b/src/trap.c index 720fef778..9e60060d3 100644 --- a/src/trap.c +++ b/src/trap.c @@ -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); } diff --git a/src/uhitm.c b/src/uhitm.c index 4638351c0..71b34b028 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -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) {