]> granicus.if.org Git - nethack/commitdiff
fix #H4353 - monster gets angry after being killed
authorPatR <rankin@nethack.org>
Tue, 31 May 2016 11:44:21 +0000 (04:44 -0700)
committerPatR <rankin@nethack.org>
Tue, 31 May 2016 11:44:21 +0000 (04:44 -0700)
...by thrown potion.  The reported case was a shopkeeper killed by
system shock from thrown potion of polymorph, but any death (acid,
burning oil explosion, water against iron golem, holy water against
undead, demon, or werecritter) to any peaceful monster could cause
similar result.

doc/fixes36.1
src/potion.c

index a7549db82984feadac3c786da36f7789ebe74501..26967c078a6c5796346c1051c1e99e47f0cd5d97 100644 (file)
@@ -276,6 +276,8 @@ when getpos was picking a location, typing '^' to move to the next known trap
        skipped some detected traps if their location was unseen
 describe detected door traps and chest traps as trapped door and trapped chest
        instead of bear trap; bear trap tile is still used on map though
+thrown potion that killed peaceful monster would cause "the <mon> gets argry"
+       after the message about it being killed
 
 
 Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
index 6d3e45f96af16af1e8106ab318f900f3462f75ab..d2bf6a0219d2a2d9d97473469bae59709cce74db 100644 (file)
@@ -1241,16 +1241,18 @@ boolean your_fault;
 {
     const char *botlnam = bottlename();
     boolean isyou = (mon == &youmonst);
-    int distance;
+    int distance, tx, ty;
     struct obj *saddle = (struct obj *) 0;
     boolean hit_saddle = FALSE;
 
     if (isyou) {
+        tx = u.ux, ty = u.uy;
         distance = 0;
         pline_The("%s crashes on your %s and breaks into shards.", botlnam,
                   body_part(HEAD));
         losehp(Maybe_Half_Phys(rnd(2)), "thrown potion", KILLED_BY_AN);
     } else {
+        tx = mon->mx, ty = mon->my;
         /* sometimes it hits the saddle */
         if (((mon->misc_worn_check & W_SADDLE)
              && (saddle = which_armor(mon, W_SADDLE)))
@@ -1259,10 +1261,10 @@ boolean your_fault;
                     && ((rnl(10) > 7 && obj->cursed)
                         || (rnl(10) < 4 && obj->blessed) || !rn2(3)))))
             hit_saddle = TRUE;
-        distance = distu(mon->mx, mon->my);
-        if (!cansee(mon->mx, mon->my))
+        distance = distu(tx, ty);
+        if (!cansee(tx, ty)) {
             pline("Crash!");
-        else {
+        else {
             char *mnam = mon_nam(mon);
             char buf[BUFSZ];
 
@@ -1285,7 +1287,7 @@ boolean your_fault;
     }
 
     /* oil doesn't instantly evaporate; Neither does a saddle hit */
-    if (obj->otyp != POT_OIL && !hit_saddle && cansee(mon->mx, mon->my))
+    if (obj->otyp != POT_OIL && !hit_saddle && cansee(tx, ty))
         pline("%s.", Tobjnam(obj, "evaporate"));
 
     if (isyou) {
@@ -1313,7 +1315,7 @@ boolean your_fault;
     } else if (hit_saddle && saddle) {
         char *mnam, buf[BUFSZ], saddle_glows[BUFSZ];
         boolean affected = FALSE;
-        boolean useeit = !Blind && canseemon(mon) && cansee(mon->mx, mon->my);
+        boolean useeit = !Blind && canseemon(mon) && cansee(tx, ty);
 
         mnam = x_monnam(mon, ARTICLE_THE, (char *) 0,
                         (SUPPRESS_IT | SUPPRESS_SADDLE), FALSE);
@@ -1331,10 +1333,8 @@ boolean your_fault;
         if (useeit && !affected)
             pline("%s %s wet.", buf, aobjnam(saddle, "get"));
     } else {
-        boolean angermon = TRUE;
+        boolean angermon = your_fault;
 
-        if (!your_fault)
-            angermon = FALSE;
         switch (obj->otyp) {
         case POT_HEALING:
         case POT_EXTRA_HEALING:
@@ -1419,7 +1419,7 @@ boolean your_fault;
                     pline("%s %s in pain!", Monnam(mon),
                           is_silent(mon->data) ? "writhes" : "shrieks");
                     if (!is_silent(mon->data))
-                        wake_nearto(mon->mx, mon->my, mon->data->mlevel * 10);
+                        wake_nearto(tx, ty, mon->data->mlevel * 10);
                     mon->mhp -= d(2, 6);
                     /* should only be by you */
                     if (mon->mhp < 1)
@@ -1451,14 +1451,14 @@ boolean your_fault;
             break;
         case POT_OIL:
             if (obj->lamplit)
-                explode_oil(obj, mon->mx, mon->my);
+                explode_oil(obj, tx, ty);
             break;
         case POT_ACID:
             if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) {
                 pline("%s %s in pain!", Monnam(mon),
                       is_silent(mon->data) ? "writhes" : "shrieks");
                 if (!is_silent(mon->data))
-                    wake_nearto(mon->mx, mon->my, mon->data->mlevel * 10);
+                    wake_nearto(tx, ty, mon->data->mlevel * 10);
                 mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8);
                 if (mon->mhp < 1) {
                     if (your_fault)
@@ -1480,27 +1480,36 @@ boolean your_fault;
             break;
         */
         }
-        if (angermon)
-            wakeup(mon);
-        else
-            mon->msleeping = 0;
+        /* target might have been killed */
+        if (mon->mhp > 0) {
+            if (angermon)
+                wakeup(mon);
+            else
+                mon->msleeping = 0;
+        }
     }
 
     /* Note: potionbreathe() does its own docall() */
-    if ((distance == 0 || ((distance < 3) && rn2(5)))
+    if ((distance == 0 || (distance < 3 && rn2(5)))
         && (!breathless(youmonst.data) || haseyes(youmonst.data)))
         potionbreathe(obj);
     else if (obj->dknown && !objects[obj->otyp].oc_name_known
-             && !objects[obj->otyp].oc_uname && cansee(mon->mx, mon->my))
+             && !objects[obj->otyp].oc_uname && cansee(tx, ty))
         docall(obj);
+
     if (*u.ushops && obj->unpaid) {
         struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
 
-        if (shkp)
+        /* neither of the first two cases should be able to happen;
+           only the hero should ever have an unpaid item, and only
+           when inside a tended shop */
+        if (!shkp) /* if shkp was killed, unpaid ought to cleared already */
+            obj->unpaid = 0;
+        else if (context.mon_moving) /* obj thrown by monster */
+            subfrombill(obj, shkp);
+        else /* obj thrown by hero */
             (void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful,
                                 FALSE);
-        else
-            obj->unpaid = 0;
     }
     obfree(obj, (struct obj *) 0);
 }