summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-07-20 17:21:09 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-07-20 17:21:09 +0000
commit3a4159644bb83b286ae10d5f37fcdbf81dced398 (patch)
treeedf72dff6f6250859ea6d051eba807049e6e661a
parente57ab785ed42435069db2f2397fe939a70119c27 (diff)
downloadcrawl-ref-3a4159644bb83b286ae10d5f37fcdbf81dced398.tar.gz
crawl-ref-3a4159644bb83b286ae10d5f37fcdbf81dced398.zip
Pan overhaul:
Allow monsters (including player ghosts) to use fire storm and ice storm, give Lom Lobon ice storm and Cerebov fire storm. Lom Lobon also gets conjure ball lightning. Mnoleg gets Summon Horrible Things instead of polymorph/shadow creatures. Gloorx gets symbol of torment instead of summon demon. Hellion hellfire burst now behaves the same way for both hellion vs player and hellion vs monster. Merged monster vs player and m vs m handling for direct spell effects such as smiting. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@6621 c06c8d41-db1a-0410-9941-cceddc491573
-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);