mon_leaving_level

From 6 year old email:  m_detach (monster death or removal from play)
and relmon (monster migrating to another level) both take a monster
off the map but they weren't consistent with each other.  Change them
to use a common routine for that.

I'm not sure whether the inconsistencies resulted in any bugs.  The
email was concerned about handling for monsters that emit light, but
those aren't actually common to the two removal methods and turned
out to be ok.
This commit is contained in:
PatR
2022-04-18 12:01:17 -07:00
parent 262e178243
commit 6880d37b33
2 changed files with 75 additions and 68 deletions

View File

@@ -325,6 +325,7 @@ mon_arrive(struct monst *mtmp, boolean with_you)
/* some monsters might need to do something special upon arrival
_after_ the current level has been fully set up; see dochug() */
mtmp->mstrategy |= STRAT_ARRIVE;
mtmp->mstate &= ~MON_MIGRATING;
/* make sure mnexto(rloc_to(set_apparxy())) doesn't use stale data */
mtmp->mux = u.ux, mtmp->muy = u.uy;
@@ -480,8 +481,9 @@ mon_arrive(struct monst *mtmp, boolean with_you)
/* heal monster for time spent elsewhere */
void
mon_catchup_elapsed_time(struct monst *mtmp,
long nmv) /* number of moves */
mon_catchup_elapsed_time(
struct monst *mtmp,
long nmv) /* number of moves */
{
int imv = 0; /* avoid zillions of casts and lint warnings */
@@ -689,10 +691,11 @@ keepdogs(boolean pets_only) /* true for ascension or final escape */
}
void
migrate_to_level(struct monst *mtmp,
xchar tolev, /* destination level */
xchar xyloc, /* MIGR_xxx destination xy location: */
coord *cc) /* optional destination coordinates */
migrate_to_level(
struct monst *mtmp,
xchar tolev, /* destination level */
xchar xyloc, /* MIGR_xxx destination xy location: */
coord *cc) /* optional destination coordinates */
{
struct obj *obj;
d_level new_lev;
@@ -724,6 +727,7 @@ migrate_to_level(struct monst *mtmp,
m_unleash(mtmp, TRUE);
}
relmon(mtmp, &g.migrating_mons); /* move it from map to g.migrating_mons */
mtmp->mstate |= MON_MIGRATING;
new_lev.dnum = ledger_to_dnum((xchar) tolev);
new_lev.dlevel = ledger_to_dlev((xchar) tolev);
@@ -743,6 +747,11 @@ migrate_to_level(struct monst *mtmp,
mtmp->mux = new_lev.dnum;
mtmp->muy = new_lev.dlevel;
mtmp->mx = mtmp->my = 0; /* this implies migration */
/* don't extinguish a mobile light; it still exists but has changed
from local (monst->mx > 0) to global (mx==0, not on this level) */
if (emits_light(mtmp->data))
vision_recalc(0);
}
/* return quality of food; the lower the better */

122
src/mon.c
View File

@@ -14,6 +14,7 @@ static boolean monlineu(struct monst *, int, int);
static long mm_2way_aggression(struct monst *, struct monst *);
static long mm_aggression(struct monst *, struct monst *);
static long mm_displacement(struct monst *, struct monst *);
static void mon_leaving_level(struct monst *);
static void m_detach(struct monst *, struct permonst *);
static void set_mon_min_mhpmax(struct monst *, int);
static void lifesaved_monster(struct monst *);
@@ -2189,50 +2190,28 @@ relmon(
struct monst *mon,
struct monst **monst_list) /* &g.migrating_mons or &g.mydogs or null */
{
struct monst *mtmp;
int mx = mon->mx, my = mon->my;
boolean on_map = (m_at(mx, my) == mon),
unhide = (monst_list != 0);
if (!fmon)
panic("relmon: no fmon available.");
if (mon == g.context.polearm.hitmon)
g.context.polearm.hitmon = (struct monst *) 0;
if (unhide) {
/* can't remain hidden across level changes (exception: wizard
clone can continue imitating some other monster form); also,
might be imitating a boulder so need line-of-sight unblocking */
mon->mundetected = 0;
if (M_AP_TYPE(mon) && M_AP_TYPE(mon) != M_AP_MONSTER)
seemimic(mon);
}
if (on_map) {
mon->mtrapped = 0;
if (mon->wormno)
remove_worm(mon);
else
remove_monster(mx, my);
}
/* take 'mon' off the map */
mon_leaving_level(mon);
/* remove 'mon' from the 'fmon' list */
if (mon == fmon) {
fmon = fmon->nmon;
} else {
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
if (mtmp->nmon == mon)
break;
struct monst *mtmp;
if (mtmp)
mtmp->nmon = mon->nmon;
else
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
if (mtmp->nmon == mon) {
mtmp->nmon = mon->nmon;
break;
}
if (!mtmp)
panic("relmon: mon not in list.");
}
if (unhide) {
if (on_map)
newsym(mx, my);
if (monst_list) {
/* insert into g.mydogs or g.migrating_mons */
mon->nmon = *monst_list;
*monst_list = mon;
@@ -2323,20 +2302,55 @@ dealloc_monst(struct monst *mon)
free((genericptr_t) mon);
}
/* remove effects of mtmp from other data structures */
/* 'mon' is being removed from level due to migration [relmon from keepdogs
or migrate_to_level] or due to death [m_detach from mondead or mongone] */
static void
mon_leaving_level(struct monst *mon)
{
int mx = mon->mx, my = mon->my;
boolean onmap = mx > 0;
/* to prevent an infinite relobj-flooreffects-hmon-killed loop */
mon->mtrapped = 0;
unstuck(mon); /* mon is not swallowing or holding you nor held by you */
/* vault guard might be at <0,0> */
if (onmap || mon == g.level.monsters[0][0]) {
if (mon->wormno)
remove_worm(mon);
else
remove_monster(mx, my);
}
if (onmap) {
mon->mundetected = 0; /* for migration; doesn't matter for death */
/* unhide mimic in case its shape has been blocking line of sight
or it is accompanying the hero to another level */
if (M_AP_TYPE(mon) != M_AP_NOTHING && M_AP_TYPE(mon) != M_AP_MONSTER)
seemimic(mon);
/* if mon is pinned by a boulder, removing mon lets boulder drop */
fill_pit(mx, my);
newsym(mx, my);
}
/* if mon is a remembered target, forget it since it isn't here anymore */
if (mon == g.context.polearm.hitmon)
g.context.polearm.hitmon = (struct monst *) 0;
}
/* 'mtmp' is going away; remove effects of mtmp from other data structures */
static void
m_detach(
struct monst *mtmp,
struct permonst *mptr) /* reflects mtmp->data _prior_ to mtmp's death */
{
boolean onmap = (mtmp->mx > 0);
if (mtmp == g.context.polearm.hitmon)
g.context.polearm.hitmon = 0;
if (mtmp->mleashed)
m_unleash(mtmp, FALSE);
/* to prevent an infinite relobj-flooreffects-hmon-killed loop */
mtmp->mtrapped = 0;
if (mtmp->mx > 0 && emits_light(mptr))
del_light_source(LS_MONSTER, monst_to_any(mtmp));
/* take mtmp off map but not out of fmon list yet (dmonsfree does that) */
mon_leaving_level(mtmp);
mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */
if (mtmp->iswiz)
wizdead();
@@ -2346,24 +2360,9 @@ m_detach(
leaddead();
if (mtmp->m_id == g.stealmid)
thiefdead();
/* release (drop onto map) all objects carried by mtmp */
relobj(mtmp, 0, FALSE);
if (onmap || mtmp == g.level.monsters[0][0]) {
if (mtmp->wormno)
remove_worm(mtmp);
else
remove_monster(mtmp->mx, mtmp->my);
}
if (emits_light(mptr))
del_light_source(LS_MONSTER, monst_to_any(mtmp));
if (M_AP_TYPE(mtmp))
seemimic(mtmp);
if (onmap)
newsym(mtmp->mx, mtmp->my);
unstuck(mtmp);
if (onmap)
fill_pit(mtmp->mx, mtmp->my);
if (mtmp->isshk)
shkgone(mtmp);
if (mtmp->wormno)
@@ -3248,7 +3247,7 @@ vamp_stone(struct monst* mtmp)
/* drop monster into "limbo" - that is, migrate to the current level */
void
m_into_limbo(struct monst* mtmp)
m_into_limbo(struct monst *mtmp)
{
xchar target_lev = ledger_no(&u.uz), xyloc = MIGR_APPROX_XY;
@@ -3257,16 +3256,15 @@ m_into_limbo(struct monst* mtmp)
}
static void
migrate_mon(struct monst* mtmp, xchar target_lev, xchar xyloc)
migrate_mon(struct monst *mtmp, xchar target_lev, xchar xyloc)
{
unstuck(mtmp);
mdrop_special_objs(mtmp);
migrate_to_level(mtmp, target_lev, xyloc, (coord *) 0);
mtmp->mstate |= MON_MIGRATING;
}
static boolean
ok_to_obliterate(struct monst* mtmp)
ok_to_obliterate(struct monst *mtmp)
{
/*
* Add checks for monsters that should not be obliterated
@@ -3274,13 +3272,13 @@ ok_to_obliterate(struct monst* mtmp)
*/
if (mtmp->data == &mons[PM_WIZARD_OF_YENDOR] || is_rider(mtmp->data)
|| has_emin(mtmp) || has_epri(mtmp) || has_eshk(mtmp)
|| (u.ustuck == mtmp) || (u.usteed == mtmp))
|| mtmp == u.ustuck || mtmp == u.usteed)
return FALSE;
return TRUE;
}
void
elemental_clog(struct monst* mon)
elemental_clog(struct monst *mon)
{
static long msgmv = 0L;
int m_lev = 0;