summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/beam.cc56
-rw-r--r--crawl-ref/source/beam.h3
-rw-r--r--crawl-ref/source/dat/database/rand_wpn.txt2
-rw-r--r--crawl-ref/source/effects.cc134
-rw-r--r--crawl-ref/source/effects.h2
-rw-r--r--crawl-ref/source/externs.h3
-rw-r--r--crawl-ref/source/ghost.cc6
-rw-r--r--crawl-ref/source/mon-data.h6
-rw-r--r--crawl-ref/source/mon-spll.h18
-rw-r--r--crawl-ref/source/mon-util.cc52
-rw-r--r--crawl-ref/source/mon-util.h3
-rw-r--r--crawl-ref/source/monstuff.cc7
-rw-r--r--crawl-ref/source/mstuff2.cc117
-rw-r--r--crawl-ref/source/mstuff2.h5
-rw-r--r--crawl-ref/source/player.cc5
-rw-r--r--crawl-ref/source/spells1.cc13
-rw-r--r--crawl-ref/source/spells1.h24
-rw-r--r--crawl-ref/source/spl-data.h2
-rw-r--r--crawl-ref/source/spl-util.cc7
-rw-r--r--crawl-ref/source/spl-util.h1
20 files changed, 264 insertions, 202 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 105ce4f5d3..681971bd5f 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -1777,17 +1777,18 @@ void fire_beam(bolt &pbolt, item_def *item, bool drop_item)
#if DEBUG_DIAGNOSTICS
if (pbolt.flavour != BEAM_LINE_OF_SIGHT)
{
- mprf( MSGCH_DIAGNOSTICS, "%s%s%s (%d,%d) to (%d,%d): "
+ mprf( MSGCH_DIAGNOSTICS, "%s%s%s [%s] (%d,%d) to (%d,%d): "
"ty=%d col=%d flav=%d hit=%d dam=%dd%d range=%d",
- (pbolt.is_beam) ? "beam" : "missile",
- (pbolt.is_explosion) ? "*" :
- (pbolt.is_big_cloud) ? "+" : "",
- (pbolt.is_tracer) ? " tracer" : "",
- pbolt.source_x, pbolt.source_y,
- pbolt.target_x, pbolt.target_y,
- pbolt.type, pbolt.colour, pbolt.flavour,
- pbolt.hit, pbolt.damage.num, pbolt.damage.size,
- pbolt.range);
+ (pbolt.is_beam) ? "beam" : "missile",
+ (pbolt.is_explosion) ? "*" :
+ (pbolt.is_big_cloud) ? "+" : "",
+ (pbolt.is_tracer) ? " tracer" : "",
+ pbolt.name.c_str(),
+ pbolt.source_x, pbolt.source_y,
+ pbolt.target_x, pbolt.target_y,
+ pbolt.type, pbolt.colour, pbolt.flavour,
+ pbolt.hit, pbolt.damage.num, pbolt.damage.size,
+ pbolt.range);
}
#endif
@@ -2815,7 +2816,7 @@ void _sticky_flame_monster( int mn, kill_category who, int levels )
// Note that beam properties must be set, as the tracer will take them
// into account, as well as the monster's intelligence.
//
-void fire_tracer(const monsters *monster, bolt &pbolt)
+void fire_tracer(const monsters *monster, bolt &pbolt, bool explode_only)
{
// Don't fiddle with any input parameters other than tracer stuff!
pbolt.is_tracer = true;
@@ -2831,19 +2832,27 @@ void fire_tracer(const monsters *monster, bolt &pbolt)
pbolt.foe_power = pbolt.fr_power = 0;
pbolt.fr_helped = pbolt.fr_hurt = 0;
pbolt.foe_helped = pbolt.foe_hurt = 0;
- pbolt.foe_ratio = 80; // default - see mons_should_fire()
- // Foe ratio for summoning greater demons & undead -- they may be
- // summoned, but they're hostile and would love nothing better
- // than to nuke the player and his minions.
- if (mons_att_wont_attack(pbolt.attitude)
- && !mons_att_wont_attack(monster->attitude))
+ // If there's a specifically requested foe_ratio, honour it.
+ if (!pbolt.foe_ratio)
{
- pbolt.foe_ratio = 25;
+ pbolt.foe_ratio = 80; // default - see mons_should_fire()
+
+ // Foe ratio for summoning greater demons & undead -- they may be
+ // summoned, but they're hostile and would love nothing better
+ // than to nuke the player and his minions.
+ if (mons_att_wont_attack(pbolt.attitude)
+ && !mons_att_wont_attack(monster->attitude))
+ {
+ pbolt.foe_ratio = 25;
+ }
}
// Fire!
- fire_beam(pbolt);
+ if (explode_only)
+ explosion(pbolt, false, false, true, true, false);
+ else
+ fire_beam(pbolt);
// Unset tracer flag (convenience).
pbolt.is_tracer = false;
@@ -4323,12 +4332,17 @@ static int _affect_monster(bolt &beam, monsters *mon, item_def *item)
{
// Can we see this monster?
if (!beam.can_see_invis && menv[tid].invisible()
- || thrower == KILL_YOU_MISSILE && !see_grid(mon->x, mon->y))
+ || (thrower == KILL_YOU_MISSILE && !see_grid(mon->x, mon->y)))
{
// Can't see this monster, ignore it.
return 0;
}
+ // Is this a self-detonating monster? Don't consider it either way
+ // if it is.
+ if (mons_self_destructs(mon))
+ return (BEAM_STOP);
+
if (!mons_atts_aligned(beam.attitude, mons_attitude(mon)))
{
beam.foe_count += 1;
@@ -5536,7 +5550,7 @@ static void _explosion_map( bolt &beam, int x, int y,
// Check count.
if (count > 10*r)
return;
-
+
const coord_def loc(beam.target_x + x, beam.target_y + y);
// Make sure we haven't run off the map.
diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h
index 8ef7072978..969d3199db 100644
--- a/crawl-ref/source/beam.h
+++ b/crawl-ref/source/beam.h
@@ -227,7 +227,8 @@ bool poison_monster( monsters *monster, kill_category who,
/* ***********************************************************************
* called from: monstuff
* *********************************************************************** */
-void fire_tracer( const monsters *monster, struct bolt &pbolt );
+void fire_tracer( const monsters *monster, struct bolt &pbolt,
+ bool explode_only = false );
bool check_line_of_sight( int sx, int sy, int tx, int ty );
diff --git a/crawl-ref/source/dat/database/rand_wpn.txt b/crawl-ref/source/dat/database/rand_wpn.txt
index 239ae319a7..677d55bfe3 100644
--- a/crawl-ref/source/dat/database/rand_wpn.txt
+++ b/crawl-ref/source/dat/database/rand_wpn.txt
@@ -445,7 +445,7 @@ Disorder
Disaster
-Unbalance
+Imbalance
Disharmony
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 05850e6ef0..86df6e4b0f 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -603,120 +603,62 @@ bool lose_stat(unsigned char which_stat, unsigned char stat_loss,
return lose_stat(which_stat, stat_loss, force, verb + " " + name, true);
}
-void direct_effect(struct bolt &pbolt)
+void direct_effect(monsters *source, spell_type spell,
+ bolt &pbolt, actor *defender)
{
- int damage_taken = 0;
-
- monsters* source = NULL;
-
- if (pbolt.beam_source != NON_MONSTER)
- source = &menv[pbolt.beam_source];
-
- switch (pbolt.type)
- {
- case DMNBM_HELLFIRE:
- pbolt.aux_source = "burst of hellfire";
- pbolt.name = "hellfire";
- pbolt.ex_size = 1;
- pbolt.flavour = BEAM_HELLFIRE;
- pbolt.is_explosion = true;
- pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP);
- pbolt.colour = RED;
- pbolt.thrower = KILL_MON_MISSILE;
- pbolt.aux_source.clear();
- pbolt.is_beam = false;
- pbolt.is_tracer = false;
- pbolt.hit = 20;
- pbolt.damage = dice_def( 3, 20 );
- explosion( pbolt );
- break;
-
- case DMNBM_SMITING:
- mpr( "Something smites you!" );
- pbolt.name = "smiting";
- pbolt.aux_source = "by divine providence";
- damage_taken = 7 + random2avg(11, 2);
- break;
-
- case DMNBM_BRAIN_FEED:
- // lose_stat() must come last {dlb}
- if (one_chance_in(3)
- && lose_stat(STAT_INTELLIGENCE, 1, source))
- {
- mpr("Something feeds on your intellect!");
- xom_is_stimulated(50);
- }
- else
- mpr("Something tries to feed on your intellect!");
- break;
- }
+ const bool mons_defender = defender->atype() == ACT_MONSTER;
+ monsters *mdef = mons_defender? dynamic_cast<monsters*>(defender) : NULL;
- // apply damage and handle death, where appropriate {dlb}
- if (damage_taken > 0)
+ if (mdef)
{
- ouch(damage_taken, pbolt.beam_source, KILLED_BY_BEAM,
- pbolt.aux_source.c_str());
+ // annoy the target
+ behaviour_event(mdef, ME_ANNOY, monster_index(source));
}
- return;
-} // end direct_effect()
-// monster-to-monster
-void mons_direct_effect(struct bolt &pbolt, int i)
-{
- // note the translation here - important {dlb}
- int o = menv[i].foe;
- monsters *monster = &menv[o];
int damage_taken = 0;
-
- // annoy the target
- behaviour_event(monster, ME_ANNOY, i);
-
- switch (pbolt.type)
+ switch (spell)
{
- case DMNBM_HELLFIRE:
- simple_monster_message(monster, " is engulfed in hellfire.");
- pbolt.name = "hellfire";
- pbolt.flavour = BEAM_LAVA;
-
- damage_taken = 5 + random2(10) + random2(5);
- damage_taken = mons_adjust_flavoured(monster, pbolt, damage_taken);
- break;
-
- case DMNBM_SMITING:
- simple_monster_message(monster, " is smitten.");
- pbolt.name = "smiting";
- pbolt.flavour = BEAM_MISSILE;
-
- damage_taken += 7 + random2avg(11, 2);
- break;
-
- case DMNBM_BRAIN_FEED: // Not implemented here (nor, probably, can be).
+ case SPELL_SMITING:
+ if (mons_defender)
+ simple_monster_message(dynamic_cast<monsters*>(defender),
+ " is smitten.");
+ else
+ mpr( "Something smites you!" );
+ pbolt.name = "smiting";
+ pbolt.flavour = BEAM_MISSILE;
+ pbolt.aux_source = "by divine providence";
+ damage_taken = 7 + random2avg(11, 2);
break;
- case DMNBM_MUTATION:
- if (mons_holiness(monster) != MH_NATURAL
- || mons_immune_magic(monster))
+ case SPELL_BRAIN_FEED:
+ if (!mons_defender)
{
- simple_monster_message(monster, " is unaffected.");
+ // lose_stat() must come last {dlb}
+ if (one_chance_in(3)
+ && lose_stat(STAT_INTELLIGENCE, 1, source))
+ {
+ mpr("Something feeds on your intellect!");
+ xom_is_stimulated(50);
+ }
+ else
+ mpr("Something tries to feed on your intellect!");
}
- else if (check_mons_resist_magic( monster, pbolt.ench_power ))
- simple_monster_message(monster, " resists.");
- else
- monster_polymorph(monster, RANDOM_MONSTER);
break;
+
+ default:
+ ASSERT(false);
}
- // Apply damage and handle death, where appropriate {dlb}
+ // apply damage and handle death, where appropriate {dlb}
if (damage_taken > 0)
{
- hurt_monster(monster, damage_taken);
-
- if (monster->hit_points < 1)
- monster_die(monster, KILL_MON_MISSILE, i);
+ if (mdef)
+ mdef->hurt(source, damage_taken);
+ else
+ ouch(damage_taken, pbolt.beam_source, KILLED_BY_BEAM,
+ pbolt.aux_source.c_str());
}
-
- return;
}
void random_uselessness(int scroll_slot)
diff --git a/crawl-ref/source/effects.h b/crawl-ref/source/effects.h
index e79c322ab1..f46bf26d2b 100644
--- a/crawl-ref/source/effects.h
+++ b/crawl-ref/source/effects.h
@@ -79,7 +79,7 @@ bool recharge_wand(const int item_slot = -1);
/* ***********************************************************************
* called from: mstuff2
* *********************************************************************** */
-void direct_effect(struct bolt &pbolt);
+void direct_effect(monsters *src, spell_type spl, bolt &pbolt, actor *defender);
// last updated 12may2000 {dlb}
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 34cbf315dc..e7b2b18d36 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -87,6 +87,7 @@ public:
virtual ~actor();
virtual int id() const = 0;
+ virtual int mindex() const = 0;
virtual actor_type atype() const = 0;
virtual kill_category kill_alignment() const = 0;
@@ -813,6 +814,7 @@ public:
// actor
int id() const;
+ int mindex() const;
int get_experience_level() const;
actor_type atype() const { return ACT_PLAYER; }
@@ -1135,6 +1137,7 @@ public:
// actor interface
int id() const;
+ int mindex() const;
int get_experience_level() const;
god_type deity() const;
bool alive() const;
diff --git a/crawl-ref/source/ghost.cc b/crawl-ref/source/ghost.cc
index 3535f4c449..8517becf97 100644
--- a/crawl-ref/source/ghost.cc
+++ b/crawl-ref/source/ghost.cc
@@ -30,6 +30,8 @@ std::vector<ghost_demon> ghosts;
static spell_type search_order_conj[] = {
// 0
SPELL_LEHUDIBS_CRYSTAL_SPEAR,
+ SPELL_FIRE_STORM,
+ SPELL_ICE_STORM,
SPELL_BOLT_OF_DRAINING,
SPELL_AGONY,
SPELL_DISINTEGRATE,
@@ -246,6 +248,10 @@ void ghost_demon::init_random_demon()
if (one_chance_in(25))
spells[0] = SPELL_HELLFIRE_BURST;
if (one_chance_in(25))
+ spells[0] = SPELL_FIRE_STORM;
+ if (one_chance_in(25))
+ spells[0] = SPELL_ICE_STORM;
+ if (one_chance_in(25))
spells[0] = SPELL_METAL_SPLINTERS;
if (one_chance_in(25))
spells[0] = SPELL_ENERGY_BOLT; // eye of devas
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index 5197d6b099..ce928f5dff 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -4226,10 +4226,10 @@ static monsterentry mondata[] = {
MONS_LOM_LOBON, '&', LIGHTBLUE, "Lom Lobon",
M_FIGHTER | M_LEVITATE | M_SEE_INVIS | M_SPELLCASTER | M_SPEAKS
| M_EVIL | M_UNIQUE,
- MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
+ MR_RES_POISON | MR_RES_FIRE | mrd(MR_RES_COLD | MR_RES_ELEC, 3),
0, 15, MONS_LOM_LOBON, MONS_LOM_LOBON, MH_DEMONIC, MAG_IMMUNE,
{ {AT_HIT, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
- { 19, 0, 0, 250 },
+ { 19, 0, 0, 360 },
10, 20, MST_LOM_LOBON, CE_NOCORPSE, Z_NOZOMBIE, S_SCREAM, I_HIGH,
HT_LAND, 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
},
@@ -4237,7 +4237,7 @@ static monsterentry mondata[] = {
{
MONS_CEREBOV, '&', RED, "Cerebov",
M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_EVIL | M_UNIQUE,
- MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE,
+ MR_RES_ELEC | MR_RES_POISON | mrd(MR_RES_HELLFIRE, 3),
0, 15, MONS_CEREBOV, MONS_CEREBOV, MH_DEMONIC, -6,
{ {AT_HIT, AF_PLAIN, 60}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 21, 0, 0, 650 },
diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h
index 35fe793695..84b312ac98 100644
--- a/crawl-ref/source/mon-spll.h
+++ b/crawl-ref/source/mon-spll.h
@@ -566,29 +566,29 @@
SPELL_SUMMON_GREATER_DEMON,
SPELL_SMITING,
SPELL_INVISIBILITY,
- SPELL_POLYMORPH_OTHER,
- SPELL_SHADOW_CREATURES,
+ SPELL_SUMMON_HORRIBLE_THINGS,
+ SPELL_SUMMON_HORRIBLE_THINGS,
SPELL_TELEPORT_SELF
}
},
{ MST_LOM_LOBON,
{
- SPELL_LIGHTNING_BOLT,
- SPELL_BOLT_OF_COLD,
+ SPELL_ICE_STORM,
+ SPELL_CONJURE_BALL_LIGHTNING,
SPELL_GREATER_HEALING,
- SPELL_SUMMON_DEMON,
- SPELL_TELEPORT_SELF,
+ SPELL_BLINK,
+ SPELL_BLINK,
SPELL_TELEPORT_SELF
}
},
{ MST_CEREBOV,
{
- SPELL_BOLT_OF_FIRE,
+ SPELL_FIRE_STORM,
SPELL_BOLT_OF_IRON,
SPELL_HASTE,
- SPELL_FIREBALL,
+ SPELL_HASTE,
SPELL_SUMMON_GREATER_DEMON,
SPELL_HASTE
}
@@ -598,7 +598,7 @@
{
SPELL_POISON_ARROW,
SPELL_MIASMA,
- SPELL_SUMMON_DEMON,
+ SPELL_SYMBOL_OF_TORMENT,
SPELL_BOLT_OF_DRAINING,
SPELL_DISPEL_UNDEAD,
SPELL_INVISIBILITY
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index a61a4bcb0b..22f0255482 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -570,6 +570,15 @@ bool mons_is_demon(int mc)
return (false);
}
+/**
+ * Returns true if the given monster's foe is also a monster.
+ */
+bool mons_foe_is_mons(const monsters *mons)
+{
+ const actor *foe = mons->get_foe();
+ return foe && foe->atype() == ACT_MONSTER;
+}
+
int mons_zombie_size(int mc)
{
return (smc->zombie_size);
@@ -1380,6 +1389,8 @@ int exper_value( const struct monsters *monster )
case SPELL_HELLFIRE_BURST:
case SPELL_HELLFIRE:
case SPELL_SYMBOL_OF_TORMENT:
+ case SPELL_ICE_STORM:
+ case SPELL_FIRE_STORM:
diff += 25;
break;
@@ -2066,6 +2077,11 @@ bool mons_eats_corpses(const monsters *m)
return (m->type == MONS_NECROPHAGE || m->type == MONS_GHOUL);
}
+bool mons_self_destructs(const monsters *m)
+{
+ return (m->type == MONS_GIANT_SPORE || m->type == MONS_BALL_LIGHTNING);
+}
+
bool mons_is_summoned(const monsters *m)
{
return (m->has_ench(ENCH_ABJ));
@@ -2442,7 +2458,11 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
// handled here as well. -- bwr
switch (monspell)
{
+ case SPELL_BRAIN_FEED:
+ return (foe != &you);
+
case SPELL_BOLT_OF_DRAINING:
+ case SPELL_MIASMA:
case SPELL_AGONY:
case SPELL_SYMBOL_OF_TORMENT:
{
@@ -2740,7 +2760,8 @@ static bool _mons_can_smite(const monsters *monster)
for (unsigned i = 0; i < hspell_pass.size(); ++i)
if (hspell_pass[i] == SPELL_SYMBOL_OF_TORMENT
|| hspell_pass[i] == SPELL_SMITING
- || hspell_pass[i] == SPELL_HELLFIRE_BURST)
+ || hspell_pass[i] == SPELL_HELLFIRE_BURST
+ || hspell_pass[i] == SPELL_FIRE_STORM)
{
return (true);
}
@@ -3553,9 +3574,9 @@ bool monsters::pickup(item_def &item, int slot, int near, bool force_merge)
monster_index(this)),
pos());
- const int index = item.index();
- unlink_item(index);
- inv[slot] = index;
+ const int item_index = item.index();
+ unlink_item(item_index);
+ inv[slot] = item_index;
pickup_message(item, near);
equip(item, slot, near);
@@ -3568,8 +3589,8 @@ bool monsters::drop_item(int eslot, int near)
if (eslot < 0 || eslot >= NUM_MONSTER_SLOTS)
return (false);
- int index = inv[eslot];
- if (index == NON_ITEM)
+ int item_index = inv[eslot];
+ if (item_index == NON_ITEM)
return (true);
// Unequip equipped items before dropping them; unequip() prevents
@@ -3578,23 +3599,23 @@ bool monsters::drop_item(int eslot, int near)
if (eslot == MSLOT_WEAPON || eslot == MSLOT_ARMOUR
|| eslot == MSLOT_ALT_WEAPON && mons_wields_two_weapons(this))
{
- if (!unequip(mitm[index], eslot, near))
+ if (!unequip(mitm[item_index], eslot, near))
return (false);
was_unequipped = true;
}
- const std::string iname = mitm[index].name(DESC_NOCAP_A);
- if (!move_item_to_grid(&index, x, y))
+ const std::string iname = mitm[item_index].name(DESC_NOCAP_A);
+ if (!move_item_to_grid(&item_index, x, y))
{
// Re-equip item if we somehow failed to drop it.
if (was_unequipped)
- equip(mitm[index], eslot, near);
+ equip(mitm[item_index], eslot, near);
return (false);
}
if (mons_friendly(this))
- mitm[index].flags |= ISFLAG_DROPPED_BY_ALLY;
+ mitm[item_index].flags |= ISFLAG_DROPPED_BY_ALLY;
if (need_message(near))
mprf("%s drops %s.", name(DESC_CAP_THE).c_str(), iname.c_str());
@@ -4283,8 +4304,8 @@ item_def *monsters::slot_item(equipment_type eq)
item_def *monsters::mslot_item(mon_inv_type mslot) const
{
- const int mindex = (mslot == NUM_MONSTER_SLOTS) ? NON_ITEM : inv[mslot];
- return (mindex == NON_ITEM ? NULL : &mitm[mindex]);
+ const int mi = (mslot == NUM_MONSTER_SLOTS) ? NON_ITEM : inv[mslot];
+ return (mi == NON_ITEM ? NULL : &mitm[mi]);
}
item_def *monsters::shield()
@@ -4356,6 +4377,11 @@ int monsters::id() const
return (type);
}
+int monsters::mindex() const
+{
+ return (monster_index(this));
+}
+
int monsters::get_experience_level() const
{
return (hit_dice);
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 06e5040b34..c37b6f1cc4 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -535,6 +535,7 @@ bool mons_is_demon( int mc );
bool mons_wields_two_weapons(const monsters *m);
bool mons_wields_two_weapons(monster_type m);
+bool mons_self_destructs(const monsters *m);
bool mons_is_summoned(const monsters *m);
// last updated 12may2000 {dlb}
@@ -690,6 +691,8 @@ bool mons_wont_attack(const monsters *m);
bool mons_att_wont_attack(mon_attitude_type fr);
mon_attitude_type mons_attitude(const monsters *m);
+bool mons_foe_is_mons(const monsters *mons);
+
bool mons_behaviour_perceptible(const monsters *mon);
bool mons_is_native_in_branch(const monsters *monster,
const branch_type branch = you.where_are_you);
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 3e291c3df1..edf4a1e124 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -4698,7 +4698,7 @@ static bool _handle_wand(monsters *monster, bolt &beem)
// set up the beam
int power = 30 + monster->hit_dice;
- bolt theBeam = mons_spells(mzap, power);
+ bolt theBeam = mons_spells(monster, mzap, power);
beem.name = theBeam.name;
beem.beam_source = monster_index(monster);
@@ -4849,7 +4849,7 @@ static bool _handle_wand(monsters *monster, bolt &beem)
// Returns a suitable breath weapon for the draconian; does not handle all
// draconians, does fire a tracer.
-static spell_type _get_draconian_breath_spell( const monsters *monster )
+static spell_type _get_draconian_breath_spell( monsters *monster )
{
spell_type draco_breath = SPELL_NO_SPELL;
@@ -5298,7 +5298,8 @@ static bool _handle_spell(monsters *monster, bolt &beem)
// beam-type spells requiring tracers
if (spell_needs_tracer(spell_cast))
{
- fire_tracer(monster, beem);
+ const bool explode = spell_is_direct_explosion(spell_cast);
+ fire_tracer(monster, beem, explode);
// Good idea?
if (mons_should_fire(beem))
spellOK = true;
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 4a659c9669..2a95359d18 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -41,6 +41,7 @@
#include "player.h"
#include "randart.h"
#include "religion.h"
+#include "spells1.h"
#include "spells3.h"
#include "spells4.h"
#include "spl-cast.h"
@@ -499,6 +500,15 @@ static void _do_high_level_summon(monsters *monster, bool monsterNearby,
}
}
+static bool _los_free_spell(spell_type spell_cast)
+{
+ return spell_cast == SPELL_HELLFIRE_BURST
+ || spell_cast == SPELL_BRAIN_FEED
+ || spell_cast == SPELL_SMITING
+ || spell_cast == SPELL_FIRE_STORM
+ || spell_cast == SPELL_AIRSTRIKE;
+}
+
void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
{
// Always do setup. It might be done already, but it doesn't
@@ -517,17 +527,16 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
monster_index(monster), spell_title(spell_cast), spell_cast);
#endif
- if (spell_cast == SPELL_HELLFIRE_BURST || spell_cast == SPELL_BRAIN_FEED
- || spell_cast == SPELL_SMITING)
+ if (_los_free_spell(spell_cast) && !spell_is_direct_explosion(spell_cast))
{
if (monster->foe == MHITYOU || monster->foe == MHITNOT)
{
if (monsterNearby)
- direct_effect(pbolt);
+ direct_effect(monster, spell_cast, pbolt, &you);
return;
}
- mons_direct_effect(pbolt, monster_index(monster));
+ direct_effect(monster, spell_cast, pbolt, monster->get_foe());
return;
}
@@ -720,6 +729,18 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
random_range(3, 5));
return;
+ case SPELL_CONJURE_BALL_LIGHTNING:
+ {
+ const int n = 2 + random2(monster->hit_dice / 4);
+ for (int i = 0; i < n; ++i)
+ {
+ create_monster(mgen_data(MONS_BALL_LIGHTNING,
+ SAME_ATTITUDE(monster), 2,
+ monster->pos(), monster->foe));
+ }
+ return;
+ }
+
case SPELL_SUMMON_UNDEAD: // Summon undead around player.
_do_high_level_summon(monster, monsterNearby, _pick_undead_summon,
2 + random2(2)
@@ -851,11 +872,20 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
}
}
- fire_beam(pbolt);
+ if (spell_is_direct_explosion(spell_cast))
+ {
+ const actor *foe = monster->get_foe();
+ const bool need_more =
+ foe && (foe == &you || see_grid(foe->pos()));
+ explosion(pbolt, false, false, true, true, need_more);
+ }
+ else
+ fire_beam(pbolt);
}
// Set up bolt structure for monster spell casting.
-void setup_mons_cast(const monsters *monster, bolt &pbolt, int spell_cast)
+void setup_mons_cast(monsters *monster, bolt &pbolt,
+ spell_type spell_cast)
{
// always set these -- used by things other than fire_beam()
@@ -871,24 +901,29 @@ void setup_mons_cast(const monsters *monster, bolt &pbolt, int spell_cast)
pbolt.beam_source = monster_index(monster);
+ // Convenience for the hapless innocent who assumes that this
+ // damn function does all possible setup. [ds]
+ if (!pbolt.target_x && !pbolt.target_y)
+ {
+ pbolt.target_x = monster->target_x;
+ pbolt.target_y = monster->target_y;
+ }
+
// set bolt type
- if (spell_cast == SPELL_HELLFIRE_BURST
- || spell_cast == SPELL_BRAIN_FEED
- || spell_cast == SPELL_SMITING)
- { // etc.
+ if (_los_free_spell(spell_cast))
+ {
switch (spell_cast)
{
- case SPELL_HELLFIRE_BURST:
- pbolt.type = DMNBM_HELLFIRE;
- break;
case SPELL_BRAIN_FEED:
pbolt.type = DMNBM_BRAIN_FEED;
- break;
+ return;
case SPELL_SMITING:
pbolt.type = DMNBM_SMITING;
+ return;
+ default:
+ // Other spells get normal setup:
break;
}
- return;
}
// The below are no-ops since they don't involve direct_effect,
@@ -910,6 +945,7 @@ void setup_mons_cast(const monsters *monster, bolt &pbolt, int spell_cast)
case SPELL_SUMMON_UNDEAD: // summon undead around player
case SPELL_SUMMON_ICE_BEAST:
case SPELL_SUMMON_MUSHROOMS:
+ case SPELL_CONJURE_BALL_LIGHTNING:
case SPELL_SUMMON_DRAKES:
case SPELL_SUMMON_HORRIBLE_THINGS:
case SPELL_SUMMON_WRAITHS:
@@ -925,7 +961,7 @@ void setup_mons_cast(const monsters *monster, bolt &pbolt, int spell_cast)
// Need to correct this for power of spellcaster
int power = 12 * monster->hit_dice;
- bolt theBeam = mons_spells(spell_cast, power);
+ bolt theBeam = mons_spells(monster, spell_cast, power);
pbolt.colour = theBeam.colour;
pbolt.range = theBeam.range;
@@ -946,6 +982,9 @@ void setup_mons_cast(const monsters *monster, bolt &pbolt, int spell_cast)
pbolt.source_y = monster->y;
pbolt.is_tracer = false;
pbolt.is_explosion = theBeam.is_explosion;
+ pbolt.ex_size = theBeam.ex_size;
+
+ pbolt.foe_ratio = theBeam.foe_ratio;
if (pbolt.name.length() && pbolt.name[0] != '0')
pbolt.aux_source = pbolt.name;
@@ -960,14 +999,6 @@ void setup_mons_cast(const monsters *monster, bolt &pbolt, int spell_cast)
pbolt.target_x = monster->x;
pbolt.target_y = monster->y;
}
-
- // Convenience for the hapless innocent who assumes that this
- // damn function does all possible setup. [ds]
- if (!pbolt.target_x && !pbolt.target_y)
- {
- pbolt.target_x = monster->target_x;
- pbolt.target_y = monster->target_y;
- }
}
void monster_teleport(monsters *monster, bool instan, bool silent)
@@ -1656,7 +1687,7 @@ void spore_goes_pop(monsters *monster)
explosion(beam, false, false, true, true, mons_near(monster));
}
-bolt mons_spells( int spell_cast, int power )
+bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
{
ASSERT(power > 0);
@@ -1945,6 +1976,42 @@ bolt mons_spells( int spell_cast, int power )
beam.is_explosion = true;
break;
+ case SPELL_FIRE_STORM:
+ setup_fire_storm(mons, power / 2, beam);
+ beam.foe_ratio = random_range(40, 55);
+ break;
+
+ case SPELL_ICE_STORM:
+ beam.name = "great blast of cold";
+ beam.colour = BLUE;
+ beam.range = 9 + random2(5);
+ beam.damage = calc_dice( 10, 18 + power / 2 );
+ beam.damage.num = 0; // only does explosion damage
+ beam.hit = 20 + power / 10; // 50: 25 100: 30
+ beam.ench_power = power; // used for radius
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.flavour = BEAM_ICE; // half resisted
+ beam.is_explosion = true;
+ beam.foe_ratio = random_range(40, 55);
+ break;
+
+ case SPELL_HELLFIRE_BURST:
+ beam.aux_source = "burst of hellfire";
+ beam.name = "hellfire";
+ beam.ex_size = 1;
+ beam.flavour = BEAM_HELLFIRE;
+ beam.is_explosion = true;
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.colour = RED;
+ beam.thrower = KILL_MON;
+ beam.aux_source.clear();
+ beam.is_beam = false;
+ beam.is_tracer = false;
+ beam.hit = 20;
+ beam.damage = mons_foe_is_mons(mons) ? dice_def(5, 7)
+ : dice_def(3, 20);
+ break;
+
case SPELL_LESSER_HEALING:
beam.name = "0";
beam.range = 5;
diff --git a/crawl-ref/source/mstuff2.h b/crawl-ref/source/mstuff2.h
index a880245436..6c364f8eeb 100644
--- a/crawl-ref/source/mstuff2.h
+++ b/crawl-ref/source/mstuff2.h
@@ -37,7 +37,7 @@ struct bolt;
/* ***********************************************************************
* called from: monstuff - mstuff2
* *********************************************************************** */
-bolt mons_spells(int spell_cast, int power);
+bolt mons_spells(monsters *mons, spell_type spell_cast, int power);
// last updated 12may2000 {dlb}
@@ -57,7 +57,8 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast);
/* ***********************************************************************
* called from: monstuff
* *********************************************************************** */
-void setup_mons_cast(const monsters *monster, bolt &pbolt, int spell_cast);
+void setup_mons_cast(monsters *monster, bolt &pbolt,
+ spell_type spell_cast);
// last updated 28july2000 (gdl)
/* ***********************************************************************
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index caf6e8b502..550bbf5851 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -5977,6 +5977,11 @@ int player::id() const
return (-1);
}
+int player::mindex() const
+{
+ return (MHITYOU);
+}
+
int player::get_experience_level() const
{
return (experience_level);
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index ca2c9294a7..e544ecfb7c 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -243,15 +243,17 @@ bool fireball(int pow, bolt &beam)
return (zapping(ZAP_FIREBALL, pow, beam, true));
}
-void cast_fire_storm(int pow, bolt &beam)
+void setup_fire_storm(const actor *source, int pow, bolt &beam)
{
beam.name = "great blast of fire";
beam.ex_size = 2 + (random2(pow) > 75);
beam.flavour = BEAM_LAVA;
beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
beam.colour = RED;
- beam.beam_source = MHITYOU;
- beam.thrower = KILL_YOU_MISSILE;
+ beam.beam_source = source->mindex();
+ // XXX: Should this be KILL_MON_MISSILE?
+ beam.thrower =
+ source->atype() == ACT_PLAYER? KILL_YOU_MISSILE : KILL_MON;
beam.aux_source.clear();
beam.obvious_effect = false;
beam.is_beam = false;
@@ -260,6 +262,11 @@ void cast_fire_storm(int pow, bolt &beam)
beam.ench_power = pow; // used for radius
beam.hit = 20 + pow / 10;
beam.damage = calc_dice(9, 20 + pow);
+}
+
+void cast_fire_storm(int pow, bolt &beam)
+{
+ setup_fire_storm(&you, pow, beam);
if (explosion(beam, false, false, true, true, false) > 0)
mpr("A raging storm of fire appears!");
diff --git a/crawl-ref/source/spells1.h b/crawl-ref/source/spells1.h
index d04fd19606..692fb5b73a 100644
--- a/crawl-ref/source/spells1.h
+++ b/crawl-ref/source/spells1.h
@@ -26,29 +26,6 @@ struct bolt;
* *********************************************************************** */
bool cast_sure_blade(int power);
-
-#if 0
-// last updated 24may2000 {dlb}
-/* ***********************************************************************
- * called from: ability - spell
- * *********************************************************************** */
-char cast_greater_healing(void);
-
-
-// last updated 24may2000 {dlb}
-/* ***********************************************************************
- * called from: ability
- * *********************************************************************** */
-char cast_greatest_healing(void);
-
-
-// last updated 24may2000 {dlb}
-/* ***********************************************************************
- * called from: ability - spell
- * *********************************************************************** */
-char cast_lesser_healing(void);
-#endif
-
// last updated 24may2000 {dlb}
/* ***********************************************************************
* called from: ability - spell
@@ -85,6 +62,7 @@ void cast_confusing_touch(int power);
void cast_cure_poison(int mabil);
int allowed_deaths_door_hp(void);
void cast_deaths_door(int pow);
+void setup_fire_storm(const actor *source, int pow, bolt &beam);
void cast_fire_storm(int pow, bolt &beam);
void cast_chain_lightning(int pow);
bool cast_revivification(int pow);
diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h
index f198140edd..b081d116ac 100644
--- a/crawl-ref/source/spl-data.h
+++ b/crawl-ref/source/spl-data.h
@@ -2240,7 +2240,7 @@
9,
200,
NULL,
- false,
+ true,
false
},
diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc
index e64c2f089f..e36d9528f2 100644
--- a/crawl-ref/source/spl-util.cc
+++ b/crawl-ref/source/spl-util.cc
@@ -235,6 +235,13 @@ bool spell_needs_tracer(spell_type spell)
return (_seekspell(spell)->ms_needs_tracer);
}
+// Checks if the spell is an explosion that can be placed anywhere even without
+// an unobstructed beam path, such as fire storm.
+bool spell_is_direct_explosion(spell_type spell)
+{
+ return (spell == SPELL_FIRE_STORM || spell == SPELL_HELLFIRE_BURST);
+}
+
bool spell_needs_foe(spell_type spell)
{
return (!_seekspell(spell)->ms_utility);
diff --git a/crawl-ref/source/spl-util.h b/crawl-ref/source/spl-util.h
index b2dd736b7c..8a76c039b5 100644
--- a/crawl-ref/source/spl-util.h
+++ b/crawl-ref/source/spl-util.h
@@ -89,6 +89,7 @@ int spell_power_cap(spell_type spell);
const char *get_spell_target_prompt( spell_type which_spell );
bool spell_needs_tracer(spell_type spell);
+bool spell_is_direct_explosion(spell_type spell);
bool spell_needs_foe(spell_type spell);
bool spell_harms_target(spell_type spell);
bool spell_harms_area(spell_type spell);