int xmin, ymin, xmax, ymax; /* level boundaries */
boolean ransacked;
+ /* mkobj.c */
+ boolean mkcorpstat_norevive; /* for trolls */
+
/* mon.c */
boolean vamp_rise_msg;
boolean disintegested;
extern void mkot_trap_warn(void);
extern boolean is_magic_key(struct monst *, struct obj *);
extern struct obj *has_magic_key(struct monst *);
-extern boolean Trollsbane_wielded(void);
/* ### attrib.c ### */
#define is_obj_mappear(mon,otyp) (M_AP_TYPE(mon) == M_AP_OBJECT \
&& (mon)->mappearance == (otyp))
+/* is mon m (presumably just killed) a troll and obj o Trollsbane? */
+#define troll_baned(m,o) \
+ ((m)->data->mlet == S_TROLL && (o) && (o)->oartifact == ART_TROLLSBANE)
+
/* Get the maximum difficulty monsters that can currently be generated,
given the current level difficulty and the hero's level. */
#define monmax_difficulty(levdif) (((levdif) + u.ulevel) / 2)
return (struct obj *) 0;
}
-/* True if anyone on the level is wielding Trollsbane, False otherwise;
- used to prevent troll resurrection (FIXME: really ought to be inhibited
- when killed by Trollsbane rather than whether anyone wields that) */
-boolean
-Trollsbane_wielded(void)
-{
- struct monst *mtmp;
- struct obj *mw_tmp;
-
- if (uwep && uwep->oartifact == ART_TROLLSBANE)
- return TRUE;
- for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
- if (DEADMONSTER(mtmp))
- continue;
- if ((mw_tmp = MON_WEP(mtmp)) != 0
- && mw_tmp->oartifact == ART_TROLLSBANE)
- return TRUE;
- }
- return FALSE;
-}
-
/*artifact.c*/
UNDEFINED_VALUE, /* ymax */
0, /* ransacked */
+ /* mkobj.c */
+ FALSE, /* mkcorpstat_norevive */
+
/* mon.c */
FALSE, /* vamp_rise_msg */
FALSE, /* disintegested */
if (mtmp && !OBJ_AT(x, y) && mtmp->mundetected
&& hides_under(mtmp->data)) {
mtmp->mundetected = 0;
- } else if (x == u.ux && y == u.uy && u.uundetected && hides_under(g.youmonst.data))
+ } else if (x == u.ux && y == u.uy
+ && u.uundetected && hides_under(g.youmonst.data))
(void) hideunder(&g.youmonst);
newsym(x, y);
} else if (in_invent)
} else { /* rot this corpse away */
You_feel("%sless hassled.", is_rider(mptr) ? "much " : "");
action = ROT_CORPSE;
- when = 250L - (g.monstermoves - body->age);
+ when = (long) d(5, 50) - (g.monstermoves - body->age);
if (when < 1L)
when = 1L;
}
}
/* Timeout callback. Revive the corpse as a zombie. */
-/*ARGSUSED*/
void
-zombify_mon(anything *arg, long timeout UNUSED)
+zombify_mon(anything *arg, long timeout)
{
struct obj *body = arg->a_obj;
int zmon = zombie_form(&mons[body->corpsenm]);
if (zmon != NON_PM) {
-
if (has_omid(body))
free_omid(body);
if (has_omonst(body))
body->corpsenm = zmon;
revive_mon(arg, timeout);
+ } else {
+ rot_corpse(arg, timeout);
}
}
place_monster(mdef, mdef->mx, mdef->my);
mdef->mhp = 0;
}
+ if (mattk->aatyp == AT_WEAP || mattk->aatyp == AT_CLAW)
+ g.mkcorpstat_norevive = troll_baned(mdef, mwep) ? TRUE : FALSE;
g.zombify = (!mwep && zombie_maker(magr)
&& (mattk->aatyp == AT_TUCH
|| mattk->aatyp == AT_CLAW
&& zombie_form(mdef->data) != NON_PM);
monkilled(mdef, "", (int) mattk->adtyp);
g.zombify = FALSE; /* reset */
+ g.mkcorpstat_norevive = FALSE;
if (!DEADMONSTER(mdef))
return mhm.hitflags; /* mdef lifesaved */
else if (mhm.hitflags == MM_AGR_DIED)
start_corpse_timeout(struct obj* body)
{
long when; /* rot away when this old */
- long corpse_age; /* age of corpse */
+ long age; /* age of corpse */
int rot_adjust;
short action;
- boolean no_revival;
- /* if a troll corpse was frozen, it won't get a revive timer */
- no_revival = (body->norevive != 0);
- body->norevive = 0; /* always clear corpse's 'frozen' flag */
+ /*
+ * Note:
+ * if body->norevive is set, the corpse will rot away instead
+ * of revive when its REVIVE_MON timer finishes.
+ */
/* lizards and lichen don't rot or revive */
if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN)
return;
- action = ROT_CORPSE; /* default action: rot away */
+ action = ROT_CORPSE; /* default action: rot away */
rot_adjust = g.in_mklev ? 25 : 10; /* give some variation */
- corpse_age = g.monstermoves - body->age;
- if (corpse_age > ROT_AGE)
+ age = g.monstermoves - body->age;
+ if (age > ROT_AGE)
when = rot_adjust;
else
- when = ROT_AGE - corpse_age;
+ when = ROT_AGE - age;
when += (long) (rnz(rot_adjust) - rot_adjust);
if (is_rider(&mons[body->corpsenm])) {
action = REVIVE_MON;
when = rider_revival_time(body, FALSE);
- } else if (mons[body->corpsenm].mlet == S_TROLL && !no_revival) {
- long age;
-
+ } else if (mons[body->corpsenm].mlet == S_TROLL) {
for (age = 2; age <= TAINT_AGE; age++)
if (!rn2(TROLL_REVIVE_CHANCE)) { /* troll revives */
action = REVIVE_MON;
when = age;
break;
}
- } else if (!no_revival && g.zombify
- && zombie_form(&mons[body->corpsenm]) != NON_PM) {
+ } else if (g.zombify && zombie_form(&mons[body->corpsenm]) != NON_PM
+ && !body->norevive) {
action = ZOMBIFY_MON;
- when = 5 + rn2(15);
+ when = rn1(15, 5); /* 5..19 */
}
(void) start_timer(when, TIMER_OBJECT, action, obj_to_any(body));
*/
struct obj *
mkcorpstat(
- int objtype, /* CORPSE or STATUE */
- struct monst *mtmp,
- struct permonst *ptr,
- int x, int y,
+ int objtype, /* CORPSE or STATUE */
+ struct monst *mtmp, /* dead monster, might be Null */
+ struct permonst *ptr, /* if non-Null, overrides mtmp->mndx */
+ int x, int y, /* where to place corpse; <0,0> => random */
unsigned corpstatflags)
{
struct obj *otmp;
} else {
otmp = mksobj_at(objtype, x, y, init, FALSE);
}
+ otmp->norevive = g.mkcorpstat_norevive;
/* when 'mtmp' is non-null save the monster's details with the
corpse or statue; it will also force the 'ptr' override below */
/* [note: thrown obj might go away during killed()/xkilled() call
(via 'thrownobj'; if swallowed, it gets added to engulfer's
minvent and might merge with a stack that's already there)] */
+ /* already_killed and poiskilled won't apply for Trollsbane */
if (needpoismsg)
pline_The("poison doesn't seem to affect %s.", mon_nam(mon));
xkilled(mon, XKILL_NOMSG);
destroyed = TRUE; /* return FALSE; */
} else if (destroyed) {
- if (!already_killed)
+ if (!already_killed) {
+ if (troll_baned(mon, obj))
+ g.mkcorpstat_norevive = TRUE;
killed(mon); /* takes care of most messages */
+ g.mkcorpstat_norevive = FALSE;
+ }
} else if (u.umconf && hand_to_hand) {
nohandglow(mon);
if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) {
|| mattk->aatyp == AT_TUCH
|| mattk->aatyp == AT_HUGS) {
if (thick_skinned(pd))
- mhm->damage = (mattk->aatyp == AT_KICK) ? 0 : (mhm->damage + 1) / 2;
+ mhm->damage = (mattk->aatyp == AT_KICK) ? 0
+ : (mhm->damage + 1) / 2;
/* add ring(s) of increase damage */
if (u.udaminc > 0) {
/* applies even if damage was 0 */
if (mhm->damage <= 0)
mhm->damage = 1;
if (!(otmp->oartifact && artifact_hit(magr, mdef, otmp,
- &mhm->damage, g.mhitu_dieroll)))
+ &mhm->damage,
+ g.mhitu_dieroll)))
hitmsg(magr, mattk);
if (!mhm->damage)
return;
now we'll know and might need to deliver skipped message
(note: if there's no message there'll be no auxilliary
damage so the message here isn't coming too late) */
- if (!artifact_hit(magr, mdef, mwep, &mhm->damage, mhm->dieroll)) {
+ if (!artifact_hit(magr, mdef, mwep, &mhm->damage,
+ mhm->dieroll)) {
if (g.vis)
pline("%s hits %s.", Monnam(magr),
mon_nam_too(mdef, magr));
damage; however, it might cause carried items to be
destroyed and they might do so */
if (DEADMONSTER(mdef)) {
- mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
+ mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0
+ : MM_AGR_DIED));
mhm->done = TRUE;
return;
}
int specialdmg) /* blessed and/or silver bonus against various things */
{
struct mhitm_data mhm;
+
mhm.damage = d((int) mattk->damn, (int) mattk->damd);
mhm.hitflags = MM_MISS;
mhm.permdmg = 0;
mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */
mdef->mhp -= mhm.damage;
if (DEADMONSTER(mdef)) {
+ /* troll killed by Trollsbane won't auto-revive; FIXME? same when
+ Trollsbane is wielded as primary and two-weaponing kills with
+ secondary, which matches monster vs monster behavior but is
+ different from the non-poly'd hero vs monster behavior */
+ if (mattk->aatyp == AT_WEAP || mattk->aatyp == AT_CLAW)
+ g.mkcorpstat_norevive = troll_baned(mdef, uwep) ? TRUE : FALSE;
/* (DEADMONSTER(mdef) and !mhm.damage => already killed) */
if (mdef->mtame && !cansee(mdef->mx, mdef->my)) {
You_feel("embarrassed for a moment.");
} else if (mhm.damage) {
killed(mdef); /* regular "you kill <mdef>" message */
}
+ g.mkcorpstat_norevive = FALSE;
return MM_DEF_DIED;
}
return MM_HIT;
struct attack *mattk, alt_attk;
struct obj *weapon, **originalweapon;
boolean altwep = FALSE, weapon_used = FALSE, odd_claw = TRUE;
- int i, tmp, armorpenalty, sum[NATTK], nsum = MM_MISS, dhit = 0, attknum = 0;
+ int i, tmp, armorpenalty, sum[NATTK], nsum = MM_MISS,
+ dhit = 0, attknum = 0;
int dieroll, multi_claw = 0;
/* with just one touch/claw/weapon attack, both rings matter;
get to make another weapon attack (note: monsters who
use weapons do not have this restriction, but they also
never have the opportunity to use two weapons) */
- if (weapon_used && (sum[i - 1] > MM_MISS) && uwep && bimanual(uwep))
+ if (weapon_used && (sum[i - 1] > MM_MISS)
+ && uwep && bimanual(uwep))
continue;
/* Certain monsters don't use weapons when encountered as enemies,
* but players who polymorph into them have hands or claws and
if (silverhit && flags.verbose)
silver_sears(&g.youmonst, mon, silverhit);
sum[i] = damageum(mon, mattk, specialdmg);
- } else if (i >= 2 && (sum[i - 1] > MM_MISS) && (sum[i - 2] > MM_MISS)) {
+ } else if (i >= 2 && (sum[i - 1] > MM_MISS)
+ && (sum[i - 2] > MM_MISS)) {
/* in case we're hugging a new target while already
holding something else; yields feedback
"<u.ustuck> is no longer in your clutches" */
x = xy.x, y = xy.y;
}
- if ((mons[montype].mlet == S_EEL && !IS_POOL(levl[x][y].typ))
- || (mons[montype].mlet == S_TROLL && Trollsbane_wielded())) {
- if (by_hero && cansee(x, y))
+ if (corpse->norevive
+ || (mons[montype].mlet == S_EEL && !IS_POOL(levl[x][y].typ))) {
+ if (cansee(x, y))
pline("%s twitches feebly.",
upstart(corpse_xname(corpse, (const char *) 0, CXN_PFX_THE)));
return (struct monst *) 0;
struct obj *otmp, *otmp2;
struct monst *mtmp2;
char owner[BUFSZ], corpse[BUFSZ];
+ unsigned save_norevive;
boolean youseeit, different_type, is_u = (mon == &g.youmonst);
int corpsenm, res = 0;
/* for a stack, only one is revived; if is_u, revive() calls
useup() which calls update_inventory() but not encumber_msg() */
corpsenm = otmp->corpsenm;
+ /* norevive applies to revive timer, not to explicit unturn_dead() */
+ save_norevive = otmp->norevive;
+ otmp->norevive = 0;
+
if ((mtmp2 = revive(otmp, !g.context.mon_moving)) != 0) {
++res;
/* might get revived as a zombie rather than corpse's monster */
pline("%s%s suddenly %s%s%s!", owner, corpse,
nonliving(mtmp2->data) ? "reanimates" : "comes alive",
different_type ? " as " : "",
- different_type ? an(pmname(mtmp2->data, Mgender(mtmp2))) : "");
+ different_type ? an(pmname(mtmp2->data, Mgender(mtmp2)))
+ : "");
else if (canseemon(mtmp2))
pline("%s suddenly appears!", Amonnam(mtmp2));
+ } else {
+ /* revival failed; corpse 'otmp' is intact */
+ otmp->norevive = save_norevive ? 1 : 0;
}
}
if (is_u && res)