summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-08 06:11:34 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-08 06:11:34 +0000
commit0a035731a014657ed31f567eb854033a1a62f0e4 (patch)
treea11451152c40e2f48966b6b1d3ea1114b2773321 /crawl-ref/source
parent5dc8d3bb786e86a7c4460f29277ef50468e3c9f8 (diff)
downloadcrawl-ref-0a035731a014657ed31f567eb854033a1a62f0e4.tar.gz
crawl-ref-0a035731a014657ed31f567eb854033a1a62f0e4.zip
Added BEAM_CHAOS and changed chaos launchers/ammo to use that. Currently only
chooses a different, random beam flavour (which undoudtedly needs to have their relative weights changed after playtesting) for each square it passes through, but in the future it might do things like bounce off walls at weird angles or animate weapons left laying on the ground. Added CLOUD_CHAOS, though it doesn't do anything yet. Monsters which are marked summoned or otherwise given ENCH_ABJ can also be marked with the type of summoning that happened, which is stored in the until-now-unused ENCH_SUMMON. This is useful for figuring out if a monster has ENCH_ABJ but isn't really summoned (like fire vortices created by Fire Storm or dancing weapons created by Tukima's Dance) so that they won't be affected by abjuration. It's also currently used to do a different "dissapears in a puff of smoke" messages for summoned monsters based on the summoning type, so that monsters summoned by Shadow Creature "dissolve into shadows" and don't leave behind any clouds, and temporary god gift monsters from good gods "dissolve into sparkling lights". In the future it might be used to do temporarily animated corpses, which turn back into a corpse when killed or when the animation runs out. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7778 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-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;
}