From 6880d37b33a31ec871aad771f9b3ac04e667f33c Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 18 Apr 2022 12:01:17 -0700 Subject: [PATCH] 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. --- src/dog.c | 21 +++++++--- src/mon.c | 120 +++++++++++++++++++++++++++--------------------------- 2 files changed, 74 insertions(+), 67 deletions(-) diff --git a/src/dog.c b/src/dog.c index 34f137818..7703bd92e 100644 --- a/src/dog.c +++ b/src/dog.c @@ -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 */ diff --git a/src/mon.c b/src/mon.c index 78327e257..67b92a377 100644 --- a/src/mon.c +++ b/src/mon.c @@ -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 { + struct monst *mtmp; + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) - if (mtmp->nmon == mon) + if (mtmp->nmon == mon) { + mtmp->nmon = mon->nmon; break; - - if (mtmp) - mtmp->nmon = mon->nmon; - else + } + 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; -- 2.50.1