diff options
-rw-r--r-- | crawl-ref/source/dat/database/monspell.txt | 26 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 5 | ||||
-rw-r--r-- | crawl-ref/source/mon-data.h | 5 | ||||
-rw-r--r-- | crawl-ref/source/mon-spll.h | 12 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 10 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 155 | ||||
-rw-r--r-- | crawl-ref/source/mstuff2.cc | 317 | ||||
-rw-r--r-- | crawl-ref/source/mstuff2.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/spl-cast.h | 7 | ||||
-rw-r--r-- | crawl-ref/source/spl-data.h | 69 |
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, |