fix github issue #1011 - monster imagination

Issue reported by AndrioCelos:  if hero was killed by a wand zapped
by a monster, the cause of death was "killed by <wand damage>
imagined by <the monster>" instead of intended "killed by <wand
damage> zapped by <the monster>".  Report mentioned that the monster
was unseen but that wasn't relevant.

This worked when monster wand zaps were briefly changed to use
-9..-0 but got broken when that was reverted to using -39..-30 (due
to -0 being the same as 0 so making zapper of wands of magic missile
ambiguous).

Fixes #1011
This commit is contained in:
PatR
2023-04-15 12:34:27 -07:00
parent 36f1596c02
commit a93ee09d1a
2 changed files with 60 additions and 41 deletions

View File

@@ -1531,6 +1531,8 @@ change 'm' prefix for #tip from 'use menu to pick among floor containers'
context-sensitive item-action Tip directly operates on the item
anti-magic field's reduction of hero's maximum energy could result in current
energy being one point higher than maximum
if hero was killed by a wand zapped by a monster, cause of death was reported
as "killed by a bolt of <damage type> imagined by <monster>"
Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository

View File

@@ -12,6 +12,7 @@
*/
#define MAGIC_COOKIE 1000
static int zaptype(int);
static void probe_objchain(struct obj *);
static boolean zombie_can_dig(coordxy x, coordxy y);
static void polyuse(struct obj *, int, int);
@@ -76,6 +77,17 @@ static const char *const flash_types[] = {
"blast of poison gas", "blast of acid", "", ""
};
/* convert monster zap/spell/breath value to hero zap/spell/breath value */
static int
zaptype(int type)
{
if (type <= -30 && -39 <= type) /* monster wand zap */
type += 30; /* first convert -39..-30 to -9..0 so that abs()
* will yield 0..9 (hero wand zap) for it */
type = abs(type);
return type;
}
/*
* Recognizing unseen wands by zapping: in 3.4.3 and earlier, zapping
* most wand types while blind would add that type to the discoveries
@@ -3492,12 +3504,13 @@ maybe_explode_trap(struct trap *ttmp, struct obj *otmp)
* If fhitm returns non-zero value, stops the beam and returns the monster
*/
struct monst *
bhit(coordxy ddx, coordxy ddy, int range, /* direction and range */
enum bhit_call_types weapon, /* defined in hack.h */
int (*fhitm)(MONST_P, OBJ_P), /* fns called when mon/obj hit */
int (*fhito)(OBJ_P, OBJ_P),
struct obj **pobj) /* object tossed/used, set to NULL
if object is destroyed */
bhit(
coordxy ddx, coordxy ddy, int range, /* direction and range */
enum bhit_call_types weapon, /* defined in hack.h */
int (*fhitm)(MONST_P, OBJ_P), /* fns called when mon/obj hit */
int (*fhito)(OBJ_P, OBJ_P),
struct obj **pobj) /* object tossed/used, set to NULL
* if object is destroyed */
{
struct monst *mtmp, *result = (struct monst *) 0;
struct obj *obj = *pobj;
@@ -3912,12 +3925,12 @@ zhitm(
struct obj **ootmp) /* to return worn armor for caller to disintegrate */
{
int tmp = 0; /* damage amount */
int abstype = abs(type) % 10;
int damgtype = zaptype(type) % 10;
boolean sho_shieldeff = FALSE;
boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */
*ootmp = (struct obj *) 0;
switch (abstype) {
switch (damgtype) {
case ZT_MAGIC_MISSILE:
if (resists_magm(mon) || defended(mon, AD_MAGM)) {
sho_shieldeff = TRUE;
@@ -4076,7 +4089,7 @@ zhitu(
const char *fltxt,
coordxy sx, coordxy sy)
{
int dam = 0, abstyp = abs(type);
int dam = 0, abstyp = zaptype(type);
switch (abstyp % 10) {
case ZT_MAGIC_MISSILE:
@@ -4388,34 +4401,33 @@ buzz(int type, int nd, coordxy sx, coordxy sy, int dx, int dy)
}
/*
* type == 0 to 9 : you shooting a wand
* type == 0 to 9 : you zapping a wand
* type == 10 to 19 : you casting a spell
* type == 20 to 29 : you breathing as a monster
* type == -10 to -19 : monster casting spell
* type == -20 to -29 : monster breathing at you
* type == -30 to -39 : monster shooting a wand
* called with dx = dy = 0 with vertical bolts
* type == -30 to -39 : monster zapping a wand
* called with dx = dy = 0 for vertical bolts
*/
void
dobuzz(
int type,
int nd,
coordxy sx, coordxy sy,
int dx, int dy,
boolean say) /* announce out of sight hit/miss events if true */
int type, /* 0..29 (by hero) or -39..-10 (by monster) */
int nd, /* damage strength ('number of dice') */
coordxy sx, coordxy sy, /* starting point */
int dx, int dy, /* direction delta */
boolean say) /* announce out of sight hit/miss events if true */
{
int range, abstype = abs(type) % 10;
int range, fltyp = zaptype(type), damgtype = fltyp % 10;
register coordxy lsx, lsy;
struct monst *mon;
coord save_bhitpos;
boolean shopdamage = FALSE;
struct obj *otmp;
int spell_type;
int fltyp = (type <= -30) ? abstype : abs(type);
int habstype = Hallucination ? rn2(6) : abstype;
int hdmgtype = Hallucination ? rn2(6) : damgtype;
/* if its a Hero Spell then get its SPE_TYPE */
spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0;
spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + damgtype : 0;
if (u.uswallow) {
register int tmp;
@@ -4443,7 +4455,7 @@ dobuzz(
range = 1;
save_bhitpos = gb.bhitpos;
tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, habstype));
tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, hdmgtype));
while (range-- > 0) {
lsx = sx;
sx += dx;
@@ -4512,7 +4524,7 @@ dobuzz(
mon->mhp = mon->mhpmax;
break; /* Out of while loop */
}
if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) {
if (mon->data == &mons[PM_DEATH] && damgtype == ZT_DEATH) {
if (canseemon(mon)) {
hit(flash_str(fltyp, FALSE), mon, ".");
pline("%s absorbs the deadly %s!", Monnam(mon),
@@ -4557,7 +4569,7 @@ dobuzz(
}
if (mon_could_move && !mon->mcanmove) /* ZT_SLEEP */
slept_monst(mon);
if (abstype != ZT_SLEEP)
if (damgtype != ZT_SLEEP)
wakeup(mon, (type >= 0) ? TRUE : FALSE);
}
}
@@ -4591,10 +4603,10 @@ dobuzz(
}
} else if (!Blind) {
pline("%s whizzes by you!", The(flash_str(fltyp, FALSE)));
} else if (abstype == ZT_LIGHTNING) {
} else if (damgtype == ZT_LIGHTNING) {
Your("%s tingles.", body_part(ARM));
}
if (abstype == ZT_LIGHTNING)
if (damgtype == ZT_LIGHTNING)
(void) flashburn((long) d(nd, 50));
stop_occupation();
nomul(0);
@@ -4654,7 +4666,7 @@ dobuzz(
dx = -dx;
break;
}
tmp_at(DISP_CHANGE, zapdir_to_glyph(dx, dy, habstype));
tmp_at(DISP_CHANGE, zapdir_to_glyph(dx, dy, hdmgtype));
}
}
}
@@ -4662,11 +4674,11 @@ dobuzz(
if (type == ZT_SPELL(ZT_FIRE))
explode(sx, sy, type, d(12, 6), 0, EXPL_FIERY);
if (shopdamage)
pay_for_damage(abstype == ZT_FIRE ? "burn away"
: abstype == ZT_COLD ? "shatter"
pay_for_damage(damgtype == ZT_FIRE ? "burn away"
: damgtype == ZT_COLD ? "shatter"
/* "damage" indicates wall rather than door */
: abstype == ZT_ACID ? "damage"
: abstype == ZT_DEATH ? "disintegrate"
: damgtype == ZT_ACID ? "damage"
: damgtype == ZT_DEATH ? "disintegrate"
: "destroy",
FALSE);
gb.bhitpos = save_bhitpos;
@@ -4786,7 +4798,7 @@ zap_over_floor(
struct trap *t;
struct rm *lev = &levl[x][y];
boolean see_it = cansee(x, y), yourzap;
int rangemod = 0, abstype = abs(type) % 10;
int rangemod = 0, damgtype = zaptype(type) % 10;
boolean lavawall = (lev->typ == LAVAWALL);
if (type == PHYS_EXPL_TYPE) {
@@ -4794,7 +4806,7 @@ zap_over_floor(
return -1000; /* not a zap anyway, shouldn't matter */
}
switch (abstype) {
switch (damgtype) {
case ZT_FIRE:
t = t_at(x, y);
if (t && t->ttyp == WEB) {
@@ -4995,9 +5007,11 @@ zap_over_floor(
yourzap = (type >= 0 && !exploding_wand_typ);
zapverb = "blast"; /* breath attack or wand explosion */
if (!exploding_wand_typ) {
if (abs(type) < ZT_SPELL(0))
int ztype = zaptype(type); /* 0..29 for both hero and monsters */
if (ztype < ZT_SPELL(0))
zapverb = "bolt"; /* wand zap */
else if (abs(type) < ZT_BREATH(0))
else if (ztype < ZT_BREATH(0))
zapverb = "spell";
} else if (exploding_wand_typ == POT_OIL
|| exploding_wand_typ == SCR_FIRE) {
@@ -5028,7 +5042,7 @@ zap_over_floor(
const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0;
rangemod = -1000;
switch (abstype) {
switch (damgtype) {
case ZT_FIRE:
new_doormask = D_NODOOR;
see_txt = "The door is consumed in flames!";
@@ -5100,7 +5114,7 @@ zap_over_floor(
}
}
if (OBJ_AT(x, y) && abstype == ZT_FIRE)
if (OBJ_AT(x, y) && damgtype == ZT_FIRE)
if (burn_floor_objects(x, y, FALSE, type > 0) && couldsee(x, y)) {
newsym(x, y);
You("%s of smoke.", !Blind ? "see a puff" : "smell a whiff");
@@ -5857,14 +5871,17 @@ makewish(void)
* Assumes that the caller will specify typ in the appropriate range for
* wand/spell/breath weapon. */
const char*
flash_str(int typ,
boolean nohallu) /* suppress hallucination (for death reasons) */
flash_str(
int typ,
boolean nohallu) /* suppress hallucination (for death reasons) */
{
static char fltxt[BUFSZ];
typ = zaptype(typ);
if (Hallucination && !nohallu) {
/* always return "blast of foo" for simplicity.
* This could be extended with hallucinatory rays, but probably not worth
* it at this time. */
* This could be extended with hallucinatory rays, but probably
* not worth it at this time. */
Sprintf(fltxt, "blast of %s", rnd_hallublast());
}
else {