]> granicus.if.org Git - nethack/commitdiff
mon_leaving_level
authorPatR <rankin@nethack.org>
Mon, 18 Apr 2022 19:01:17 +0000 (12:01 -0700)
committerPatR <rankin@nethack.org>
Mon, 18 Apr 2022 19:01:17 +0000 (12:01 -0700)
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
src/mon.c

index 34f137818d6a8f8b55acc98158e12c41185709ce..7703bd92e25a8ca1b8943bd76b9e3b8b9cc6dfec 100644 (file)
--- 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 */
index 78327e2577d8b946776fd1340bdb22af7d960686..67b92a3777a79895595b411928b845cd714d4c8a 100644 (file)
--- 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 monstmtmp)
+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 monstmtmp, 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 monstmtmp)
+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 monstmon)
+elemental_clog(struct monst *mon)
 {
     static long msgmv = 0L;
     int m_lev = 0;