]> granicus.if.org Git - nethack/commitdiff
It's OK for pets to oscillate near the player
authorAlex Smith <ais523@nethack4.org>
Wed, 1 Nov 2017 14:55:40 +0000 (14:55 +0000)
committerAlex Smith <ais523@nethack4.org>
Wed, 1 Nov 2017 14:55:40 +0000 (14:55 +0000)
This change was coded by FIQ, who suggested it by email.

The main change here is related to monster anti-oscillation code.
When a monster believes it's stuck in an AI loop, it looks for an
alternative strategy. That applies to pets too. However, if the
pet is currently near the player, we can typically assume that it's
there because it wants to be there, and an oscillation is not
because it's stuck but because it's already in the best possible
place. This commit causes pets to be "allowed" to stay near the
player, rather than running the wrong way down a corridor because
it's the only way to do something different than what they're
currently doing.

If the pet is far from the player, we use the old behaviour unless
the pet is leashed or the player tried to call it with a whistle
or the like, in order to avoid the risk of a genuine AI loop trying
to get back to the player. (Whistling happens rarely enough that it
won't cause AI loops of its own - the player isn't going to whistle
every turn - and it makes flavour sense that a pet might interpret
it as "you're going in the wrong direction!".)

src/dogmove.c
src/mon.c

index 5a385b6aa6c7a42ca0bed3d88e9085952c51c758..200779ea3edf363853615745b96c3fce6329dbd7 100644 (file)
@@ -1086,11 +1086,18 @@ int after; /* this is extra fast monster movement */
             continue;
 
         /* lessen the chance of backtracking to previous position(s) */
-        k = has_edog ? uncursedcnt : cnt;
-        for (j = 0; j < MTSZ && j < k - 1; j++)
-            if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
-                if (rn2(MTSZ * (k - j)))
-                    goto nxti;
+        /* This causes unintended issues for pets trying to follow
+           the hero. Thus, only run it if not leashed and >5 tiles
+           away. */
+        if (!mtmp->mleashed &&
+            distmin(mtmp->mx, mtmp->my, u.ux, u.uy) > 5) {
+            k = has_edog ? uncursedcnt : cnt;
+            for (j = 0; j < MTSZ && j < k - 1; j++)
+                if (nx == mtmp->mtrack[j].x &&
+                    ny == mtmp->mtrack[j].y)
+                    if (rn2(MTSZ * (k - j)))
+                        goto nxti;
+        }
 
         j = ((ndist = GDIST(nx, ny)) - nidist) * appr;
         if ((j == 0 && !rn2(++chcnt)) || j < 0
index d01a79c95a56b23967594d5309b7c38f405e7256..a872b93a94941ab93b69a530ae833acd2470521b 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -2787,8 +2787,13 @@ wake_nearby()
             mtmp->msleeping = 0;
             if (!unique_corpstat(mtmp->data))
                 mtmp->mstrategy &= ~STRAT_WAITMASK;
-            if (mtmp->mtame && !mtmp->isminion)
-                EDOG(mtmp)->whistletime = moves;
+            if (mtmp->mtame) {
+                if (!mtmp->isminion)
+                    EDOG(mtmp)->whistletime = moves;
+                /* Clear mtrack. This is to fix up a pet who is
+                   stuck "fleeing" its master. */
+                memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack));
+            }
         }
     }
 }