summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/beam.cc123
-rw-r--r--crawl-ref/source/beam.h3
-rw-r--r--crawl-ref/source/cloud.cc7
-rw-r--r--crawl-ref/source/enum.h4
-rw-r--r--crawl-ref/source/externs.h4
-rw-r--r--crawl-ref/source/item_use.cc153
-rw-r--r--crawl-ref/source/item_use.h2
-rw-r--r--crawl-ref/source/mon-util.cc58
-rw-r--r--crawl-ref/source/mon-util.h18
-rw-r--r--crawl-ref/source/monplace.cc3
-rw-r--r--crawl-ref/source/monplace.h37
-rw-r--r--crawl-ref/source/monstuff.cc140
-rw-r--r--crawl-ref/source/mstuff2.cc172
-rw-r--r--crawl-ref/source/mstuff2.h4
-rw-r--r--crawl-ref/source/spells1.cc16
-rw-r--r--crawl-ref/source/spells2.cc6
-rw-r--r--crawl-ref/source/spells3.cc2
-rw-r--r--crawl-ref/source/spl-cast.cc13
-rw-r--r--crawl-ref/source/view.cc4
-rw-r--r--crawl-ref/source/xom.cc7
20 files changed, 527 insertions, 249 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index bde83713a3..d7d7a3dd47 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -93,6 +93,8 @@ static void _zappy(zap_type z_type, int power, bolt &pbolt);
static bool _nasty_beam(monsters *mon, const bolt &beam);
static bool _nice_beam(monsters *mon, const bolt &beam);
+static beam_type _chaos_beam_flavour();
+
static std::set<std::string> beam_message_cache;
static bool _beam_is_blockable(bolt &pbolt)
@@ -146,10 +148,6 @@ void zap_animation(int colour, const monsters *mon, bool force)
{
coord_def p = you.pos();
- // Default to whatever colour magic is today.
- if (colour == -1)
- colour = element_colour(EC_MAGIC);
-
if (mon)
{
if (!force && !player_monster_visible( mon ))
@@ -165,6 +163,10 @@ void zap_animation(int colour, const monsters *mon, bool force)
if (in_los_bounds(drawp))
{
+ // Default to whatever colour magic is today.
+ if (colour == -1)
+ colour = EC_MAGIC;
+
#ifdef USE_TILE
tiles.add_overlay(p, tileidx_zap(colour));
#else
@@ -185,6 +187,8 @@ static void _ench_animation( int flavour, const monsters *mon, bool force )
(flavour == BEAM_PAIN) ? EC_UNHOLY :
(flavour == BEAM_DISPEL_UNDEAD) ? EC_HOLY :
(flavour == BEAM_POLYMORPH) ? EC_MUTAGENIC :
+ (flavour == BEAM_CHAOS
+ || flavour == BEAM_RANDOM) ? EC_RANDOM :
(flavour == BEAM_TELEPORT
|| flavour == BEAM_BANISH
|| flavour == BEAM_BLINK) ? EC_WARP
@@ -201,6 +205,7 @@ static void _beam_set_default_values(bolt &beam, int power)
beam.damage = dice_def( 1, 0 ); // default for "0" beams (I think)
beam.type = 0; // default for "0" beams
beam.flavour = BEAM_MAGIC; // default for "0" beams
+ beam.real_flavour = BEAM_MAGIC; // default for "0" beams
beam.ench_power = power;
beam.obvious_effect = false;
beam.is_beam = false; // default for all beams.
@@ -1348,6 +1353,7 @@ static void _zappy( zap_type z_type, int power, bolt &pbolt )
// Fill
pbolt.name = zinfo->name;
pbolt.flavour = zinfo->flavour;
+ pbolt.real_flavour = zinfo->flavour;
pbolt.colour = zinfo->colour;
pbolt.type = dchar_glyph(zinfo->glyph);
pbolt.obvious_effect = zinfo->always_obvious;
@@ -1405,6 +1411,33 @@ static bool _affect_mon_in_wall(bolt &pbolt, item_def *item,
return (false);
}
+static beam_type _chaos_beam_flavour()
+{
+ const beam_type flavour = static_cast<beam_type>(
+ random_choose_weighted(
+ 10, BEAM_FIRE,
+ 10, BEAM_COLD,
+ 10, BEAM_ELECTRICITY,
+ 10, BEAM_POISON,
+ 10, BEAM_NEG,
+ 10, BEAM_ACID,
+ 10, BEAM_HELLFIRE,
+ 10, BEAM_NAPALM,
+ 10, BEAM_HELLFROST,
+ 10, BEAM_SLOW,
+ 10, BEAM_HASTE,
+ 10, BEAM_HEALING,
+ 10, BEAM_PARALYSIS,
+ 10, BEAM_CONFUSION,
+ 10, BEAM_INVISIBILITY,
+ 10, BEAM_POLYMORPH,
+ 10, BEAM_BANISH,
+ 10, BEAM_DISINTEGRATION,
+ 0 ));
+
+ return (flavour);
+}
+
/*
* Beam pseudo code:
*
@@ -1432,6 +1465,8 @@ static bool _affect_mon_in_wall(bolt &pbolt, item_def *item,
void fire_beam(bolt &pbolt)
{
+ pbolt.real_flavour = pbolt.flavour;
+
const int reflections = pbolt.reflections;
if (reflections == 0)
{
@@ -1536,6 +1571,13 @@ void fire_beam(bolt &pbolt)
{
testpos = ray.pos();
+ // Random beams: randomize before affect().
+ if (pbolt.real_flavour == BEAM_RANDOM)
+ pbolt.flavour = static_cast<beam_type>(
+ random_range(BEAM_FIRE, BEAM_ACID));
+ else if (pbolt.real_flavour == BEAM_CHAOS)
+ pbolt.flavour = _chaos_beam_flavour();
+
// Shooting through clouds affects accuracy.
if (env.cgrid(testpos) != EMPTY_CLOUD)
pbolt.hit = std::max(pbolt.hit - 2, 0);
@@ -1628,14 +1670,6 @@ void fire_beam(bolt &pbolt)
// hit and the beam is type 'term on target'.
if (!beamTerminate || !pbolt.is_explosion)
{
- // Random beams: randomize before affect().
- bool random_beam = false;
- if (pbolt.flavour == BEAM_RANDOM)
- {
- random_beam = true;
- pbolt.flavour = static_cast<beam_type>(
- random_range(BEAM_FIRE, BEAM_ACID));
- }
if (!pbolt.affects_nothing)
{
@@ -1643,12 +1677,6 @@ void fire_beam(bolt &pbolt)
if (pbolt.reflections > reflections)
return;
}
-
- if (random_beam)
- {
- pbolt.flavour = BEAM_RANDOM;
- pbolt.effect_known = false;
- }
}
ASSERT(pbolt.reflections == reflections);
@@ -1667,8 +1695,13 @@ void fire_beam(bolt &pbolt)
if (pbolt.aimed_at_feet)
beamTerminate = true;
- // Actually draw the beam/missile/whatever,
- // if the player can see the cell.
+ // Reset chaos beams so that it won't be considered an invisible
+ // enchantment beam for the purposes of animation.
+ if (pbolt.real_flavour == BEAM_CHAOS)
+ pbolt.flavour = pbolt.real_flavour;
+
+ // Actually draw the beam/missile/whatever, if the player can see
+ // the cell.
if (!pbolt.is_tracer && !pbolt.is_enchantment() && see_grid(testpos))
{
// We don't clean up the old position.
@@ -1696,7 +1729,8 @@ void fire_beam(bolt &pbolt)
#ifndef USE_TILE
cgotoxy(drawpos.x, drawpos.y);
put_colour_ch(
- pbolt.colour == BLACK ? random_colour() : pbolt.colour,
+ pbolt.colour == BLACK ? random_colour()
+ : element_colour(pbolt.colour),
pbolt.type );
#endif
// Get curses to update the screen so we can see the beam.
@@ -2663,6 +2697,13 @@ void mimic_alert(monsters *mimic)
static bool _isBouncy(bolt &beam, unsigned char gridtype)
{
+ if ( beam.real_flavour == BEAM_CHAOS
+ && grid_is_solid(static_cast<dungeon_feature_type>(gridtype))
+ && coinflip() )
+ {
+ return (true);
+ }
+
if (beam.is_enchantment())
return (false);
@@ -3378,7 +3419,7 @@ static void _affect_place_explosion_clouds(bolt &beam, const coord_def& p)
_whose_kill(beam) == KC_OTHER ? BEH_HOSTILE : BEH_FRIENDLY;
mons_place(
- mgen_data(MONS_FIRE_VORTEX, att, 2, p,
+ mgen_data(MONS_FIRE_VORTEX, att, 2, SPELL_FIRE_STORM, p,
MHITNOT, 0, god));
}
}
@@ -3616,6 +3657,8 @@ static void _reflect_beam(bolt &beam)
#endif
}
+ beam.flavour = beam.real_flavour;
+
fire_beam(beam);
}
@@ -3809,7 +3852,7 @@ static int _affect_player( bolt &beam, item_def *item, bool affect_items )
return (_range_used_on_hit(beam));
}
- _ench_animation( beam.flavour );
+ _ench_animation( beam.real_flavour );
// these colors are misapplied - see mons_ench_f2() {dlb}
switch (beam.flavour)
@@ -4404,7 +4447,7 @@ static int _affect_monster(bolt &beam, monsters *mon, item_def *item)
// Doing this here so that the player gets to see monsters
// "flicker and vanish" when turning invisible....
- _ench_animation( beam.flavour, mon );
+ _ench_animation( beam.real_flavour, mon );
// now do enchantment affect
mon_resist_type ench_result = _affect_monster_enchantment(beam, mon);
@@ -5184,6 +5227,8 @@ int explosion( bolt &beam, bool hole_in_the_middle,
bool explode_in_wall, bool stop_at_statues,
bool stop_at_walls, bool show_more, bool affect_items)
{
+ beam.real_flavour = beam.flavour;
+
if (in_bounds(beam.source) && beam.source != beam.target
&& (!explode_in_wall || stop_at_statues || stop_at_walls))
{
@@ -5398,23 +5443,20 @@ int explosion( bolt &beam, bool hole_in_the_middle,
static void _explosion_cell(bolt &beam, const coord_def& p, bool drawOnly,
bool affect_items)
{
- bool random_beam = false;
coord_def realpos = beam.target + p;
if (!drawOnly)
{
- // Random beams: randomize before affect().
- if (beam.flavour == BEAM_RANDOM)
- {
- random_beam = true;
+ // Random/chaos beams: randomize before affect().
+ if (beam.real_flavour == BEAM_RANDOM)
beam.flavour = static_cast<beam_type>(
random_range(BEAM_FIRE, BEAM_ACID) );
- }
+ else if (beam.real_flavour == BEAM_CHAOS)
+ beam.flavour = _chaos_beam_flavour();
affect(beam, realpos, NULL, affect_items);
- if (random_beam)
- beam.flavour = BEAM_RANDOM;
+ beam.flavour = beam.real_flavour;
}
// Early out for tracer.
@@ -5580,14 +5622,15 @@ static bool _nice_beam(monsters *mon, const bolt &beam)
// (extended from setup_mons_cast() and zapping() which act as limited ones).
bolt::bolt() : range(0), type('*'),
colour(BLACK),
- flavour(BEAM_MAGIC), drop_item(false), item(NULL), source(),
- target(), pos(), damage(0,0), ench_power(0), hit(0),
- thrower(KILL_MISC), ex_size(0), beam_source(MHITNOT), name(),
- is_beam(false), is_explosion(false), is_big_cloud(false),
- aimed_at_spot(false), aux_source(), affects_nothing(false),
- effect_known(true), obvious_effect(false), fr_count(0),
- foe_count(0), fr_power(0), foe_power(0), fr_hurt(0),
- foe_hurt(0), fr_helped(0), foe_helped(0),
+ flavour(BEAM_MAGIC), real_flavour(BEAM_MAGIC), drop_item(false),
+ item(NULL), source(), target(), pos(), damage(0,0),
+ ench_power(0), hit(0), thrower(KILL_MISC), ex_size(0),
+ beam_source(MHITNOT), name(), is_beam(false),
+ is_explosion(false), is_big_cloud(false), aimed_at_spot(false),
+ aux_source(), affects_nothing(false), effect_known(true),
+ obvious_effect(false),
+ fr_count(0), foe_count(0), fr_power(0), foe_power(0),
+ fr_hurt(0), foe_hurt(0), fr_helped(0),foe_helped(0),
dropped_item(false), item_pos(), item_index(NON_ITEM),
range_used(0), is_tracer(false), aimed_at_feet(false),
msg_generated(false), in_explosion_phase(false),
diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h
index 69d12c6051..c805611783 100644
--- a/crawl-ref/source/beam.h
+++ b/crawl-ref/source/beam.h
@@ -40,6 +40,9 @@ struct bolt
unsigned type; // missile gfx
int colour;
beam_type flavour;
+ beam_type real_flavour; // for random and chaos beams this
+ // will remain the same while flavour
+ // changes
bool drop_item; // should drop an item when done
item_def* item; // item to drop
coord_def source; // beam origin
diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc
index daed16067d..f664ccc5c3 100644
--- a/crawl-ref/source/cloud.cc
+++ b/crawl-ref/source/cloud.cc
@@ -411,6 +411,8 @@ cloud_type beam2cloud(beam_type flavour)
case BEAM_MIASMA:
case BEAM_POTION_MIASMA:
return CLOUD_MIASMA;
+ case BEAM_CHAOS:
+ return CLOUD_CHAOS;
case BEAM_RANDOM:
return CLOUD_RANDOM;
}
@@ -443,6 +445,8 @@ beam_type cloud2beam(cloud_type flavour)
return BEAM_STEAM;
case CLOUD_MIASMA:
return BEAM_MIASMA;
+ case CLOUD_CHAOS:
+ return BEAM_CHAOS;
case CLOUD_RANDOM:
return BEAM_RANDOM;
}
@@ -619,6 +623,7 @@ bool is_damaging_cloud(cloud_type type, bool temp)
// ... unless a Ring of Flames is up and it's a fire cloud.
if (temp && you.duration[DUR_FIRE_SHIELD])
return (false);
+ case CLOUD_CHAOS:
case CLOUD_COLD:
return (true);
@@ -682,6 +687,8 @@ std::string cloud_name(cloud_type type)
return "black smoke";
case CLOUD_MIST:
return "thin mist";
+ case CLOUD_CHAOS:
+ return "seething chaos";
default:
return "buggy goodness";
}
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index e8eaf0cf59..4523d77359 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -209,7 +209,7 @@ enum beam_type // beam[].flavour
BEAM_ICE,
BEAM_NUKE,
BEAM_RANDOM, // currently translates into FIRE..ACID
- // 24
+ BEAM_CHAOS,
// Enchantments
BEAM_FIRST_ENCHANTMENT = 25, // 25
@@ -411,6 +411,7 @@ enum cloud_type
CLOUD_STEAM,
CLOUD_MIASMA,
CLOUD_MIST,
+ CLOUD_CHAOS,
CLOUD_RANDOM = 98,
CLOUD_DEBUGGING = 99 // 99: used once as 'nonexistent cloud' {dlb}
};
@@ -3016,6 +3017,7 @@ enum zap_type
ZAP_PETRIFY,
ZAP_ENSLAVE_SOUL,
ZAP_HELLFROST,
+ ZAP_CHAOS,
NUM_ZAPS
};
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index fe7983ae6a..44d6910904 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1237,7 +1237,9 @@ public:
void init_experience();
- void mark_summoned(int longevity, bool mark_items_summoned );
+ void mark_summoned(int longevity, bool mark_items_summoned,
+ int summon_type = 0);
+ bool is_summoned(int* duration = NULL, int* summon_type = NULL) const;
bool has_action_energy() const;
void check_redraw(const coord_def &oldpos) const;
void apply_location_effects(const coord_def &oldpos);
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index bb053758d6..51250a0145 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -1748,140 +1748,6 @@ void _merge_ammo_in_inventory(int slot)
}
}
-std::string setup_chaos_ammo(bolt &pbolt, item_def ammo)
-{
- ASSERT(!is_artefact(ammo));
-
- const bool poisoned = (get_ammo_brand(ammo) == SPMSL_POISONED);
-
- // Don't choose BEAM_POISON or BEAM_HEALING if we have poisoned ammo.
- const int pois_weight = poisoned ? 0 : 10;
- const int heal_weight = poisoned ? 0 : 10;
-
- const beam_type flavour = static_cast<beam_type>(
- random_choose_weighted( pois_weight, BEAM_POISON,
- heal_weight, BEAM_HEALING,
-
- 10, BEAM_FIRE,
- 10, BEAM_COLD,
- 10, BEAM_ELECTRICITY,
- 10, BEAM_NEG,
- 10, BEAM_ACID,
- 10, BEAM_HELLFIRE,
- 10, BEAM_NAPALM,
- 10, BEAM_HELLFROST,
- 10, BEAM_SLOW,
- 10, BEAM_HASTE,
- 10, BEAM_PARALYSIS,
- 10, BEAM_CONFUSION,
- 10, BEAM_INVISIBILITY,
- 10, BEAM_POLYMORPH,
- 10, BEAM_BANISH,
- 10, BEAM_DISINTEGRATION,
- 0 ));
-
- std::string name;
- int colour;
-
- if (poisoned)
- name = "poison ";
-
- switch(flavour)
- {
- case BEAM_POISON:
- name += "poison";
- colour = EC_POISON;
- break;
- case BEAM_HEALING:
- name += "healing";
- colour = EC_HEAL;
- break;
- case BEAM_FIRE:
- name += "flame";
- colour = EC_FIRE;
- break;
- case BEAM_COLD:
- name += "frost";
- colour = EC_ICE;
- break;
- case BEAM_ELECTRICITY:
- name += "lightning";
- colour = EC_ELECTRICITY;
- break;
- case BEAM_NEG:
- name += "negative energy";
- colour = EC_NECRO;
- break;
- case BEAM_ACID:
- name += "acid";
- colour = YELLOW;
- break;
- case BEAM_HELLFIRE:
- name += "hellfire";
- colour = EC_FIRE;
- break;
- case BEAM_NAPALM:
- name += "sticky fire";
- colour = EC_FIRE;
- break;
- case BEAM_HELLFROST:
- name += "hellfrost";
- colour = EC_ICE;
- break;
- case BEAM_SLOW:
- name += "slowing";
- colour = EC_ENCHANT;
- break;
- case BEAM_HASTE:
- name += "hasting";
- colour = EC_ENCHANT;
- break;
- case BEAM_PARALYSIS:
- name += "paralysis";
- colour = EC_ENCHANT;
- break;
- case BEAM_CONFUSION:
- name += "confusion";
- colour = EC_ENCHANT;
- break;
- case BEAM_INVISIBILITY:
- name += "invisibility";
- colour = EC_ENCHANT;
- break;
- case BEAM_POLYMORPH:
- name += "polymorphing";
- colour = EC_MUTAGENIC;
- break;
- case BEAM_BANISH:
- name += "banishment";
- colour = EC_WARP;
- break;
- case BEAM_DISINTEGRATION:
- name += "disintegration";
- colour = EC_DEATH;
- break;
- default:
- ASSERT(!"Invalid chaos ammo flavour.");
- break;
- }
-
- pbolt.name = "bolt of ";
- pbolt.name += name;
-
- pbolt.flavour = flavour;
- pbolt.colour = colour;
- pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT);
-
- // Get name for a plain arrow/bolt/dart/needle.
- ammo.special = 0;
-
- std::string ammo_name = ammo.name(DESC_NOCAP_A);
- ammo_name += " of ";
- ammo_name += name;
-
- return ammo_name;
-}
-
// throw_it - currently handles player throwing only. Monster
// throwing is handled in mstuff2:mons_throw()
// Note: If teleport is true, assume that pbolt is already set up,
@@ -2542,12 +2408,23 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
// Chaos overides flame and frost/ice.
if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS)
{
- ammo_name = setup_chaos_ammo(pbolt, item);
+ // Chaos can't be poisoned, since that might conflict with
+ // the random healing effect or overlap with the random
+ // poisoning effect.
+ poisoned = false;
// [dshaligram] Branded arrows are much stronger.
dice_mult = (dice_mult * 150) / 100;
pbolt.effect_known = false;
+
+ pbolt.flavour = BEAM_CHAOS;
+ pbolt.name = "bolt of chaos";
+
+ pbolt.colour = EC_RANDOM;
+ pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT);
+ pbolt.thrower = KILL_YOU_MISSILE;
+ pbolt.aux_source.clear();
}
else if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME)
&& ammo_brand != SPMSL_ICE && bow_brand != SPWPN_FROST)
@@ -2664,7 +2541,11 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
item_def ammo = item;
if (ammo.base_type == OBJ_MISSILES)
{
- if (pbolt.flavour == BEAM_FIRE)
+ if (pbolt.flavour == BEAM_CHAOS)
+ {
+ ammo.special = SPMSL_CHAOS;
+ }
+ else if (pbolt.flavour == BEAM_FIRE)
{
if (ammo.special != SPMSL_FLAME)
ammo.special = SPMSL_FLAME;
diff --git a/crawl-ref/source/item_use.h b/crawl-ref/source/item_use.h
index c6f5820b18..31009b522e 100644
--- a/crawl-ref/source/item_use.h
+++ b/crawl-ref/source/item_use.h
@@ -160,8 +160,6 @@ bool puton_item(int slot, bool prompt_finger = true);
bool enchant_weapon(enchant_stat_type which_stat, bool quiet, item_def &wpn);
bool enchant_armour(int &ac_change, bool quiet, item_def &arm);
-std::string setup_chaos_ammo(bolt &pbolt, item_def item);
-
bool throw_it(bolt &pbolt, int throw_2, bool teleport = false,
int acc_bonus = 0, dist *target = NULL);
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 8421a7eb0a..88eeeabbd6 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -2316,9 +2316,53 @@ 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)
+bool mons_is_summoned(const monsters *m, int *duration, int *summon_type)
{
- return (m->has_ench(ENCH_ABJ));
+ const mon_enchant abj = m->get_ench(ENCH_ABJ);
+ if (abj.ench == ENCH_NONE)
+ {
+ if (duration != NULL)
+ *duration = -1;
+ if (summon_type != NULL)
+ *summon_type = 0;
+
+ return (false);
+ }
+ if (duration != NULL)
+ *duration = abj.duration;
+
+ const mon_enchant summ = m->get_ench(ENCH_SUMMON);
+ if (summ.ench == ENCH_NONE)
+ {
+ if (summon_type != NULL)
+ *summon_type = 0;
+
+ return (true);
+ }
+ if (summon_type != NULL)
+ *summon_type = summ.degree;
+
+ switch(summ.degree)
+ {
+ // Temporarily dancing weapons are really there.
+ case SPELL_TUKIMAS_DANCE:
+
+ // A corpse/skeleton which was temporarily animated.
+ case SPELL_ANIMATE_DEAD:
+ case SPELL_ANIMATE_SKELETON:
+
+ // Fire vortices are made from real fire.
+ case SPELL_FIRE_STORM:
+
+ // Clones aren't really summoned (though their equipment might be).
+ case MON_SUMM_CLONE:
+
+ // Some object which was animated, and thus not really summoned.
+ case MON_SUMM_ANIMATE:
+ return (false);
+ }
+
+ return (true);
}
bool mons_is_shapeshifter(const monsters *m)
@@ -6619,9 +6663,12 @@ void monsters::apply_enchantment(const mon_enchant &me)
}
}
-void monsters::mark_summoned(int longevity, bool mark_items)
+void monsters::mark_summoned(int longevity, bool mark_items, int summon_type)
{
add_ench( mon_enchant(ENCH_ABJ, longevity) );
+ if (summon_type != 0)
+ add_ench( mon_enchant(ENCH_SUMMON, summon_type, KC_OTHER, INT_MAX) );
+
if (mark_items)
{
for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
@@ -6633,6 +6680,11 @@ void monsters::mark_summoned(int longevity, bool mark_items)
}
}
+bool monsters::is_summoned(int* duration, int* summon_type) const
+{
+ return mons_is_summoned(this, duration, summon_type);
+}
+
void monsters::apply_enchantments()
{
if (enchantments.empty())
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index b7536dee3f..4360ea4553 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -85,6 +85,21 @@ enum mon_attack_flavour
AF_STEAL_FOOD
};
+// Non-spell "summoning" types to give to monsters::mark_summoned(), or as
+// the fourth paramater of mgen_data's second constructor.
+//
+// Negative values since spells are non-negative.
+enum mon_summon_type
+{
+ MON_SUMM_CLONE = -10000, // Cloned from another monster
+ MON_SUMM_ANIMATE, // Item/feature/substance which was animated
+ MON_SUMM_CHAOS, // Was made from pure chaos
+ MON_SUMM_MISCAST, // Spell miscast
+ MON_SUMM_ZOT, // Zot trap
+ MON_SUMM_WRATH, // Divine wrath
+ MON_SUMM_AID // Divine aid
+};
+
// properties of the monster class (other than resists/vulnerabilities)
enum mons_class_flags
{
@@ -547,7 +562,8 @@ bool mons_is_demon( int mc );
bool mons_class_wields_two_weapons(int mc);
bool mons_wields_two_weapons(const monsters *m);
bool mons_self_destructs(const monsters *m);
-bool mons_is_summoned(const monsters *m);
+bool mons_is_summoned(const monsters *m, int* duration = NULL,
+ int *summon_info = NULL);
bool mons_is_shapeshifter(const monsters *m);
// last updated 12may2000 {dlb}
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 2bb70188b6..dc3d6f7af2 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -947,7 +947,8 @@ static int _place_monster_aux( const mgen_data &mg,
// dur should always be 1-6 for monsters that can be abjured.
if (mg.abjuration_duration >= 1 && mg.abjuration_duration <= 6)
- menv[id].mark_summoned( mg.abjuration_duration, true );
+ menv[id].mark_summoned( mg.abjuration_duration, true,
+ mg.summon_type );
menv[id].foe = mg.foe;
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index 4ddd2d1a21..2b4529e59f 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -127,6 +127,11 @@ struct mgen_data
// that aren't summoned.
int abjuration_duration;
+ // For summoned monsters this is their type of summoning, either the
+ // spell which summoned them or one of the values of the enumeration
+ // mon_summon_type in mon-util.h
+ int summon_type;
+
// Where the monster will be created.
coord_def pos;
@@ -189,10 +194,33 @@ struct mgen_data
level_area_type ltype = you.level_type)
: cls(mt), base_type(base), behaviour(beh),
- abjuration_duration(abj), pos(p), foe(mfoe), flags(monflags),
- god(which_god), number(monnumber), colour(moncolour),
+ abjuration_duration(abj), summon_type(0), pos(p), foe(mfoe),
+ flags(monflags), god(which_god), number(monnumber), colour(moncolour),
+ power(monpower), proximity(prox), level_type(ltype), map_mask(0)
+ {
+ }
+
+ mgen_data(monster_type mt,
+ beh_type beh,
+ int abj,
+ int st,
+ const coord_def &p = coord_def(-1, -1),
+ unsigned short mfoe = MHITNOT,
+ unsigned monflags = 0,
+ god_type which_god = GOD_NO_GOD,
+ monster_type base = MONS_PROGRAM_BUG,
+ int monnumber = 0,
+ int moncolour = BLACK,
+ int monpower = you.your_level,
+ proximity_type prox = PROX_ANYWHERE,
+ level_area_type ltype = you.level_type)
+
+ : cls(mt), base_type(base), behaviour(beh),
+ abjuration_duration(abj), summon_type(st), pos(p), foe(mfoe),
+ flags(monflags), god(which_god), number(monnumber), colour(moncolour),
power(monpower), proximity(prox), level_type(ltype), map_mask(0)
{
+ ASSERT(summon_type == 0 || (abj >= 1 && abj <= 6));
}
bool permit_bands() const { return (flags & MG_PERMIT_BANDS); }
@@ -217,9 +245,10 @@ struct mgen_data
int abj_deg = 0,
unsigned flags = 0,
bool alert = false,
- god_type god = GOD_NO_GOD)
+ god_type god = GOD_NO_GOD,
+ int summon_type = 0)
{
- return mgen_data(what, BEH_HOSTILE, abj_deg, where,
+ return mgen_data(what, BEH_HOSTILE, abj_deg, summon_type, where,
alert ? MHITYOU : MHITNOT,
flags, god);
}
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index a9cc692af0..e884628f9a 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -308,9 +308,23 @@ void monster_drop_ething(monsters *monster, bool mark_item_origins,
mprf(MSGCH_SOUND, grid_item_destruction_message(grd(monster->pos())));
}
-static void _place_monster_corpse(const monsters *monster)
+static void _place_monster_corpse(const monsters *monster, bool silent,
+ int summon_type)
{
- int corpse_class = mons_species(monster->type);
+ bool force = false;
+ int corpse_class = mons_species(monster->type);
+
+ // If this was a corpse that was temporarily animated then turn the
+ // monster back into a corpse.
+ if (mons_class_is_zombified(monster->type)
+ && (summon_type == SPELL_ANIMATE_DEAD
+ || summon_type == SPELL_ANIMATE_SKELETON
+ || summon_type == MON_SUMM_ANIMATE))
+ {
+ force = true;
+ corpse_class = mons_zombie_base(monster);
+ }
+
if (corpse_class == MONS_DRACONIAN)
corpse_class = draco_subspecies(monster);
@@ -321,7 +335,7 @@ static void _place_monster_corpse(const monsters *monster)
// Doesn't leave a corpse.
if (mons_weight(corpse_class) == 0 || mons_enslaved_body_and_soul(monster)
- || coinflip())
+ || (!force && coinflip()))
{
return;
}
@@ -355,7 +369,15 @@ static void _place_monster_corpse(const monsters *monster)
move_item_to_grid( &o, monster->pos() );
if (see_grid(monster->pos()))
{
- const bool poison = (mons_corpse_effect(monster->type) == CE_POISONOUS
+ if (force && !silent)
+ {
+ if (you.can_see(monster))
+ simple_monster_message(monster, " turns back into a corpse!");
+ else
+ mprf("%s appears out of nowhere!",
+ mitm[o].name(DESC_CAP_A).c_str());
+ }
+ const bool poison = (mons_corpse_effect(corpse_class) == CE_POISONOUS
&& player_res_poison() <= 0);
tutorial_dissection_reminder(!poison);
}
@@ -864,6 +886,76 @@ static void _spore_goes_pop(monsters *monster, killer_type killer,
mgrd(monster->pos()) = monster_index(monster);
}
+void _monster_die_cloud(const monsters* monster, bool corpse, bool silent,
+ bool summoned, int summon_type)
+{
+ // Chaos spawn always leave behind a cloud of chaos.
+ if (monster->type == MONS_CHAOS_SPAWN)
+ {
+ summoned = true;
+ corpse = false;
+ }
+
+ if (!summoned)
+ return;
+
+ std::string prefix;
+ std::string msg = " disappears in a puff of smoke!";
+ cloud_type cloud = random_smoke_type();
+ int dur = 1 + random2(3);
+
+ if (corpse)
+ {
+ if (mons_weight(mons_species(monster->type)) == 0)
+ return;
+
+ prefix = "'s corpse";
+ }
+
+ switch(summon_type)
+ {
+ case SPELL_SHADOW_CREATURES:
+ msg = " disolves into shadows!";
+ cloud = CLOUD_NONE;
+ break;
+
+ case MON_SUMM_CHAOS:
+ msg = " degenerates into a cloud of primal chaos!";
+ cloud = CLOUD_CHAOS;
+ break;
+
+ case MON_SUMM_WRATH:
+ case MON_SUMM_AID:
+ if (is_good_god(monster->god))
+ {
+ msg = " disolves into sparkling lights!";
+ cloud = CLOUD_NONE;
+ }
+ break;
+ }
+
+ if (monster->god == GOD_XOM && one_chance_in(10)
+ || cloud != CLOUD_NONE && monster->type == MONS_CHAOS_SPAWN)
+ {
+ msg = " degenerates into a cloud of primal chaos!";
+ cloud = CLOUD_CHAOS;
+ }
+
+ if (mons_is_holy(monster) && summon_type != SPELL_SHADOW_CREATURES
+ && summon_type != MON_SUMM_CHAOS)
+ {
+ msg = " disolves into sparkling lights!";
+ cloud = CLOUD_NONE;
+ }
+
+ if (!silent)
+ simple_monster_message(monster, (prefix + msg).c_str());
+
+ if (cloud != CLOUD_NONE)
+ place_cloud( cloud, monster->pos(), dur,
+ monster->kill_alignment() );
+}
+
void monster_die(monsters *monster, killer_type killer,
int killer_index, bool silent, bool wizard)
{
@@ -882,9 +974,11 @@ void monster_die(monsters *monster, killer_type killer,
if (mons_near(monster) || wizard)
remove_auto_exclude(monster);
+ int summon_type = 0;
+ const bool summoned = mons_is_summoned(monster, NULL, &summon_type);
const int monster_killed = monster_index(monster);
const bool hard_reset = testbits(monster->flags, MF_HARD_RESET);
- const bool gives_xp = !mons_is_summoned(monster)
+ const bool gives_xp = !summoned
&& !mons_enslaved_body_and_soul(monster);
const bool drop_items = !hard_reset && !mons_is_holy(monster);
@@ -1372,15 +1466,9 @@ void monster_die(monsters *monster, killer_type killer,
// Monster doesn't die, just goes back to wherever it came from
// This must only be called by monsters running out of time (or
// abjuration), because it uses the beam variables! Or does it???
- if (!silent)
- {
- simple_monster_message( monster,
- " disappears in a puff of smoke!" );
- }
-
- place_cloud( random_smoke_type(),
- monster->pos(), 1 + random2(3),
- monster->kill_alignment() );
+ if (!wizard)
+ _monster_die_cloud(monster, false, silent, summoned,
+ summon_type);
// KILL_RESET monsters no longer lose their whole inventory, only
// items they were generated with.
@@ -1462,23 +1550,10 @@ void monster_die(monsters *monster, killer_type killer,
curr_PlaceInfo += delta;
curr_PlaceInfo.assert_validity();
- if (monster->has_ench(ENCH_ABJ))
- {
- if (mons_weight(mons_species(monster->type)))
- {
- simple_monster_message(monster,
- "'s corpse disappears in a puff of smoke!");
-
- place_cloud( random_smoke_type(),
- monster->pos(), 1 + random2(3),
- monster->kill_alignment() );
- }
- }
- else
- {
+ _monster_die_cloud(monster, true, silent, summoned, summon_type);
+ if (!summoned)
// Have to add case for disintegration effect here? {dlb}
- _place_monster_corpse(monster);
- }
+ _place_monster_corpse(monster, silent, summon_type);
}
_fire_monster_death_event(monster, killer, killer_index);
@@ -1767,6 +1842,7 @@ bool monster_polymorph(monsters *monster, monster_type targetc,
mon_enchant neutral = monster->get_ench(ENCH_NEUTRAL);
mon_enchant shifter = monster->get_ench(ENCH_GLOWING_SHAPESHIFTER,
ENCH_SHAPESHIFTER);
+ mon_enchant summon = monster->get_ench(ENCH_SUMMON);
mon_enchant tp = monster->get_ench(ENCH_TP);
// Note: define_monster() will clear out all enchantments! -- bwr
@@ -1776,6 +1852,7 @@ bool monster_polymorph(monsters *monster, monster_type targetc,
monster->add_ench(charm);
monster->add_ench(neutral);
monster->add_ench(shifter);
+ monster->add_ench(summon);
monster->add_ench(tp);
monster->ench_countdown = old_ench_countdown;
@@ -1783,8 +1860,7 @@ bool monster_polymorph(monsters *monster, monster_type targetc,
if (mons_class_flag(monster->type, M_INVIS))
monster->add_ench(ENCH_INVIS);
- if (!player_messaged && mons_near(monster)
- && player_monster_visible(monster))
+ if (!player_messaged && you.can_see(monster))
{
mprf("%s appears out of thin air!", monster->name(DESC_CAP_A).c_str());
player_messaged = true;
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 76ab701b82..0c6a7a269e 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -203,6 +203,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
{
create_monster(
mgen_data(RANDOM_MONSTER, SAME_ATTITUDE(monster), 5,
+ SPELL_SHADOW_CREATURES,
monster->pos(), monster->foe));
}
return;
@@ -931,9 +932,9 @@ bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used)
// fire/ice and incorrect ammo. They now have the same restrictions
// as players.
- int bow_brand = SPWPN_NORMAL;
- const int ammo_brand = get_ammo_brand(item);
- const bool poison = (ammo_brand == SPMSL_POISONED);
+ int bow_brand = SPWPN_NORMAL;
+ const int ammo_brand = get_ammo_brand(item);
+ bool poison = (ammo_brand == SPMSL_POISONED);
if (projected == LRET_LAUNCHED)
{
@@ -1044,9 +1045,19 @@ bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used)
// Chaos overides flame and frost
if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS)
{
- (void) setup_chaos_ammo(pbolt, item);
- baseHit += 2;
+ // Chaos can't be poisoned, since that might conflict with
+ // the random healing effect or overlap with the random
+ // poisoning effect.
+ poison = false;
+
+ baseHit += 2;
exDamBonus += 6;
+
+ pbolt.flavour = BEAM_CHAOS;
+ pbolt.name = "bolt of chaos";
+
+ pbolt.colour = EC_RANDOM;
+ pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP);
}
// WEAPON or AMMO of FIRE
else if (bow_brand == SPWPN_FLAME && ammo_brand != SPMSL_ICE
@@ -1797,27 +1808,36 @@ static int _monster_abjure_square(const coord_def &pos,
if (!target->alive() || ((bool)wont_attack == mons_wont_attack(target)))
return (0);
- mon_enchant abj = target->get_ench(ENCH_ABJ);
- if (abj.ench == ENCH_NONE)
+ int duration;
+
+ if (!target->is_summoned(&duration))
return (0);
pow = std::max(20, fuzz_value(pow, 40, 25));
if (!actual)
- return (pow > 40 || pow >= abj.duration);
+ return (pow > 40 || pow >= duration);
// TSO and Trog's abjuration protection.
+ bool shielded = false;
if (you.religion == GOD_SHINING_ONE)
{
pow = pow * (30 - target->hit_dice) / 30;
- if (pow < abj.duration)
- simple_god_message(" protects your fellow warrior from evil magic!");
+ if (pow < duration)
+ {
+ simple_god_message(" protects your fellow warrior from evil "
+ "magic!");
+ shielded = true;
+ }
}
else if (you.religion == GOD_TROG)
{
pow = pow * 4 / 5;
- if (pow < abj.duration)
+ if (pow < duration)
+ {
simple_god_message(" shields your ally from puny magic!");
+ shielded = true;
+ }
}
else if (is_sanctuary(target->pos()))
{
@@ -1828,10 +1848,11 @@ static int _monster_abjure_square(const coord_def &pos,
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Abj: dur: %d, pow: %d, ndur: %d",
- abj.duration, pow, abj.duration - pow);
+ duration, pow, duration - pow);
#endif
- if (!target->lose_ench_duration(abj, pow))
+ mon_enchant abj = target->get_ench(ENCH_ABJ);
+ if (!target->lose_ench_duration(abj, pow) && !shielded)
simple_monster_message(target, " shudders.");
return (1);
@@ -2117,3 +2138,128 @@ void mons_clear_trapping_net(monsters *mon)
mon->del_ench(ENCH_HELD, true);
}
+
+bool mons_clonable(const monsters* mon, bool needs_adjacent)
+{
+ // No uniques, pandemonium lords or player ghosts. Also, figuring
+ // out the name for the clone of a named monster isn't worth it.
+ if (mons_is_unique(mon->type) || mon->is_named() || mon->ghost.get())
+ return (false);
+
+ if (needs_adjacent)
+ {
+ // Is there space for the clone?
+ bool square_found = false;
+ for (int i = 0; i < 8; i++)
+ {
+ const coord_def p = mon->pos() + Compass[i];
+
+ if (in_bounds(p) && p != you.pos() && mgrd(p) == NON_MONSTER
+ && monster_habitable_grid(mon, grd(p)))
+ {
+ square_found = true;
+ break;
+ }
+ }
+ if (!square_found)
+ return (false);
+ }
+
+ // Is the monster carrying an artefact?
+ for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
+ {
+ const int index = mon->inv[i];
+
+ if (index == NON_ITEM)
+ continue;
+
+ if (is_artefact(mitm[index]))
+ return (false);
+ }
+
+ return (true);
+}
+
+int clone_mons(const monsters* orig, bool quiet, bool* obvious,
+ coord_def pos)
+{
+ // Is there an open slot in menv?
+ int midx = NON_MONSTER;
+ for (int i = 0; i < MAX_MONSTERS; i++)
+ if (menv[i].type == -1)
+ {
+ midx = i;
+ break;
+ }
+
+ if (midx == NON_MONSTER)
+ return (NON_MONSTER);
+
+ if (!in_bounds(pos))
+ {
+ // Find an adjacent square.
+ int squares = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ const coord_def p = orig->pos() + Compass[i];
+
+ if (in_bounds(p) && p != you.pos() && mgrd(p) == NON_MONSTER
+ && monster_habitable_grid(orig, grd(p)))
+ {
+ if (one_chance_in(++squares))
+ pos = p;
+ }
+ }
+ if (squares == 0)
+ return (NON_MONSTER);
+ }
+
+ ASSERT(mgrd(pos) == NON_MONSTER && you.pos() != pos);
+
+ monsters &mon(menv[midx]);
+
+ mon = *orig;
+ mon.position = pos;
+ mgrd(pos) = midx;
+
+ // Duplicate objects, or unequip them if they can't be duplicated.
+ for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
+ {
+ const int old_index = orig->inv[i];
+
+ if (old_index == NON_ITEM)
+ continue;
+
+ const int new_index = get_item_slot(0);
+ if (new_index == NON_ITEM)
+ {
+ mon.unequip(mitm[old_index], i, 0, true);
+ mon.inv[i] = NON_ITEM;
+ continue;
+ }
+
+ mon.inv[i] = new_index;
+ mitm[new_index] = mitm[old_index];
+ }
+
+ bool _obvious;
+ if (obvious == NULL)
+ obvious = &_obvious;
+ *obvious = false;
+
+ if (you.can_see(orig) && you.can_see(&mon))
+ {
+ if (!quiet)
+ simple_monster_message(orig, " is duplicated!");
+ *obvious = true;
+ }
+
+ mark_interesting_monst(&mon, mon.behaviour);
+ if (you.can_see(&mon))
+ {
+ seen_monster(&mon);
+ viewwindow(true, false);
+ }
+
+ return (midx);
+}
diff --git a/crawl-ref/source/mstuff2.h b/crawl-ref/source/mstuff2.h
index d0f9a32744..d1ec4febdd 100644
--- a/crawl-ref/source/mstuff2.h
+++ b/crawl-ref/source/mstuff2.h
@@ -36,4 +36,8 @@ bool silver_statue_effects(monsters *mons);
bool moth_incite_monsters(const monsters *mon);
void mons_clear_trapping_net(monsters *mon);
+bool mons_clonable(const monsters* orig, bool needs_adjacent = true);
+int clone_mons(const monsters* orig, bool quiet = false,
+ bool* obvious = NULL, coord_def pos = coord_def(0, 0) );
+
#endif
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index dd1e0b7497..7353430c9a 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -1086,36 +1086,40 @@ void abjuration(int pow)
if (mons_wont_attack(monster))
continue;
- mon_enchant abj = monster->get_ench(ENCH_ABJ);
- if (abj.ench != ENCH_NONE)
+ int duration;
+ if (monster->is_summoned(&duration))
{
int sockage = std::max(fuzz_value(abjdur, 60, 30), 40);
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "%s abj: dur: %d, abj: %d",
- monster->name(DESC_PLAIN).c_str(), abj.duration, sockage);
+ monster->name(DESC_PLAIN).c_str(), duration, sockage);
#endif
+ bool shielded = false;
// TSO and Trog's abjuration protection.
if (mons_is_god_gift(monster, GOD_SHINING_ONE))
{
sockage = sockage * (30 - monster->hit_dice) / 45;
- if (sockage < abj.duration)
+ if (sockage < duration)
{
simple_god_message(" protects a fellow warrior from your evil magic!",
GOD_SHINING_ONE);
+ shielded = true;
}
}
else if (mons_is_god_gift(monster, GOD_TROG))
{
sockage = sockage * 8 / 15;
- if (sockage < abj.duration)
+ if (sockage < duration)
{
simple_god_message(" shields an ally from your puny magic!",
GOD_TROG);
+ shielded = true;
}
}
- if (!monster->lose_ench_duration(abj, sockage))
+ mon_enchant abj = monster->get_ench(ENCH_ABJ);
+ if (!monster->lose_ench_duration(abj, sockage) && !shielded)
simple_monster_message(monster, " shudders.");
}
}
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index 379ac587a4..f67085a98f 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -1624,8 +1624,8 @@ static bool _summon_holy_being_wrapper(int pow, god_type god, monster_type mon,
create_monster(
mgen_data(mon,
friendly ? BEH_FRIENDLY : BEH_HOSTILE,
- dur, you.pos(),
- friendly ? you.pet_target : MHITYOU,
+ dur, friendly ? MON_SUMM_AID : MON_SUMM_WRATH,
+ you.pos(), friendly ? you.pet_target : MHITYOU,
MG_FORCE_BEH, god));
if (monster == -1)
@@ -1709,7 +1709,7 @@ bool cast_tukimas_dance(int pow, god_type god,
create_monster(
mgen_data(MONS_DANCING_WEAPON,
friendly ? BEH_FRIENDLY : BEH_HOSTILE,
- dur, you.pos(),
+ dur, SPELL_TUKIMAS_DANCE, you.pos(),
friendly ? you.pet_target : MHITYOU,
0, god));
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index 2a796129b8..a63facdc81 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -546,7 +546,7 @@ bool cast_shadow_creatures(god_type god)
const int monster =
create_monster(
- mgen_data(RANDOM_MONSTER, BEH_FRIENDLY, 2,
+ mgen_data(RANDOM_MONSTER, BEH_FRIENDLY, 2, SPELL_SHADOW_CREATURES,
you.pos(), you.pet_target,
MG_FORCE_BEH, god), false);
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index b78045eea0..164a716382 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -2446,7 +2446,7 @@ void MiscastEffect::do_miscast()
{
severity = (pow * fail * (10 + pow) / 7 * WILD_MAGIC_NASTINESS) / 100;
-#if DEBUG_DIAGNOSTICS || DEBUG_MISCAT
+#if DEBUG_DIAGNOSTICS || DEBUG_MISCAST
mprf(MSGCH_DIAGNOSTICS, "'%s' miscast power: %d",
spell != SPELL_NO_SPELL ? spell_title(spell)
: spelltype_short_name(sp_type),
@@ -2468,7 +2468,7 @@ void MiscastEffect::do_miscast()
severity = 0;
}
-#if DEBUG_DIAGNOSTICS || DEBUG_MISCAT
+#if DEBUG_DIAGNOSTICS || DEBUG_MISCAST
mprf(MSGCH_DIAGNOSTICS, "Sptype: %s, severity: %d",
spelltype_short_name(sp_type), severity );
#endif
@@ -2715,6 +2715,15 @@ bool MiscastEffect::_create_monster(monster_type what, int abj_deg,
data.abjuration_duration = 6;
}
+ // If data.abjuration_duration == 0 then data.summon_type will simply
+ // be ignored.
+ if (you.penance[god] > 0)
+ data.summon_type = MON_SUMM_WRATH;
+ else if (source == ZOT_TRAP_MISCAST)
+ data.summon_type = MON_SUMM_ZOT;
+ else
+ data.summon_type = MON_SUMM_MISCAST;
+
return (create_monster(data) != -1);
}
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 45cfbb0a74..935db3a3ef 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -1532,6 +1532,10 @@ inline static void _update_cloud_grid(int cloudno)
which_colour = EC_MIST;
break;
+ case CLOUD_CHAOS:
+ which_colour = EC_RANDOM;
+ break;
+
default:
which_colour = LIGHTGREY;
break;
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index 54b797c3d5..dd75840a3f 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -742,7 +742,7 @@ static bool _xom_is_good(int sever)
summons[i] =
create_monster(
- mgen_data(monster, BEH_FRIENDLY, 3,
+ mgen_data(monster, BEH_FRIENDLY, 3, MON_SUMM_AID,
you.pos(), you.pet_target, MG_FORCE_BEH, GOD_XOM));
if (summons[i] != -1)
@@ -818,7 +818,7 @@ static bool _xom_is_good(int sever)
const int summons =
create_monster(
- mgen_data(mon, beha, 6,
+ mgen_data(mon, beha, 6, MON_SUMM_AID,
you.pos(), hitting, MG_FORCE_BEH, GOD_XOM));
if (summons != -1)
@@ -1153,7 +1153,8 @@ static bool _xom_is_bad(int sever)
if (create_monster(
mgen_data::hostile_at(
_xom_random_punishment_demon(sever),
- you.pos(), 4, 0, true, GOD_XOM)) != -1)
+ you.pos(), 4, 0, true, GOD_XOM,
+ MON_SUMM_WRATH)) != -1)
{
success = true;
}