wand/spell/breath killer reason
Extend "killed by the touch of death inflicted by <monster>" to buzz(). "Killed by a bolt of cold" becomes "killed by a bolt of cold zapped by <monster>" or "killed by a blast of cold" becomes "killed by a blast of cold exhaled by <monster>" and so forth. More work than expected; the zap code isn't passed enough context. BZ_M_WAND() was producing the wrong value for wands zapped by monsters.
This commit is contained in:
@@ -252,6 +252,9 @@ const struct instance_globals_b g_init_b = {
|
||||
UNDEFINED_PTR, /* bbubbles */
|
||||
/* pickup.c */
|
||||
FALSE, /* bucx_filter */
|
||||
/* zap.c */
|
||||
NULL, /* buzzer -- monst that zapped/cast/breathed to initiate buzz() */
|
||||
|
||||
TRUE, /* havestate*/
|
||||
IVMAGIC /* b_magic to validate that structure layout has been preserved */
|
||||
};
|
||||
|
||||
11
src/mcastu.c
11
src/mcastu.c
@@ -39,7 +39,6 @@ static void cursetxt(struct monst *, boolean);
|
||||
static int choose_magic_spell(int);
|
||||
static int choose_clerical_spell(int);
|
||||
static int m_cure_self(struct monst *, int);
|
||||
static char *death_inflicted_by(char *, const char *, struct monst *);
|
||||
static void cast_wizard_spell(struct monst *, int, int);
|
||||
static void cast_cleric_spell(struct monst *, int, int);
|
||||
static boolean is_undirected_spell(unsigned int, int);
|
||||
@@ -375,7 +374,7 @@ touch_of_death(struct monst *mtmp)
|
||||
}
|
||||
|
||||
/* give a reason for death by some monster spells */
|
||||
static char *
|
||||
char *
|
||||
death_inflicted_by(
|
||||
char *outbuf, /* assumed big enough; pm_names are short */
|
||||
const char *deathreason, /* cause of death */
|
||||
@@ -909,7 +908,7 @@ spell_would_be_useless(struct monst *mtmp, unsigned int adtyp, int spellnum)
|
||||
|
||||
/* monster uses spell (ranged) */
|
||||
int
|
||||
buzzmu(register struct monst *mtmp, register struct attack *mattk)
|
||||
buzzmu(struct monst *mtmp, struct attack *mattk)
|
||||
{
|
||||
/* don't print constant stream of curse messages for 'normal'
|
||||
spellcasting monsters at range */
|
||||
@@ -925,8 +924,10 @@ buzzmu(register struct monst *mtmp, register struct attack *mattk)
|
||||
if (canseemon(mtmp))
|
||||
pline("%s zaps you with a %s!", Monnam(mtmp),
|
||||
flash_str(BZ_OFS_AD(mattk->adtyp), FALSE));
|
||||
buzz(BZ_M_SPELL(BZ_OFS_AD(mattk->adtyp)), (int) mattk->damn, mtmp->mx,
|
||||
mtmp->my, sgn(gt.tbx), sgn(gt.tby));
|
||||
gb.buzzer = mtmp;
|
||||
buzz(BZ_M_SPELL(BZ_OFS_AD(mattk->adtyp)), (int) mattk->damn,
|
||||
mtmp->mx, mtmp->my, sgn(gt.tbx), sgn(gt.tby));
|
||||
gb.buzzer = 0;
|
||||
return MM_HIT;
|
||||
}
|
||||
return MM_MISS;
|
||||
|
||||
@@ -927,8 +927,10 @@ breamm(struct monst* mtmp, struct attack* mattk, struct monst* mtarg)
|
||||
if (canseemon(mtmp))
|
||||
pline("%s breathes %s!",
|
||||
Monnam(mtmp), breathwep_name(typ));
|
||||
gb.buzzer = mtmp;
|
||||
dobuzz(BZ_M_BREATH(BZ_OFS_AD(typ)), (int) mattk->damn,
|
||||
mtmp->mx, mtmp->my, sgn(gt.tbx), sgn(gt.tby), utarget);
|
||||
gb.buzzer = 0;
|
||||
nomul(0);
|
||||
/* breath runs out sometimes. Also, give monster some
|
||||
* cunning; don't breath if the target fell asleep.
|
||||
|
||||
@@ -1659,19 +1659,27 @@ use_offensive(struct monst *mtmp)
|
||||
if (oseen)
|
||||
makeknown(otmp->otyp);
|
||||
gm.m_using = TRUE;
|
||||
gc.current_wand = otmp;
|
||||
gb.buzzer = mtmp;
|
||||
buzz(BZ_M_WAND(BZ_OFS_WAN(otmp->otyp)),
|
||||
(otmp->otyp == WAN_MAGIC_MISSILE) ? 2 : 6, mtmp->mx, mtmp->my,
|
||||
sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my));
|
||||
gb.buzzer = 0;
|
||||
gc.current_wand = 0;
|
||||
gm.m_using = FALSE;
|
||||
return (DEADMONSTER(mtmp)) ? 1 : 2;
|
||||
case MUSE_FIRE_HORN:
|
||||
case MUSE_FROST_HORN:
|
||||
mplayhorn(mtmp, otmp, FALSE);
|
||||
gm.m_using = TRUE;
|
||||
gb.buzzer = mtmp;
|
||||
gc.current_wand = otmp; /* needed by zhitu() */
|
||||
buzz(BZ_M_WAND(BZ_OFS_AD((otmp->otyp == FROST_HORN) ? AD_COLD
|
||||
: AD_FIRE)),
|
||||
rn1(6, 6), mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx),
|
||||
sgn(mtmp->muy - mtmp->my));
|
||||
gb.buzzer = 0;
|
||||
gc.current_wand = 0;
|
||||
gm.m_using = FALSE;
|
||||
return (DEADMONSTER(mtmp)) ? 1 : 2;
|
||||
case MUSE_WAN_TELEPORTATION:
|
||||
|
||||
@@ -615,12 +615,15 @@ do_improvisation(struct obj* instr)
|
||||
losehp(damage, buf, KILLED_BY); /* fire or frost damage */
|
||||
}
|
||||
} else {
|
||||
int type = BZ_OFS_AD((instr->otyp == FROST_HORN) ? AD_COLD : AD_FIRE);
|
||||
int type = BZ_OFS_AD((instr->otyp == FROST_HORN) ? AD_COLD
|
||||
: AD_FIRE);
|
||||
|
||||
if (!Blind)
|
||||
pline("A %s blasts out of the horn!", flash_str(type, FALSE));
|
||||
Hero_playnotes(obj_to_instr(&itmp), improvisation, 50);
|
||||
gc.current_wand = instr;
|
||||
ubuzz(BZ_U_WAND(type), rn1(6, 6));
|
||||
gc.current_wand = 0;
|
||||
}
|
||||
makeknown(instr->otyp);
|
||||
break;
|
||||
|
||||
14
src/priest.c
14
src/priest.c
@@ -753,9 +753,11 @@ in_your_sanctuary(
|
||||
void
|
||||
ghod_hitsu(struct monst *priest)
|
||||
{
|
||||
struct mkroom *troom;
|
||||
struct monst *oldbuzzer;
|
||||
struct obj *oldcurrwand;
|
||||
coordxy x, y, ax, ay;
|
||||
int roomno = (int) temple_occupied(u.urooms);
|
||||
struct mkroom *troom;
|
||||
|
||||
if (!roomno || !has_shrine(priest))
|
||||
return;
|
||||
@@ -818,8 +820,14 @@ ghod_hitsu(struct monst *priest)
|
||||
break;
|
||||
}
|
||||
|
||||
buzz(BZ_M_SPELL(BZ_OFS_AD(AD_ELEC)), 6, x, y, sgn(gt.tbx),
|
||||
sgn(gt.tby)); /* bolt of lightning */
|
||||
/* bolt of lightning cast by unspecified monster */
|
||||
oldcurrwand = gc.current_wand;
|
||||
gc.current_wand = 0;
|
||||
oldbuzzer = gb.buzzer;
|
||||
gb.buzzer = 0;
|
||||
buzz(BZ_M_SPELL(BZ_OFS_AD(AD_ELEC)), 6, x, y, sgn(gt.tbx), sgn(gt.tby));
|
||||
gb.buzzer = oldbuzzer;
|
||||
gc.current_wand = oldcurrwand;
|
||||
exercise(A_WIS, FALSE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1721,9 +1721,11 @@ do_storms(void)
|
||||
if (count < 100) {
|
||||
dirx = rn2(3) - 1;
|
||||
diry = rn2(3) - 1;
|
||||
if (dirx != 0 || diry != 0)
|
||||
buzz(-15, /* "monster" LIGHTNING spell */
|
||||
8, x, y, dirx, diry);
|
||||
if (dirx != 0 || diry != 0) {
|
||||
/* BZ_M_SPELL(BZ_OFS_AD(AD_ELEC)): monster LIGHTNING spell */
|
||||
gb.buzzer = 0; /* unspecified attacker */
|
||||
buzz(BZ_M_SPELL(BZ_OFS_AD(AD_ELEC)), 8, x, y, dirx, diry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
124
src/zap.c
124
src/zap.c
@@ -52,25 +52,31 @@ static void wishcmdassist(int);
|
||||
#define M_IN_WATER(ptr) \
|
||||
((ptr)->mlet == S_EEL || amphibious(ptr) || is_swimmer(ptr))
|
||||
|
||||
static const char are_blinded_by_the_flash[] =
|
||||
"are blinded by the flash!";
|
||||
static const char are_blinded_by_the_flash[] = "are blinded by the flash!";
|
||||
|
||||
static const char *const flash_types[] =
|
||||
{
|
||||
"magic missile", /* Wands must be 0-9 */
|
||||
"bolt of fire", "bolt of cold", "sleep ray", "death ray",
|
||||
"bolt of lightning", "", "", "", "",
|
||||
/*
|
||||
* FIXME:
|
||||
* flash_types[0] for wand of magic missile is ambiguous.
|
||||
* A positive index means zapped/cast/breathed by hero.
|
||||
* A negative index means zapped/cast/breathed by a monster.
|
||||
* Since abs(-0)==abs(0), there's no way to tell who zapped a wand of
|
||||
* magic missile by just checking the index.
|
||||
*/
|
||||
static const char *const flash_types[] = {
|
||||
"magic missile", /* Wands must be 0-9 */
|
||||
"bolt of fire", "bolt of cold", "sleep ray", "death ray",
|
||||
"bolt of lightning", "", "", "", "",
|
||||
|
||||
"magic missile", /* Spell equivalents must be 10-19 */
|
||||
"fireball", "cone of cold", "sleep ray", "finger of death",
|
||||
"bolt of lightning", /* there is no spell, used for retribution */
|
||||
"", "", "", "",
|
||||
"magic missile", /* Spell equivalents must be 10-19 */
|
||||
"fireball", "cone of cold", "sleep ray", "finger of death",
|
||||
"bolt of lightning", /* there is no spell, used for retribution */
|
||||
"", "", "", "",
|
||||
|
||||
"blast of missiles", /* Dragon breath equivalents 20-29*/
|
||||
"blast of fire", "blast of frost", "blast of sleep gas",
|
||||
"blast of disintegration", "blast of lightning",
|
||||
"blast of poison gas", "blast of acid", "", ""
|
||||
};
|
||||
"blast of missiles", /* Dragon breath equivalents 20-29*/
|
||||
"blast of fire", "blast of frost", "blast of sleep gas",
|
||||
"blast of disintegration", "blast of lightning",
|
||||
"blast of poison gas", "blast of acid", "", ""
|
||||
};
|
||||
|
||||
/*
|
||||
* Recognizing unseen wands by zapping: in 3.4.3 and earlier, zapping
|
||||
@@ -2854,10 +2860,10 @@ ubreatheu(struct attack *mattk)
|
||||
|
||||
/* light damages hero in gremlin form */
|
||||
int
|
||||
lightdamage(struct obj *obj, /* item making light (fake book if spell) */
|
||||
boolean ordinary, /* wand/camera zap vs wand destruction */
|
||||
int amt) /* pseudo-damage used to determine blindness
|
||||
duration */
|
||||
lightdamage(
|
||||
struct obj *obj, /* item making light (fake book if spell) */
|
||||
boolean ordinary, /* wand/camera zap vs wand destruction */
|
||||
int amt) /* pseudo-damage used to determine blindness duration */
|
||||
{
|
||||
char buf[BUFSZ];
|
||||
const char *how;
|
||||
@@ -3300,7 +3306,8 @@ weffects(struct obj *obj)
|
||||
else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH)
|
||||
ubuzz(BZ_U_SPELL(BZ_OFS_SPE(otyp)), u.ulevel / 2 + 1);
|
||||
else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING)
|
||||
ubuzz(BZ_U_WAND(BZ_OFS_WAN(otyp)), (otyp == WAN_MAGIC_MISSILE) ? 2 : 6);
|
||||
ubuzz(BZ_U_WAND(BZ_OFS_WAN(otyp)),
|
||||
(otyp == WAN_MAGIC_MISSILE) ? 2 : 6);
|
||||
else
|
||||
impossible("weffects: unexpected spell or wand");
|
||||
disclose = TRUE;
|
||||
@@ -4058,7 +4065,10 @@ zhitm(
|
||||
}
|
||||
|
||||
static void
|
||||
zhitu(int type, int nd, const char *fltxt, coordxy sx, coordxy sy)
|
||||
zhitu(
|
||||
int type, int nd,
|
||||
const char *fltxt,
|
||||
coordxy sx, coordxy sy)
|
||||
{
|
||||
int dam = 0, abstyp = abs(type);
|
||||
|
||||
@@ -4197,11 +4207,47 @@ zhitu(int type, int nd, const char *fltxt, coordxy sx, coordxy sy)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Half_spell_damage protection yields half-damage for wands & spells,
|
||||
including hero's own ricochets; breath attacks do full damage */
|
||||
if (dam && Half_spell_damage && !(abstyp >= 20 && abstyp <= 29))
|
||||
dam = (dam + 1) / 2;
|
||||
losehp(dam, fltxt, KILLED_BY_AN);
|
||||
/*
|
||||
* 3.7: when fatal, this used to yield "Killed by <fltxt>." without any
|
||||
* information about who was responsible. Now 'buzzer' is used to try
|
||||
* to supply "zapped/cast/breathed by <mon> [imitating <other_mon>]."
|
||||
*
|
||||
* Room for improvement: there is no monster available when player is
|
||||
* hit by divine lighting or by Plane of Air thunderstorm so cause of
|
||||
* death remains "killed by a bolt of lightning" w/o extra explanation.
|
||||
*
|
||||
* Wand of death, spell of finger of death, and disintegration breath
|
||||
* don't use this routine so don't include 'inflicted by'.
|
||||
*/
|
||||
{
|
||||
char kbuf[BUFSZ];
|
||||
struct obj *otmp = gc.current_wand;
|
||||
/* fire horn and frost horn get handled as wands by caller */
|
||||
const char *verb = (abstyp < 10) /* wand */
|
||||
? ((otmp && otmp->oclass == TOOL_CLASS) ? "played"
|
||||
: "zapped")
|
||||
: (abstyp < 20) ? "cast"
|
||||
: (abstyp < 30) ? "exhaled"
|
||||
: "imagined"; /* should never happen */
|
||||
|
||||
if (type < 0 || (type == 0 && gb.buzzer != 0)) {
|
||||
/* if gb.buzzer is Null, kbuf[] will end up with just <fltxt> */
|
||||
(void) death_inflicted_by(kbuf, fltxt, gb.buzzer);
|
||||
/* change "death inflicted by mon" to "death <verb> by mon" */
|
||||
if (gb.buzzer)
|
||||
(void) strsubst(kbuf, "inflicted", verb);
|
||||
} else {
|
||||
/* FIXME: "zapped by herself" is suitable for a rebound;
|
||||
"zapped at herself" would be better if player explicitly
|
||||
targeted hero */
|
||||
Sprintf(kbuf, "%s %s by %sself", fltxt, verb, uhim());
|
||||
}
|
||||
/* Half_spell_damage protection yields half-damage for wands & spells,
|
||||
including hero's own ricochets; breath attacks do full damage */
|
||||
if (dam && Half_spell_damage && abstyp < 20)
|
||||
dam = (dam + 1) / 2;
|
||||
losehp(dam, kbuf, KILLED_BY_AN);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4210,10 +4256,10 @@ zhitu(int type, int nd, const char *fltxt, coordxy sx, coordxy sy)
|
||||
* at position x,y; return the number of objects burned
|
||||
*/
|
||||
int
|
||||
burn_floor_objects(coordxy x, coordxy y,
|
||||
boolean give_feedback, /* caller needs to decide about
|
||||
visibility checks */
|
||||
boolean u_caused)
|
||||
burn_floor_objects(
|
||||
coordxy x, coordxy y,
|
||||
boolean give_feedback, /* caller needs to decide about visibility checks */
|
||||
boolean u_caused)
|
||||
{
|
||||
struct obj *obj, *obj2;
|
||||
long i, scrquan, delquan;
|
||||
@@ -4288,9 +4334,10 @@ zap_hit(int ac,
|
||||
}
|
||||
|
||||
static void
|
||||
disintegrate_mon(struct monst *mon,
|
||||
int type, /* hero vs other */
|
||||
const char *fltxt)
|
||||
disintegrate_mon(
|
||||
struct monst *mon,
|
||||
int type, /* hero vs other */
|
||||
const char *fltxt)
|
||||
{
|
||||
struct obj *otmp, *otmp2, *m_amulet = mlifesaver(mon);
|
||||
|
||||
@@ -4428,7 +4475,8 @@ dobuzz(
|
||||
if (type >= 0)
|
||||
mon->mstrategy &= ~STRAT_WAITMASK;
|
||||
buzzmonst:
|
||||
gn.notonhead = (mon->mx != gb.bhitpos.x || mon->my != gb.bhitpos.y);
|
||||
gn.notonhead = (mon->mx != gb.bhitpos.x
|
||||
|| mon->my != gb.bhitpos.y);
|
||||
if (zap_hit(find_mac(mon), spell_type)) {
|
||||
if (mon_reflects(mon, (char *) 0)) {
|
||||
if (cansee(mon->mx, mon->my)) {
|
||||
@@ -4667,9 +4715,9 @@ melt_ice(coordxy x, coordxy y, const char *msg)
|
||||
* permanent instead.
|
||||
*/
|
||||
void
|
||||
start_melt_ice_timeout(coordxy x, coordxy y,
|
||||
long min_time) /* <x,y>'s old melt timeout (deleted by
|
||||
time we get here) */
|
||||
start_melt_ice_timeout(
|
||||
coordxy x, coordxy y,
|
||||
long min_time) /* <x,y>'s old melt timeout (deleted by time we get here) */
|
||||
{
|
||||
int when;
|
||||
long where;
|
||||
|
||||
Reference in New Issue
Block a user