]> granicus.if.org Git - nethack/commitdiff
monster sanity checking
authorPatR <rankin@nethack.org>
Mon, 14 Mar 2016 22:42:03 +0000 (15:42 -0700)
committerPatR <rankin@nethack.org>
Mon, 14 Mar 2016 22:42:03 +0000 (15:42 -0700)
Add some more checks for monsters when the sanity_check option
is enabled.

src/mon.c
src/mondata.c

index c97963abe9bd03242fcbab854fc4497d1f198e7b..b0eec652ef7f2d99601c7bab70b59be86f44bdb6 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -13,7 +13,8 @@
 
 STATIC_VAR boolean vamp_rise_msg;
 
-STATIC_DCL void FDECL(sanity_check_single_mon, (struct monst *, const char *));
+STATIC_DCL void FDECL(sanity_check_single_mon, (struct monst *, BOOLEAN_P,
+                                                const char *));
 STATIC_DCL boolean FDECL(restrap, (struct monst *));
 STATIC_DCL long FDECL(mm_aggression, (struct monst *, struct monst *));
 STATIC_DCL long FDECL(mm_displacement, (struct monst *, struct monst *));
@@ -41,35 +42,75 @@ const char *warnings[] = {
 
 
 void
-sanity_check_single_mon(mtmp, msg)
+sanity_check_single_mon(mtmp, chk_geno, msg)
 struct monst *mtmp;
+boolean chk_geno;
 const char *msg;
 {
     if (DEADMONSTER(mtmp))
         return;
-    if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS])
-        impossible("illegal mon data (%s)", msg);
+    if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS]) {
+        impossible("illegal mon data %s; mnum=%d (%s)",
+                   fmt_ptr((genericptr_t) mtmp->data), mtmp->mnum, msg);
+    } else {
+        int mndx = monsndx(mtmp->data);
+
+        if (mtmp->mnum != mndx) {
+            impossible("monster mnum=%d, monsndx=%d (%s)",
+                       mtmp->mnum, mndx, msg);
+            mtmp->mnum = mndx;
+        }
+        if (chk_geno && (mvitals[mndx].mvflags & G_GENOD) != 0)
+            impossible("genocided %s in play (%s)", mons[mndx].mname, msg);
+    }
+    if (mtmp->isshk && !has_eshk(mtmp))
+        impossible("shk without eshk (%s)", msg);
+    if (mtmp->ispriest && !has_epri(mtmp))
+        impossible("priest without epri (%s)", msg);
+    if (mtmp->isgd && !has_egd(mtmp))
+        impossible("guard without egd (%s)", msg);
+    if (mtmp->isminion && !has_emin(mtmp))
+        impossible("minion without emin (%s)", msg);
+    /* guardian angel on astral level is tame but has emin rather than edog */
+    if (mtmp->mtame && !has_edog(mtmp) && !mtmp->isminion)
+        impossible("pet without edog (%s)", msg);
 }
 
 void
 mon_sanity_check()
 {
-    int x,y;
-    struct monst *mtmp = fmon;
+    int x, y;
+    struct monst *mtmp, *m;
 
-    while (mtmp) {
-        sanity_check_single_mon(mtmp, "fmon");
-        mtmp = mtmp->nmon;
+    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+        sanity_check_single_mon(mtmp, TRUE, "fmon");
+        x = mtmp->mx, y = mtmp->my;
+        if (!isok(x, y) || (x == 0 && !mtmp->isgd))
+            impossible("mon (%s) claims to be at <%d,%d>?",
+                       fmt_ptr((genericptr_t) mtmp), x, y);
+        else if (level.monsters[x][y] != mtmp)
+            impossible("mon (%s) at <%d,%d> is not there!",
+                       fmt_ptr((genericptr_t) mtmp), x, y);
     }
+
     for (x = 0; x < COLNO; x++)
         for (y = 0; y < ROWNO; y++)
-            if ((mtmp = m_at(x,y)) != 0)
-                sanity_check_single_mon(mtmp, "m_at");
+            if ((mtmp = level.monsters[x][y]) != 0) {
+                for (m = fmon; m; m = m->nmon)
+                    if (m == mtmp)
+                        break;
+                if (!m)
+                    impossible("map mon (%s) at <%d,%d> not in fmon list!",
+                               fmt_ptr((genericptr_t) mtmp), x, y);
+                else if ((mtmp->mx != x || mtmp->my != y)
+                         && mtmp->data != &mons[PM_LONG_WORM])
+                    impossible("map mon (%s) at <%d,%d> is found at <%d,%d>?",
+                               fmt_ptr((genericptr_t) mtmp),
+                               mtmp->mx, mtmp->my, x, y);
+            }
 
-    mtmp = migrating_mons;
-    while (mtmp) {
-        sanity_check_single_mon(mtmp, "migr");
-        mtmp = mtmp->nmon;
+    for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
+        sanity_check_single_mon(mtmp, FALSE, "migr");
     }
 }
 
index 97bee8ae19e9cb3235d63ccc6540f1d0d1b49e17..0e924f3fc371bdf9c5d29f3b959c034cf35468ff 100644 (file)
@@ -3,8 +3,9 @@
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
-
-/*      These routines provide basic data for any type of monster. */
+/*
+ *      These routines provide basic data for any type of monster.
+ */
 
 /* set up an individual monster's base type (initial creation, shapechange) */
 void
@@ -16,6 +17,7 @@ int flag;
     int new_speed, old_speed = mon->data ? mon->data->mmove : 0;
 
     mon->data = ptr;
+    mon->mnum = (short) monsndx(ptr);
     if (flag == -1)
         return; /* "don't care" */