secondary damage for monster spell attacks

Have monster spells
| "shower of missiles" (AT_MAGC+AD_MAGM: Angels, Yeenoghu)
scuff an engraving at the hero's spot if there is one,
| "frost" (AT_MAGC+AD_COLD: only Asmodeus)
freeze water and lava terrain,
| "flames" (AT_MAGC+AD_FIRE: moot, no monster has this attack)
burn items on the floor at the hero's spot and melt ice terrain,
| "pillar of flame" (AT_MAGC+AD_CLRC+randomly chosen clerical spell)
which already burns floor items, melt ice too, and
| "lightning" (same casters as pillar of flame)
give a tiny chance of destroying iron bars.  The chance to hit bars
is low and the hero has to be targeted while located on an iron bars
spot so probably won't happen before the sun burns out, but only
needed one extra line of code.

Only the first two have been thoroughly tested.
This commit is contained in:
PatR
2024-01-16 14:01:38 -08:00
parent a5c7fede99
commit 6b8079a16f
3 changed files with 83 additions and 18 deletions

View File

@@ -3756,6 +3756,7 @@ extern void start_melt_ice_timeout(coordxy, coordxy, long);
extern void melt_ice_away(union any *, long) NONNULLARG1;
extern int zap_over_floor(coordxy, coordxy, int, boolean *,
boolean, short) NONNULLARG4;
extern void mon_spell_hits_spot(struct monst *, int, coordxy x, coordxy y);
extern void fracture_rock(struct obj *) NONNULLARG1;
extern boolean break_statue(struct obj *) NONNULLARG1;
extern int u_adtyp_resistance_obj(int);

View File

@@ -233,15 +233,22 @@ castmu(
mtmp->mspec_used = (int) ((mtmp->m_lev < 8) ? (10 - mtmp->m_lev) : 2);
}
/* monster can cast spells, but is casting a directed spell at the
wrong place? If so, give a message, and return. Do this *after*
penalizing mspec_used. */
/* Monster can cast spells, but is casting a directed spell at the
* wrong place? If so, give a message, and return.
* Do this *after* penalizing mspec_used.
*
* FIXME?
* Shouldn't wall of lava have a case similar to wall of water?
* And should cold damage hit water or lava instead of missing
* even when the caster has targeted the wrong spot? Likewise
* for fire mis-aimed at ice.
*/
if (!foundyou && thinks_it_foundyou
&& !is_undirected_spell(mattk->adtyp, spellnum)) {
pline_xy(mtmp->mx, mtmp->my, "%s casts a spell at %s!",
canseemon(mtmp) ? Monnam(mtmp) : "Something",
is_waterwall(mtmp->mux,mtmp->muy) ? "empty water"
: "thin air");
canseemon(mtmp) ? Monnam(mtmp) : "Something",
is_waterwall(mtmp->mux, mtmp->muy) ? "empty water"
: "thin air");
return M_ATTK_MISS;
}
@@ -256,16 +263,14 @@ castmu(
}
if (canspotmon(mtmp) || !is_undirected_spell(mattk->adtyp, spellnum)) {
pline_xy(mtmp->mx, mtmp->my, "%s casts a spell%s!",
canspotmon(mtmp) ? Monnam(mtmp) : "Something",
is_undirected_spell(mattk->adtyp, spellnum)
? ""
: (Invis && !perceives(mtmp->data)
&& (mtmp->mux != u.ux || mtmp->muy != u.uy))
? " at a spot near you"
: (Displaced
&& (mtmp->mux != u.ux || mtmp->muy != u.uy))
? " at your displaced image"
: " at you");
canspotmon(mtmp) ? Monnam(mtmp) : "Something",
is_undirected_spell(mattk->adtyp, spellnum) ? ""
: (Invis && !perceives(mtmp->data)
&& !u_at(mtmp->mux, mtmp->muy))
? " at a spot near you"
: (Displaced && !u_at(mtmp->mux, mtmp->muy))
? " at your displaced image"
: " at you");
}
/*
@@ -288,6 +293,10 @@ castmu(
dmg = (dmg + 1) / 2;
ret = M_ATTK_HIT;
/*
* FIXME: none of these hit the steed when hero is riding, nor do
* they inflict damage on carried items.
*/
switch (mattk->adtyp) {
case AD_FIRE:
pline("You're enveloped in flames.");
@@ -300,6 +309,8 @@ castmu(
monstunseesu(M_SEEN_FIRE);
}
burn_away_slime();
/* burn up flammable items on the floor, melt ice terrain */
mon_spell_hits_spot(mtmp, AD_FIRE, u.ux, u.uy);
break;
case AD_COLD:
pline("You're covered in frost.");
@@ -311,6 +322,10 @@ castmu(
} else {
monstunseesu(M_SEEN_COLD);
}
/* freeze water or lava terrain */
/* FIXME: mon_spell_hits_spot() uses zap_over_floor(); unlike with
* fire, it does not target susceptible floor items with cold */
mon_spell_hits_spot(mtmp, AD_COLD, u.ux, u.uy);
break;
case AD_MAGM:
You("are hit by a shower of missiles!");
@@ -323,6 +338,8 @@ castmu(
dmg = d((int) mtmp->m_lev / 2 + 1, 6);
monstunseesu(M_SEEN_MAGR);
}
/* shower of magic missiles scuffs an engraving */
mon_spell_hits_spot(mtmp, AD_MAGM, u.ux, u.uy);
break;
case AD_SPEL: /* wizard spell */
case AD_CLRC: /* clerical spell */
@@ -334,7 +351,7 @@ castmu(
dmg = 0; /* done by the spell casting functions */
break;
}
}
} /* switch */
if (dmg)
mdamageu(mtmp, dmg);
return ret;
@@ -618,6 +635,10 @@ cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum)
dmg = d(8, 6);
if (Half_physical_damage)
dmg = (dmg + 1) / 2;
#if 0 /* since inventory items aren't affected, don't include this */
/* make floor items wet */
water_damage_chain(level.objects[u.ux][u.uy], TRUE);
#endif
break;
case CLC_FIRE_PILLAR:
pline("A pillar of fire strikes all around you!");
@@ -637,7 +658,8 @@ cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum)
destroy_item(POTION_CLASS, AD_FIRE);
destroy_item(SPBOOK_CLASS, AD_FIRE);
ignite_items(gi.invent);
(void) burn_floor_objects(u.ux, u.uy, TRUE, FALSE);
/* burn up flammable items on the floor, melt ice terrain */
mon_spell_hits_spot(mtmp, AD_FIRE, u.ux, u.uy);
break;
case CLC_LIGHTNING: {
boolean reflects;
@@ -662,6 +684,12 @@ cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum)
dmg = (dmg + 1) / 2;
destroy_item(WAND_CLASS, AD_ELEC);
destroy_item(RING_CLASS, AD_ELEC);
/* lightning might destroy iron bars if hero is on such a spot;
reflection protects terrain here [execution won't get here due
to 'if (reflects) break' above] but hero resistance doesn't;
do this before maybe blinding the hero via flashburn() */
mon_spell_hits_spot(mtmp, AD_ELEC, u.ux, u.uy);
/* blind hero; no effect if already blind */
(void) flashburn((long) rnd(100));
break;
}

View File

@@ -5302,6 +5302,42 @@ zap_over_floor(
return rangemod;
}
/* monster has cast flames or frost at target on <x,y>; called by mcastu() */
void
mon_spell_hits_spot(
struct monst *caster UNUSED,
int adtyp, /* canonical damage type */
coordxy x, coordxy y) /* so far, only used for targeting <u.ux,u.uy> */
{
/* "shower of missiles" or [hypothetical] "acid rain" attack:
thoroughly clobber an engraving (unless its type makes it be
scuff-protected); zap_over_floor() doesn't handle this */
if (adtyp == AD_MAGM || adtyp == AD_ACID) {
struct engr *ep = engr_at(x, y);
char *etext = ep ? ep->engr_txt[actual_text] : NULL;
if (etext)
wipe_engr_at(x, y, (int) strlen(etext) + d(6, 6), TRUE);
/* hero and player will still remember prior text until the spot
is re-examined (lookhere or move off and back on) */
}
/* hit items and/or terrain; only matters for AD_FIRE and AD_COLD but
accept any basic damage type that zap_over_floor() might handle */
if (adtyp >= AD_MAGM && adtyp <= AD_ACID) {
boolean shopdummy = FALSE; /* zap_over_floor() requires this even
* though it's only used when zapdmgtyp
* is non-negative (hero's fault) */
int zt_typ = adtyp - 1, /* convert AD_xxxx to ZT_xxxx */
zapdmgtyp = -ZT_SPELL(zt_typ); /* damage is from monster spell */
(void) zap_over_floor(x, y, zapdmgtyp, &shopdummy, TRUE, 0);
} else {
impossible("Unsupported damage type (%d) for mon_spell_hits_spot.",
adtyp);
}
}
/* fractured by pick-axe or wand of striking or by vault guard */
void
fracture_rock(struct obj *obj) /* no texts here! */