fix #H4353 - monster gets angry after being killed

...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.
This commit is contained in:
PatR
2016-05-31 04:44:21 -07:00
parent 71113a6971
commit 30855febad
2 changed files with 32 additions and 21 deletions
+2
View 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 skipped some detected traps if their location was unseen
describe detected door traps and chest traps as trapped door and trapped chest 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 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 Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
+30 -21
View File
@@ -1241,16 +1241,18 @@ boolean your_fault;
{ {
const char *botlnam = bottlename(); const char *botlnam = bottlename();
boolean isyou = (mon == &youmonst); boolean isyou = (mon == &youmonst);
int distance; int distance, tx, ty;
struct obj *saddle = (struct obj *) 0; struct obj *saddle = (struct obj *) 0;
boolean hit_saddle = FALSE; boolean hit_saddle = FALSE;
if (isyou) { if (isyou) {
tx = u.ux, ty = u.uy;
distance = 0; distance = 0;
pline_The("%s crashes on your %s and breaks into shards.", botlnam, pline_The("%s crashes on your %s and breaks into shards.", botlnam,
body_part(HEAD)); body_part(HEAD));
losehp(Maybe_Half_Phys(rnd(2)), "thrown potion", KILLED_BY_AN); losehp(Maybe_Half_Phys(rnd(2)), "thrown potion", KILLED_BY_AN);
} else { } else {
tx = mon->mx, ty = mon->my;
/* sometimes it hits the saddle */ /* sometimes it hits the saddle */
if (((mon->misc_worn_check & W_SADDLE) if (((mon->misc_worn_check & W_SADDLE)
&& (saddle = which_armor(mon, W_SADDLE))) && (saddle = which_armor(mon, W_SADDLE)))
@@ -1259,10 +1261,10 @@ boolean your_fault;
&& ((rnl(10) > 7 && obj->cursed) && ((rnl(10) > 7 && obj->cursed)
|| (rnl(10) < 4 && obj->blessed) || !rn2(3))))) || (rnl(10) < 4 && obj->blessed) || !rn2(3)))))
hit_saddle = TRUE; hit_saddle = TRUE;
distance = distu(mon->mx, mon->my); distance = distu(tx, ty);
if (!cansee(mon->mx, mon->my)) if (!cansee(tx, ty)) {
pline("Crash!"); pline("Crash!");
else { } else {
char *mnam = mon_nam(mon); char *mnam = mon_nam(mon);
char buf[BUFSZ]; char buf[BUFSZ];
@@ -1285,7 +1287,7 @@ boolean your_fault;
} }
/* oil doesn't instantly evaporate; Neither does a saddle hit */ /* 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")); pline("%s.", Tobjnam(obj, "evaporate"));
if (isyou) { if (isyou) {
@@ -1313,7 +1315,7 @@ boolean your_fault;
} else if (hit_saddle && saddle) { } else if (hit_saddle && saddle) {
char *mnam, buf[BUFSZ], saddle_glows[BUFSZ]; char *mnam, buf[BUFSZ], saddle_glows[BUFSZ];
boolean affected = FALSE; 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, mnam = x_monnam(mon, ARTICLE_THE, (char *) 0,
(SUPPRESS_IT | SUPPRESS_SADDLE), FALSE); (SUPPRESS_IT | SUPPRESS_SADDLE), FALSE);
@@ -1331,10 +1333,8 @@ boolean your_fault;
if (useeit && !affected) if (useeit && !affected)
pline("%s %s wet.", buf, aobjnam(saddle, "get")); pline("%s %s wet.", buf, aobjnam(saddle, "get"));
} else { } else {
boolean angermon = TRUE; boolean angermon = your_fault;
if (!your_fault)
angermon = FALSE;
switch (obj->otyp) { switch (obj->otyp) {
case POT_HEALING: case POT_HEALING:
case POT_EXTRA_HEALING: case POT_EXTRA_HEALING:
@@ -1419,7 +1419,7 @@ boolean your_fault;
pline("%s %s in pain!", Monnam(mon), pline("%s %s in pain!", Monnam(mon),
is_silent(mon->data) ? "writhes" : "shrieks"); is_silent(mon->data) ? "writhes" : "shrieks");
if (!is_silent(mon->data)) 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); mon->mhp -= d(2, 6);
/* should only be by you */ /* should only be by you */
if (mon->mhp < 1) if (mon->mhp < 1)
@@ -1451,14 +1451,14 @@ boolean your_fault;
break; break;
case POT_OIL: case POT_OIL:
if (obj->lamplit) if (obj->lamplit)
explode_oil(obj, mon->mx, mon->my); explode_oil(obj, tx, ty);
break; break;
case POT_ACID: case POT_ACID:
if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) { if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) {
pline("%s %s in pain!", Monnam(mon), pline("%s %s in pain!", Monnam(mon),
is_silent(mon->data) ? "writhes" : "shrieks"); is_silent(mon->data) ? "writhes" : "shrieks");
if (!is_silent(mon->data)) 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); mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8);
if (mon->mhp < 1) { if (mon->mhp < 1) {
if (your_fault) if (your_fault)
@@ -1480,27 +1480,36 @@ boolean your_fault;
break; break;
*/ */
} }
if (angermon) /* target might have been killed */
wakeup(mon); if (mon->mhp > 0) {
else if (angermon)
mon->msleeping = 0; wakeup(mon);
else
mon->msleeping = 0;
}
} }
/* Note: potionbreathe() does its own docall() */ /* 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))) && (!breathless(youmonst.data) || haseyes(youmonst.data)))
potionbreathe(obj); potionbreathe(obj);
else if (obj->dknown && !objects[obj->otyp].oc_name_known 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); docall(obj);
if (*u.ushops && obj->unpaid) { if (*u.ushops && obj->unpaid) {
struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); 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, (void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful,
FALSE); FALSE);
else
obj->unpaid = 0;
} }
obfree(obj, (struct obj *) 0); obfree(obj, (struct obj *) 0);
} }