diff options
-rw-r--r-- | crawl-ref/source/beam.cc | 56 | ||||
-rw-r--r-- | crawl-ref/source/beam.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/dat/database/rand_wpn.txt | 2 | ||||
-rw-r--r-- | crawl-ref/source/effects.cc | 134 | ||||
-rw-r--r-- | crawl-ref/source/effects.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/ghost.cc | 6 | ||||
-rw-r--r-- | crawl-ref/source/mon-data.h | 6 | ||||
-rw-r--r-- | crawl-ref/source/mon-spll.h | 18 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 52 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/mstuff2.cc | 117 | ||||
-rw-r--r-- | crawl-ref/source/mstuff2.h | 5 | ||||
-rw-r--r-- | crawl-ref/source/player.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/spells1.cc | 13 | ||||
-rw-r--r-- | crawl-ref/source/spells1.h | 24 | ||||
-rw-r--r-- | crawl-ref/source/spl-data.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/spl-util.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/spl-util.h | 1 |
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); |