summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/mon-cast.cc
diff options
context:
space:
mode:
authorAdam Borowski <kilobyte@angband.pl>2009-12-27 17:48:37 +0100
committerAdam Borowski <kilobyte@angband.pl>2009-12-27 17:48:37 +0100
commit42d227a273a1334b60ca7574a8127d1a4b2744a1 (patch)
tree2655bcdeab4c1e157906b88ccefdda7645ee580a /crawl-ref/source/mon-cast.cc
parent5b7701dc9d19fdad4de1a64b41995d65c03b7df6 (diff)
parentdc3e12a4da48363a7cadb77f30b8e784d5f82acf (diff)
downloadcrawl-ref-42d227a273a1334b60ca7574a8127d1a4b2744a1.tar.gz
crawl-ref-42d227a273a1334b60ca7574a8127d1a4b2744a1.zip
Merge branch 'master' into iood
Diffstat (limited to 'crawl-ref/source/mon-cast.cc')
-rw-r--r--crawl-ref/source/mon-cast.cc249
1 files changed, 237 insertions, 12 deletions
diff --git a/crawl-ref/source/mon-cast.cc b/crawl-ref/source/mon-cast.cc
index 4f86ede2f8..f236c31c16 100644
--- a/crawl-ref/source/mon-cast.cc
+++ b/crawl-ref/source/mon-cast.cc
@@ -16,12 +16,15 @@
#include "fprop.h"
#include "fight.h"
#include "ghost.h"
+#include "items.h"
#include "misc.h"
+#include "message.h"
#include "mon-behv.h"
#include "mon-iter.h"
#include "mon-place.h"
#include "mon-project.h"
#include "terrain.h"
+#include "tutorial.h"
#include "mgen_data.h"
#include "coord.h"
#include "mon-speak.h"
@@ -40,6 +43,7 @@
#include "teleport.h"
#include "view.h"
#include "viewchar.h"
+#include "xom.h"
static bool _valid_mon_spells[NUM_SPELLS];
@@ -733,7 +737,8 @@ static bool _los_free_spell(spell_type spell_cast)
|| spell_cast == SPELL_SMITING
|| spell_cast == SPELL_HAUNT
|| spell_cast == SPELL_FIRE_STORM
- || spell_cast == SPELL_AIRSTRIKE);
+ || spell_cast == SPELL_AIRSTRIKE
+ || spell_cast == SPELL_MISLEAD);
}
// Set up bolt structure for monster spell casting.
@@ -768,6 +773,7 @@ bool setup_mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
case SPELL_BRAIN_FEED:
pbolt.type = DMNBM_BRAIN_FEED;
return (true);
+ case SPELL_MISLEAD:
case SPELL_SMITING:
case SPELL_AIRSTRIKE:
pbolt.type = DMNBM_SMITING;
@@ -787,6 +793,9 @@ bool setup_mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
case SPELL_VAMPIRE_SUMMON:
case SPELL_SHADOW_CREATURES: // summon anything appropriate for level
case SPELL_FAKE_RAKSHASA_SUMMON:
+ case SPELL_FAKE_MARA_SUMMON:
+ case SPELL_SUMMON_PLAYER_GHOST:
+ case SPELL_SUMMON_RAKSHASA:
case SPELL_SUMMON_DEMON:
case SPELL_SUMMON_UGLY_THING:
case SPELL_ANIMATE_DEAD:
@@ -820,6 +829,7 @@ bool setup_mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
case SPELL_CHAIN_LIGHTNING: // the only user is reckless
case SPELL_SUMMON_EYEBALLS:
case SPELL_SUMMON_BUTTERFLIES:
+ case SPELL_MISLEAD:
return (true);
default:
if (check_validity)
@@ -1548,6 +1558,130 @@ void mons_cast_haunt(monsters *monster)
_pick_random_wraith, random_range(3, 6), GOD_NO_GOD, &fpos);
}
+int _count_mara_fakes()
+{
+ int count = 0;
+ for (monster_iterator mi; mi; ++mi)
+ {
+ if (mi->type == MONS_MARA_FAKE)
+ count++;
+ }
+
+ return count;
+}
+
+bool _unsuitable_misled_monster(monster_type mons)
+{
+ return (mons_is_unique(mons) || mons_is_mimic(mons)
+ || mons_class_is_stationary(mons) || mons_genus(mons) == MONS_DRACONIAN
+ || mons == MONS_DANCING_WEAPON || mons == MONS_UGLY_THING
+ || mons == MONS_VERY_UGLY_THING || mons == MONS_ZOMBIE_SMALL
+ || mons == MONS_ZOMBIE_LARGE || mons == MONS_SKELETON_SMALL
+ || mons == MONS_SKELETON_LARGE || mons == MONS_SIMULACRUM_SMALL
+ || mons == MONS_SIMULACRUM_LARGE || mons == MONS_SPECTRAL_THING
+ || mons == MONS_SLIME_CREATURE || mons == MONS_BALLISTOMYCETE
+ || mons == MONS_HYDRA || mons == MONS_PLAYER_GHOST
+ || mons == MONS_SHAPESHIFTER || mons == MONS_PANDEMONIUM_DEMON
+ || mons == MONS_KILLER_KLOWN || mons == MONS_KRAKEN
+ || mons == MONS_KRAKEN_TENTACLE
+ || mons == MONS_GLOWING_SHAPESHIFTER);
+}
+
+monster_type _get_misled_monster (monsters *monster)
+{
+ monster_type mons = random_monster_at_grid(monster->pos());
+ if (_unsuitable_misled_monster(mons))
+ mons = random_monster_at_grid(monster->pos());
+
+ if (_unsuitable_misled_monster(mons))
+ return (MONS_GIANT_BAT);
+
+ return mons;
+}
+
+int _update_mislead_monsters(monsters* monster)
+{
+ int count = 0;
+
+ for (monster_iterator mi; mi; ++mi)
+ {
+ if (*mi == monster)
+ continue;
+
+ // Don't affect uniques, named monsters, and monsters with special tiles.
+ if (mons_is_unique(mi->type) || !mi->mname.empty()
+ || mi->props.exists("monster_tile") || mi->props.exists("mislead_as"))
+ {
+ continue;
+ }
+ else
+ {
+ mi->props["mislead_as"] = short(_get_misled_monster(*mi));
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void mons_cast_mislead(monsters *monster)
+{
+ // This really only affects the player; it causes confusion when cast on
+ // non-player foes, but that is dealt with inside ye-great-Switch-of-Doom.
+ if (monster->foe != MHITYOU)
+ return;
+
+ // Prevents Mislead spam by Mara and co. {due}
+ if (you.duration[DUR_MISLED] > 10 && one_chance_in(3))
+ return;
+
+ if (wearing_amulet(AMU_CLARITY))
+ {
+ mpr("Your vision blurs momentarily.");
+ return;
+ }
+
+ _update_mislead_monsters(monster);
+
+ const int old_value = you.duration[DUR_MISLED];
+ you.increase_duration(DUR_MISLED, monster->hit_dice * 12 / 3, 50);
+ if (you.duration[DUR_MISLED] > old_value)
+ {
+ you.check_awaken(500);
+
+ if (old_value <= 0)
+ {
+ mpr("But for a moment, strange images dance in front of your eyes.", MSGCH_WARN);
+#ifdef USE_TILE
+ tiles.add_overlay(you.pos(), tileidx_zap(MAGENTA));
+ update_screen();
+#else
+ flash_view(MAGENTA);
+#endif
+ more();
+ }
+ else
+ mpr("You are even more misled!", MSGCH_WARN);
+
+ learned_something_new(TUT_YOU_ENCHANTED);
+
+ xom_is_stimulated((you.duration[DUR_MISLED] - old_value)
+ / BASELINE_DELAY);
+ }
+
+ return;
+}
+
+bool _find_players_ghost ()
+{
+ bool found = false;
+ for (monster_iterator mi; mi; ++mi)
+ if (mi->type == MONS_PLAYER_GHOST && mi->mname == you.your_name)
+ found = true;
+
+ return found;
+}
+
void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
bool do_noise, bool special_ability)
{
@@ -1611,8 +1745,8 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
const bool wizard = monster->is_actual_spellcaster();
god_type god = (priest || !(priest || wizard)) ? monster->god : GOD_NO_GOD;
- // Used for summon X elemental, and nothing else. {bookofjude}
- monster_type el_summon_type = MONS_NO_MONSTER;
+ // Used for summon X elemental and nothing else. {bookofjude}
+ monster_type summon_type = MONS_NO_MONSTER;
switch (spell_cast)
{
@@ -1673,20 +1807,20 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
return;
case SPELL_WATER_ELEMENTALS:
- if (el_summon_type == MONS_NO_MONSTER)
- el_summon_type = MONS_WATER_ELEMENTAL;
+ if (summon_type == MONS_NO_MONSTER)
+ summon_type = MONS_WATER_ELEMENTAL;
// Deliberate fall through
case SPELL_EARTH_ELEMENTALS:
- if (el_summon_type == MONS_NO_MONSTER)
- el_summon_type = MONS_EARTH_ELEMENTAL;
+ if (summon_type == MONS_NO_MONSTER)
+ summon_type = MONS_EARTH_ELEMENTAL;
// Deliberate fall through
case SPELL_AIR_ELEMENTALS:
- if (el_summon_type == MONS_NO_MONSTER)
- el_summon_type = MONS_AIR_ELEMENTAL;
+ if (summon_type == MONS_NO_MONSTER)
+ summon_type = MONS_AIR_ELEMENTAL;
// Deliberate fall through
case SPELL_FIRE_ELEMENTALS:
- if (el_summon_type == MONS_NO_MONSTER)
- el_summon_type = MONS_FIRE_ELEMENTAL;
+ if (summon_type == MONS_NO_MONSTER)
+ summon_type = MONS_FIRE_ELEMENTAL;
if (_mons_abjured(monster, monsterNearby))
return;
@@ -1696,11 +1830,42 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
create_monster(
- mgen_data(el_summon_type, SAME_ATTITUDE(monster), monster,
+ mgen_data(summon_type, SAME_ATTITUDE(monster), monster,
+ 3, spell_cast, monster->pos(), monster->foe, 0, god));
+ }
+ return;
+
+ case SPELL_SUMMON_RAKSHASA:
+ sumcount2 = 1 + random2(4) + random2(monster->hit_dice / 7 + 1);
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ create_monster(
+ mgen_data(MONS_RAKSHASA, SAME_ATTITUDE(monster), monster,
3, spell_cast, monster->pos(), monster->foe, 0, god));
}
return;
+ case SPELL_SUMMON_PLAYER_GHOST:
+
+ // Do nothing in the arena; this could instead create a ghost of an
+ // existant monster, but that would require the spell being dealth with
+ // as a bolt instead.
+ if (crawl_state.arena)
+ return;
+
+ // Only summon one ghost.
+ if (_find_players_ghost())
+ return;
+
+ mpr("There is a horrible, sudden wrenching feeling in your soul!", MSGCH_WARN);
+
+ create_monster(
+ mgen_data(MONS_PLAYER_GHOST, SAME_ATTITUDE(monster), monster,
+ 6, spell_cast, monster->pos(), monster->foe, 0, god));
+
+ return;
+
case SPELL_KRAKEN_TENTACLES:
{
int kraken_index = monster->mindex();
@@ -1743,6 +1908,66 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
mpr("Tentacles burst out of the water!");
return;
}
+ case SPELL_FAKE_MARA_SUMMON:
+ // We only want there to be two fakes, which, plus Mara, means
+ // a total of three Maras; if we already have two, give up, otherwise
+ // we want to summon either one more or two more.
+ sumcount2 = 2 - _count_mara_fakes();
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ mgen_data summ_mon = mgen_data(MONS_MARA_FAKE, SAME_ATTITUDE(monster),
+ monster, 3, spell_cast, monster->pos(),
+ monster->foe, 0, god);
+ // This is somewhat hacky, to prevent "A Mara", and such, as MONS_FAKE_MARA
+ // is not M_UNIQUE.
+ summ_mon.mname = "Mara";
+ summ_mon.extra_flags |= MF_NAME_REPLACE;
+
+ int created = create_monster(summ_mon);
+ if (created == -1)
+ continue;
+
+ // Mara's clones are special; they have the same stats as him, and
+ // are exact clones, so they are created damaged if necessary, with
+ // identical enchants and with the same items.
+ monsters *new_fake = &menv[created];
+ new_fake->hit_points = monster->hit_points;
+ new_fake->max_hit_points = monster->max_hit_points;
+ mon_enchant_list::iterator ei;
+ for (ei = monster->enchantments.begin(); ei != monster->enchantments.end(); ++ei)
+ {
+ new_fake->enchantments.insert(*ei);
+ }
+
+ // Code basically lifted from clone_monster. In theory, it only needs
+ // to copy weapon and armour slots; instead, copy the whole inventory.
+ for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
+ {
+ const int old_index = monster->inv[i];
+
+ if (old_index == NON_ITEM)
+ continue;
+
+ const int new_index = get_item_slot(0);
+ if (new_index == NON_ITEM)
+ {
+ new_fake->unequip(mitm[old_index], i, 0, true);
+ new_fake->inv[i] = NON_ITEM;
+ continue;
+ }
+
+ new_fake->inv[i] = new_index;
+ mitm[new_index] = mitm[old_index];
+ mitm[new_index].set_holding_monster(new_fake->mindex());
+
+ // Mark items as summoned, so there's no way to get three nice
+ // weapons or such out of him.
+ mitm[new_index].flags |= ISFLAG_SUMMONED;
+ }
+ }
+ return;
+
case SPELL_FAKE_RAKSHASA_SUMMON:
sumcount2 = (coinflip() ? 2 : 3);