summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,