]> granicus.if.org Git - nethack/commitdiff
Monster movement and object pickup cleanup
authorPasi Kallinen <paxed@alt.org>
Wed, 1 Feb 2023 08:23:20 +0000 (10:23 +0200)
committerPasi Kallinen <paxed@alt.org>
Wed, 1 Feb 2023 08:23:23 +0000 (10:23 +0200)
Clean up some of the code for monster deciding what objects
to pick up, removing duplicate code.  There should be no real
difference in behaviour, other than monsters now can pick up
one stack of items at a time; previously monster could pick up
gold, then a practical item, followed by a magical item all
in a single turn, although this very rarely mattered.

Not extensively tested.

Code originally from NetHack4.

include/extern.h
src/mon.c
src/monmove.c

index 910f546b921219b8b83cffc7161c88fb8b14df19..ab57154d6581096af77b5b6aa9407843bb9a7b00 100644 (file)
@@ -1553,9 +1553,10 @@ extern int meatcorpse(struct monst *);
 extern void mon_give_prop(struct monst *, int);
 extern void mon_givit(struct monst *, struct permonst *);
 extern void mpickgold(struct monst *);
-extern boolean mpickstuff(struct monst *, const char *);
+extern boolean mpickstuff(struct monst *);
 extern int curr_mon_load(struct monst *);
 extern int max_mon_load(struct monst *);
+extern boolean can_touch_safely(struct monst *, struct obj *);
 extern int can_carry(struct monst *, struct obj *);
 extern long mon_allowflags(struct monst *);
 extern int mfndpos(struct monst *, coord *, long *, long);
@@ -1682,6 +1683,7 @@ extern int mstrength(struct permonst *);
 
 /* ### monmove.c ### */
 
+extern boolean mon_would_take_item(struct monst *, struct obj *);
 extern boolean itsstuck(struct monst *);
 extern boolean mb_trapped(struct monst *, boolean);
 extern void mon_track_add(struct monst *, coordxy, coordxy);
index dee643ae4b12c64a001820dd376fdc1cfc953a6d..a181e11f84dde04f718502d3c581cd6df44aba5a 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -11,7 +11,6 @@ static void sanity_check_single_mon(struct monst *, boolean, const char *);
 static struct obj *make_corpse(struct monst *, unsigned);
 static int minliquid_core(struct monst *);
 static void m_calcdistress(struct monst *);
-static boolean can_touch_safely(struct monst *, struct obj *);
 static boolean monlineu(struct monst *, int, int);
 static long mm_2way_aggression(struct monst *, struct monst *);
 static long mm_aggression(struct monst *, struct monst *);
@@ -1577,8 +1576,9 @@ mpickgold(register struct monst* mtmp)
     }
 }
 
+/* monster picks up one item stack from the map location they are at */
 boolean
-mpickstuff(struct monst *mtmp, const char *str)
+mpickstuff(struct monst *mtmp)
 {
     register struct obj *otmp, *otmp2, *otmp3;
     int carryamt = 0;
@@ -1587,6 +1587,14 @@ mpickstuff(struct monst *mtmp, const char *str)
     if (mtmp->isshk && inhishop(mtmp))
         return FALSE;
 
+    /* non-tame monsters normally don't go shopping */
+    if (!mtmp->mtame && *in_rooms(mtmp->mx, mtmp->my, SHOPBASE) && rn2(25))
+        return FALSE;
+
+    /* item in a pool, but monster can't swim */
+    if (!could_reach_item(mtmp, mtmp->mx, mtmp->my))
+        return FALSE;
+
     for (otmp = gl.level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) {
         otmp2 = otmp->nexthere;
 
@@ -1596,21 +1604,19 @@ mpickstuff(struct monst *mtmp, const char *str)
             continue;
 
         /* Nymphs take everything.  Most monsters don't pick up corpses. */
-        if (!str ? searches_for_item(mtmp, otmp)
-                 : !!(strchr(str, otmp->oclass))) {
+        if (mon_would_take_item(mtmp, otmp)) {
+
             if (otmp->otyp == CORPSE && mtmp->data->mlet != S_NYMPH
                 /* let a handful of corpse types thru to can_carry() */
                 && !touch_petrifies(&mons[otmp->corpsenm])
                 && otmp->corpsenm != PM_LIZARD
                 && !acidic(&mons[otmp->corpsenm]))
                 continue;
-            if (!touch_artifact(otmp, mtmp))
+            if (!can_touch_safely(mtmp, otmp))
                 continue;
             carryamt = can_carry(mtmp, otmp);
             if (carryamt == 0)
                 continue;
-            if (is_pool(mtmp->mx, mtmp->my))
-                continue;
             /* handle cases where the critter can only get some */
             otmp3 = otmp;
             if (carryamt != otmp->quan) {
@@ -1681,7 +1687,7 @@ max_mon_load(struct monst* mtmp)
 }
 
 /* can monster touch object safely? */
-static boolean
+boolean
 can_touch_safely(struct monst *mtmp, struct obj *otmp)
 {
     int otyp = otmp->otyp;
index c12407ba782531e3032e42e1c523faeb055e9a42..cdc20c83d68d95287e8cede87aa064d5570c7423 100644 (file)
@@ -841,9 +841,39 @@ static NEARDATA const char practical[] = { WEAPON_CLASS, ARMOR_CLASS,
 static NEARDATA const char magical[] = { AMULET_CLASS, POTION_CLASS,
                                          SCROLL_CLASS, WAND_CLASS,
                                          RING_CLASS,   SPBOOK_CLASS, 0 };
-static NEARDATA const char indigestion[] = { BALL_CLASS, ROCK_CLASS, 0 };
-static NEARDATA const char boulder_class[] = { ROCK_CLASS, 0 };
-static NEARDATA const char gem_class[] = { GEM_CLASS, 0 };
+
+/* monster mtmp would love to take object otmp? */
+boolean
+mon_would_take_item(struct monst *mtmp, struct obj *otmp)
+{
+    int pctload = (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp);
+
+    if (is_unicorn(mtmp->data) && objects[otmp->otyp].oc_material != GEMSTONE)
+        return FALSE;
+    if (!mindless(mtmp->data) && !is_animal(mtmp->data) && pctload < 75
+        && searches_for_item(mtmp, otmp))
+        return TRUE;
+    if (likes_gold(mtmp->data) && otmp->otyp == GOLD_PIECE && pctload < 95)
+        return TRUE;
+    if (likes_gems(mtmp->data) && otmp->oclass == GEM_CLASS
+        && objects[otmp->otyp].oc_material != MINERAL && pctload < 85)
+        return TRUE;
+    if (likes_objs(mtmp->data) && index(practical, otmp->oclass)
+        && pctload < 75)
+        return TRUE;
+    if (likes_magic(mtmp->data) && index(magical, otmp->oclass)
+        && pctload < 85)
+        return TRUE;
+    if (throws_rocks(mtmp->data) && otmp->otyp == BOULDER
+        && pctload < 50 && !Sokoban)
+        return TRUE;
+    if (mtmp->data == &mons[PM_GELATINOUS_CUBE]
+        && otmp->oclass != ROCK_CLASS && otmp->oclass != BALL_CLASS
+        && !(otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
+        return TRUE;
+
+    return FALSE;
+}
 
 boolean
 itsstuck(register struct monst* mtmp)
@@ -1079,11 +1109,9 @@ m_move(register struct monst* mtmp, register int after)
     coordxy ggx, ggy, nix, niy;
     xint16 chcnt;
     int chi; /* could be schar except for stupid Sun-2 compiler */
-    boolean likegold = 0, likegems = 0, likeobjs = 0, likemagic = 0,
-            conceals = 0;
-    boolean likerock = 0, can_tunnel = 0;
+    boolean can_tunnel = 0;
     boolean can_open = 0, can_unlock = 0 /*, doorbuster = 0 */;
-    boolean uses_items = 0, setlikes = 0;
+    boolean getitems = FALSE;
     boolean avoid = FALSE;
     boolean better_with_displacing = FALSE;
     boolean sawmon = canspotmon(mtmp); /* before it moved */
@@ -1248,24 +1276,13 @@ m_move(register struct monst* mtmp, register int after)
              * situation where you toss arrows at it and it has nothing
              * better to do than pick the arrows up.
              */
-            register int pctload =
-                (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp);
-
-            /* look for gold or jewels nearby */
-            likegold = (likes_gold(ptr) && pctload < 95);
-            likegems = (likes_gems(ptr) && pctload < 85);
-            uses_items = (!mindless(ptr) && !is_animal(ptr) && pctload < 75);
-            likeobjs = (likes_objs(ptr) && pctload < 75);
-            likemagic = (likes_magic(ptr) && pctload < 85);
-            likerock = (throws_rocks(ptr) && pctload < 50 && !Sokoban);
-            conceals = hides_under(ptr);
-            setlikes = TRUE;
+            getitems = TRUE;
         }
     }
 
 #define SQSRCHRADIUS 5
 
-    {
+    if (getitems) {
         register int minr = SQSRCHRADIUS; /* not too far away */
         register struct obj *otmp;
         register coordxy xx, yy;
@@ -1280,10 +1297,7 @@ m_move(register struct monst* mtmp, register int after)
         if (!mtmp->mpeaceful && is_mercenary(ptr))
             minr = 1;
 
-        if ((likegold || likegems || likeobjs || likemagic || likerock
-             || conceals) && (!*in_rooms(omx, omy, SHOPBASE)
-                              || (!rn2(25) && !mtmp->isshk))) {
- look_for_obj:
+        if ((!*in_rooms(omx, omy, SHOPBASE) || (!rn2(25) && !mtmp->isshk))) {
             oomx = min(COLNO - 1, omx + minr);
             oomy = min(ROWNO - 1, omy + minr);
             lmx = max(1, omx - minr);
@@ -1332,48 +1346,25 @@ m_move(register struct monst* mtmp, register int after)
                         continue;
                     }
 
-                    if (((likegold && otmp->oclass == COIN_CLASS)
-                         || (likeobjs && strchr(practical, otmp->oclass)
-                             && (otmp->otyp != CORPSE
-                                 || (ptr->mlet == S_NYMPH
-                                     && !is_rider(&mons[otmp->corpsenm]))))
-                         || (likemagic && strchr(magical, otmp->oclass))
-                         || (uses_items && searches_for_item(mtmp, otmp))
-                         || (likerock && otmp->otyp == BOULDER)
-                         || (likegems && otmp->oclass == GEM_CLASS
-                             && objects[otmp->otyp].oc_material != MINERAL)
-                         || (conceals && !cansee(otmp->ox, otmp->oy))
-                         || (ptr == &mons[PM_GELATINOUS_CUBE]
-                             && !strchr(indigestion, otmp->oclass)
-                             && !(otmp->otyp == CORPSE
-                                  && touch_petrifies(&mons[otmp->corpsenm]))))
-                        && touch_artifact(otmp, mtmp)) {
-                        if (can_carry(mtmp, otmp) > 0
-                            && (throws_rocks(ptr) || !sobj_at(BOULDER, xx, yy))
-                            && (!is_unicorn(ptr)
-                                || objects[otmp->otyp].oc_material == GEMSTONE)
-                            /* Don't get stuck circling an Elbereth */
-                            && !onscary(xx, yy, mtmp)) {
-                            minr = distmin(omx, omy, xx, yy);
-                            oomx = min(COLNO - 1, omx + minr);
-                            oomy = min(ROWNO - 1, omy + minr);
-                            lmx = max(1, omx - minr);
-                            lmy = max(0, omy - minr);
-                            ggx = otmp->ox;
-                            ggy = otmp->oy;
-                            if (ggx == omx && ggy == omy) {
-                                mmoved = MMOVE_DONE; /* actually unnecessary */
-                                goto postmov;
-                            }
+                    if (((mon_would_take_item(mtmp, otmp) && (can_carry(mtmp, otmp) > 0))
+                         || (hides_under(ptr) && !cansee(otmp->ox, otmp->oy)))
+                        && can_touch_safely(mtmp, otmp)
+                        /* Don't get stuck circling an Elbereth */
+                        && !onscary(xx, yy, mtmp)) {
+                        minr = distmin(omx, omy, xx, yy);
+                        oomx = min(COLNO - 1, omx + minr);
+                        oomy = min(ROWNO - 1, omy + minr);
+                        lmx = max(1, omx - minr);
+                        lmy = max(0, omy - minr);
+                        ggx = otmp->ox;
+                        ggy = otmp->oy;
+                        if (ggx == omx && ggy == omy) {
+                            mmoved = MMOVE_DONE; /* actually unnecessary */
+                            goto postmov;
                         }
                     }
                 }
             }
-        } else if (likegold) {
-            /* don't try to pick up anything else, but use the same loop */
-            uses_items = 0;
-            likegems = likeobjs = likemagic = likerock = conceals = 0;
-            goto look_for_obj;
         }
 
         if (minr < SQSRCHRADIUS && appr == -1) {
@@ -1718,21 +1709,6 @@ m_move(register struct monst* mtmp, register int after)
                 newsym(mtmp->mx, mtmp->my);
         }
         if (OBJ_AT(mtmp->mx, mtmp->my) && mtmp->mcanmove) {
-            /* recompute the likes tests, in case we polymorphed
-             * or if the "likegold" case got taken above */
-            if (setlikes) {
-                int pctload = (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp);
-
-                /* look for gold or jewels nearby */
-                likegold = (likes_gold(ptr) && pctload < 95);
-                likegems = (likes_gems(ptr) && pctload < 85);
-                uses_items =
-                    (!mindless(ptr) && !is_animal(ptr) && pctload < 75);
-                likeobjs = (likes_objs(ptr) && pctload < 75);
-                likemagic = (likes_magic(ptr) && pctload < 85);
-                likerock = (throws_rocks(ptr) && pctload < 50 && !Sokoban);
-                conceals = hides_under(ptr);
-            }
 
             /* Maybe a rock mole just ate some metal object */
             if (metallivorous(ptr)) {
@@ -1740,9 +1716,6 @@ m_move(register struct monst* mtmp, register int after)
                     return MMOVE_DIED; /* it died */
             }
 
-            if (g_at(mtmp->mx, mtmp->my) && likegold)
-                mpickgold(mtmp);
-
             /* Maybe a cube ate just about anything */
             if (ptr == &mons[PM_GELATINOUS_CUBE]) {
                 if ((etmp = meatobj(mtmp)) >= 2)
@@ -1756,22 +1729,8 @@ m_move(register struct monst* mtmp, register int after)
                     return etmp; /* it died or got forced off the level */
             }
 
-            if (!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25)) {
-                boolean picked = FALSE;
-
-                if (likeobjs)
-                    picked |= mpickstuff(mtmp, practical);
-                if (likemagic)
-                    picked |= mpickstuff(mtmp, magical);
-                if (likerock)
-                    picked |= mpickstuff(mtmp, boulder_class);
-                if (likegems)
-                    picked |= mpickstuff(mtmp, gem_class);
-                if (uses_items)
-                    picked |= mpickstuff(mtmp, (char *) 0);
-                if (picked)
-                    mmoved = MMOVE_DONE;
-            }
+            if (mpickstuff(mtmp))
+                mmoved = MMOVE_DONE;
 
             if (mtmp->minvis) {
                 newsym(mtmp->mx, mtmp->my);