summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-14 02:23:59 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-14 02:23:59 +0000
commitd8e6562b8929ce087fc55ce19fca1716a6d68b0a (patch)
treee46534565f5d9176042c0cded4beef19692b0059 /crawl-ref/source
parent5669e0adf581fd18cebab4b0b50b1280c693d971 (diff)
downloadcrawl-ref-d8e6562b8929ce087fc55ce19fca1716a6d68b0a.tar.gz
crawl-ref-d8e6562b8929ce087fc55ce19fca1716a6d68b0a.zip
Got rid of setup_dragon(), moving it's functionality into setup_mons_cast() and
mons_spells(), and added the new spells Fire Breath, Cold Breath and Draconian Breath to trigger that functionality. Also added the new spell Acid Splash to replace monstuff's _plant_spit(), and Sticky Flame Splash, which is exactly the same as Sticky Flame except for the messages it gives and when it makes noise (monsters now spit sticky flame instead of breathing it). All things that were handled as monster special abilities are still handled as such, and were just changed to manually invoke mons_cast(). The spell messages in dat/database/monspell.txt can now take advantage of a new substitution, "@target@", which is expanded into the spell's target. Added the spell flags SPFLAG_INNATE, for monster spells which are innate even when the monster is a priest or wizard, and which can be used by them when silenced, and SPFLAG_NOISY, for spells which produce noise even when used by monsters other than priests or wizards. Added the monster class flags M_SPELL_NO_SILENT, for monsters which aren't wizards or priests, yet still can't use spells if silenced (currently only used for Geryon blowing his horn to summon beasts), and M_NOISY_SPELLS, for monsters which can cast spells when silenced, yet whose spells make noise when not silenced (currently only used by curse skulls and Murray). git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7828 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/dat/database/monspell.txt26
-rw-r--r--crawl-ref/source/enum.h5
-rw-r--r--crawl-ref/source/mon-data.h5
-rw-r--r--crawl-ref/source/mon-spll.h12
-rw-r--r--crawl-ref/source/mon-util.h10
-rw-r--r--crawl-ref/source/monstuff.cc155
-rw-r--r--crawl-ref/source/mstuff2.cc317
-rw-r--r--crawl-ref/source/mstuff2.h1
-rw-r--r--crawl-ref/source/spl-cast.h7
-rw-r--r--crawl-ref/source/spl-data.h69
10 files changed, 377 insertions, 230 deletions
diff --git a/crawl-ref/source/dat/database/monspell.txt b/crawl-ref/source/dat/database/monspell.txt
index a017dd3cfc..9e232d65d3 100644
--- a/crawl-ref/source/dat/database/monspell.txt
+++ b/crawl-ref/source/dat/database/monspell.txt
@@ -2,14 +2,38 @@
# Individual spells.
#####################################################
%%%%
+Acid Splash cast
+
+@The_monster@ spits acid at @target@.
+%%%%
+Acid Splash cast unseen
+
+You hear a spitting sound.
+%%%%
+Draconian Breath cast
+
+@The_monster@ breathes.
+%%%%
+Draconian Breath cast unseen
+
+You hear a roar.
+%%%%
Poison Splash cast
-@The_monster@ spits poison.
+@The_monster@ spits poison at @target@.
%%%%
Poison Splash cast unseen
You hear a spitting sound.
%%%%
+Sticky Flame Splash cast
+
+@The_monster@ spits sticky flame at @target@.
+%%%%
+Sticky Flame Splash cast unseen
+
+You hear a spitting sound.
+%%%%
Symbol of Torment cast
@The_monster@ calls on the powers of Hell!
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 3f75a5be06..b679185b2c 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -2778,6 +2778,11 @@ enum spell_type
SPELL_SUMMON_DRAKES,
SPELL_BLINK_OTHER,
SPELL_SUMMON_MUSHROOMS,
+ SPELL_ACID_SPLASH,
+ SPELL_STICKY_FLAME_SPLASH, // 225
+ SPELL_FIRE_BREATH,
+ SPELL_COLD_BREATH,
+ SPELL_DRACONIAN_BREATH,
NUM_SPELLS,
SPELL_NO_SPELL = 250
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index a2b768e15c..177526b22a 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -1647,7 +1647,7 @@ static monsterentry mondata[] = {
{
MONS_CURSE_SKULL, 'z', LIGHTCYAN, "curse skull",
M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS | M_STATIONARY | M_EVIL
- | M_SPEAKS,
+ | M_SPEAKS | M_NOISY_SPELLS,
MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE | mrd(MR_RES_COLD, 2),
0, 50, MONS_LICH, MONS_CURSE_SKULL, MH_UNDEAD, MAG_IMMUNE,
{ AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -3999,7 +3999,8 @@ static monsterentry mondata[] = {
{
MONS_MURRAY, 'z', LIGHTRED, "Murray",
- M_SPELLCASTER | M_SEE_INVIS | M_EVIL | M_SPEAKS | M_UNIQUE,
+ M_SPELLCASTER | M_SEE_INVIS | M_EVIL | M_SPEAKS | M_UNIQUE
+ | M_NOISY_SPELLS,
MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE | mrd(MR_RES_COLD, 2),
0, 10, MONS_LICH, MONS_CURSE_SKULL, MH_UNDEAD, MAG_IMMUNE,
{ {AT_BITE, AF_PLAIN, 20}, {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK },
diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h
index 84b312ac98..3d9a82bc42 100644
--- a/crawl-ref/source/mon-spll.h
+++ b/crawl-ref/source/mon-spll.h
@@ -354,11 +354,11 @@
{ MST_MOTTLED_DRAGON,
{
- SPELL_STICKY_FLAME,
- SPELL_STICKY_FLAME,
+ SPELL_STICKY_FLAME_SPLASH,
+ SPELL_STICKY_FLAME_SPLASH,
SPELL_NO_SPELL,
- SPELL_STICKY_FLAME,
- SPELL_STICKY_FLAME,
+ SPELL_STICKY_FLAME_SPLASH,
+ SPELL_STICKY_FLAME_SPLASH,
SPELL_NO_SPELL
}
},
@@ -882,8 +882,8 @@
{ MST_HELL_HOG,
{
- SPELL_STICKY_FLAME,
- SPELL_STICKY_FLAME,
+ SPELL_STICKY_FLAME_SPLASH,
+ SPELL_STICKY_FLAME_SPLASH,
SPELL_NO_SPELL,
SPELL_NO_SPELL,
SPELL_NO_SPELL,
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 7777dc6dda..01eb8b8545 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -142,7 +142,15 @@ enum mons_class_flags
M_SPECIAL_ABILITY = (1<<26), // XXX: eventually make these spells?
M_NO_REGEN = (1<<27), // cannot regenerate
- M_NO_SKELETON = (1<<29), // boneless corpses
+ M_SPELL_NO_SILENT = (1<<28), // cannot cast spells when silenced,
+ // even though it's not a priest or
+ // wizard
+
+ M_NOISY_SPELLS = (1<<29), // can cast spells when silenced, but
+ // casting makes noise when not
+ // silenced
+
+ M_NO_SKELETON = (1<<30), // boneless corpses
M_NO_EXP_GAIN = (1<<31) // worth 0 xp
};
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 418aadb7b1..9c349d3d3a 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -74,7 +74,6 @@ static bool _mon_can_move_to_pos(const monsters *monster,
static bool _is_trap_safe(const monsters *monster, const coord_def& where,
bool just_check = false);
static bool _monster_move(monsters *monster);
-static bool _plant_spit(monsters *monster, bolt &pbolt);
static spell_type _map_wand_to_mspell(int wand_type);
// [dshaligram] Doesn't need to be extern.
@@ -4715,6 +4714,8 @@ static bool _handle_special_ability(monsters *monster, bolt & beem)
const msg_channel_type spl = (mons_friendly(monster) ? MSGCH_FRIEND_SPELL
: MSGCH_MONSTER_SPELL);
+ spell_type spell = SPELL_NO_SPELL;
+
switch (mclass)
{
case MONS_ORC_KNIGHT:
@@ -4864,8 +4865,22 @@ static bool _handle_special_ability(monsters *monster, bolt & beem)
break;
if (one_chance_in(3))
- used = _plant_spit(monster, beem);
+ {
+ spell = SPELL_ACID_SPLASH;
+ setup_mons_cast(monster, beem, spell);
+
+ // Fire tracer.
+ fire_tracer(monster, beem);
+ // Good idea?
+ if (mons_should_fire(beem))
+ {
+ _make_mons_stop_fleeing(monster);
+ mons_cast(monster, beem, spell);
+ mmov.reset();
+ used = true;
+ }
+ }
break;
case MONS_MOTH_OF_WRATH:
@@ -5020,16 +5035,27 @@ static bool _handle_special_ability(monsters *monster, bolt & beem)
break;
}
}
+ // Intentional fallthrough
+
+ case MONS_WHITE_DRACONIAN:
+ case MONS_RED_DRACONIAN:
+ spell = SPELL_DRACONIAN_BREATH;
+ // Intentional fallthrough
+
+ case MONS_ICE_DRAGON:
+ if (spell == SPELL_NO_SPELL)
+ spell = SPELL_COLD_BREATH;
+ // Intentional fallthrough
// Dragon breath weapons:
case MONS_DRAGON:
case MONS_HELL_HOUND:
- case MONS_ICE_DRAGON:
case MONS_LINDWURM:
case MONS_FIREDRAKE:
case MONS_XTAHUA:
- case MONS_WHITE_DRACONIAN:
- case MONS_RED_DRACONIAN:
+ if (spell == SPELL_NO_SPELL)
+ spell = SPELL_FIRE_BREATH;
+
if (monster->has_ench(ENCH_CONFUSION))
break;
@@ -5039,7 +5065,7 @@ static bool _handle_special_ability(monsters *monster, bolt & beem)
if (monster->type != MONS_HELL_HOUND && x_chance_in_y(3, 13)
|| one_chance_in(10))
{
- setup_dragon(monster, beem);
+ setup_mons_cast(monster, beem, spell);
// Fire tracer.
fire_tracer(monster, beem);
@@ -5048,8 +5074,7 @@ static bool _handle_special_ability(monsters *monster, bolt & beem)
if (mons_should_fire(beem))
{
_make_mons_stop_fleeing(monster);
- simple_monster_message(monster, " breathes.", spl);
- fire_beam(beem);
+ mons_cast(monster, beem, spell);
mmov.reset();
used = true;
}
@@ -5545,31 +5570,11 @@ static spell_type _get_draconian_breath_spell( monsters *monster )
{
switch (draco_subspecies( monster ))
{
- case MONS_BLACK_DRACONIAN:
- draco_breath = SPELL_LIGHTNING_BOLT;
- break;
-
- case MONS_PALE_DRACONIAN:
- draco_breath = SPELL_STEAM_BALL;
- break;
-
- case MONS_GREEN_DRACONIAN:
- draco_breath = SPELL_POISONOUS_CLOUD;
- break;
-
- case MONS_PURPLE_DRACONIAN:
- draco_breath = SPELL_ISKENDERUNS_MYSTIC_BLAST;
- break;
-
- case MONS_MOTTLED_DRACONIAN:
- draco_breath = SPELL_STICKY_FLAME;
- break;
-
case MONS_DRACONIAN:
case MONS_YELLOW_DRACONIAN: // already handled as ability
- case MONS_RED_DRACONIAN: // already handled as ability
- case MONS_WHITE_DRACONIAN: // already handled as ability
+ break;
default:
+ draco_breath = SPELL_DRACONIAN_BREATH;
break;
}
}
@@ -5601,36 +5606,6 @@ static bool _is_emergency_spell(const monster_spells &msp, int spell)
return (msp[5] == spell);
}
-static bool _mons_announce_cast(monsters *monster, bool nearby,
- spell_type spell_cast,
- spell_type draco_breath)
-{
- const msg_channel_type spl = (mons_friendly(monster) ? MSGCH_FRIEND_SPELL
- : MSGCH_MONSTER_SPELL);
-
- if (nearby)
- {
- if (spell_cast == draco_breath)
- {
- if (simple_monster_message(monster, " breathes.", spl))
- return (true);
- else
- {
- if (!silenced(monster->pos())
- && !silenced(you.pos()))
- {
- mpr("You hear a roar.", MSGCH_SOUND);
- return (true);
- }
- }
- }
- else if (monster->type == -1)
- monster->hit_points = -1;
- }
-
- return (false);
-}
-
//---------------------------------------------------------------
//
// handle_spell
@@ -5657,12 +5632,9 @@ static bool _handle_spell(monsters *monster, bolt &beem)
return (false);
}
- // Geryon can't summon beasts if he's silenced since he uses a horn,
- // and we have to check for him explicitly since he's neither a priest
- // nor a wizard.
if (silenced(monster->pos())
- && (monster->type == MONS_GERYON
- || mons_class_flag(monster->type, M_PRIEST | M_ACTUAL_SPELLS)))
+ && mons_class_flag(monster->type,
+ M_PRIEST | M_ACTUAL_SPELLS | M_SPELL_NO_SILENT))
{
return (false);
}
@@ -5941,9 +5913,8 @@ static bool _handle_spell(monsters *monster, bolt &beem)
return (false);
}
- const bool did_noise =
- _mons_announce_cast(monster, monsterNearby,
- spell_cast, draco_breath);
+ if (monster->type == MONS_BALL_LIGHTNING)
+ monster->hit_points = -1;
// FINALLY! determine primary spell effects {dlb}:
if (spell_cast == SPELL_BLINK)
@@ -5951,8 +5922,7 @@ static bool _handle_spell(monsters *monster, bolt &beem)
// Why only cast blink if nearby? {dlb}
if (monsterNearby)
{
- if (!did_noise)
- mons_cast_noise(monster, beem, spell_cast);
+ mons_cast_noise(monster, beem, spell_cast);
simple_monster_message(monster, " blinks!");
monster_blink(monster);
@@ -5967,7 +5937,7 @@ static bool _handle_spell(monsters *monster, bolt &beem)
if (spell_needs_foe(spell_cast))
_make_mons_stop_fleeing(monster);
- mons_cast(monster, beem, spell_cast, !did_noise);
+ mons_cast(monster, beem, spell_cast);
mmov.reset();
monster->lose_energy(EUT_SPELL);
}
@@ -7954,49 +7924,6 @@ forget_it:
return ret;
} // end monster_move()
-static void _setup_plant_spit(monsters *monster, bolt &pbolt)
-{
- pbolt.name = "acid";
- pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP);
- // immobile plants get long-range spit...
- pbolt.range = LOS_RADIUS;
- pbolt.colour = YELLOW;
- pbolt.flavour = BEAM_ACID;
- pbolt.beam_source = monster_index(monster);
- pbolt.damage = dice_def( 3, 7 );
- pbolt.hit = 20 + (3 * monster->hit_dice);
- pbolt.thrower = KILL_MON_MISSILE;
- pbolt.aux_source.clear();
-}
-
-static bool _plant_spit(monsters *monster, bolt &pbolt)
-{
- bool did_spit = false;
-
- char spit_string[INFO_SIZE];
-
- _setup_plant_spit(monster, pbolt);
-
- // Fire tracer.
- fire_tracer(monster, pbolt);
-
- if (mons_should_fire(pbolt))
- {
- _make_mons_stop_fleeing(monster);
- strcpy( spit_string, " spits" );
- if (pbolt.target == you.pos())
- strcat( spit_string, " at you" );
-
- strcat( spit_string, "." );
- simple_monster_message( monster, spit_string );
-
- fire_beam( pbolt );
- did_spit = true;
- }
-
- return (did_spit);
-}
-
static void _mons_in_cloud(monsters *monster)
{
int wc = env.cgrid(monster->pos());
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 1e9deb03e7..477d886d1f 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -36,6 +36,7 @@
#include "spells1.h"
#include "spells3.h"
#include "spells4.h"
+#include "spl-cast.h"
#include "spl-mis.h"
#include "spl-util.h"
#include "stuff.h"
@@ -503,21 +504,67 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
void mons_cast_noise(monsters *monster, bolt &pbolt, spell_type spell_cast)
{
+ bool force_silent = false;
+
+ spell_type real_spell = spell_cast;
+
+ if (spell_cast == SPELL_DRACONIAN_BREATH)
+ {
+ int type = monster->type;
+ if (mons_genus(type) == MONS_DRACONIAN)
+ type = draco_subspecies(monster);
+
+ switch(type)
+ {
+ case MONS_MOTTLED_DRACONIAN:
+ real_spell = SPELL_STICKY_FLAME_SPLASH;
+ break;
+
+ case MONS_YELLOW_DRACONIAN:
+ real_spell = SPELL_ACID_SPLASH;
+ break;
+
+ case MONS_PLAYER_GHOST:
+ // Draining breath is silent.
+ force_silent = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (monster->type == MONS_SHADOW_DRAGON)
+ // Draining breath is silent.
+ force_silent = true;
+
const bool unseen = !you.can_see(monster);
- const bool silent = silenced(monster->pos());
+ const bool silent = silenced(monster->pos()) || force_silent;
if (unseen && silent)
return;
+ const unsigned int flags = get_spell_flags(real_spell);
+
const bool priest = mons_class_flag(monster->type, M_PRIEST);
const bool wizard = mons_class_flag(monster->type, M_ACTUAL_SPELLS);
- const bool innate = !(priest || wizard);
+ const bool innate = !(priest || wizard) || (flags & SPFLAG_INNATE);
int noise;
- if(silent || innate)
+ if(silent
+ || (innate
+ && !mons_class_flag(monster->type, M_SPELL_NO_SILENT
+ | M_NOISY_SPELLS)
+ && !(flags & SPFLAG_NOISY)))
+ {
noise = 0;
+ }
else
- noise = spell_noise(spell_cast);
+ {
+ if (mons_genus(monster->type) == MONS_DRAGON)
+ noise = get_shout_noise_level(S_ROAR);
+ else
+ noise = spell_noise(real_spell);
+ }
const std::string cast_str = " cast";
std::string suffix;
@@ -529,7 +576,7 @@ void mons_cast_noise(monsters *monster, bolt &pbolt, spell_type spell_cast)
std::string key;
// First try the individual spell.
- key = spell_title(spell_cast) + cast_str;
+ key = spell_title(real_spell) + cast_str;
std::string msg = getSpeakString(key + suffix);
if (msg.empty() && silent)
@@ -603,6 +650,25 @@ void mons_cast_noise(monsters *monster, bolt &pbolt, spell_type spell_cast)
return;
}
+ std::string target = "something";
+
+ if (pbolt.target == you.pos())
+ target = "you";
+ else if (see_grid(pbolt.target))
+ {
+ int midx = mgrd(pbolt.target);
+ if (midx != NON_MONSTER)
+ {
+ monsters* mtarg = &menv[midx];
+
+ if (you.can_see(mtarg))
+ target = mtarg->name(mons_friendly(mtarg) ? DESC_NOCAP_YOUR :
+ DESC_NOCAP_THE);
+ }
+ }
+
+ msg = replace_all(msg, "@target@", target);
+
const msg_channel_type chan =
(unseen ? MSGCH_SOUND :
mons_friendly(monster) ? MSGCH_FRIEND_SPELL :
@@ -851,101 +917,6 @@ void monster_teleport(monsters *monster, bool instan, bool silent)
}
}
-void setup_dragon(struct monsters *monster, bolt &pbolt)
-{
- const int type = (mons_genus(monster->type) == MONS_DRACONIAN)
- ? draco_subspecies(monster) : monster->type;
- int scaling = 100;
-
- pbolt.name.clear();
- switch (type)
- {
- case MONS_FIREDRAKE:
- case MONS_HELL_HOUND:
- case MONS_DRAGON:
- case MONS_LINDWURM:
- case MONS_XTAHUA:
- pbolt.name += "blast of flame";
- pbolt.aux_source = "blast of fiery breath";
- pbolt.flavour = BEAM_FIRE;
- pbolt.colour = RED;
- pbolt.range = 6;
- break;
-
- case MONS_ICE_DRAGON:
- pbolt.name += "blast of cold";
- pbolt.aux_source = "blast of icy breath";
- pbolt.flavour = BEAM_COLD;
- pbolt.colour = WHITE;
- pbolt.range = 7;
- break;
-
- case MONS_RED_DRACONIAN:
- pbolt.name += "searing blast";
- pbolt.aux_source = "blast of searing breath";
- pbolt.flavour = BEAM_FIRE;
- pbolt.colour = RED;
- pbolt.range = 6;
- scaling = 65;
- break;
-
- case MONS_WHITE_DRACONIAN:
- pbolt.name += "chilling blast";
- pbolt.aux_source = "blast of chilling breath";
- pbolt.flavour = BEAM_COLD;
- pbolt.colour = WHITE;
- pbolt.range = 7;
- scaling = 65;
- break;
-
- case MONS_PLAYER_GHOST: // draconians only
- pbolt.name += "blast of negative energy";
- pbolt.aux_source = "blast of draining breath";
- pbolt.flavour = BEAM_NEG;
- pbolt.colour = DARKGREY;
- pbolt.range = LOS_RADIUS;
- scaling = 65;
- break;
-
- default:
- DEBUGSTR("Bad monster class in setup_dragon()");
- break;
- }
-
-#ifdef DEBUG_DIAGNOSTICS
- mprf( MSGCH_DIAGNOSTICS, "bolt name: '%s'", pbolt.name.c_str() );
-#endif
-
- pbolt.damage = dice_def( 3, (monster->hit_dice * 2) );
- pbolt.damage.size = scaling * pbolt.damage.size / 100;
- pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP);
- pbolt.hit = 30;
- pbolt.beam_source = monster_index(monster);
- pbolt.thrower = KILL_MON;
- pbolt.is_beam = true;
-
- // Accuracy is lowered by one quarter if the dragon is attacking
- // a target that is wielding a weapon of dragon slaying (which
- // makes the dragon/draconian avoid looking at the foe).
- // FIXME: This effect is not yet implemented for player draconians
- // or characters in dragon form breathing at monsters wielding a
- // weapon with this brand.
- if (is_dragonkind(monster, monster))
- {
- if (actor *foe = monster->get_foe())
- {
- if (const item_def *weapon = foe->weapon())
- {
- if (get_weapon_brand(*weapon) == SPWPN_DRAGON_SLAYING)
- {
- pbolt.hit *= 3;
- pbolt.hit /= 4;
- }
- }
- }
- }
-}
-
void setup_generic_throw(struct monsters *monster, struct bolt &pbolt)
{
// FIXME we should use a sensible range here
@@ -1415,7 +1386,58 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
beam.range = spell_range(spell_cast, power, true);
- switch (spell_cast)
+ const int drac_type = (mons_genus(mons->type) == MONS_DRACONIAN)
+ ? draco_subspecies(mons) : mons->type;
+
+ int real_spell = spell_cast;
+
+ if (spell_cast == SPELL_DRACONIAN_BREATH)
+ {
+ switch(drac_type)
+ {
+ case MONS_BLACK_DRACONIAN:
+ real_spell = SPELL_LIGHTNING_BOLT;
+ break;
+
+ case MONS_MOTTLED_DRACONIAN:
+ real_spell = SPELL_STICKY_FLAME_SPLASH;
+ break;
+
+ case MONS_YELLOW_DRACONIAN:
+ real_spell = SPELL_ACID_SPLASH;
+ break;
+
+ case MONS_GREEN_DRACONIAN:
+ real_spell = SPELL_POISONOUS_CLOUD;
+ break;
+
+ case MONS_PURPLE_DRACONIAN:
+ real_spell = SPELL_ISKENDERUNS_MYSTIC_BLAST;
+ break;
+
+ case MONS_RED_DRACONIAN:
+ real_spell = SPELL_FIRE_BREATH;
+ break;
+
+ case MONS_WHITE_DRACONIAN:
+ real_spell = SPELL_COLD_BREATH;
+ break;
+
+ case MONS_PALE_DRACONIAN:
+ real_spell = SPELL_STEAM_BALL;
+ break;
+
+ case MONS_PLAYER_GHOST:
+ // Handled later
+ break;
+
+ default:
+ DEBUGSTR("Invalid monster using draconian breath spell");
+ break;
+ }
+ }
+
+ switch (real_spell)
{
case SPELL_MAGIC_DART:
beam.colour = LIGHTMAGENTA; // inv_colour [throw_2];
@@ -1763,6 +1785,7 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
beam.is_beam = true;
break;
+ case SPELL_STICKY_FLAME_SPLASH:
case SPELL_STICKY_FLAME:
beam.colour = RED;
beam.name = "sticky flame";
@@ -1841,6 +1864,17 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
beam.is_beam = false;
break;
+ case SPELL_ACID_SPLASH:
+ beam.colour = YELLOW;
+ beam.name = "splash of acid";
+ beam.damage = dice_def( 3, 7 );
+ beam.hit = 20 + (3 * mons->hit_dice);
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.thrower = KILL_MON_MISSILE;
+ beam.flavour = BEAM_ACID;
+ beam.is_beam = false;
+ break;
+
case SPELL_DISINTEGRATE:
beam.name = "0";
beam.type = 0;
@@ -1927,10 +1961,91 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
beam.is_beam = true;
break;
+ case SPELL_FIRE_BREATH:
+ beam.name = "blast of flame";
+ beam.aux_source = "blast of fiery breath";
+ beam.damage = dice_def( 3, (mons->hit_dice * 2) );
+ beam.colour = RED;
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.thrower = KILL_MON;
+ beam.hit = 30;
+ beam.flavour = BEAM_FIRE;
+ beam.is_beam = true;
+ break;
+
+ case SPELL_COLD_BREATH:
+ beam.name = "blast of cold";
+ beam.aux_source = "blast of icy breath";
+ beam.damage = dice_def( 3, (mons->hit_dice * 2) );
+ beam.colour = WHITE;
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.thrower = KILL_MON;
+ beam.hit = 30;
+ beam.flavour = BEAM_COLD;
+ beam.is_beam = true;
+ break;
+
+ case SPELL_DRACONIAN_BREATH:
+ beam.damage = dice_def( 3, (mons->hit_dice * 2) );
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.thrower = KILL_MON;
+ beam.hit = 30;
+ beam.is_beam = true;
+ break;
+
default:
DEBUGSTR("Unknown spell");
}
+ if (spell_cast == SPELL_DRACONIAN_BREATH)
+ {
+ int scaling = 100;
+ switch(drac_type)
+ {
+ case MONS_RED_DRACONIAN:
+ beam.name = "searing blast";
+ beam.aux_source = "blast of searing breath";
+ scaling = 65;
+ break;
+
+ case MONS_WHITE_DRACONIAN:
+ beam.name = "chilling blast";
+ beam.aux_source = "blast of chilling breath";
+ scaling = 65;
+ break;
+
+ case MONS_PLAYER_GHOST: // draconians only
+ beam.name = "blast of negative energy";
+ beam.aux_source = "blast of draining breath";
+ beam.flavour = BEAM_NEG;
+ beam.colour = DARKGREY;
+ scaling = 65;
+ break;
+ }
+ beam.damage.size = scaling * beam.damage.size / 100;
+ }
+
+ // Accuracy is lowered by one quarter if the dragon is attacking
+ // a target that is wielding a weapon of dragon slaying (which
+ // makes the dragon/draconian avoid looking at the foe).
+ // FIXME: This effect is not yet implemented for player draconians
+ // or characters in dragon form breathing at monsters wielding a
+ // weapon with this brand.
+ if (is_dragonkind(mons, mons))
+ {
+ if (actor *foe = mons->get_foe())
+ {
+ if (const item_def *weapon = foe->weapon())
+ {
+ if (get_weapon_brand(*weapon) == SPWPN_DRAGON_SLAYING)
+ {
+ beam.hit *= 3;
+ beam.hit /= 4;
+ }
+ }
+ }
+ }
+
return (beam);
} // end mons_spells()
diff --git a/crawl-ref/source/mstuff2.h b/crawl-ref/source/mstuff2.h
index 9eb26839f4..65e3d0d0bb 100644
--- a/crawl-ref/source/mstuff2.h
+++ b/crawl-ref/source/mstuff2.h
@@ -17,7 +17,6 @@
struct bolt;
bolt mons_spells(monsters *mons, spell_type spell_cast, int power);
-void setup_dragon(monsters *monster, bolt &pbolt);
void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
bool do_noise = true);
void mons_cast_noise(monsters *monster, bolt &pbolt, spell_type spell_cast);
diff --git a/crawl-ref/source/spl-cast.h b/crawl-ref/source/spl-cast.h
index eaee3478a0..ce18606e1b 100644
--- a/crawl-ref/source/spl-cast.h
+++ b/crawl-ref/source/spl-cast.h
@@ -32,8 +32,11 @@ enum spflag_type
// is still a battle spell
SPFLAG_CARD = 0x02000, // a card effect spell
SPFLAG_MONSTER = 0x04000, // monster-only spell
- SPFLAG_TESTING = 0x08000, // a testing/debugging spell
- SPFLAG_DEVEL = 0x10000 // a spell under development
+ SPFLAG_INNATE = 0x08000, // an innate spell, even if
+ // use by a priest/wizard
+ SPFLAG_NOISY = 0x10000, // makes noise, even if innate
+ SPFLAG_TESTING = 0x20000, // a testing/debugging spell
+ SPFLAG_DEVEL = 0x40000 // a spell under development
};
enum spret_type
diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h
index ac91b1eccc..ac8f747a2f 100644
--- a/crawl-ref/source/spl-data.h
+++ b/crawl-ref/source/spl-data.h
@@ -2724,11 +2724,11 @@
{
SPELL_POISON_SPLASH, "Poison Splash",
SPTYP_POISON,
- SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER | SPFLAG_INNATE | SPFLAG_NOISY,
2,
0,
7, 7,
- 0,
+ 2,
NULL,
true,
false
@@ -2839,6 +2839,71 @@
},
{
+ SPELL_ACID_SPLASH, "Acid Splash",
+ SPTYP_CONJURATION,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER | SPFLAG_INNATE | SPFLAG_NOISY,
+ 5,
+ 0,
+ LOS_RADIUS, LOS_RADIUS,
+ 0,
+ NULL,
+ true,
+ false
+},
+
+{
+ SPELL_STICKY_FLAME_SPLASH, "Sticky Flame Splash",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER | SPFLAG_INNATE | SPFLAG_NOISY,
+ 4,
+ 100,
+ 5, 5,
+ 0,
+ NULL,
+ true,
+ false
+},
+
+{
+ SPELL_FIRE_BREATH, "Fire Breath",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER | SPFLAG_INNATE | SPFLAG_NOISY,
+ 5,
+ 0,
+ 6, 6,
+ 0,
+ NULL,
+ true,
+ false
+},
+
+{
+ SPELL_COLD_BREATH, "Cold Breath",
+ SPTYP_CONJURATION | SPTYP_ICE,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER | SPFLAG_INNATE | SPFLAG_NOISY,
+ 5,
+ 0,
+ 6, 6,
+ 0,
+ NULL,
+ true,
+ false
+},
+
+{
+ SPELL_DRACONIAN_BREATH, "Draconian Breath",
+ SPTYP_CONJURATION,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER | SPFLAG_INNATE | SPFLAG_NOISY,
+ 8,
+ 0,
+ LOS_RADIUS, LOS_RADIUS,
+ 0,
+ NULL,
+ true,
+ false
+},
+
+{
SPELL_NO_SPELL, "nonexistent spell",
0,
0,