mondead() uncluttering
Pull request #1005 introduced some code that needed minor reformatting. This goes beyond that, splitting the livelog/#chronicle handling and the vampire unshifting code out of mondead() into separate routines. The livelog phrasing for death of a unique monster always assumed that the hero was directly responsible: "killed|destroyed <unique mon|shk+details> (Nth time)." If it dies while monsters are moving, switch to: "<unique mon|shk+details> has been killed|destroyed (Nth time)." It isn't phrased as if the hero is responsible if the monster dies due to passive counter-attack against poly'd hero but that isn't blatantly wrong and doesn't seem worth worrying about.
This commit is contained in:
@@ -19,6 +19,8 @@ static void mon_leaving_level(struct monst *);
|
|||||||
static void m_detach(struct monst *, struct permonst *, boolean);
|
static void m_detach(struct monst *, struct permonst *, boolean);
|
||||||
static void set_mon_min_mhpmax(struct monst *, int);
|
static void set_mon_min_mhpmax(struct monst *, int);
|
||||||
static void lifesaved_monster(struct monst *);
|
static void lifesaved_monster(struct monst *);
|
||||||
|
static boolean vamprises(struct monst *);
|
||||||
|
static void logdeadmon(struct monst *, int);
|
||||||
static boolean ok_to_obliterate(struct monst *);
|
static boolean ok_to_obliterate(struct monst *);
|
||||||
static void qst_guardians_respond(void);
|
static void qst_guardians_respond(void);
|
||||||
static void peacefuls_respond(struct monst *);
|
static void peacefuls_respond(struct monst *);
|
||||||
@@ -39,13 +41,6 @@ extern const struct shclass shtypes[]; /* defined in shknam.c */
|
|||||||
|| !gl.level.flags.deathdrops \
|
|| !gl.level.flags.deathdrops \
|
||||||
|| (gl.level.flags.graveyard && is_undead(mdat) && rn2(3)))
|
|| (gl.level.flags.graveyard && is_undead(mdat) && rn2(3)))
|
||||||
|
|
||||||
/* A specific combination of x_monnam flags for livelogging. The livelog
|
|
||||||
* shouldn't show that you killed a hallucinatory monster and not what it
|
|
||||||
* actually is. */
|
|
||||||
#define livelog_mon_nam(mtmp) \
|
|
||||||
x_monnam(mtmp, ARTICLE_THE, (char *) 0, \
|
|
||||||
(SUPPRESS_IT | SUPPRESS_HALLUCINATION), FALSE)
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* part of the original warning code which was replaced in 3.3.1 */
|
/* part of the original warning code which was replaced in 3.3.1 */
|
||||||
@@ -2622,6 +2617,157 @@ lifesaved_monster(struct monst* mtmp)
|
|||||||
|
|
||||||
DISABLE_WARNING_FORMAT_NONLITERAL
|
DISABLE_WARNING_FORMAT_NONLITERAL
|
||||||
|
|
||||||
|
/* when a ahape-shifted vampire is killed, it reverts to base form instead
|
||||||
|
of dying; moved into separate routine to unclutter mondead() */
|
||||||
|
static boolean
|
||||||
|
vamprises(struct monst *mtmp)
|
||||||
|
{
|
||||||
|
int mndx = mtmp->cham;
|
||||||
|
|
||||||
|
if (mndx >= LOW_PM && mndx != monsndx(mtmp->data)
|
||||||
|
&& !(gm.mvitals[mndx].mvflags & G_GENOD)) {
|
||||||
|
coord new_xy;
|
||||||
|
char buf[BUFSZ];
|
||||||
|
/* alternate message phrasing for some monster types */
|
||||||
|
boolean spec_mon = (nonliving(mtmp->data)
|
||||||
|
|| noncorporeal(mtmp->data)
|
||||||
|
|| amorphous(mtmp->data)),
|
||||||
|
spec_death = (gd.disintegested /* disintegrated/digested */
|
||||||
|
|| noncorporeal(mtmp->data)
|
||||||
|
|| amorphous(mtmp->data));
|
||||||
|
coordxy x = mtmp->mx, y = mtmp->my;
|
||||||
|
|
||||||
|
/* construct a format string before transformation;
|
||||||
|
will be capitalized when used, expects one %s arg */
|
||||||
|
Snprintf(buf, sizeof buf,
|
||||||
|
"%s suddenly %s and rises as %%s!",
|
||||||
|
x_monnam(mtmp, ARTICLE_THE,
|
||||||
|
spec_mon ? (char *) 0 : "seemingly dead",
|
||||||
|
(SUPPRESS_INVISIBLE | SUPPRESS_IT), FALSE),
|
||||||
|
spec_death ? "reconstitutes" : "transforms");
|
||||||
|
mtmp->mcanmove = 1;
|
||||||
|
mtmp->mfrozen = 0;
|
||||||
|
set_mon_min_mhpmax(mtmp, 10); /* mtmp->mhpmax=max(m_lev+1,10) */
|
||||||
|
mtmp->mhp = mtmp->mhpmax;
|
||||||
|
/* mtmp==u.ustuck can happen if previously a fog cloud
|
||||||
|
or poly'd hero is hugging a vampire bat */
|
||||||
|
if (mtmp == u.ustuck) {
|
||||||
|
if (u.uswallow)
|
||||||
|
expels(mtmp, mtmp->data, FALSE);
|
||||||
|
else
|
||||||
|
uunstick();
|
||||||
|
}
|
||||||
|
/* if fog cloud is on a closed door space, move it to a more
|
||||||
|
appropriate spot for its intended new form */
|
||||||
|
if (amorphous(mtmp->data) && closed_door(mtmp->mx, mtmp->my)) {
|
||||||
|
if (enexto(&new_xy, mtmp->mx, mtmp->my, &mons[mndx]))
|
||||||
|
rloc_to(mtmp, new_xy.x, new_xy.y);
|
||||||
|
}
|
||||||
|
(void) newcham(mtmp, &mons[mndx], NO_NC_FLAGS);
|
||||||
|
if (mtmp->data == &mons[mndx])
|
||||||
|
mtmp->cham = NON_PM;
|
||||||
|
else
|
||||||
|
mtmp->cham = mndx;
|
||||||
|
|
||||||
|
if (canspotmon(mtmp)) {
|
||||||
|
/* 3.6.0 used a_monnam(mtmp); that was weird if mtmp was
|
||||||
|
named: "Dracula suddenly transforms and rises as Dracula";
|
||||||
|
3.6.1 used mtmp->data->mname; that ignored hallucination */
|
||||||
|
pline(upstart(buf),
|
||||||
|
x_monnam(mtmp, ARTICLE_A, (char *) 0,
|
||||||
|
(SUPPRESS_NAME | SUPPRESS_IT | SUPPRESS_INVISIBLE),
|
||||||
|
FALSE));
|
||||||
|
gv.vamp_rise_msg = TRUE;
|
||||||
|
}
|
||||||
|
newsym(x, y);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
RESTORE_WARNING_FORMAT_NONLITERAL
|
||||||
|
|
||||||
|
/* A specific combination of x_monnam flags for livelogging. The livelog
|
||||||
|
* shouldn't show that you killed a hallucinatory monster and not what it
|
||||||
|
* actually is. */
|
||||||
|
#define livelog_mon_nam(mtmp) \
|
||||||
|
x_monnam(mtmp, ARTICLE_THE, (char *) 0, \
|
||||||
|
(SUPPRESS_IT | SUPPRESS_HALLUCINATION), FALSE)
|
||||||
|
|
||||||
|
/* when a mon has died, mabye record an achievment of issue livelog message;
|
||||||
|
moved into separate routine to unclutter mondead() */
|
||||||
|
static void
|
||||||
|
logdeadmon(struct monst *mtmp, int mndx)
|
||||||
|
{
|
||||||
|
int howmany = gm.mvitals[mndx].died;
|
||||||
|
|
||||||
|
if (mndx == PM_MEDUSA && howmany == 1) {
|
||||||
|
record_achievement(ACH_MEDU); /* also generates a livelog event */
|
||||||
|
} else if (unique_corpstat(mtmp->data)
|
||||||
|
|| (mtmp->isshk && !mtmp->mrevived)) {
|
||||||
|
char shkdetail[QBUFSZ];
|
||||||
|
const char *mkilled;
|
||||||
|
boolean herodidit = !gc.context.mon_moving;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* livelog event; unique_corpstat() includes the Wizard and
|
||||||
|
* any High Priest even though they aren't actually unique.
|
||||||
|
*
|
||||||
|
* Shopkeeper kills are logged, but only the first time per
|
||||||
|
* shopkeeper, since their shared kill counter wouldn't work
|
||||||
|
* for this purpose (and it wouldn't account for polymorphed
|
||||||
|
* shopkeepers either).
|
||||||
|
*/
|
||||||
|
shkdetail[0] = '\0';
|
||||||
|
if (mtmp->isshk) {
|
||||||
|
howmany = 1;
|
||||||
|
/* ", the <shoptype> priorietor" needs a trailing comma for
|
||||||
|
the alternate phrasing "<shk>, shkdetails, has been killed"
|
||||||
|
when hero isn't directly responsible */
|
||||||
|
Snprintf(shkdetail, sizeof shkdetail, ", the %s %s%s",
|
||||||
|
shtypes[ESHK(mtmp)->shoptype - SHOPBASE].name,
|
||||||
|
/* in case shk name doesn't include Mr or Ms honoric */
|
||||||
|
mtmp->female ? "proprietrix" : "proprietor",
|
||||||
|
herodidit ? "" : ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* killing a unique more than once doesn't get logged every time;
|
||||||
|
the Wizard and the Riders can be killed more than once
|
||||||
|
"naturally", others require deliberate player action such as
|
||||||
|
use of undead turning to revive a corpse or petrification plus
|
||||||
|
stone-to-flesh to create and revive a statue */
|
||||||
|
if (howmany <= 3 || howmany == 5 || howmany == 10 || howmany == 25
|
||||||
|
|| (howmany % 50) == 0) { /* 50, 100, 150, 200, 250 */
|
||||||
|
char xtra[40]; /* space for " (Nth time)" when N > 1 */
|
||||||
|
long llevent_type = LL_UMONST;
|
||||||
|
|
||||||
|
/* the first kill of any unique monster is a major event;
|
||||||
|
all kills of the Wizard and the Riders are major when
|
||||||
|
they're logged but they still don't get logged every time */
|
||||||
|
if (howmany == 1 || mtmp->iswiz || is_rider(mtmp->data))
|
||||||
|
llevent_type |= LL_ACHIEVE;
|
||||||
|
xtra[0] = '\0';
|
||||||
|
if (howmany > 1) /* "(2nd time)" or "(50th time)" */
|
||||||
|
Sprintf(xtra, " (%d%s time)", howmany, ordin(howmany));
|
||||||
|
|
||||||
|
mkilled = nonliving(mtmp->data) ? "destroyed" : "killed";
|
||||||
|
/* hero is responsible: "killed <monst>" */
|
||||||
|
if (herodidit)
|
||||||
|
livelog_printf(llevent_type, "%s %s%s%s",
|
||||||
|
mkilled,
|
||||||
|
livelog_mon_nam(mtmp), shkdetail, xtra);
|
||||||
|
else /* trap, pet, conflict: "<monst> has been killed" */
|
||||||
|
livelog_printf(llevent_type, "%s%s has been %s%s",
|
||||||
|
livelog_mon_nam(mtmp), shkdetail,
|
||||||
|
mkilled, xtra);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef livelog_mon_nam
|
||||||
|
|
||||||
|
/* monster 'mtmp' has died; maybe life-save, otherwise unshapeshift and
|
||||||
|
update vanquished stats and update map */
|
||||||
void
|
void
|
||||||
mondead(struct monst *mtmp)
|
mondead(struct monst *mtmp)
|
||||||
{
|
{
|
||||||
@@ -2638,66 +2784,9 @@ mondead(struct monst *mtmp)
|
|||||||
if (!DEADMONSTER(mtmp))
|
if (!DEADMONSTER(mtmp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (is_vampshifter(mtmp)) {
|
/* vampire in bat/fog/wolf form reverts to vampire instead of dying */
|
||||||
/* this only happens if shapeshifted */
|
if (is_vampshifter(mtmp) && vamprises(mtmp))
|
||||||
mndx = mtmp->cham;
|
return;
|
||||||
if (mndx >= LOW_PM && mndx != monsndx(mtmp->data)
|
|
||||||
&& !(gm.mvitals[mndx].mvflags & G_GENOD)) {
|
|
||||||
coord new_xy;
|
|
||||||
char buf[BUFSZ];
|
|
||||||
/* alternate message phrasing for some monster types */
|
|
||||||
boolean spec_mon = (nonliving(mtmp->data)
|
|
||||||
|| noncorporeal(mtmp->data)
|
|
||||||
|| amorphous(mtmp->data)),
|
|
||||||
spec_death = (gd.disintegested /* disintegrated/digested */
|
|
||||||
|| noncorporeal(mtmp->data)
|
|
||||||
|| amorphous(mtmp->data));
|
|
||||||
coordxy x = mtmp->mx, y = mtmp->my;
|
|
||||||
|
|
||||||
/* construct a format string before transformation;
|
|
||||||
will be capitalized when used, expects one %s arg */
|
|
||||||
Sprintf(buf, "%s suddenly %s and rises as %%s!",
|
|
||||||
x_monnam(mtmp, ARTICLE_THE,
|
|
||||||
spec_mon ? (char *) 0 : "seemingly dead",
|
|
||||||
(SUPPRESS_INVISIBLE | SUPPRESS_IT), FALSE),
|
|
||||||
spec_death ? "reconstitutes" : "transforms");
|
|
||||||
mtmp->mcanmove = 1;
|
|
||||||
mtmp->mfrozen = 0;
|
|
||||||
set_mon_min_mhpmax(mtmp, 10); /* mtmp->mhpmax=max(m_lev+1,10) */
|
|
||||||
mtmp->mhp = mtmp->mhpmax;
|
|
||||||
/* mtmp==u.ustuck can happen if previously a fog cloud
|
|
||||||
or poly'd hero is hugging a vampire bat */
|
|
||||||
if (mtmp == u.ustuck) {
|
|
||||||
if (u.uswallow)
|
|
||||||
expels(mtmp, mtmp->data, FALSE);
|
|
||||||
else
|
|
||||||
uunstick();
|
|
||||||
}
|
|
||||||
/* if fog cloud is on a closed door space, move it to a more
|
|
||||||
appropriate spot for its intended new form */
|
|
||||||
if (amorphous(mtmp->data) && closed_door(mtmp->mx, mtmp->my)) {
|
|
||||||
if (enexto(&new_xy, mtmp->mx, mtmp->my, &mons[mndx]))
|
|
||||||
rloc_to(mtmp, new_xy.x, new_xy.y);
|
|
||||||
}
|
|
||||||
(void) newcham(mtmp, &mons[mndx], NO_NC_FLAGS);
|
|
||||||
if (mtmp->data == &mons[mndx])
|
|
||||||
mtmp->cham = NON_PM;
|
|
||||||
else
|
|
||||||
mtmp->cham = mndx;
|
|
||||||
if (canspotmon(mtmp)) {
|
|
||||||
/* 3.6.0 used a_monnam(mtmp); that was weird if mtmp was
|
|
||||||
named: "Dracula suddenly transforms and rises as Dracula";
|
|
||||||
3.6.1 used mtmp->data->mname; that ignored hallucination */
|
|
||||||
pline(upstart(buf),
|
|
||||||
x_monnam(mtmp, ARTICLE_A, (char *) 0,
|
|
||||||
(SUPPRESS_NAME | SUPPRESS_IT
|
|
||||||
| SUPPRESS_INVISIBLE), FALSE));
|
|
||||||
gv.vamp_rise_msg = TRUE;
|
|
||||||
}
|
|
||||||
newsym(x, y);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (be_sad)
|
if (be_sad)
|
||||||
You("have a sad feeling for a moment, then it passes.");
|
You("have a sad feeling for a moment, then it passes.");
|
||||||
@@ -2762,65 +2851,18 @@ mondead(struct monst *mtmp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mndx == PM_MEDUSA && gm.mvitals[mndx].died == 1) {
|
/* achievement and/or livelog */
|
||||||
record_achievement(ACH_MEDU); /* also generates a livelog event */
|
logdeadmon(mtmp, mndx);
|
||||||
} else if (unique_corpstat(mtmp->data)
|
|
||||||
|| (mtmp->isshk && !mtmp->mrevived)) {
|
|
||||||
/*
|
|
||||||
* livelog event; unique_corpstat() includes the Wizard and
|
|
||||||
* any High Priest even though they aren't actually unique.
|
|
||||||
*
|
|
||||||
* Shopkeeper kills are logged, but only the first time per
|
|
||||||
* shopkeeper, since their shared kill counter wouldn't work
|
|
||||||
* for this purpose (and it wouldn't account for polymorphed
|
|
||||||
* shopkeepers either).
|
|
||||||
*/
|
|
||||||
int howmany = gm.mvitals[mndx].died;
|
|
||||||
char shkdetail[100];
|
|
||||||
shkdetail[0]='\0';
|
|
||||||
if (mtmp->isshk) {
|
|
||||||
struct eshk *eshk = ESHK(mtmp);
|
|
||||||
howmany = 1;
|
|
||||||
Sprintf(shkdetail, ", the %s proprietor",
|
|
||||||
shtypes[eshk->shoptype - SHOPBASE].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* killing a unique more than once doesn't get logged every time;
|
|
||||||
the Wizard and the Riders can be killed more than once
|
|
||||||
"naturally", others require deliberate player action such as
|
|
||||||
use of undead turning to revive a corpse or petrification plus
|
|
||||||
stone-to-flesh to create and revive a statue */
|
|
||||||
if (howmany <= 3 || howmany == 5 || howmany == 10 || howmany == 25
|
|
||||||
|| (howmany % 50) == 0) { /* 50, 100, 150, 200, 250 */
|
|
||||||
char xtra[40];
|
|
||||||
long llevent_type = LL_UMONST;
|
|
||||||
|
|
||||||
/* first kill of any unique is a major event; all kills of the
|
|
||||||
Wizard and the Riders are major if they're logged but they
|
|
||||||
still don't get logged every time */
|
|
||||||
if (howmany == 1 || mtmp->iswiz || is_rider(mtmp->data))
|
|
||||||
llevent_type |= LL_ACHIEVE;
|
|
||||||
xtra[0] = '\0';
|
|
||||||
if (howmany > 1) /* "(2nd time)" or "(50th time)" */
|
|
||||||
Sprintf(xtra, " (%d%s time)", howmany, ordin(howmany));
|
|
||||||
|
|
||||||
livelog_printf(llevent_type, "%s %s%s%s",
|
|
||||||
nonliving(mtmp->data) ? "destroyed" : "killed",
|
|
||||||
livelog_mon_nam(mtmp), shkdetail, xtra);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
|
if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
|
||||||
unmap_object(mtmp->mx, mtmp->my);
|
unmap_object(mtmp->mx, mtmp->my);
|
||||||
|
|
||||||
|
/* remove 'mtmp' from play; it will stay on the fmon list until end of
|
||||||
|
current move, then dmonsfree() will get rid of it */
|
||||||
m_detach(mtmp, mptr, TRUE);
|
m_detach(mtmp, mptr, TRUE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RESTORE_WARNING_FORMAT_NONLITERAL
|
|
||||||
|
|
||||||
#undef livelog_mon_nam
|
|
||||||
|
|
||||||
/* TRUE if corpse might be dropped, magr may die if mon was swallowed */
|
/* TRUE if corpse might be dropped, magr may die if mon was swallowed */
|
||||||
boolean
|
boolean
|
||||||
corpse_chance(
|
corpse_chance(
|
||||||
|
|||||||
Reference in New Issue
Block a user