summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/beam.cc33
-rw-r--r--crawl-ref/source/cloud.cc135
-rw-r--r--crawl-ref/source/cloud.h10
-rw-r--r--crawl-ref/source/cmd-keys.h2
-rw-r--r--crawl-ref/source/cmd-name.h2
-rw-r--r--crawl-ref/source/command.cc1
-rw-r--r--crawl-ref/source/debug.cc183
-rw-r--r--crawl-ref/source/debug.h1
-rw-r--r--crawl-ref/source/decks.cc10
-rw-r--r--crawl-ref/source/directn.cc13
-rw-r--r--crawl-ref/source/effects.cc20
-rw-r--r--crawl-ref/source/enum.h4
-rw-r--r--crawl-ref/source/externs.h45
-rw-r--r--crawl-ref/source/fight.cc10
-rw-r--r--crawl-ref/source/hiscores.cc16
-rw-r--r--crawl-ref/source/it_use2.cc10
-rw-r--r--crawl-ref/source/it_use3.cc7
-rw-r--r--crawl-ref/source/item_use.cc9
-rw-r--r--crawl-ref/source/libutil.cc14
-rw-r--r--crawl-ref/source/luadgn.cc9
-rw-r--r--crawl-ref/source/mon-util.cc253
-rw-r--r--crawl-ref/source/mon-util.h3
-rw-r--r--crawl-ref/source/monstuff.cc125
-rw-r--r--crawl-ref/source/monstuff.h3
-rw-r--r--crawl-ref/source/mstuff2.cc55
-rw-r--r--crawl-ref/source/ouch.h3
-rw-r--r--crawl-ref/source/player.cc61
-rw-r--r--crawl-ref/source/religion.cc91
-rw-r--r--crawl-ref/source/religion.h4
-rw-r--r--crawl-ref/source/spells1.cc18
-rw-r--r--crawl-ref/source/spells1.h5
-rw-r--r--crawl-ref/source/spells2.cc2
-rw-r--r--crawl-ref/source/spells4.cc20
-rw-r--r--crawl-ref/source/spells4.h3
-rw-r--r--crawl-ref/source/spl-book.cc16
-rw-r--r--crawl-ref/source/spl-cast.cc1993
-rw-r--r--crawl-ref/source/spl-cast.h8
-rw-r--r--crawl-ref/source/spl-mis.h126
-rw-r--r--crawl-ref/source/spl-util.cc143
-rw-r--r--crawl-ref/source/spl-util.h8
-rw-r--r--crawl-ref/source/tags.cc6
-rw-r--r--crawl-ref/source/traps.cc6
-rw-r--r--crawl-ref/source/xom.cc15
43 files changed, 2572 insertions, 929 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 7580b544b9..24d3eb172f 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -2985,7 +2985,8 @@ static void _beam_explodes(bolt &beam, const coord_def& p)
// cloud producer -- POISON BLAST
if (beam.name == "blast of poison")
{
- big_cloud(CLOUD_POISON, _whose_kill(beam), p.x, p.y, 0, 7 + random2(5));
+ big_cloud(CLOUD_POISON, _whose_kill(beam), beam.killer(), p.x, p.y,
+ 0, 7 + random2(5));
return;
}
@@ -2993,13 +2994,13 @@ static void _beam_explodes(bolt &beam, const coord_def& p)
if (beam.name == "foul vapour")
{
cl_type = (beam.flavour == BEAM_MIASMA) ? CLOUD_MIASMA : CLOUD_STINK;
- big_cloud( cl_type, _whose_kill(beam), p.x, p.y, 0, 9 );
+ big_cloud( cl_type, _whose_kill(beam), beam.killer(), p.x, p.y, 0, 9 );
return;
}
if (beam.name == "freezing blast")
{
- big_cloud( CLOUD_COLD, _whose_kill(beam), p.x, p.y,
+ big_cloud( CLOUD_COLD, _whose_kill(beam), beam.killer(), p.x, p.y,
random_range(10, 15), 9 );
return;
}
@@ -3302,7 +3303,8 @@ static int _affect_wall(bolt &beam, const coord_def& p)
else if (player_can_smell())
_beam_mpr(MSGCH_PLAIN, "You smell burning wax.");
- place_cloud(CLOUD_FIRE, p, random2(10) + 15, _whose_kill(beam));
+ place_cloud(CLOUD_FIRE, p, random2(10) + 15, _whose_kill(beam),
+ beam.killer());
beam.obvious_effect = true;
@@ -3406,37 +3408,43 @@ static int _affect_place_clouds(bolt &beam, const coord_def& p)
// POISON BLAST
if (beam.name == "blast of poison")
- place_cloud( CLOUD_POISON, p, random2(4) + 2, _whose_kill(beam) );
+ place_cloud( CLOUD_POISON, p, random2(4) + 2, _whose_kill(beam),
+ beam.killer() );
// FIRE/COLD over water/lava
if (grd(p) == DNGN_LAVA && beam.flavour == BEAM_COLD
|| grid_is_watery(grd(p)) && _is_fiery(beam))
{
- place_cloud( CLOUD_STEAM, p, 2 + random2(5), _whose_kill(beam) );
+ place_cloud( CLOUD_STEAM, p, 2 + random2(5), _whose_kill(beam),
+ beam.killer() );
}
if (grid_is_watery(grd(p)) && beam.flavour == BEAM_COLD
&& beam.damage.num * beam.damage.size > 35)
{
place_cloud( CLOUD_COLD, p, beam.damage.num * beam.damage.size / 30 + 1,
- _whose_kill(beam) );
+ _whose_kill(beam), beam.killer() );
}
// GREAT BLAST OF COLD
if (beam.name == "great blast of cold")
- place_cloud( CLOUD_COLD, p, random2(5) + 3, _whose_kill(beam) );
+ place_cloud( CLOUD_COLD, p, random2(5) + 3, _whose_kill(beam),
+ beam.killer() );
// BALL OF STEAM
if (beam.name == "ball of steam")
- place_cloud( CLOUD_STEAM, p, random2(5) + 2, _whose_kill(beam) );
+ place_cloud( CLOUD_STEAM, p, random2(5) + 2, _whose_kill(beam),
+ beam.killer() );
if (beam.flavour == BEAM_MIASMA)
- place_cloud( CLOUD_MIASMA, p, random2(5) + 2, _whose_kill(beam) );
+ place_cloud( CLOUD_MIASMA, p, random2(5) + 2, _whose_kill(beam),
+ beam.killer() );
// POISON GAS
if (beam.name == "poison gas")
- place_cloud( CLOUD_POISON, p, random2(4) + 3, _whose_kill(beam) );
+ place_cloud( CLOUD_POISON, p, random2(4) + 3, _whose_kill(beam),
+ beam.killer() );
return (0);
}
@@ -5731,6 +5739,9 @@ killer_type bolt::killer() const
case KILL_MON_MISSILE:
return (KILL_MON_MISSILE);
+ case KILL_YOU_CONF:
+ return (KILL_YOU_CONF);
+
default:
return (KILL_MON_MISSILE);
}
diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc
index 2e5c912bb7..a0f5b180df 100644
--- a/crawl-ref/source/cloud.cc
+++ b/crawl-ref/source/cloud.cc
@@ -46,24 +46,47 @@ static unsigned char _actual_spread_rate(cloud_type type, int spread_rate)
}
}
+static bool _killer_whose_match(kill_category whose, killer_type killer)
+{
+ switch(whose)
+ {
+ case KC_YOU:
+ return (killer == KILL_YOU_MISSILE || killer == KILL_YOU_CONF);
+
+ case KC_FRIENDLY:
+ return (killer == KILL_MON_MISSILE || killer == KILL_YOU_CONF);
+
+ case KC_OTHER:
+ return (killer == KILL_MON_MISSILE || killer == KILL_MISC);
+
+ case KC_NCATEGORIES:
+ ASSERT(false);
+ }
+ return (false);
+}
+
static void _new_cloud( int cloud, cloud_type type, const coord_def& p,
- int decay, kill_category whose,
+ int decay, kill_category whose, killer_type killer,
unsigned char spread_rate )
{
ASSERT( env.cloud[ cloud ].type == CLOUD_NONE );
+ ASSERT(_killer_whose_match(whose, killer));
+
env.cloud[ cloud ].type = type;
env.cloud[ cloud ].decay = decay;
env.cloud[ cloud ].x = p.x;
env.cloud[ cloud ].y = p.y;
env.cloud[ cloud ].whose = whose;
+ env.cloud[ cloud ].killer = killer;
env.cloud[ cloud ].spread_rate = spread_rate;
env.cgrid(p) = cloud;
env.cloud_no++;
}
static void _place_new_cloud(cloud_type cltype, const coord_def& p, int decay,
- kill_category whose, int spread_rate)
+ kill_category whose, killer_type killer,
+ int spread_rate)
{
if (env.cloud_no >= MAX_CLOUDS)
return;
@@ -73,7 +96,7 @@ static void _place_new_cloud(cloud_type cltype, const coord_def& p, int decay,
{
if (env.cloud[ci].type == CLOUD_NONE) // i.e., is empty
{
- _new_cloud( ci, cltype, p, decay, whose, spread_rate );
+ _new_cloud( ci, cltype, p, decay, whose, killer, spread_rate );
break;
}
}
@@ -102,7 +125,7 @@ static int _spread_cloud(const cloud_struct &cloud)
if (newdecay >= cloud.decay)
newdecay = cloud.decay - 1;
- _place_new_cloud( cloud.type, *ai, newdecay, cloud.whose,
+ _place_new_cloud( cloud.type, *ai, newdecay, cloud.whose, cloud.killer,
cloud.spread_rate );
extra_decay += 8;
@@ -170,6 +193,7 @@ void delete_cloud( int cloud )
env.cloud[ cloud ].x = 0;
env.cloud[ cloud ].y = 0;
env.cloud[ cloud ].whose = KC_OTHER;
+ env.cloud[ cloud ].killer = KILL_NONE;
env.cloud[ cloud ].spread_rate = 0;
env.cgrid(cloud_pos) = EMPTY_CLOUD;
env.cloud_no--;
@@ -197,10 +221,30 @@ void move_cloud( int cloud, const coord_def& newpos )
void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
kill_category whose, int spread_rate )
{
+ check_place_cloud(cl_type, p, lifetime, whose,
+ cloud_struct::whose_to_killer(whose), spread_rate);
+}
+
+// Places a cloud with the given stats assuming one doesn't already
+// exist at that point.
+void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
+ killer_type killer, int spread_rate )
+{
+ check_place_cloud(cl_type, p, lifetime,
+ cloud_struct::killer_to_whose(killer), killer,
+ spread_rate);
+}
+
+// Places a cloud with the given stats assuming one doesn't already
+// exist at that point.
+void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
+ kill_category whose, killer_type killer,
+ int spread_rate )
+{
if (!in_bounds(p) || env.cgrid(p) != EMPTY_CLOUD)
return;
- place_cloud( cl_type, p, lifetime, whose, spread_rate );
+ place_cloud( cl_type, p, lifetime, whose, killer, spread_rate );
}
int steam_cloud_damage(const cloud_struct &cloud)
@@ -221,6 +265,26 @@ int steam_cloud_damage(const cloud_struct &cloud)
void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
kill_category whose, int _spread_rate)
{
+ place_cloud(cl_type, ctarget, cl_range, whose,
+ cloud_struct::whose_to_killer(whose), _spread_rate);
+}
+
+// Places a cloud with the given stats. May delete old clouds to
+// make way if there are too many on level. Will overwrite an old
+// cloud under some circumstances.
+void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
+ killer_type killer, int _spread_rate)
+{
+ place_cloud(cl_type, ctarget, cl_range,
+ cloud_struct::killer_to_whose(killer), killer, _spread_rate);
+}
+
+// Places a cloud with the given stats. May delete old clouds to
+// make way if there are too many on level. Will overwrite an old
+// cloud under some circumstances.
+void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
+ kill_category whose, killer_type killer, int _spread_rate)
+{
if (is_sanctuary(ctarget) && !is_harmless_cloud(cl_type))
return;
@@ -277,7 +341,7 @@ void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
if (cl_new != -1)
{
_new_cloud( cl_new, cl_type, ctarget, cl_range * 10,
- whose, spread_rate );
+ whose, killer, spread_rate );
}
else
{
@@ -287,7 +351,7 @@ void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
if (env.cloud[ci].type == CLOUD_NONE) // ie is empty
{
_new_cloud( ci, cl_type, ctarget, cl_range * 10,
- whose, spread_rate );
+ whose, killer, spread_rate );
break;
}
}
@@ -635,9 +699,62 @@ std::string cloud_name(cloud_type type)
////////////////////////////////////////////////////////////////////////
// cloud_struct
-killer_type cloud_struct::beam_thrower() const
+kill_category cloud_struct::killer_to_whose(killer_type killer)
{
- return (whose == KC_YOU ? KILL_YOU_MISSILE : KILL_MON_MISSILE);
+ switch(killer)
+ {
+ case KILL_YOU:
+ case KILL_YOU_MISSILE:
+ case KILL_YOU_CONF:
+ return (KC_YOU);
+
+ case KILL_MON:
+ case KILL_MON_MISSILE:
+ case KILL_MISC:
+ return (KC_OTHER);
+
+ default:
+ ASSERT(false);
+ }
+ return (KC_OTHER);
+}
+
+killer_type cloud_struct::whose_to_killer(kill_category whose)
+{
+ switch(whose)
+ {
+ case KC_YOU: return(KILL_YOU_MISSILE);
+ case KC_FRIENDLY: return(KILL_MON_MISSILE);
+ case KC_OTHER: return(KILL_MON_MISSILE);
+ case KC_NCATEGORIES: ASSERT(false);
+ }
+ return (KILL_NONE);
+}
+
+void cloud_struct::set_whose(kill_category _whose)
+{
+ whose = _whose;
+ killer = whose_to_killer(whose);
+}
+
+void cloud_struct::set_killer(killer_type _killer)
+{
+ killer = _killer;
+ whose = killer_to_whose(killer);
+
+ switch(killer)
+ {
+ case KILL_YOU:
+ killer = KILL_YOU_MISSILE;
+ break;
+
+ case KILL_MON:
+ killer = KILL_MON_MISSILE;
+ break;
+
+ default:
+ break;
+ }
}
//////////////////////////////////////////////////////////////////////////
// Fog machine stuff
diff --git a/crawl-ref/source/cloud.h b/crawl-ref/source/cloud.h
index b4e5d229bf..1485f3782c 100644
--- a/crawl-ref/source/cloud.h
+++ b/crawl-ref/source/cloud.h
@@ -42,8 +42,18 @@ void move_cloud( int cloud, const coord_def& newpos );
void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
kill_category whose, int spread_rate = -1 );
+void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
+ killer_type killer, int spread_rate = -1 );
+void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
+ kill_category whose, killer_type killer,
+ int spread_rate = -1 );
void place_cloud( cloud_type cl_type, const coord_def& ctarget,
int cl_range, kill_category whose, int spread_rate = -1 );
+void place_cloud( cloud_type cl_type, const coord_def& ctarget,
+ int cl_range, killer_type killer, int spread_rate = -1 );
+void place_cloud( cloud_type cl_type, const coord_def& ctarget,
+ int cl_range, kill_category whose, killer_type killer,
+ int spread_rate = -1 );
void manage_clouds(void);
diff --git a/crawl-ref/source/cmd-keys.h b/crawl-ref/source/cmd-keys.h
index 041daef752..b495e60414 100644
--- a/crawl-ref/source/cmd-keys.h
+++ b/crawl-ref/source/cmd-keys.h
@@ -129,6 +129,8 @@
{'g', CMD_TARGET_WIZARD_GIVE_ITEM},
{'m', CMD_TARGET_WIZARD_MOVE},
{'w', CMD_TARGET_WIZARD_PATHFIND},
+{'G', CMD_TARGET_WIZARD_GAIN_LEVEL},
+{'M', CMD_TARGET_WIZARD_MISCAST},
#endif
{'v', CMD_TARGET_DESCRIBE},
{'?', CMD_TARGET_HELP},
diff --git a/crawl-ref/source/cmd-name.h b/crawl-ref/source/cmd-name.h
index 5ed02439ba..5e4330deef 100644
--- a/crawl-ref/source/cmd-name.h
+++ b/crawl-ref/source/cmd-name.h
@@ -184,6 +184,8 @@
{CMD_TARGET_WIZARD_GIVE_ITEM, "CMD_TARGET_WIZARD_GIVE_ITEM"},
{CMD_TARGET_WIZARD_MOVE, "CMD_TARGET_WIZARD_MOVE"},
{CMD_TARGET_WIZARD_PATHFIND, "CMD_TARGET_WIZARD_PATHFIND"},
+{CMD_TARGET_WIZARD_GAIN_LEVEL, "CMD_TARGET_WIZARD_GAIN_LEVEL"},
+{CMD_TARGET_WIZARD_MISCAST, "CMD_TARGET_WIZARD_MISCAST"},
{CMD_TARGET_MOUSE_MOVE, "CMD_TARGET_MOUSE_MOVE"},
{CMD_TARGET_MOUSE_SELECT, "CMD_TARGET_MOUSE_SELECT"},
{CMD_TARGET_HELP, "CMD_TARGET_HELP"},
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index c3bb854955..796c7182aa 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -765,6 +765,7 @@ static const char *targeting_help_1 =
"<w>F</w>: cycle monster friendly/good neutral/neutral/hostile\n"
"<w>P</w>: apply divine blessing to monster\n"
"<w>m</w>: move monster or player\n"
+ "<w>M</w>: cause spell miscast for monster or player\n"
"<w>w</w>: calculate shortest path to any point on the map\n"
#endif
;
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index bc7b14a405..aea6851a9d 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -1,7 +1,7 @@
/*
* File: debug.cc
* Summary: Debug and wizard related functions.
- * Written by: Linley Henzell and Jesse Jones
+* Written by: Linley Henzell and Jesse Jones
*
* Modified for Crawl Reference by $Author$ on $Date$
*
@@ -89,6 +89,7 @@
#include "skills2.h"
#include "spl-book.h"
#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
@@ -4249,6 +4250,186 @@ void debug_pathfind(int mid)
mprf("-> #waypoints: %d", path.size());
}
}
+
+static void _miscast_screen_update()
+{
+ viewwindow(true, false);
+
+ you.redraw_status_flags =
+ REDRAW_LINE_1_MASK | REDRAW_LINE_2_MASK | REDRAW_LINE_3_MASK;
+ print_stats();
+
+#ifndef USE_TILE
+ update_monster_pane();
+#endif
+}
+
+void debug_miscast( int target_index )
+{
+ crawl_state.cancel_cmd_repeat();
+
+ actor* target;
+ if (target_index == NON_MONSTER)
+ target = dynamic_cast<actor*>(&you);
+ else
+ target = dynamic_cast<actor*>(&menv[target_index]);
+
+ if (!target->alive())
+ {
+ mpr("Can't make already dead target miscast.");
+ return;
+ }
+
+ char specs[100];
+ mpr( "Miscast which school or spell, by name? ", MSGCH_PROMPT );
+ if (cancelable_get_line(specs, sizeof specs) || !*specs)
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+
+ spell_type spell = spell_by_name(specs, true);
+ spschool_flag_type school = school_by_name(specs);
+
+ // Prefer exact matches for school name over partial matches for
+ // spell name.
+ if (school != SPTYP_NONE
+ && (strcasecmp(specs, spelltype_short_name(school)) == 0
+ || strcasecmp(specs, spelltype_long_name(school)) == 0))
+ {
+ spell = SPELL_NO_SPELL;
+ }
+
+ if (spell == SPELL_NO_SPELL && school == SPTYP_NONE)
+ {
+ mpr("No matching spell or spell school.");
+ return;
+ }
+ else if (spell != SPELL_NO_SPELL && school != SPTYP_NONE)
+ {
+ mprf("Ambiguous: can be spell '%s' or school '%s'.",
+ spell_title(spell), spelltype_short_name(school));
+ return;
+ }
+
+ int disciplines = 0;
+ if (spell != SPELL_NO_SPELL)
+ {
+ disciplines = get_spell_disciplines(spell);
+
+ if (disciplines == 0)
+ {
+ mprf("Spell '%s' has no disciplines.", spell_title(spell));
+ return;
+ }
+ }
+
+ if (school == SPTYP_HOLY || (disciplines & SPTYP_HOLY))
+ {
+ mpr("Can't miscast holy spells.");
+ return;
+ }
+
+ if (spell != SPELL_NO_SPELL)
+ mprf("Miscasting spell %s.", spell_title(spell));
+ else
+ mprf("Miscasting school %s.", spelltype_long_name(school));
+
+ if (spell != SPELL_NO_SPELL)
+ mpr( "Enter spell_power,spell_failure: ",
+ MSGCH_PROMPT );
+ else
+ mpr( "Enter miscast_level or spell_power,spell_failure: ",
+ MSGCH_PROMPT );
+
+ if (cancelable_get_line(specs, sizeof specs) || !*specs)
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+
+ int level = -1, pow = -1, fail = -1;
+
+ if (strchr(specs, ','))
+ {
+ std::vector<std::string> nums = split_string(",", specs);
+ pow = atoi(nums[0].c_str());
+ fail = atoi(nums[1].c_str());
+
+ if (pow <= 0 || fail <= 0)
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+ }
+ else
+ {
+ if (spell != SPELL_NO_SPELL)
+ {
+ mpr("Can only enter fixed miscast level for schools, not spells.");
+ return;
+ }
+
+ level = atoi(specs);
+ if (level < 0)
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+ else if (level > 3)
+ {
+ mpr("Miscast level can be at most 3.");
+ return;
+ }
+ }
+
+ // Handle repeats ourselves since miscasts are likely to interrupt
+ // command repetions, especially if the player is the target.
+ int repeats = _debug_prompt_for_int("Number of repitions? ", true);
+ if (repeats < 1)
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+
+ // Supress "nothing happens" message for monster miscasts which are
+ // only harmless messages, since a large number of those are missing
+ // monster messages.
+ nothing_happens_when_type nothing = NH_DEFAULT;
+ if (target_index != NON_MONSTER && level == 0)
+ nothing = NH_NEVER;
+
+ MiscastEffect *miscast;
+
+ if (spell != SPELL_NO_SPELL)
+ miscast = new MiscastEffect(target, target_index, spell, pow, fail,
+ "", nothing);
+ else
+ {
+ if (level != -1)
+ miscast = new MiscastEffect(target, target_index, school,
+ level, "wizard testing miscast",
+ nothing);
+ else
+ miscast = new MiscastEffect(target, target_index, school,
+ pow, fail, "wizard testing miscast",
+ nothing);
+ }
+ // Merely creating the miscast object causes one miscast effect to
+ // happen.
+ repeats--;
+ if (level != 0)
+ _miscast_screen_update();
+
+ while (target->alive() && repeats-- > 0)
+ {
+ miscast->do_miscast();
+ if (level != 0)
+ _miscast_screen_update();
+ }
+
+ delete miscast;
+}
#endif
#ifdef DEBUG_DIAGNOSTICS
diff --git a/crawl-ref/source/debug.h b/crawl-ref/source/debug.h
index ca73dcbbcd..1edf54f960 100644
--- a/crawl-ref/source/debug.h
+++ b/crawl-ref/source/debug.h
@@ -119,6 +119,7 @@ void wizard_give_monster_item(monsters* mon);
void wizard_move_player_or_monster(int x, int y);
void debug_make_monster_shout(monsters* mon);
void debug_pathfind(int mid);
+void debug_miscast( int target );
#ifdef DEBUG_DIAGNOSTICS
diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc
index 6f6983c276..46848623ef 100644
--- a/crawl-ref/source/decks.cc
+++ b/crawl-ref/source/decks.cc
@@ -44,6 +44,7 @@
#include "spells3.h"
#include "spells4.h"
#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
@@ -2737,6 +2738,10 @@ bool card_effect(card_type which_card, deck_rarity_type rarity,
bool rc = true;
const int power = _card_power(rarity);
+ const god_type god =
+ (crawl_state.is_god_acting()) ? crawl_state.which_god_acting()
+ : GOD_NO_GOD;
+
#ifdef DEBUG_DIAGNOSTICS
msg::streams(MSGCH_DIAGNOSTICS) << "Card power: " << power
<< ", rarity: " << static_cast<int>(rarity)
@@ -2844,8 +2849,9 @@ bool card_effect(card_type which_card, deck_rarity_type rarity,
case CARD_WILD_MAGIC:
// Yes, high power is bad here.
- miscast_effect( SPTYP_RANDOM, random2(power/15) + 5,
- random2(power), 0, "a card of wild magic" );
+ MiscastEffect( &you, god == GOD_NO_GOD ? NON_MONSTER : -god,
+ SPTYP_RANDOM, random2(power/15) + 5, random2(power),
+ "a card of wild magic" );
break;
case CARD_FAMINE:
diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc
index 8d62b42c81..3ec1dd79d9 100644
--- a/crawl-ref/source/directn.cc
+++ b/crawl-ref/source/directn.cc
@@ -1077,6 +1077,19 @@ void direction(dist& moves, targeting_type restricts,
debug_pathfind(mid);
break;
+
+ case CMD_TARGET_WIZARD_GAIN_LEVEL:
+ break;
+
+ case CMD_TARGET_WIZARD_MISCAST:
+ if (!you.wizard || !in_bounds(moves.tx, moves.ty))
+ break;
+ mid = mgrd[moves.tx][moves.ty];
+ if (mid == NON_MONSTER && you.pos() != moves.target())
+ break;
+
+ debug_miscast(mid);
+ break;
#endif
case CMD_TARGET_DESCRIBE:
full_describe_square(moves.target());
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index baaecf2767..03196f3c49 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -53,7 +53,7 @@
#include "spells2.h"
#include "spells3.h"
#include "spl-book.h"
-#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
@@ -404,10 +404,16 @@ void banished(dungeon_feature_type gate_type, const std::string &who)
}
else if (who == "drawing a card")
you.entry_cause = EC_SELF_RISKY;
- else if (who.find("miscast") != std::string::npos)
+ else if (who.find("you miscast") != std::string::npos)
you.entry_cause = EC_MISCAST;
else if (who == "wizard command")
you.entry_cause = EC_SELF_EXPLICIT;
+ else if (who.find("effects of Hell") != std::string::npos)
+ you.entry_cause = EC_ENVIRONMENT;
+ else if (who.find("Zot") != std::string::npos)
+ you.entry_cause = EC_TRAP;
+ else if (who.find("trap") != std::string::npos)
+ you.entry_cause = EC_TRAP;
else
you.entry_cause = EC_MONSTER;
@@ -2147,8 +2153,9 @@ static void _hell_effects()
else // 1 in 8 odds {dlb}
which_miscast = SPTYP_ENCHANTMENT;
- miscast_effect(which_miscast, 4 + random2(6), random2avg(97, 3),
- 100, "the effects of Hell");
+ MiscastEffect(&you, MISC_KNOWN_MISCAST, which_miscast,
+ 4 + random2(6), random2avg(97, 3),
+ "the effects of Hell");
}
else if (temp_rand > 7) // 10 in 27 odds {dlb}
{
@@ -2202,8 +2209,9 @@ static void _hell_effects()
}
else
{
- miscast_effect(which_miscast, 4 + random2(6),
- random2avg(97, 3), 100, "the effects of Hell");
+ MiscastEffect(&you, MISC_KNOWN_MISCAST, which_miscast,
+ 4 + random2(6), random2avg(97, 3),
+ "the effects of Hell");
}
}
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 92984e860c..44852ac7ee 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -619,6 +619,8 @@ enum command_type
CMD_TARGET_WIZARD_GIVE_ITEM,
CMD_TARGET_WIZARD_MOVE,
CMD_TARGET_WIZARD_PATHFIND,
+ CMD_TARGET_WIZARD_GAIN_LEVEL,
+ CMD_TARGET_WIZARD_MISCAST,
CMD_TARGET_MOUSE_MOVE,
CMD_TARGET_MOUSE_SELECT,
CMD_TARGET_HELP,
@@ -1428,6 +1430,8 @@ enum entry_cause_type
EC_GOD_RETRIBUTION,
EC_GOD_ACT, // Xom sending the player somewhere for amusement.
EC_MONSTER,
+ EC_TRAP, // Zot traps
+ EC_ENVIRONMENT, // Hell effects.
NUM_ENTRY_CAUSE_TYPES
};
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index c1734d0aa6..3edf66accc 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -134,9 +134,15 @@ public:
{
}
- virtual std::string name(description_level_type type) const = 0;
- virtual std::string pronoun(pronoun_type which_pronoun) const = 0;
+ virtual std::string name(description_level_type type,
+ bool force_visible = false) const = 0;
+ virtual std::string pronoun(pronoun_type which_pronoun,
+ bool force_visible = false) const = 0;
virtual std::string conj_verb(const std::string &verb) const = 0;
+ virtual std::string hand_name(bool plural,
+ bool *can_plural = NULL) const = 0;
+ virtual std::string foot_name(bool plural,
+ bool *can_plural = NULL) const = 0;
virtual bool fumbles_attack(bool verbose = true) = 0;
@@ -157,7 +163,7 @@ public:
virtual int hurt(const actor *attacker, int amount) = 0;
virtual void heal(int amount, bool max_too = false) = 0;
virtual void banish(const std::string &who = "") = 0;
- virtual void blink() = 0;
+ virtual void blink(bool allow_partial_control = true) = 0;
virtual void teleport(bool right_now = false, bool abyss_shift = false) = 0;
virtual void poison(actor *attacker, int amount = 1) = 0;
virtual bool sicken(int amount) = 0;
@@ -199,6 +205,7 @@ public:
virtual int res_poison() const = 0;
virtual int res_negative_energy() const = 0;
virtual int res_rotting() const = 0;
+ virtual int res_torment() const = 0;
virtual flight_type flight_mode() const = 0;
virtual bool is_levitating() const = 0;
@@ -834,9 +841,12 @@ public:
item_def *weapon(int which_attack = -1);
item_def *shield();
- std::string name(description_level_type type) const;
- std::string pronoun(pronoun_type pro) const;
+ std::string name(description_level_type type,
+ bool force_visible = false) const;
+ std::string pronoun(pronoun_type pro, bool force_visible = false) const;
std::string conj_verb(const std::string &verb) const;
+ std::string hand_name(bool plural, bool *can_plural = NULL) const;
+ std::string foot_name(bool plural, bool *can_plural = NULL) const;
bool fumbles_attack(bool verbose = true);
bool cannot_fight() const;
@@ -849,7 +859,7 @@ public:
bool can_safely_mutate() const;
bool mutate();
void banish(const std::string &who = "");
- void blink();
+ void blink(bool allow_partial_control = true);
void teleport(bool right_now = false, bool abyss_shift = false);
void drain_stat(int stat, int amount, actor* attacker);
@@ -881,6 +891,7 @@ public:
int res_poison() const;
int res_negative_energy() const;
int res_rotting() const;
+ int res_torment() const;
bool confusable() const;
bool slowable() const;
@@ -1067,6 +1078,8 @@ public:
// AI_SEE_MONSTER
public:
+ mon_attitude_type temp_attitude() const;
+
// Returns true if the monster is named with a proper name, or is
// a player ghost.
bool is_named() const;
@@ -1183,16 +1196,18 @@ public:
bool can_use_missile(const item_def &item) const;
- std::string name(description_level_type type) const;
- std::string name(description_level_type type, bool force_visible) const;
+ std::string name(description_level_type type,
+ bool force_visible = false) const;
// Base name of the monster, bypassing any mname setting. For an orc priest
// named Arbolt, name() will return "Arbolt", but base_name() will return
// "orc priest".
std::string base_name(description_level_type type,
bool force_visible) const;
- std::string pronoun(pronoun_type pro) const;
+ std::string pronoun(pronoun_type pro, bool force_visible = false) const;
std::string conj_verb(const std::string &verb) const;
+ std::string hand_name(bool plural, bool *can_plural = NULL) const;
+ std::string foot_name(bool plural, bool *can_plural = NULL) const;
bool fumbles_attack(bool verbose = true);
bool cannot_fight() const;
@@ -1219,6 +1234,7 @@ public:
int res_poison() const;
int res_negative_energy() const;
int res_rotting() const;
+ int res_torment() const;
flight_type flight_mode() const;
bool is_levitating() const;
@@ -1232,6 +1248,7 @@ public:
bool cannot_move() const;
bool cannot_act() const;
bool confused() const;
+ bool confused_by_you() const;
bool caught() const;
bool asleep() const;
bool backlit(bool check_haloed = true) const;
@@ -1253,7 +1270,7 @@ public:
void rot(actor *agent, int rotlevel, int immed_rot);
int hurt(const actor *agent, int amount);
void heal(int amount, bool max_too = false);
- void blink();
+ void blink(bool allow_partial_control = true);
void teleport(bool right_now = false, bool abyss_shift = false);
void put_to_sleep(int power = 0);
@@ -1314,8 +1331,14 @@ struct cloud_struct
int decay;
unsigned char spread_rate;
kill_category whose;
+ killer_type killer;
+
+ void set_whose(kill_category _whose);
+ void set_killer(killer_type _killer);
+
+ static kill_category killer_to_whose(killer_type killer);
+ static killer_type whose_to_killer(kill_category whose);
- killer_type beam_thrower() const;
coord_def pos() const { return coord_def(x,y); }
};
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index b2ea2259bf..8ae70f1a74 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -71,7 +71,7 @@
#include "spells1.h"
#include "spells3.h"
#include "spells4.h"
-#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "stuff.h"
#include "transfor.h"
@@ -498,12 +498,10 @@ void melee_attack::check_special_wield_effects()
break;
case SPWLD_WUCAD_MU:
- // XXX At some distant point in the future, allow
- // miscast_effect to operate on any actor.
- if (one_chance_in(9) && attacker->atype() == ACT_PLAYER)
+ if (one_chance_in(9))
{
- miscast_effect( SPTYP_DIVINATION, random2(9), random2(70), 100,
- "the Staff of Wucad Mu" );
+ MiscastEffect(attacker, MELEE_MISCAST, SPTYP_DIVINATION,
+ random2(9), random2(70), "the Staff of Wucad Mu");
}
break;
default:
diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc
index 6267202d22..a4af6be2b3 100644
--- a/crawl-ref/source/hiscores.cc
+++ b/crawl-ref/source/hiscores.cc
@@ -1629,8 +1629,12 @@ std::string scorefile_entry::death_description(death_desc_verbosity verbosity)
needs_damage = true;
break;
- case KILLED_BY_XOM: // only used for old Xom kills
- desc += terse? "xom" : "Killed for Xom's enjoyment";
+ case KILLED_BY_XOM:
+ if (terse)
+ desc += "xom";
+ else
+ desc += auxkilldata.empty() ? "Killed for Xom's enjoyment"
+ : auxkilldata;
needs_damage = true;
break;
@@ -1699,6 +1703,14 @@ std::string scorefile_entry::death_description(death_desc_verbosity verbosity)
desc += terse? "bleeding" : " bled to death";
break;
+ case KILLED_BY_DIVINE_WRATH:
+ if (terse)
+ desc += "divine wrath";
+ else
+ desc += auxkilldata.empty() ? "Divine wrath" : auxkilldata;
+ needs_damage = true;
+ break;
+
default:
desc += terse? "program bug" : "Nibbled to death by software bugs";
break;
diff --git a/crawl-ref/source/it_use2.cc b/crawl-ref/source/it_use2.cc
index ad53a89f49..542e9adbf1 100644
--- a/crawl-ref/source/it_use2.cc
+++ b/crawl-ref/source/it_use2.cc
@@ -38,7 +38,7 @@
#include "religion.h"
#include "skills2.h"
#include "spells2.h"
-#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "stuff.h"
#include "tutorial.h"
@@ -437,8 +437,8 @@ bool unwield_item(bool showMsgs)
case SPWPN_STAFF_OF_WUCAD_MU:
item.plus = 0;
item.plus2 = 0;
- miscast_effect( SPTYP_DIVINATION, 9, 90, 100,
- "the Staff of Wucad Mu" );
+ MiscastEffect( &you, WIELD_MISCAST, SPTYP_DIVINATION, 9, 90,
+ "the Staff of Wucad Mu" );
break;
default:
break;
@@ -502,8 +502,8 @@ bool unwield_item(bool showMsgs)
// if it's to be allowed as a player spell. -- bwr
// int effect = 9 - random2avg( you.skills[SK_TRANSLOCATIONS] * 2, 2 );
- miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100,
- "distortion unwield" );
+ MiscastEffect( &you, WIELD_MISCAST, SPTYP_TRANSLOCATION, 9, 90,
+ "distortion unwield" );
break;
// NOTE: When more are added here, *must* duplicate unwielding
diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc
index a4bdde12f1..6d085b389e 100644
--- a/crawl-ref/source/it_use3.cc
+++ b/crawl-ref/source/it_use3.cc
@@ -50,6 +50,7 @@
#include "spells3.h"
#include "spl-book.h"
#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
@@ -534,8 +535,10 @@ bool evoke_wielded()
if (one_chance_in(3))
{
- miscast_effect( SPTYP_DIVINATION, random2(9),
- random2(70), 100, "the Staff of Wucad Mu" );
+ // NH_NEVER prevents "nothing happens" messages.
+ MiscastEffect( &you, NON_MONSTER, SPTYP_DIVINATION,
+ random2(9), random2(70),
+ "the Staff of Wucad Mu", NH_NEVER );
}
break;
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index ee78a30170..31955957f9 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -72,6 +72,7 @@
#include "spells3.h"
#include "spl-book.h"
#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
@@ -738,8 +739,8 @@ void wield_effects(int item_wield_2, bool showMsgs)
break;
case SPWPN_STAFF_OF_WUCAD_MU:
- miscast_effect( SPTYP_DIVINATION, 9, 90, 100,
- "the Staff of Wucad Mu" );
+ MiscastEffect(&you, WIELD_MISCAST, SPTYP_DIVINATION, 9, 90,
+ "the Staff of Wucad Mu" );
you.special_wield = SPWLD_WUCAD_MU;
break;
}
@@ -3895,8 +3896,8 @@ static bool affix_weapon_enchantment()
mprf("%s twongs alarmingly.", itname.c_str());
// from unwield_item
- miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100,
- "distortion affixation" );
+ MiscastEffect( &you, NON_MONSTER, SPTYP_TRANSLOCATION, 9, 90,
+ "distortion affixation" );
success = false;
break;
diff --git a/crawl-ref/source/libutil.cc b/crawl-ref/source/libutil.cc
index 8d225b7cd3..7aa9b4ef12 100644
--- a/crawl-ref/source/libutil.cc
+++ b/crawl-ref/source/libutil.cc
@@ -339,10 +339,14 @@ std::string pluralise(const std::string &name,
// knife -> knives
return name.substr(0, name.length() - 2) + "ves";
}
- else if (ends_with(name, "elf") || ends_with(name, "olf")
- || ends_with(name, "arf"))
+ else if (ends_with(name, "ff"))
{
- // Elf, wolf, dwarf.
+ // staff -> staves
+ return name.substr(0, name.length() - 2) + "ves";
+ }
+ else if (ends_with(name, "f"))
+ {
+ // elf -> elves
return name.substr(0, name.length() - 1) + "ves";
}
else if (ends_with(name, "mage"))
@@ -373,10 +377,6 @@ std::string pluralise(const std::string &name,
// efreet -> efreeti. Not sure this is correct.
return name + "i";
}
- else if (ends_with(name, "staff"))
- {
- return name.substr(0, name.length() - 2) + "ves";
- }
return name + "s";
}
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index 0804d859c7..beab44ba13 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -1572,13 +1572,15 @@ static int lua_cloud_pow_max;
static int lua_cloud_pow_rolls;
static int make_a_lua_cloud(int x, int y, int garbage, int spread_rate,
- cloud_type ctype, kill_category whose)
+ cloud_type ctype, kill_category whose,
+ killer_type killer)
{
UNUSED( garbage );
+
const int pow = random_range(lua_cloud_pow_min,
lua_cloud_pow_max,
lua_cloud_pow_rolls);
- place_cloud( ctype, coord_def(x, y), pow, whose, spread_rate );
+ place_cloud( ctype, coord_def(x, y), pow, whose, killer, spread_rate );
return 1;
}
@@ -1663,7 +1665,8 @@ static int dgn_apply_area_cloud(lua_State *ls)
}
apply_area_cloud(make_a_lua_cloud, x, y, 0, size,
- ctype, kc, spread_rate);
+ ctype, kc, cloud_struct::whose_to_killer(kc),
+ spread_rate);
return (0);
}
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 2ee0dbe997..cc156fd9e0 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -2101,6 +2101,16 @@ size_type mons_size(const monsters *m)
return m->body_size();
}
+mon_attitude_type monsters::temp_attitude() const
+{
+ if (has_ench(ENCH_CHARM))
+ return ATT_FRIENDLY;
+ else if (has_ench(ENCH_NEUTRAL))
+ return ATT_NEUTRAL;
+ else
+ return attitude;
+}
+
bool mons_friendly(const monsters *m)
{
return (m->attitude == ATT_FRIENDLY || m->has_ench(ENCH_CHARM));
@@ -2681,7 +2691,8 @@ bool mons_has_ranged_attack( const monsters *mon )
// 3 : It sticks to her sword! (lower case possessive)
// ... as needed
-const char *mons_pronoun(monster_type mon_type, pronoun_type variant)
+const char *mons_pronoun(monster_type mon_type, pronoun_type variant,
+ bool visible)
{
gender_type gender = GENDER_NEUTER;
@@ -2711,6 +2722,9 @@ const char *mons_pronoun(monster_type mon_type, pronoun_type variant)
}
}
+ if (!visible)
+ gender = GENDER_NEUTER;
+
switch(variant)
{
case PRONOUN_CAP:
@@ -4309,11 +4323,6 @@ bool monsters::has_base_name() const
return (!mname.empty() && !ghost.get());
}
-std::string monsters::name(description_level_type desc) const
-{
- return this->name(desc, false);
-}
-
std::string monsters::name(description_level_type desc, bool force_vis) const
{
const bool possessive =
@@ -4340,9 +4349,10 @@ std::string monsters::base_name(description_level_type desc, bool force_vis)
}
}
-std::string monsters::pronoun(pronoun_type pro) const
+std::string monsters::pronoun(pronoun_type pro, bool force_visible) const
{
- return (mons_pronoun(static_cast<monster_type>(type), pro));
+ return (mons_pronoun(static_cast<monster_type>(type), pro,
+ force_visible || you.can_see(this)));
}
std::string monsters::conj_verb(const std::string &verb) const
@@ -4356,6 +4366,213 @@ std::string monsters::conj_verb(const std::string &verb) const
return (pluralise(verb));
}
+std::string monsters::hand_name(bool plural, bool *can_plural) const
+{
+ bool _can_plural;
+ if (can_plural == NULL)
+ can_plural = &_can_plural;
+ *can_plural = true;
+
+ std::string str;
+ char ch = mons_char(type);
+
+ switch(get_mon_shape(this))
+ {
+ case MON_SHAPE_CENTAUR:
+ case MON_SHAPE_NAGA:
+ // Defaults to "hand"
+ break;
+ case MON_SHAPE_HUMANOID:
+ case MON_SHAPE_HUMANOID_WINGED:
+ case MON_SHAPE_HUMANOID_TAILED:
+ case MON_SHAPE_HUMANOID_WINGED_TAILED:
+ if (ch == 'T' || ch == 'd' || ch == 'n' || mons_is_demon(type))
+ str = "claw";
+ break;
+
+ case MON_SHAPE_QUADRUPED:
+ case MON_SHAPE_QUADRUPED_TAILLESS:
+ case MON_SHAPE_QUADRUPED_WINGED:
+ case MON_SHAPE_ARACHNID:
+ if (type == MONS_SCORPION)
+ str = "pincer";
+ else
+ {
+ str = "front ";
+ return (str + foot_name(plural, can_plural));
+ }
+ break;
+
+ case MON_SHAPE_BLOB:
+ case MON_SHAPE_SNAKE:
+ case MON_SHAPE_FISH:
+ return foot_name(plural);
+
+ case MON_SHAPE_BAT:
+ str = "wing";
+ break;
+
+ case MON_SHAPE_INSECT:
+ case MON_SHAPE_INSECT_WINGED:
+ case MON_SHAPE_CENTIPEDE:
+ str = "antena";
+ break;
+
+ case MON_SHAPE_SNAIL:
+ str = "eye-stalk";
+ break;
+
+ case MON_SHAPE_PLANT:
+ str = "leaf";
+ break;
+
+ case MON_SHAPE_MISC:
+ if (ch == 'x' || ch == 'X')
+ {
+ str = "tentacle";
+ break;
+ }
+ // Deliberate fallthrough.
+ case MON_SHAPE_FUNGUS:
+ str = "body";
+ *can_plural = false;
+ break;
+
+ case MON_SHAPE_ORB:
+ switch(type)
+ {
+ case MONS_GIANT_SPORE:
+ str = "rhizome";
+ break;
+
+ case MONS_GIANT_EYEBALL:
+ case MONS_EYE_OF_DRAINING:
+ case MONS_SHINING_EYE:
+ case MONS_EYE_OF_DEVASTATION:
+ *can_plural = false;
+ // Deliberate fallthrough.
+ case MONS_GREAT_ORB_OF_EYES:
+ str = "pupil";
+ break;
+
+ case MONS_GIANT_ORANGE_BRAIN:
+ default:
+ str = "body";
+ can_plural = false;
+ break;
+ }
+ }
+
+ if (str.empty())
+ str = "hand";
+
+ if (plural && *can_plural)
+ str = pluralise(str);
+
+ return (str);
+}
+
+std::string monsters::foot_name(bool plural, bool *can_plural) const
+{
+ bool _can_plural;
+ if (can_plural == NULL)
+ can_plural = &_can_plural;
+ *can_plural = true;
+
+ std::string str;
+ char ch = mons_char(type);
+
+ switch(get_mon_shape(this))
+ {
+ case MON_SHAPE_INSECT:
+ case MON_SHAPE_INSECT_WINGED:
+ case MON_SHAPE_ARACHNID:
+ case MON_SHAPE_CENTIPEDE:
+ str = "leg";
+ break;
+
+ case MON_SHAPE_HUMANOID:
+ case MON_SHAPE_HUMANOID_WINGED:
+ case MON_SHAPE_HUMANOID_TAILED:
+ case MON_SHAPE_HUMANOID_WINGED_TAILED:
+ if (type == MONS_MINOTAUR)
+ str = "hoof";
+ else if (swimming() && (type == MONS_MERFOLK || type == MONS_MERMAID))
+ {
+ str = "tail";
+ *can_plural = false;
+ }
+ break;
+
+ case MON_SHAPE_CENTAUR:
+ str = "hoof";
+ break;
+
+ case MON_SHAPE_QUADRUPED:
+ case MON_SHAPE_QUADRUPED_TAILLESS:
+ case MON_SHAPE_QUADRUPED_WINGED:
+ if (ch == 'h')
+ str = "paw";
+ else if (ch == 'l' || ch == 'D')
+ str = "talon";
+ else if (type == MONS_YAK || type == MONS_DEATH_YAK)
+ str = "hoof";
+ else if (ch == 'H')
+ {
+ if (type == MONS_MANTICORE || type == MONS_SPHINX)
+ str = "paw";
+ else
+ str = "talon";
+ }
+ break;
+
+ case MON_SHAPE_BAT:
+ str = "claw";
+ break;
+
+ case MON_SHAPE_SNAKE:
+ case MON_SHAPE_FISH:
+ str = "tail";
+ *can_plural = false;
+ break;
+
+ case MON_SHAPE_PLANT:
+ str = "root";
+ break;
+
+ case MON_SHAPE_FUNGUS:
+ str = "stem";
+ *can_plural = false;
+ break;
+
+ case MON_SHAPE_BLOB:
+ str = "pseudopod";
+ break;
+
+ case MON_SHAPE_MISC:
+ if (ch == 'x' || ch == 'X')
+ {
+ str = "tentacle";
+ break;
+ }
+ // Deliberate fallthrough.
+ case MON_SHAPE_SNAIL:
+ case MON_SHAPE_NAGA:
+ case MON_SHAPE_ORB:
+ str = "underside";
+ *can_plural = false;
+ break;
+ }
+
+ if (str.empty())
+ return (plural ? "feet" : "foot");
+
+ if (plural && *can_plural)
+ str = pluralise(str);
+
+ return (str);
+}
+
int monsters::id() const
{
return (type);
@@ -4459,6 +4676,15 @@ bool monsters::confused() const
return (mons_is_confused(this));
}
+bool monsters::confused_by_you() const
+{
+ if (mons_class_flag(type, M_CONFUSED))
+ return false;
+
+ const mon_enchant me = get_ench(ENCH_CONFUSION);
+ return (me.ench == ENCH_CONFUSION && me.who == KC_YOU);
+}
+
bool monsters::paralysed() const
{
return (mons_is_paralysed(this));
@@ -4591,6 +4817,15 @@ int monsters::res_rotting() const
return (mons_holiness(this) == MH_NATURAL ? 0 : 1);
}
+int monsters::res_torment() const
+{
+ mon_holy_type holy = mons_holiness(this);
+ if (holy == MH_UNDEAD || holy == MH_DEMONIC || holy == MH_NONLIVING)
+ return (1);
+
+ return (0);
+}
+
flight_type monsters::flight_mode() const
{
return (mons_flies(this));
@@ -4631,7 +4866,7 @@ int monsters::skill(skill_type sk, bool) const
}
}
-void monsters::blink()
+void monsters::blink(bool)
{
monster_blink(this);
}
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index e4dd300dd9..aabc2142c7 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -669,7 +669,8 @@ bool mons_has_ranged_attack( const monsters *mon );
/* ***********************************************************************
* called from:
* *********************************************************************** */
-const char *mons_pronoun(monster_type mon_type, pronoun_type variant);
+const char *mons_pronoun(monster_type mon_type, pronoun_type variant,
+ bool visible = true);
// last updated 14mar2001 (gdl)
/* ***********************************************************************
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index f1aeaccf6e..2d4f98eae6 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -60,7 +60,7 @@
#include "player.h"
#include "randart.h"
#include "religion.h"
-#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "spells3.h"
#include "spells4.h"
@@ -696,12 +696,77 @@ static void _fire_monster_death_event(monsters *monster,
}
}
-void monster_die(monsters *monster, killer_type killer, int i, bool silent)
+static void _mummy_curse(monsters* monster, killer_type killer, int index)
+{
+ int pow;
+
+ switch(killer)
+ {
+ // Mummy killed by trap or something other than the player or
+ // another monster, so no curse.
+ case KILL_MISC:
+ // Mummy sent to the Abyss wasn't actually killed, so no curse.
+ case KILL_RESET:
+ case KILL_DISMISSED:
+ return;
+
+ default:
+ break;
+ }
+
+ switch(monster->type)
+ {
+ case MONS_MUMMY: pow = 1; break;
+ case MONS_GUARDIAN_MUMMY: pow = 3; break;
+ case MONS_MUMMY_PRIEST: pow = 8; break;
+ case MONS_GREATER_MUMMY: pow = 11; break;
+
+ default:
+ mpr("Unkown mummy type.", MSGCH_DIAGNOSTICS);
+ return;
+ }
+
+ // Killed by a Zot trap, a god, etc
+ if (index != NON_MONSTER && invalid_monster_index(killer))
+ return;
+
+ actor* target;
+ if (index == NON_MONSTER)
+ target = dynamic_cast<actor*>(&you);
+ else
+ {
+ // Mummies committing suicide don't cause a death curse.
+ if (index == (int) monster_index(monster))
+ return;
+ target = dynamic_cast<actor*>(&menv[index]);
+ }
+
+ // Mummy was killed by a giant spore or ball lightning?
+ if (!target->alive())
+ return;
+
+ if (monster->type == MONS_MUMMY && killer == NON_MONSTER)
+ curse_an_item(true);
+ else
+ {
+ if (index == NON_MONSTER)
+ mpr("You feel extremely nervous for a moment...",
+ MSGCH_MONSTER_SPELL);
+ else if (you.can_see(target))
+ mprf(MSGCH_MONSTER_SPELL, "A malignant arua surrounds %s.",
+ target->name(DESC_NOCAP_THE).c_str());
+ MiscastEffect(target, monster_index(monster), SPTYP_NECROMANCY,
+ pow, random2avg(88, 3), "a mummy death curse");
+ }
+}
+
+void monster_die(monsters *monster, killer_type killer,
+ int killer_index, bool silent)
{
if (monster->type == -1)
return;
- if (!silent && _monster_avoided_death(monster, killer, i))
+ if (!silent && _monster_avoided_death(monster, killer, killer_index))
return;
mons_clear_trapping_net(monster);
@@ -717,15 +782,14 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
bool drop_items = !hard_reset && !mons_is_holy(monster);
#ifdef DGL_MILESTONES
- _check_kill_milestone(monster, killer, i);
+ _check_kill_milestone(monster, killer, killer_index);
#endif
// Award experience for suicide if the suicide was caused by the
// player.
- if (MON_KILL(killer) && monster_killed == i)
+ if (MON_KILL(killer) && monster_killed == killer_index)
{
- const mon_enchant me = monster->get_ench(ENCH_CONFUSION);
- if (me.ench == ENCH_CONFUSION && me.who == KC_YOU)
+ if (monster->confused_by_you())
killer = KILL_YOU_CONF;
}
else if (MON_KILL(killer) && monster->has_ench(ENCH_CHARM))
@@ -781,7 +845,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
if (killer == KILL_YOU)
crawl_state.cancel_cmd_repeat();
- const bool pet_kill = _is_pet_kill(killer, i);
+ const bool pet_kill = _is_pet_kill(killer, killer_index);
if (monster->type == MONS_GIANT_SPORE
|| monster->type == MONS_BALL_LIGHTNING)
@@ -1020,10 +1084,11 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
&& pet_kill)
{
bool notice = false;
- const bool anon = (i == ANON_FRIENDLY_MONSTER);
+ const bool anon = (killer_index == ANON_FRIENDLY_MONSTER);
const mon_holy_type targ_holy = mons_holiness(monster),
- attacker_holy = anon ? MH_NATURAL : mons_holiness(&menv[i]);
+ attacker_holy = anon ? MH_NATURAL
+ : mons_holiness(&menv[killer_index]);
if (attacker_holy == MH_UNDEAD)
{
@@ -1034,7 +1099,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
// "slave", and I think it's okay that Yredelemnul
// ignores kills done by confused monsters as opposed
// to enslaved or friendly ones. (jpeg)
- if (mons_friendly(&menv[i]))
+ if (mons_friendly(&menv[killer_index]))
{
notice |=
did_god_conduct(DID_LIVING_KILLED_BY_UNDEAD_SLAVE,
@@ -1052,7 +1117,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
|| you.religion == GOD_VEHUMET
|| you.religion == GOD_MAKHLEB
|| you.religion == GOD_LUGONU
- || !anon && mons_is_god_gift(&menv[i]))
+ || !anon && mons_is_god_gift(&menv[killer_index]))
{
// Yes, we are splitting undead pets from the others
// as a way to focus Necromancy vs Summoning (ignoring
@@ -1114,9 +1179,9 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
&& mons_is_evil_or_unholy(monster)
&& !player_under_penance()
&& random2(you.piety) >= piety_breakpoint(0)
- && !invalid_monster_index(i))
+ && !invalid_monster_index(killer_index))
{
- monsters *mon = &menv[i];
+ monsters *mon = &menv[killer_index];
// Randomly bless the follower who killed.
if (!one_chance_in(3) && mon->alive()
@@ -1139,9 +1204,9 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
&& random2(you.piety) >= piety_breakpoint(2)
&& !player_under_penance()
&& !one_chance_in(3)
- && !invalid_monster_index(i))
+ && !invalid_monster_index(killer_index))
{
- bless_follower(&menv[i]);
+ bless_follower(&menv[killer_index]);
}
}
@@ -1221,25 +1286,9 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
}
else if (!mons_is_summoned(monster))
{
- if (monster->type == MONS_MUMMY)
+ if (mons_genus(monster->type) == MONS_MUMMY)
{
- if (YOU_KILL(killer) && killer != KILL_YOU_CONF)
- curse_an_item(true);
- }
- else if (monster->type == MONS_GUARDIAN_MUMMY
- || monster->type == MONS_GREATER_MUMMY
- || monster->type == MONS_MUMMY_PRIEST)
- {
- if (YOU_KILL(killer) && killer != KILL_YOU_CONF)
- {
- mpr("You feel extremely nervous for a moment...",
- MSGCH_MONSTER_SPELL);
-
- miscast_effect( SPTYP_NECROMANCY,
- 3 + (monster->type == MONS_GREATER_MUMMY) * 8
- + (monster->type == MONS_MUMMY_PRIEST) * 5,
- random2avg(88, 3), 100, "a mummy death curse" );
- }
+ _mummy_curse(monster, killer, killer_index);
}
}
@@ -1253,7 +1302,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
KC_OTHER;
unsigned int exp_gain = 0, avail_gain = 0;
- _give_adjusted_experience(monster, killer, pet_kill, i,
+ _give_adjusted_experience(monster, killer, pet_kill, killer_index,
&exp_gain, &avail_gain);
PlaceInfo& curr_PlaceInfo = you.get_place_info();
@@ -1288,7 +1337,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
}
}
- _fire_monster_death_event(monster, killer, i);
+ _fire_monster_death_event(monster, killer, killer_index);
const coord_def mwhere = monster->pos();
if (drop_items)
@@ -7504,7 +7553,7 @@ static void _mons_in_cloud(monsters *monster)
return;
beam.flavour = BEAM_CONFUSION;
- beam.thrower = cloud.beam_thrower();
+ beam.thrower = cloud.killer;
if (cloud.whose == KC_FRIENDLY)
beam.beam_source = ANON_FRIENDLY_MONSTER;
@@ -7608,7 +7657,7 @@ static void _mons_in_cloud(monsters *monster)
if (monster->hit_points < 1)
{
mon_enchant death_ench(ENCH_NONE, 0, cloud.whose);
- monster_die(monster, death_ench.killer(), death_ench.kill_agent());
+ monster_die(monster, cloud.killer, death_ench.kill_agent());
}
}
}
diff --git a/crawl-ref/source/monstuff.h b/crawl-ref/source/monstuff.h
index ab5eabbc14..eb3b90e846 100644
--- a/crawl-ref/source/monstuff.h
+++ b/crawl-ref/source/monstuff.h
@@ -89,7 +89,7 @@ bool monster_polymorph(monsters *monster, monster_type targetc,
* spells1 - spells2 - spells3 - spells4
* *********************************************************************** */
void monster_die(monsters *monster, killer_type killer,
- int i, bool silent = false);
+ int killer_index, bool silent = false);
void mons_check_pool(monsters *monster, killer_type killer = KILL_NONE,
int killnum = -1);
@@ -112,7 +112,6 @@ void behaviour_event(monsters *mon, int event_type, int src = MHITNOT,
* *********************************************************************** */
bool curse_an_item(bool decay_potions, bool quiet = false);
-
/* ***********************************************************************
* called from: fight
* *********************************************************************** */
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 1db8c63795..5c83c00577 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -44,7 +44,7 @@
#include "spells1.h"
#include "spells3.h"
#include "spells4.h"
-#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "stuff.h"
#include "traps.h"
@@ -59,8 +59,6 @@ void mons_trap(monsters *monster)
if (!is_trap_square(grd[monster->x][monster->y]))
return;
- int temp_rand = 0; // probability determination {dlb}
-
// single calculation permissible {dlb}
bool monsterNearby = mons_near(monster);
@@ -282,13 +280,19 @@ void mons_trap(monsters *monster)
// an "early return" - zot traps are *never* revealed - instead,
// enchantment messages serve as clues to the trap's presence: {dlb}
case TRAP_ZOT:
- if (monsterNearby)
+ if (mons_friendly(monster) || mons_good_neutral(monster))
+ {
+ MiscastEffect( monster, ZOT_TRAP_MISCAST, SPTYP_RANDOM,
+ 3, "the power of Zot" );
+ return; // early return
+ }
+ else if (monsterNearby)
{
if (one_chance_in(5))
{
mpr("The power of Zot is invoked against you!");
- miscast_effect( SPTYP_RANDOM, 10 + random2(30),
- 75 + random2(100), 0, "the power of Zot" );
+ MiscastEffect( &you, ZOT_TRAP_MISCAST, SPTYP_RANDOM,
+ 3, "the power of Zot" );
return; // early return {dlb}
}
@@ -303,30 +307,24 @@ void mons_trap(monsters *monster)
mpr("You hear a distant \"Zot\"!", MSGCH_SOUND);
}
- // Determine trap effects upon monster, based upon
- // whether it is naughty or nice to the player. {dlb}
-
- // NB: beem[].colour values are mislabeled as colours (?) -
- // cf. mons_ench_f2() [which are also mislabeled] {dlb}
- temp_rand = random2(16);
-
- beem.thrower = KILL_MON; // probably unnecessary
- beem.aux_source.clear();
-
- if (mons_friendly(monster))
+ // XXX: It seem that back when a beam's colour determined its
+ // flavour that Zot traps would heal, haste or make invisible
+ // hostile monsters. The code has been fixed to work but
+ // commented out.
+#if 0
+ if (!mons_friendly(monster) && !mons_good_neutral(monster))
{
- beem.colour = ((temp_rand < 3) ? CYAN : //paralyze - 3 in 16
- (temp_rand < 7) ? RED // confuse - 4 in 16
- : BLACK); // slow - 9 in 16
- }
- else
- {
- beem.colour = ((temp_rand < 3) ? BLUE : //haste - 3 in 16 {dlb}
- (temp_rand < 7) ? MAGENTA //invis - 4 in 16 {dlb}
- : GREEN); // heal - 9 in 16 {dlb}
+ int temp_rand = random2(16);
+
+ beem.thrower = KILL_MON; // probably unnecessary
+ beem.aux_source.clear();
+ beem.flavour = ((temp_rand < 3) ? BEAM_HASTE : // 3 in 16 {dlb}
+ (temp_rand < 7) ? BEAM_INVISIBILITY //4 in 16 {dlb}
+ : BEAM_HEALING); // 9 in 16 {dlb}
+ mons_ench_f2(monster, beem);
}
+#endif
- mons_ench_f2(monster, beem);
damage_taken = 0; // just to be certain {dlb}
break;
@@ -2454,7 +2452,8 @@ bool orange_statue_effects(monsters *mons)
{
mpr("A hostile presence attacks your mind!", MSGCH_WARN);
- miscast_effect(SPTYP_DIVINATION, random2(15), random2(150), 100,
+ MiscastEffect( &you, monster_index(mons), SPTYP_DIVINATION,
+ random2(15), random2(150),
"an orange crystal statue");
return (true);
}
diff --git a/crawl-ref/source/ouch.h b/crawl-ref/source/ouch.h
index 9408b60a6c..b949de14d6 100644
--- a/crawl-ref/source/ouch.h
+++ b/crawl-ref/source/ouch.h
@@ -58,7 +58,8 @@ enum kill_method_type
KILLED_BY_CURARE, // 30
KILLED_BY_MELTING,
KILLED_BY_BLEEDING,
- KILLED_BY_BEOGH_SMITING, // 33
+ KILLED_BY_BEOGH_SMITING,
+ KILLED_BY_DIVINE_WRATH, // 34
NUM_KILLBY
};
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 23ca730271..3b5e0d7d7d 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -5954,12 +5954,12 @@ item_def *player::shield()
return slot_item(EQ_SHIELD);
}
-std::string player::name(description_level_type type) const
+std::string player::name(description_level_type type, bool) const
{
return (pronoun_you(type));
}
-std::string player::pronoun(pronoun_type pro) const
+std::string player::pronoun(pronoun_type pro, bool) const
{
switch (pro)
{
@@ -5977,6 +5977,54 @@ std::string player::conj_verb(const std::string &verb) const
return (verb);
}
+std::string player::hand_name(bool plural, bool *can_plural) const
+{
+ if (can_plural != NULL)
+ *can_plural = true;
+ return your_hand(plural);
+}
+
+std::string player::foot_name(bool plural, bool *can_plural) const
+{
+ bool _can_plural;
+ if (can_plural == NULL)
+ can_plural = &_can_plural;
+ *can_plural = true;
+
+ std::string str;
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR)
+ {
+ str = "lowest portion";
+ *can_plural = false;
+ }
+ else if (!transform_changed_physiology())
+ {
+ if (player_mutation_level(MUT_HOOVES))
+ str = "hoof";
+ else if (player_mutation_level(MUT_TALONS))
+ str = "talon";
+ else if (you.species == SP_NAGA)
+ {
+ str = "underbelly";
+ *can_plural = false;
+ }
+ else if (you.species == SP_MERFOLK && player_is_swimming())
+ {
+ str = "tail";
+ *can_plural = false;
+ }
+ }
+
+ if (str.empty())
+ return (plural ? "feet" : "foot");
+
+ if (plural && *can_plural)
+ str = pluralise(str);
+
+ return str;
+}
+
int player::id() const
{
return (-1);
@@ -6335,6 +6383,11 @@ int player::res_rotting() const
return 0;
}
+int player::res_torment() const
+{
+ return player_res_torment();
+}
+
bool player::confusable() const
{
return (player_mental_clarity() == 0);
@@ -6423,9 +6476,9 @@ void player::expose_to_element(beam_type element, int st)
::expose_player_to_element(element, st);
}
-void player::blink()
+void player::blink(bool allow_partial_control)
{
- random_blink(true);
+ random_blink(allow_partial_control);
}
void player::teleport(bool now, bool abyss_shift)
diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc
index 08ecfd5d8c..0cc03f80bd 100644
--- a/crawl-ref/source/religion.cc
+++ b/crawl-ref/source/religion.cc
@@ -75,7 +75,7 @@
#include "spells3.h"
#include "spells4.h"
#include "spl-book.h"
-#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "stash.h"
#include "state.h"
@@ -3257,7 +3257,7 @@ bool trog_burn_books()
mpr( "The fire roars with new energy!" );
const int extra_dur = count + random2(rarity/2);
env.cloud[cloud].decay += extra_dur * 5;
- env.cloud[cloud].whose = KC_YOU;
+ env.cloud[cloud].set_whose(KC_YOU);
continue;
}
@@ -3617,7 +3617,7 @@ static bool _elyvilon_retribution()
break;
case 2: // mostly flavour messages
- miscast_effect(SPTYP_POISON, 0, 0, one_chance_in(3),
+ MiscastEffect(&you, -god, SPTYP_POISON, one_chance_in(3) ? 1 : 0,
"the will of Elyvilon");
break;
@@ -3703,8 +3703,8 @@ static bool _kikubaaqudgha_retribution()
god_speaks(god, (coinflip()) ? "You hear Kikubaaqudgha cackling."
: "Kikubaaqudgha's malice focuses upon you.");
- miscast_effect(SPTYP_NECROMANCY, 5 + you.experience_level,
- random2avg(88, 3), 100, "the malice of Kikubaaqudgha");
+ MiscastEffect(&you, -god, SPTYP_NECROMANCY, 5 + you.experience_level,
+ random2avg(88, 3), "the malice of Kikubaaqudgha");
}
return (true);
@@ -3739,8 +3739,8 @@ static bool _yredelemnul_retribution()
else
{
simple_god_message("'s anger turns toward you for a moment.", god);
- miscast_effect( SPTYP_NECROMANCY, 5 + you.experience_level,
- random2avg(88, 3), 100, "the anger of Yredelemnul" );
+ MiscastEffect( &you, -god, SPTYP_NECROMANCY, 5 + you.experience_level,
+ random2avg(88, 3), "the anger of Yredelemnul" );
}
return (true);
@@ -3833,8 +3833,8 @@ static bool _trog_retribution()
// fire magic. -- bwr
dec_penance(god, 2);
mpr( "You feel Trog's fiery rage upon you!", MSGCH_WARN );
- miscast_effect( SPTYP_FIRE, 8 + you.experience_level,
- random2avg(98, 3), 100, "the fiery rage of Trog" );
+ MiscastEffect( &you, -god, SPTYP_FIRE, 8 + you.experience_level,
+ random2avg(98, 3), "the fiery rage of Trog" );
}
return (true);
@@ -3849,7 +3849,7 @@ static bool _beogh_retribution()
{
case 0: // smiting (25%)
case 1:
- god_smites_you(GOD_BEOGH, KILLED_BY_BEOGH_SMITING);
+ god_smites_you(GOD_BEOGH);
break;
case 2: // send out one or two dancing weapons (12.5%)
@@ -4014,7 +4014,8 @@ static bool _sif_muna_retribution()
case 5:
case 6:
- miscast_effect(SPTYP_DIVINATION, 9, 90, 100, "the will of Sif Muna");
+ MiscastEffect(&you, -god, SPTYP_DIVINATION, 9, 90,
+ "the will of Sif Muna");
break;
case 7:
@@ -4046,7 +4047,8 @@ static bool _lugonu_retribution()
if (coinflip())
{
simple_god_message("'s wrath finds you!", god);
- miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100, "Lugonu's touch" );
+ MiscastEffect( &you, -god, SPTYP_TRANSLOCATION, 9, 90,
+ "Lugonu's touch" );
// No return - Lugonu's touch is independent of other effects.
}
@@ -4108,9 +4110,10 @@ static bool _vehumet_retribution()
const god_type god = GOD_VEHUMET;
simple_god_message("'s vengeance finds you.", god);
- miscast_effect( coinflip() ? SPTYP_CONJURATION : SPTYP_SUMMONING,
- 8 + you.experience_level, random2avg(98, 3), 100,
- "the wrath of Vehumet" );
+ MiscastEffect( &you, -god,
+ coinflip() ? SPTYP_CONJURATION : SPTYP_SUMMONING,
+ 8 + you.experience_level, random2avg(98, 3),
+ "the wrath of Vehumet" );
return (true);
}
@@ -4641,7 +4644,7 @@ void beogh_idol_revenge()
else
revenge = _get_beogh_speech("idol other").c_str();
- god_smites_you(GOD_BEOGH, KILLED_BY_BEOGH_SMITING, revenge);
+ god_smites_you(GOD_BEOGH, revenge);
if (you.religion == GOD_BEOGH)
{
@@ -4802,28 +4805,32 @@ void excommunication(god_type new_god)
break;
case GOD_KIKUBAAQUDGHA:
- miscast_effect(SPTYP_NECROMANCY, 5 + you.experience_level,
- random2avg(88, 3), 100, "the malice of Kikubaaqudgha");
+ MiscastEffect(&you, -old_god, SPTYP_NECROMANCY,
+ 5 + you.experience_level, random2avg(88, 3),
+ "the malice of Kikubaaqudgha");
_inc_penance(old_god, 30);
break;
case GOD_YREDELEMNUL:
- miscast_effect(SPTYP_NECROMANCY, 5 + you.experience_level,
- random2avg(88, 3), 100, "the anger of Yredelemnul");
+ MiscastEffect(&you, -old_god, SPTYP_NECROMANCY,
+ 5 + you.experience_level, random2avg(88, 3),
+ "the anger of Yredelemnul");
_inc_penance(old_god, 30);
break;
case GOD_VEHUMET:
- miscast_effect((coinflip() ? SPTYP_CONJURATION : SPTYP_SUMMONING),
- 8 + you.experience_level, random2avg(98, 3), 100,
- "the wrath of Vehumet");
+ MiscastEffect(&you, -old_god,
+ (coinflip() ? SPTYP_CONJURATION : SPTYP_SUMMONING),
+ 8 + you.experience_level, random2avg(98, 3),
+ "the wrath of Vehumet");
_inc_penance(old_god, 25);
break;
case GOD_MAKHLEB:
- miscast_effect((coinflip() ? SPTYP_CONJURATION : SPTYP_SUMMONING),
- 8 + you.experience_level, random2avg(98, 3), 100,
- "the fury of Makhleb");
+ MiscastEffect(&you, -old_god,
+ (coinflip() ? SPTYP_CONJURATION : SPTYP_SUMMONING),
+ 8 + you.experience_level, random2avg(98, 3),
+ "the fury of Makhleb");
_inc_penance(old_god, 25);
break;
@@ -5665,9 +5672,12 @@ harm_protection_type god_protects_from_harm(god_type god, bool actual)
return HPT_NONE;
}
-void god_smites_you(god_type god, kill_method_type death_type,
- const char *message)
+void god_smites_you(god_type god, const char *message,
+ kill_method_type death_type)
+
{
+ ASSERT(god != GOD_NO_GOD);
+
// Your god won't protect you from his own smiting, and Xom is too
// capricious to protect you from any god's smiting.
if (you.religion != god && you.religion != GOD_XOM
@@ -5679,6 +5689,29 @@ void god_smites_you(god_type god, kill_method_type death_type,
}
else
{
+ if (death_type == NUM_KILLBY)
+ switch(god)
+ {
+ case GOD_BEOGH:
+ death_type = KILLED_BY_BEOGH_SMITING;
+ break;
+ case GOD_SHINING_ONE:
+ death_type = KILLED_BY_TSO_SMITING;
+ break;
+ default:
+ death_type = KILLED_BY_DIVINE_WRATH;
+ break;
+ }
+
+ std::string aux;
+
+ if (death_type != KILLED_BY_BEOGH_SMITING
+ && death_type != KILLED_BY_TSO_SMITING)
+ {
+ aux = "smited by ";
+ aux += god_name(god);
+ }
+
// If there's a message, display it before smiting.
if (message)
god_speaks(god, message);
@@ -5689,7 +5722,7 @@ void god_smites_you(god_type god, kill_method_type death_type,
divine_hurt += random2( you.experience_level );
simple_god_message( " smites you!", god );
- ouch( divine_hurt, 0, death_type );
+ ouch( divine_hurt, 0, death_type, aux.c_str() );
dec_penance( god, 1 );
}
}
diff --git a/crawl-ref/source/religion.h b/crawl-ref/source/religion.h
index 2ff9afb3bf..fc46af69c1 100644
--- a/crawl-ref/source/religion.h
+++ b/crawl-ref/source/religion.h
@@ -95,8 +95,8 @@ bool god_hates_killing(god_type god, const monsters* mon);
bool god_likes_butchery(god_type god);
bool god_hates_butchery(god_type god);
harm_protection_type god_protects_from_harm(god_type god, bool actual = true);
-void god_smites_you(god_type god, kill_method_type death_type,
- const char *message = NULL);
+void god_smites_you(god_type god, const char *message = NULL,
+ kill_method_type death_type = NUM_KILLBY);
void divine_retribution(god_type god);
bool beogh_water_walk();
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index e7d1d3715b..4164092c1f 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -537,7 +537,7 @@ bool conjure_flame(int pow)
mpr( "The fire roars with new energy!" );
const int extra_dur = 2 + std::min(random2(pow) / 2, 20);
env.cloud[cloud].decay += extra_dur * 5;
- env.cloud[cloud].whose = KC_YOU;
+ env.cloud[cloud].set_whose(KC_YOU);
return (true);
}
@@ -608,8 +608,22 @@ int cast_big_c(int pow, cloud_type cty, kill_category whose, bolt &beam)
void big_cloud(cloud_type cl_type, kill_category whose,
int cl_x, int cl_y, int pow, int size, int spread_rate)
{
+ big_cloud(cl_type, whose, cloud_struct::whose_to_killer(whose),
+ cl_x, cl_y, pow, size, spread_rate);
+}
+
+void big_cloud(cloud_type cl_type, killer_type killer,
+ int cl_x, int cl_y, int pow, int size, int spread_rate)
+{
+ big_cloud(cl_type, cloud_struct::killer_to_whose(killer), killer,
+ cl_x, cl_y, pow, size, spread_rate);
+}
+
+void big_cloud(cloud_type cl_type, kill_category whose, killer_type killer,
+ int cl_x, int cl_y, int pow, int size, int spread_rate)
+{
apply_area_cloud(make_a_normal_cloud, cl_x, cl_y, pow, size,
- cl_type, whose, spread_rate);
+ cl_type, whose, killer, spread_rate);
}
static bool _mons_hostile(const monsters *mon)
diff --git a/crawl-ref/source/spells1.h b/crawl-ref/source/spells1.h
index 692fb5b73a..d2a2af9246 100644
--- a/crawl-ref/source/spells1.h
+++ b/crawl-ref/source/spells1.h
@@ -44,7 +44,10 @@ int cast_vitalisation(int pow);
* *********************************************************************** */
void big_cloud(cloud_type cl_type, kill_category whose, int cl_x, int cl_y,
int pow, int size, int spread_rate = -1);
-
+void big_cloud(cloud_type cl_type, killer_type killer, int cl_x, int cl_y,
+ int pow, int size, int spread_rate = -1);
+void big_cloud(cloud_type cl_type, kill_category whose, killer_type killer,
+ int cl_x, int cl_y, int pow, int size, int spread_rate = -1);
// last updated 24may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index 2736a57266..378832cd63 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -50,7 +50,7 @@
#include "randart.h"
#include "religion.h"
#include "spells4.h"
-#include "spl-cast.h"
+#include "spl-mis.h"
#include "stuff.h"
#include "tiles.h"
#include "terrain.h"
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index 3cd219f7ff..4c7cdf143f 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -51,7 +51,7 @@
#include "skills.h"
#include "spells1.h"
#include "spells4.h"
-#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "stuff.h"
#include "terrain.h"
@@ -887,13 +887,13 @@ static int _distortion_monsters(coord_def where, int pow, int message)
{
if (you.skills[SK_TRANSLOCATIONS] < random2(8))
{
- miscast_effect( SPTYP_TRANSLOCATION, pow / 9 + 1, pow, 100,
- "cast bend on self" );
+ MiscastEffect( &you, NON_MONSTER, SPTYP_TRANSLOCATION,
+ pow / 9 + 1, pow, "cast bend on self" );
}
else
{
- miscast_effect( SPTYP_TRANSLOCATION, 1, 1, 100,
- "cast bend on self" );
+ MiscastEffect( &you, NON_MONSTER, SPTYP_TRANSLOCATION, 1, 1,
+ "cast bend on self" );
}
return 1;
@@ -1079,11 +1079,15 @@ static int _make_a_rot_cloud(const coord_def& where, int pow, cloud_type ctype)
}
int make_a_normal_cloud(int x, int y, int pow, int spread_rate,
- cloud_type ctype, kill_category whose)
+ cloud_type ctype, kill_category whose,
+ killer_type killer)
{
+ if (killer == KILL_NONE)
+ killer = cloud_struct::whose_to_killer(whose);
+
place_cloud( ctype, coord_def(x, y),
(3 + random2(pow / 4) + random2(pow / 4) + random2(pow / 4)),
- whose, spread_rate );
+ whose, killer, spread_rate );
return 1;
}
@@ -1681,7 +1685,7 @@ void do_monster_rot(int mon)
if (mons_holiness(&menv[mon]) == MH_UNDEAD && !one_chance_in(5))
{
apply_area_cloud(make_a_normal_cloud, menv[mon].x, menv[mon].y,
- 10, 1, CLOUD_MIASMA, KC_YOU);
+ 10, 1, CLOUD_MIASMA, KC_YOU, KILL_YOU_MISSILE);
}
player_hurt_monster( mon, damage );
diff --git a/crawl-ref/source/spells4.h b/crawl-ref/source/spells4.h
index aea2d92342..a98d295e4e 100644
--- a/crawl-ref/source/spells4.h
+++ b/crawl-ref/source/spells4.h
@@ -20,7 +20,8 @@ struct bolt;
bool backlight_monsters(coord_def where, int pow, int garbage);
int make_a_normal_cloud(int x, int y, int pow, int spread_rate,
- cloud_type ctype, kill_category);
+ cloud_type ctype, kill_category,
+ killer_type killer = KILL_NONE);
int disperse_monsters(coord_def where, int pow, int message);
void cast_bend(int pow);
diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc
index 2a1b9bf5a3..a1d0f448e6 100644
--- a/crawl-ref/source/spl-book.cc
+++ b/crawl-ref/source/spl-book.cc
@@ -39,6 +39,7 @@
#include "player.h"
#include "religion.h"
#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
@@ -1326,20 +1327,23 @@ bool learn_spell(int book)
if (you.inv[ book ].sub_type == BOOK_NECRONOMICON)
{
mpr("The pages of the Necronomicon glow with a dark malevolence...");
- miscast_effect( SPTYP_NECROMANCY, 8, random2avg(88, 3), 100,
- "reading the Necronomicon" );
+ MiscastEffect( &you, MISC_KNOWN_MISCAST, SPTYP_NECROMANCY,
+ 8, random2avg(88, 3),
+ "reading the Necronomicon" );
}
else if (you.inv[ book ].sub_type == BOOK_DEMONOLOGY)
{
mpr("This book does not appreciate being disturbed by one of your ineptitude!");
- miscast_effect( SPTYP_SUMMONING, 7, random2avg(88, 3), 100,
- "reading the book of Demonology" );
+ MiscastEffect( &you, MISC_KNOWN_MISCAST, SPTYP_SUMMONING,
+ 7, random2avg(88, 3),
+ "reading the book of Demonology" );
}
else if (you.inv[ book ].sub_type == BOOK_ANNIHILATIONS)
{
mpr("This book does not appreciate being disturbed by one of your ineptitude!");
- miscast_effect( SPTYP_CONJURATION, 8, random2avg(88, 3), 100,
- "reading the book of Annihilations" );
+ MiscastEffect( &you, MISC_KNOWN_MISCAST, SPTYP_CONJURATION,
+ 8, random2avg(88, 3),
+ "reading the book of Annihilations" );
}
#ifdef WIZARD
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index dc0609259e..aebcbba27b 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -54,6 +54,7 @@
#include "spells3.h"
#include "spells4.h"
#include "spl-book.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
@@ -1125,14 +1126,6 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail)
return (SPRET_FAIL);
}
- unsigned int sptype = 0;
-
- do
- {
- sptype = 1 << (random2(SPTYP_LAST_EXPONENT+1));
- }
- while (!spell_typematch(spell, sptype));
-
// all spell failures give a bit of magical radiation..
// failure is a function of power squared multiplied
// by how badly you missed the spell. High power
@@ -1146,8 +1139,8 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail)
// miscasts are uncontrolled
contaminate_player( cont_points );
- miscast_effect( sptype, spell_mana(spell),
- spfail_chance - spfl, 100 );
+ MiscastEffect( &you, NON_MONSTER, spell, spell_mana(spell),
+ spfail_chance - spfl );
return (SPRET_FAIL);
}
@@ -2214,80 +2207,617 @@ void exercise_spell( spell_type spell, bool spc, bool success )
did_god_conduct( DID_SPELL_PRACTISE, exer_norm );
}
-static bool _send_abyss(const char *cause)
+MiscastEffect::MiscastEffect(actor* _target, int _source, spell_type _spell,
+ int _pow, int _fail, std::string _cause,
+ nothing_happens_when_type _nothing_happens) :
+ target(_target), source(_source), cause(_cause), spell(_spell),
+ school(SPTYP_NONE), pow(_pow), fail(_fail), level(-1), kc(KC_NCATEGORIES),
+ kt(KILL_NONE), mon_target(NULL), mon_source(NULL),
+ nothing_happens_when(_nothing_happens)
+{
+ ASSERT(is_valid_spell(_spell));
+ unsigned int schools = get_spell_disciplines(_spell);
+ ASSERT(schools != SPTYP_NONE);
+ ASSERT(!(schools & SPTYP_HOLY));
+
+ init();
+ do_miscast();
+}
+
+MiscastEffect::MiscastEffect(actor *_target, int _source,
+ spschool_flag_type _school, int _level,
+ std::string _cause,
+ nothing_happens_when_type _nothing_happens) :
+ target(_target), source(_source), cause(_cause), spell(SPELL_NO_SPELL),
+ school(_school), pow(-1), fail(-1), level(_level), kc(KC_NCATEGORIES),
+ kt(KILL_NONE), mon_target(NULL), mon_source(NULL),
+ nothing_happens_when(_nothing_happens)
+{
+ ASSERT(!_cause.empty());
+ ASSERT(count_bits(_school) == 1);
+ ASSERT(_school < SPTYP_HOLY || _school == SPTYP_RANDOM);
+ ASSERT(level >= 0 && level <= 3);
+
+ init();
+ do_miscast();
+}
+
+MiscastEffect::MiscastEffect(actor *_target, int _source,
+ spschool_flag_type _school, int _pow, int _fail,
+ std::string _cause,
+ nothing_happens_when_type _nothing_happens) :
+ target(_target), source(_source), cause(_cause), spell(SPELL_NO_SPELL),
+ school(_school), pow(_pow), fail(_fail), level(-1), kc(KC_NCATEGORIES),
+ kt(KILL_NONE), mon_target(NULL), mon_source(NULL),
+ nothing_happens_when(_nothing_happens)
+{
+ ASSERT(!_cause.empty());
+ ASSERT(count_bits(_school) == 1);
+ ASSERT(_school < SPTYP_HOLY || _school == SPTYP_RANDOM);
+
+ init();
+ do_miscast();
+}
+
+void MiscastEffect::init()
{
- if (you.level_type != LEVEL_ABYSS)
+ ASSERT(spell != SPELL_NO_SPELL && school == SPTYP_NONE
+ || spell == SPELL_NO_SPELL && school != SPTYP_NONE);
+ ASSERT(pow != -1 && fail != -1 && level == -1
+ || pow == -1 && fail == -1 && level >= 0 && level <= 3);
+
+ ASSERT(target != NULL);
+ // A dead but not-yet-exploded giant spore or ball lightning *might*
+ // be the target of a miscast effect.
+ ASSERT(target->alive() || target->id() == MONS_GIANT_SPORE
+ || target->id() == MONS_BALL_LIGHTNING);
+
+ source_known = target_known = false;
+
+ mon_target = mon_source = NULL;
+ act_source = NULL;
+
+ const bool death_curse = (cause.find("death curse") != std::string::npos);
+
+ if (target->atype() == ACT_MONSTER)
{
- you.banish(cause ? cause : "");
- return (true);
+ mon_target = dynamic_cast<monsters*>(target);
+ target_known = you.can_see(mon_target);
}
else
+ target_known = true;
+
+ kill_source = source;
+ if (source == WIELD_MISCAST || source == MELEE_MISCAST)
{
- mpr("The world appears momentarily distorted.");
- return (false);
+ if (target->atype() == ACT_MONSTER)
+ {
+ mon_source = dynamic_cast<monsters*>(target);
+ kill_source = monster_index(mon_source);
+ }
+ else
+ kill_source = NON_MONSTER;
+ }
+
+ if (kill_source == NON_MONSTER)
+ {
+ kc = KC_YOU;
+ kt = KILL_YOU_MISSILE;
+ act_source = dynamic_cast<actor*>(&you);
+ source_known = true;
+ }
+ else if (kill_source >= 0 && kill_source < NON_MONSTER)
+ {
+ mon_source = &menv[kill_source];
+ act_source = dynamic_cast<actor*>(mon_source);
+ ASSERT(mon_source->type != -1);
+
+ if (death_curse && target->atype() == ACT_MONSTER
+ && mon_target->confused_by_you())
+ {
+ kt = KILL_YOU_CONF;
+ }
+ else if (!death_curse && mon_source->confused_by_you()
+ && !mons_friendly(mon_source))
+ {
+ kt = KILL_YOU_CONF;
+ }
+ else
+ kt = KILL_MON_MISSILE;
+
+ if (mons_friendly(mon_source))
+ kc = KC_FRIENDLY;
+ else
+ kc = KC_OTHER;
+
+ source_known = you.can_see(mon_source);
+
+ if (target_known && death_curse)
+ source_known = true;
+ }
+ else
+ {
+ ASSERT(source == ZOT_TRAP_MISCAST
+ || source == MISC_KNOWN_MISCAST
+ || source == MISC_UNKNOWN_MISCAST
+ || (source < 0 && -source < NUM_GODS));
+
+ kc = KC_OTHER;
+ kt = KILL_MISC;
+
+ if (source == ZOT_TRAP_MISCAST)
+ {
+ source_known = target_known;
+
+ if (target->atype() == ACT_MONSTER
+ && mon_target->confused_by_you())
+ {
+ kt = KILL_YOU_CONF;
+ }
+ }
+ else if (source == MISC_KNOWN_MISCAST)
+ source_known = true;
+ else if (source == MISC_UNKNOWN_MISCAST)
+ source_known = false;
+ else
+ source_known = true;
+ }
+
+ ASSERT(kc != KC_NCATEGORIES && kt != KILL_NONE);
+
+ if (death_curse && !invalid_monster_index(kill_source))
+ {
+ if (starts_with(cause, "a "))
+ cause.replace(cause.begin(), cause.begin() + 1, "an indirect");
+ if (starts_with(cause, "an "))
+ cause.replace(cause.begin(), cause.begin() + 2, "an indirect");
+ else
+ cause = replace_all(cause, "death curse", "indirect death curse");
+ }
+
+ // source_known = false for MELEE_MISCAST so that melee miscasts
+ // won't give a "nothing happens" message.
+ if (source == MELEE_MISCAST)
+ source_known = false;
+
+ beam.is_beam = false;
+ beam.is_explosion = true;
+
+ if (cause.empty())
+ cause = get_default_cause();
+ beam.aux_source = cause;
+ beam.beam_source = kill_source;
+ beam.thrower = kt;
+}
+
+std::string MiscastEffect::get_default_cause()
+{
+ // This is only for true miscasts, which means both a spell and that
+ // the source of the miscast is the same as the target of the miscast.
+ ASSERT(source >= 0 && source <= NON_MONSTER);
+ ASSERT(spell != SPELL_NO_SPELL);
+ ASSERT(school == SPTYP_NONE);
+
+ if (source == NON_MONSTER)
+ {
+ ASSERT(target->atype() == ACT_PLAYER);
+ std::string str = "you miscasting ";
+ str += spell_title(spell);
+ return str;
+ }
+
+ ASSERT(mon_source != NULL);
+ ASSERT(mon_source == mon_target);
+
+ if (you.can_see(mon_source))
+ {
+ std::string str = mon_source->base_name(DESC_PLAIN, false);
+
+ str += "'s spell miscasting";
+ str = replace_all(str, "s's", "s'");
+ return str;
+ }
+ else
+ return "something's spell miscasting";
+}
+
+bool MiscastEffect::neither_end_silenced()
+{
+ return (!silenced(you.pos()) && !silenced(target->pos()));
+}
+
+void MiscastEffect::do_miscast()
+{
+ // Repeated calls to do_miscast() on a single object instance have
+ // killed a target which was alive when the object was created,
+ // or the target is a dead but not-yet-exploded giant spore or
+ // ball lightning.
+ if (!target->alive())
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Miscast target '%s' already dead",
+ target->name(DESC_PLAIN, true).c_str());
+ return;
+ }
+
+ spschool_flag_type sp_type;
+ int severity;
+
+ if (spell != SPELL_NO_SPELL)
+ {
+ std::vector<int> school_list;
+ for (int i = 0; i < SPTYP_LAST_EXPONENT; i++)
+ if (spell_typematch(spell, 1 << i))
+ school_list.push_back(i);
+
+ unsigned int _school = school_list[random2(school_list.size())];
+ sp_type = static_cast<spschool_flag_type>(1 << _school);
+ }
+ else
+ {
+ sp_type = school;
+ if (sp_type == SPTYP_RANDOM)
+ {
+ int exp = (random2(SPTYP_LAST_EXPONENT));
+ sp_type = (spschool_flag_type) (1 << exp);
+ }
+ }
+
+ if (level != -1)
+ severity = level;
+ else
+ {
+ severity = (pow * fail * (10 + pow) / 7 * WILD_MAGIC_NASTINESS) / 100;
+
+#if DEBUG_DIAGNOSTICS || DEBUG_MISCAT
+ mprf(MSGCH_DIAGNOSTICS, "'%s' miscast power: %d",
+ spell != SPELL_NO_SPELL ? spell_title(spell)
+ : spelltype_short_name(sp_type),
+ severity);
+#endif
+
+ if (random2(40) > severity && random2(40) > severity)
+ {
+ if (target->atype() == ACT_PLAYER)
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return;
+ }
+
+ severity /= 100;
+ severity = random2(severity);
+ if (severity > 3)
+ severity = 3;
+ else if (severity < 0)
+ severity = 0;
+ }
+
+#if DEBUG_DIAGNOSTICS || DEBUG_MISCAT
+ mprf(MSGCH_DIAGNOSTICS, "Sptype: %u, severity: %d",
+ spelltype_short_name(sp_type), severity );
+#endif
+
+ beam.ex_size = 1;
+ beam.name = "";
+ beam.damage = dice_def(0, 0);
+ beam.flavour = BEAM_NONE;
+ beam.msg_generated = false;
+ beam.in_explosion_phase = false;
+
+ // Do this here since multiple miscasts (wizmode testing) might move
+ // the target around.
+ beam.source_x = target->pos().x;
+ beam.source_y = target->pos().y;
+ beam.target_x = target->pos().x;
+ beam.target_y = target->pos().y;
+ beam.pos = target->pos();
+
+ all_msg = you_msg = mon_msg = mon_msg_seen = mon_msg_unseen = "";
+ msg_ch = MSGCH_PLAIN;
+
+ switch (sp_type)
+ {
+ case SPTYP_CONJURATION: _conjuration(severity); break;
+ case SPTYP_ENCHANTMENT: _enchantment(severity); break;
+ case SPTYP_TRANSLOCATION: _translocation(severity); break;
+ case SPTYP_SUMMONING: _summoning(severity); break;
+ case SPTYP_NECROMANCY: _necromancy(severity); break;
+ case SPTYP_TRANSMIGRATION: _transmigration(severity); break;
+ case SPTYP_FIRE: _fire(severity); break;
+ case SPTYP_ICE: _ice(severity); break;
+ case SPTYP_EARTH: _earth(severity); break;
+ case SPTYP_AIR: _air(severity); break;
+ case SPTYP_POISON: _poison(severity); break;
+ case SPTYP_DIVINATION:
+ // Divination miscasts have nothing in common between the player
+ // and monsters.
+ if (target->atype() == ACT_PLAYER)
+ _divination_you(severity);
+ else
+ _divination_mon(severity);
+ break;
+
+ default:
+ ASSERT(false);
+ }
+
+ if (target->atype() == ACT_PLAYER)
+ xom_is_stimulated(severity * 50);
+}
+
+void MiscastEffect::do_msg(bool suppress_nothing_happnes)
+{
+ if (mon_target != NULL && !mons_near(mon_target))
+ return;
+
+ std::string msg;
+
+ if (!all_msg.empty())
+ msg = all_msg;
+ else if (target->atype() == ACT_PLAYER)
+ msg = you_msg;
+ else if (!mon_msg.empty())
+ {
+ msg = mon_msg;
+ // Monster might be unseen with hands that can't be seen.
+ ASSERT(msg.find("@hand") == std::string::npos);
+ }
+ else
+ {
+ if (you.can_see(target))
+ msg = mon_msg_seen;
+ else
+ {
+ msg = mon_msg_unseen;
+ // Can't see the hands of invisible monsters.
+ ASSERT(msg.find("@hand") == std::string::npos);
+ }
+ }
+
+ if (msg.empty())
+ {
+ if (!suppress_nothing_happnes
+ && (nothing_happens_when == NH_ALWAYS
+ || (nothing_happens_when == NH_DEFAULT && source_known
+ && target_known)))
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+
+ return;
+ }
+
+ msg = replace_all(msg, "@hand@", target->hand_name(false));
+ msg = replace_all(msg, "@hands@", target->hand_name(true));
+
+ if (target->atype() == ACT_MONSTER)
+ msg = do_mon_str_replacements(msg, mon_target, S_SILENT);
+
+ mpr(msg.c_str(), msg_ch);
+}
+
+void MiscastEffect::_ouch(int dam, beam_type flavour)
+{
+ do_msg(true);
+
+ if (target->atype() == ACT_MONSTER)
+ {
+ bolt beem;
+
+ beem.flavour = flavour;
+ dam = mons_adjust_flavoured(mon_target, beem, dam, true);
+ hurt_monster(mon_target, dam);
+
+ if (mon_target->hit_points < 1)
+ monster_die(mon_target, kt, kill_source);
+ }
+ else
+ {
+ kill_method_type method;
+
+ if (source == NON_MONSTER && spell != SPELL_NO_SPELL)
+ method = KILLED_BY_WILD_MAGIC;
+ else if (source == ZOT_TRAP_MISCAST)
+ method = KILLED_BY_TRAP;
+ else if (source < 0 && -source < NUM_GODS)
+ {
+ god_type god = static_cast<god_type>(-source);
+
+ if (god == GOD_XOM && you.penance[GOD_XOM] == 0)
+ method = KILLED_BY_XOM;
+ else
+ {
+ method = KILLED_BY_DIVINE_WRATH;
+
+ if (you.penance[god] == 0)
+ mpr("God making you miscast, but not under penance.",
+ MSGCH_DIAGNOSTICS);
+ }
+ }
+ else if (source >= 0 && source < NON_MONSTER)
+ method = KILLED_BY_MONSTER;
+ else
+ method = KILLED_BY_SOMETHING;
+
+ dam = check_your_resists(dam, flavour);
+
+ bool see_source = false;
+ if (kill_source != NON_MONSTER)
+ see_source = you.can_see(&menv[kill_source]);
+
+ ouch(dam, kill_source, method, cause.c_str(), see_source);
+ }
+}
+
+void MiscastEffect::_explosion()
+{
+ ASSERT(!beam.name.empty());
+ ASSERT(beam.damage.num != 0 && beam.damage.size != 0);
+ ASSERT(beam.flavour != BEAM_NONE);
+
+ do_msg(true);
+ explosion(beam, false, true);
+}
+
+void MiscastEffect::_potion_effect(int pot_eff, int pot_pow)
+{
+ if (target->atype() == ACT_PLAYER)
+ {
+ potion_effect(static_cast<potion_type>(pot_eff), pot_pow, false);
+ return;
+ }
+
+ switch(pot_eff)
+ {
+ case POT_LEVITATION:
+ // There's no levitation enchantment for monsters, and anyways
+ // it's not nearly as inconveniencing for monsters as for the
+ // player, so backlight them instead.
+ mon_target->add_ench( mon_enchant(ENCH_BACKLIGHT, pot_pow, kc) );
+ break;
+ case POT_BERSERK_RAGE:
+ if (target->can_go_berserk())
+ {
+ target->go_berserk(false);
+ break;
+ }
+ // Intentional fallthrough if that didn't work.
+ case POT_SLOWING:
+ target->slow_down(pot_pow);
+ break;
+ case POT_PARALYSIS:
+ target->paralyse(pot_pow);
+ break;
+ case POT_CONFUSION:
+ target->confuse(pot_pow);
+ break;
+
+ default:
+ ASSERT(false);
+ }
+}
+
+void MiscastEffect::send_abyss()
+{
+ if (you.level_type == LEVEL_ABYSS)
+ {
+ you_msg = "The world appears momentarily distorted.";
+ mon_msg_seen = "@The_monster@ wobbles for a moment.";
+ mon_msg_unseen = "An empty piece of space momentarily distorts.";
+ do_msg();
+ return;
+ }
+
+ target->banish(cause);
+}
+
+bool MiscastEffect::_create_monster(monster_type what, int abj_deg,
+ bool alert)
+{
+ const god_type god =
+ (crawl_state.is_god_acting()) ? crawl_state.which_god_acting()
+ : GOD_NO_GOD;
+
+ mgen_data data = mgen_data::hostile_at(what, target->pos(),
+ abj_deg, 0, alert, god);
+
+ // hostile_at() assumes the monster is hostile to the player,
+ // but should be hostile to the target monster unless the miscast
+ // is a result of either divine wrath or a Zot trap.
+ if (target->atype() == ACT_MONSTER && you.penance[god] == 0
+ && source != ZOT_TRAP_MISCAST)
+ {
+ switch(mon_target->temp_attitude())
+ {
+ case ATT_FRIENDLY: data.behaviour = BEH_HOSTILE; break;
+ case ATT_HOSTILE: data.behaviour = BEH_FRIENDLY; break;
+ case ATT_GOOD_NEUTRAL:
+ case ATT_NEUTRAL:
+ data.behaviour = BEH_NEUTRAL;
+ break;
+ }
+
+ if (alert)
+ data.foe = monster_index(mon_target);
+
+ // No permanent allies from miscasts.
+ if (data.behaviour == BEH_FRIENDLY && abj_deg == 0)
+ data.abjuration_duration = 6;
}
+
+ return (create_monster(data) != -1);
}
-static void _miscast_conjuration(int severity, const char* cause)
+void MiscastEffect::_conjuration(int severity)
{
- bolt beam;
switch (severity)
{
case 0: // just a harmless message
switch (random2(10))
{
case 0:
- msg::stream << "Sparks fly from your " << your_hand(true)
- << '!' << std::endl;
+ you_msg = "Sparks fly from your @hands@!";
+ mon_msg_seen = "Sparks fly from @the_monster@'s @hands@!";
break;
case 1:
- mpr("The air around you crackles with energy!");
+ you_msg = "The air around you crackles with energy!";
+ mon_msg_seen = "The air around @the_monster@ crackles "
+ "with energy!";
break;
case 2:
- msg::stream << "Wisps of smoke drift from your "
- << your_hand(true) << '.' << std::endl;
+ you_msg = "Wisps of smoke drift from your @hands@.";
+ mon_msg_seen = "Wisps of smoke drift from @the_monster@'s "
+ "@hands@.";
break;
case 3:
- mpr("You feel a strange surge of energy!");
+ you_msg = "You feel a strange surge of energy!";
+ // Monster messages needed.
break;
case 4:
- mpr("You are momentarily dazzled by a flash of light!");
+ you_msg = "You are momentarily dazzled by a flash of light!";
+ mon_msg_seen = "@The_monster@ emits a flash of light!";
break;
case 5:
- mpr("Strange energies run through your body.");
+ you_msg = "Strange energies run through your body.";
+ // Monster messages needed.
break;
case 6:
- mpr("Your skin tingles.");
+ you_msg = "Your skin tingles.";
+ // Monster messages needed.
break;
case 7:
- mpr("Your skin glows momentarily.");
+ you_msg = "Your skin glows momentarily.";
+ mon_msg_seen = "@The_monster@ glows momentarily.";
+ // A smal glow isn't going to make it past invisibility.
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
if (player_can_smell())
- mpr("You smell something strange.");
+ all_msg = "You smell something strange.";
else if (you.species == SP_MUMMY)
- mpr("Your bandages flutter.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ you_msg = "Your bandages flutter.";
}
+ do_msg();
break;
case 1: // a bit less harmless stuff
switch (random2(2))
{
case 0:
- msg::stream << "Smoke pours from your " << your_hand(true)
- << '!' << std::endl;
- big_cloud( CLOUD_GREY_SMOKE, (cause ? KC_OTHER : KC_YOU),
- you.x_pos, you.y_pos, 20,
- 7 + random2(7) );
+ you_msg = "Smoke pours from your @hands@!";
+ mon_msg_seen = "Smoke pours from @the_monster@'s @hands@!";
+ mon_msg_unseen = "Smoke appears from out of nowhere!";
+
+ do_msg();
+ big_cloud( CLOUD_GREY_SMOKE, kc, kt,
+ target->pos().x, target->pos().y,
+ 20, 7 + random2(7) );
break;
case 1:
- mpr("A wave of violent energy washes through your body!");
- ouch(6 + random2avg(7, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "A wave of violent energy washes through your body!";
+ // Monster messages needed.
+ _ouch(6 + random2avg(7, 2));
break;
}
break;
@@ -2296,29 +2826,24 @@ static void _miscast_conjuration(int severity, const char* cause)
switch (random2(2))
{
case 0:
- mpr("Energy rips through your body!");
- ouch(9 + random2avg(17, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "Energy rips through your body!";
+ // Monster messages needed.
+ _ouch(9 + random2avg(17, 2));
break;
case 1:
- mpr("You are caught in a violent explosion!");
- beam.type = dchar_glyph(DCHAR_FIRED_BURST);
- beam.damage = dice_def( 3, 12 );
+ you_msg = "You are caught in a violent explosion!";
+ mon_msg_seen = "@The_monster@ is caugh in a violent explosion!";
+ mon_msg_unseen = "A violent explosion happens from "
+ "out of thin air!";
+
+ beam.damage = dice_def( 3, 12 );
beam.flavour = BEAM_MISSILE; // unsure about this
// BEAM_EXPLOSION instead? {dlb}
- beam.target_x = you.x_pos;
- beam.target_y = you.y_pos;
- beam.name = "explosion";
+ beam.name = "explosion";
beam.colour = random_colour();
- beam.beam_source = NON_MONSTER;
- beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
- beam.aux_source.clear();
- if (cause)
- beam.aux_source = cause;
- beam.ex_size = 1;
- beam.is_explosion = true;
- explosion(beam);
+ _explosion();
break;
}
break;
@@ -2327,34 +2852,53 @@ static void _miscast_conjuration(int severity, const char* cause)
switch (random2(2))
{
case 0:
- mpr("You are blasted with magical energy!");
- ouch(12 + random2avg(29, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "You are blasted with magical energy!";
+ mon_msg_seen = "@The_monster@ is blasted with magical energy!";
+ // No message for invis monsters?
+ _ouch(12 + random2avg(29, 2));
break;
case 1:
- mpr("There is a sudden explosion of magical energy!");
- beam.type = dchar_glyph(DCHAR_FIRED_BURST);
- beam.damage = dice_def( 3, 20 );
+ all_msg = "There is a sudden explosion of magical energy!";
+
+ beam.type = dchar_glyph(DCHAR_FIRED_BURST);
+ beam.damage = dice_def( 3, 20 );
beam.flavour = BEAM_MISSILE; // unsure about this
// BEAM_EXPLOSION instead? {dlb}
- beam.target_x = you.x_pos;
- beam.target_y = you.y_pos;
- beam.name = "explosion";
- beam.colour = random_colour();
- beam.beam_source = NON_MONSTER;
- beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
- beam.aux_source.clear();
- if (cause)
- beam.aux_source = cause;
+ beam.name = "explosion";
+ beam.colour = random_colour();
beam.ex_size = coinflip() ? 1 : 2;
- beam.is_explosion = true;
- explosion(beam);
+ _explosion();
break;
}
}
}
-static void _miscast_enchantment(int severity, const char* cause)
+static void _your_hands_glow(actor* target, std::string& you_msg,
+ std::string& mon_msg_seen)
+{
+ you_msg = "Your @hands@ ";
+ mon_msg_seen = "@The_monster@'s @hands@ ";
+ // No message for invisible monsters.
+
+ bool pluralized = true;
+ target->hand_name(true, &pluralized);
+
+ if (pluralized)
+ {
+ you_msg += "glow";
+ mon_msg_seen += "glow";
+ }
+ else
+ {
+ you_msg += "glows";
+ mon_msg_seen += "glows";
+ }
+ you_msg += " momentarily.";
+ mon_msg_seen += " momentarily.";
+}
+
+void MiscastEffect::_enchantment(int severity)
{
switch (severity)
{
@@ -2362,51 +2906,67 @@ static void _miscast_enchantment(int severity, const char* cause)
switch (random2(10))
{
case 0:
- msg::stream << "Your " << your_hand(true)
- << " glow momentarily." << std::endl;
+ _your_hands_glow(target, you_msg, mon_msg_seen);
break;
case 1:
- mpr("The air around you crackles with energy!");
+ you_msg = "The air around you crackles with energy!";
+ mon_msg_seen = "The air around @the_monster@ crackles with"
+ " energy!";
break;
case 2:
- mpr("Multicolored lights dance before your eyes!");
+ you_msg = "Multicolored lights dance before your eyes!";
+ // Monster messages needed.
break;
case 3:
- mpr("You feel a strange surge of energy!");
+ you_msg = "You feel a strange surge of energy!";
+ // Monster messages needed.
break;
case 4:
- mpr("Waves of light ripple over your body.");
+ you_msg = "Waves of light ripple over your body.";
+ mon_msg_seen = "Waves of light ripple over @the_monster@'s body.";
break;
case 5:
- mpr("Strange energies run through your body.");
+ you_msg = "Strange energies run through your body.";
+ // Monster messages needed.
break;
case 6:
- mpr("Your skin tingles.");
+ you_msg = "Your skin tingles.";
+ // Monster messages needed.
break;
case 7:
- mpr("Your skin glows momentarily.");
+ you_msg = "Your skin glows momentarily.";
+ mon_msg_seen = "@The_monster@'s body glows momentarily.";
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
- if (!silenced(you.pos()))
- mpr("You hear something strange.", MSGCH_SOUND);
- else if (you.attribute[ATTR_TRANSFORMATION] != TRAN_AIR)
- mpr("Your skull vibrates slightly.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ if (neither_end_silenced())
+ {
+ // XXX: Should use noisy().
+ all_msg = "You hear something strange.";
+ msg_ch = MSGCH_SOUND;
+ return;
+ }
+ else if (target->atype() == ACT_PLAYER
+ && you.attribute[ATTR_TRANSFORMATION] != TRAN_AIR)
+ {
+ you_msg = "Your skull vibrates slightly.";
+ }
break;
}
+ do_msg();
break;
case 1: // slightly annoying
switch (random2(2))
{
case 0:
- potion_effect(POT_LEVITATION, 20);
+ _potion_effect(POT_LEVITATION, 20);
break;
case 1:
+ // XXX: Something else for monsters?
random_uselessness();
break;
}
@@ -2418,24 +2978,39 @@ static void _miscast_enchantment(int severity, const char* cause)
case 0:
case 1:
case 2:
- mpr("You sense a malignant aura.");
- curse_an_item(false);
- break;
+ if (target->atype() == ACT_PLAYER)
+ {
+ mpr("You sense a malignant aura.");
+ curse_an_item(false);
+ break;
+ }
+ // Intentional fall-through for monsters.
case 3:
case 4:
case 5:
- potion_effect(POT_SLOWING, 10);
+ _potion_effect(POT_SLOWING, 10);
break;
case 6:
- potion_effect(POT_BERSERK_RAGE, 10);
+ _potion_effect(POT_BERSERK_RAGE, 10);
break;
}
break;
case 3: // potentially lethal
- switch (random2(4))
+ // Only use first two cases for monsters.
+ switch (random2(target->atype() == ACT_PLAYER ? 4 : 2))
{
case 0:
+ _potion_effect(POT_PARALYSIS, 10);
+ break;
+ case 1:
+ _potion_effect(POT_CONFUSION, 10);
+ break;
+ case 2:
+ mpr("You feel saturated with unharnessed energies!");
+ you.magic_contamination += random2avg(19,3);
+ break;
+ case 3:
do
{
curse_an_item(false);
@@ -2444,63 +3019,61 @@ static void _miscast_enchantment(int severity, const char* cause)
mpr("You sense an overwhelmingly malignant aura!");
break;
- case 1:
- potion_effect(POT_PARALYSIS, 10);
- break;
- case 2:
- potion_effect(POT_CONFUSION, 10);
- break;
- case 3:
- mpr("You feel saturated with unharnessed energies!");
- you.magic_contamination += random2avg(19,3);
- break;
}
break;
}
}
-static void _miscast_translocation(int severity, const char* cause)
+void MiscastEffect::_translocation(int severity)
{
- const god_type god =
- (crawl_state.is_god_acting()) ? crawl_state.which_god_acting()
- : GOD_NO_GOD;
-
switch (severity)
{
case 0: // harmless messages only
switch (random2(10))
{
case 0:
- mpr("Space warps around you.");
+ you_msg = "Space warps around you.";
+ mon_msg_seen = "Space warps around @the_monster@.";
break;
case 1:
- mpr("The air around you crackles with energy!");
+ you_msg = "The air around you crackles with energy!";
+ mon_msg_seen = "The air around @the_monster@ crackles with "
+ "energy!";
break;
case 2:
- mpr("You feel a wrenching sensation.");
+ you_msg = "You feel a wrenching sensation.";
+ // Monster messages needed.
break;
case 3:
- mpr("You feel a strange surge of energy!");
+ you_msg = "You feel a strange surge of energy!";
+ // Monster messages needed.
break;
case 4:
- mpr("You spin around.");
+ you_msg = "You spin around.";
+ mon_msg_seen = "@The_monster@ spins around.";
break;
case 5:
- mpr("Strange energies run through your body.");
+ you_msg = "Strange energies run through your body.";
+ // Monster messages needed.
break;
case 6:
- mpr("Your skin tingles.");
+ you_msg = "Your skin tingles.";
+ // Monster messages needed.
break;
case 7:
- mpr("The world appears momentarily distorted!");
+ you_msg = "The world appears momentarily distorted!";
+ mon_msg_seen = "@The_monster@ appears momentarily distorted!";
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
- mpr("You feel uncomfortable.");
+ you_msg = "You feel uncomfortable.";
+ // Monster messages needed.
break;
}
+ do_msg();
break;
case 1: // mostly harmless
@@ -2509,24 +3082,25 @@ static void _miscast_translocation(int severity, const char* cause)
case 0:
case 1:
case 2:
- mpr("You are caught in a localised field of spatial distortion.");
- ouch(4 + random2avg(9, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "You are caught in a localised field of spatial "
+ "distortion.";
+ mon_msg_seen = "@The_monster@ is caught in a localised field of "
+ "spatial distortion.";
+ mon_msg_unseen = "A piece of empty space twists and distorts.";
+ _ouch(4 + random2avg(9, 2));
break;
case 3:
case 4:
- mpr("Space bends around you!");
- random_blink(false);
- ouch(4 + random2avg(7, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "Space bends around you!";
+ mon_msg_seen = "Space bends around @the_monster@!";
+ mon_msg_unseen = "A piece of empty space twists and distorts.";
+ _ouch(4 + random2avg(7, 2));
+ target->blink(false);
break;
case 5:
- if (create_monster(
- mgen_data::hostile_at(MONS_SPATIAL_VORTEX,
- you.pos(), 3, 0, false, god)) != -1)
- {
- mpr("Space twists in upon itself!");
- }
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ if (_create_monster(MONS_SPATIAL_VORTEX, 3))
+ all_msg = "Space twists in upon itself!";
+ do_msg();
break;
}
break;
@@ -2537,20 +3111,27 @@ static void _miscast_translocation(int severity, const char* cause)
case 0:
case 1:
case 2:
- mpr("You are caught in a strong localised spatial distortion.");
- ouch(9 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "You are caught in a strong localised spatial "
+ "distortion.";
+ mon_msg_seen = "@The_monster@ is caught in a strong localised "
+ "spatial distortion.";
+ mon_msg_unseen = "A piece of empty space twists and writhes.";
+ _ouch(9 + random2avg(23, 2));
break;
case 3:
case 4:
- mpr("Space warps around you!");
+ you_msg = "Space warps around you!";
+ mon_msg_seen = "Space warps around @the_monster!";
+ mon_msg_unseen = "A piece of empty space twists and writhes.";
+
+ _ouch(5 + random2avg(9, 2));
if (one_chance_in(3))
- you_teleport_now( true );
+ target->teleport(true);
else
- random_blink( false );
+ target->blink(false);
- ouch(5 + random2avg(9, 2), 0, KILLED_BY_WILD_MAGIC, cause);
- potion_effect(POT_CONFUSION, 40);
+ _potion_effect(POT_CONFUSION, 40);
break;
case 5:
{
@@ -2558,42 +3139,43 @@ static void _miscast_translocation(int severity, const char* cause)
for (int i = 1 + random2(3); i >= 0; --i)
{
- if (create_monster(
- mgen_data::hostile_at(MONS_SPATIAL_VORTEX,
- you.pos(), 3, 0, false, god)) != -1)
- {
+ if (_create_monster(MONS_SPATIAL_VORTEX, 3))
success = true;
- }
}
if (success)
- mpr("Space twists in upon itself!");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ all_msg = "Space twists in upon itself!";
break;
}
case 6:
- _send_abyss(cause);
+ send_abyss();
break;
}
break;
case 3: // much less harmless
- switch (random2(4))
+ // Don't use the last case for monsters.
+ switch (random2(target->atype() == ACT_PLAYER ? 4 : 3))
{
case 0:
- mpr("You are caught in an extremely strong localised spatial distortion!");
- ouch(15 + random2avg(29, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "You are caught in an extremely strong localised "
+ "spatial distortion!";
+ mon_msg_seen = "@The_monster@ is caught in an extremely strong "
+ "localised spatial distortion!";
+ mon_msg_unseen = "A rift temporarily opens in the fabric of space!";
+ _ouch(15 + random2avg(29, 2));
break;
case 1:
- mpr("Space warps crazily around you!");
- you_teleport_now( true );
+ you_msg = "Space warps crazily around you!";
+ mon_msg_seen = "Space warps crazily around @the_monster@!";
+ mon_msg_unseen = "A rift temporarily opens in the fabric of space!";
- ouch(9 + random2avg(17, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ _ouch(9 + random2avg(17, 2));
+ you_teleport_now( true );
potion_effect(POT_CONFUSION, 60);
break;
case 2:
- _send_abyss(cause);
+ send_abyss();
break;
case 3:
mpr("You feel saturated with unharnessed energies!");
@@ -2604,51 +3186,68 @@ static void _miscast_translocation(int severity, const char* cause)
}
}
-static void _miscast_summoning(int severity, const char* cause)
+void MiscastEffect::_summoning(int severity)
{
- const god_type god =
- (crawl_state.is_god_acting()) ? crawl_state.which_god_acting()
- : GOD_NO_GOD;
-
switch (severity)
{
case 0: // harmless messages only
switch (random2(10))
{
case 0:
- mpr("Shadowy shapes form in the air around you, then vanish.");
+ you_msg = "Shadowy shapes form in the air around you, "
+ "then vanish.";
+ mon_msg_seen = "Shadowy shapes form in the air around "
+ "@the_monster@, then vanish.";
break;
case 1:
- if (!silenced(you.pos()))
- mpr("You hear strange voices.", MSGCH_SOUND);
- else
- mpr("You feel momentarily dizzy.");
+ if (neither_end_silenced())
+ {
+ all_msg = "You hear strange voices.";
+ msg_ch = MSGCH_SOUND;
+ }
+ else if (target->atype() == ACT_PLAYER)
+ you_msg = "You feel momentarily dizzy.";
break;
case 2:
- mpr("Your head hurts.");
+ you_msg = "Your head hurts.";
+ // Monster messages needed.
break;
case 3:
- mpr("You feel a strange surge of energy!");
+ you_msg = "You feel a strange surge of energy!";
+ // Monster messages needed.
break;
case 4:
- mpr("Your brain hurts!");
+ you_msg = "Your brain hurts!";
+ // Monster messages needed.
break;
case 5:
- mpr("Strange energies run through your body.");
+ you_msg = "Strange energies run through your body.";
+ // Monster messages needed.
break;
case 6:
- mpr("The world appears momentarily distorted.");
+ you_msg = "The world appears momentarily distorted.";
+ mon_msg_seen = "@The_monster@ appears momentarily distorted.";
break;
case 7:
- mpr("Space warps around you.");
+ you_msg = "Space warps around you.";
+ mon_msg_seen = "Space warps around @the_monster@.";
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
- mpr("Distant voices call out to you!");
+ if (neither_end_silenced())
+ {
+ you_msg = "Distant voices call out to you!";
+ mon_msg_seen = "Distant voices call out to @the_monster@!";
+ msg_ch = MSGCH_SOUND;
+ }
+ else if (target->atype() == ACT_PLAYER)
+ you_msg = "You feel watched.";
break;
}
+ do_msg();
break;
case 1: // a little bad
@@ -2657,30 +3256,23 @@ static void _miscast_summoning(int severity, const char* cause)
case 0: // identical to translocation
case 1:
case 2:
- mpr("You are caught in a localised spatial distortion.");
- ouch(5 + random2avg(9, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "You are caught in a localised spatial "
+ "distortion.";
+ mon_msg_seen = "@The_monster@ is caught in a localised spatial "
+ "distortion.";
+ mon_msg_unseen = "An empty piece of space distorts and twists.";
+ _ouch(5 + random2avg(9, 2));
break;
case 3:
- if (create_monster(
- mgen_data::hostile_at(MONS_SPATIAL_VORTEX,
- you.pos(), 3, 0, false, god)) != -1)
- {
- mpr("Space twists in upon itself!");
- }
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ if (_create_monster(MONS_SPATIAL_VORTEX, 3))
+ all_msg = "Space twists in upon itself!";
+ do_msg();
break;
case 4:
case 5:
- if (create_monster(
- mgen_data::hostile_at(
- summon_any_demon(DEMON_LESSER),
- you.pos(), 5, 0, true, god)) != -1)
- {
- mpr("Something appears in a flash of light!");
- }
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ if (_create_monster(summon_any_demon(DEMON_LESSER), 5, true))
+ all_msg = "Something appears in a flash of light!";
+ do_msg();
break;
}
break;
@@ -2694,32 +3286,21 @@ static void _miscast_summoning(int severity, const char* cause)
for (int i = 1 + random2(3); i >= 0; --i)
{
- if (create_monster(
- mgen_data::hostile_at(MONS_SPATIAL_VORTEX,
- you.pos(), 3, 0, false, god)) != -1)
- {
+ if (_create_monster(MONS_SPATIAL_VORTEX, 3))
success = true;
- }
}
if (success)
- mpr("Space twists in upon itself!");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ all_msg = "Space twists in upon itself!";
+ do_msg();
break;
}
case 1:
case 2:
- if (create_monster(
- mgen_data::hostile_at(
- summon_any_demon(DEMON_COMMON),
- you.pos(), 5, 0, true, god)) != -1)
- {
- mpr("Something forms out of thin air!");
- }
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ if (_create_monster(summon_any_demon(DEMON_COMMON), 5, true))
+ all_msg = "Something forms from out of thin air!";
+ do_msg();
break;
case 3:
@@ -2730,19 +3311,17 @@ static void _miscast_summoning(int severity, const char* cause)
for (int i = 1 + random2(2); i >= 0; --i)
{
- if (create_monster(
- mgen_data::hostile_at(
- summon_any_demon(DEMON_LESSER),
- you.pos(), 5, 0, true, god)) != -1)
- {
+ if (_create_monster(summon_any_demon(DEMON_LESSER), 5, true))
success = true;
- }
}
- if (success)
- mpr("A chorus of chattering voices calls out to you!");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ if (success && neither_end_silenced())
+ {
+ you_msg = "A chorus of chattering voices calls out to you!";
+ mon_msg = "A chorus of chattering voices calls out!";
+ msg_ch = MSGCH_SOUND;
+ }
+ do_msg();
break;
}
}
@@ -2752,26 +3331,15 @@ static void _miscast_summoning(int severity, const char* cause)
switch (random2(4))
{
case 0:
- if (create_monster(
- mgen_data::hostile_at(MONS_ABOMINATION_SMALL,
- you.pos(), 0, 0, true, god)) != -1)
- {
- mpr("Something forms out of thin air.");
- }
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ if (_create_monster(MONS_ABOMINATION_SMALL, 0, true))
+ all_msg = "Something forms from out of thin air.";
+ do_msg();
break;
case 1:
- if (create_monster(
- mgen_data::hostile_at(
- summon_any_demon(DEMON_GREATER),
- you.pos(), 0, 0, true, god)) != -1)
- {
- mpr("You sense a hostile presence.");
- }
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ if (_create_monster(summon_any_demon(DEMON_GREATER), 0, true))
+ all_msg = "You sense a hostile presence.";
+ do_msg();
break;
case 2:
@@ -2780,31 +3348,29 @@ static void _miscast_summoning(int severity, const char* cause)
for (int i = 1 + random2(2); i >= 0; --i)
{
- if (create_monster(
- mgen_data::hostile_at(
- summon_any_demon(DEMON_COMMON),
- you.pos(), 3, 0, true, god)) != -1)
- {
+ if (_create_monster(summon_any_demon(DEMON_COMMON), 3, true))
success = true;
- }
}
if (success)
- mpr("Something turns its malign attention towards you...");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ {
+ you_msg = "Something turns its malign attention towards "
+ "you...";
+ mon_msg = "You sense a malign presence.";
+ }
+ do_msg();
break;
}
case 3:
- _send_abyss(cause);
+ send_abyss();
break;
}
break;
}
}
-static void _miscast_divination(int severity, const char* cause)
+void MiscastEffect::_divination_you(int severity)
{
switch (severity)
{
@@ -2912,9 +3478,14 @@ static void _miscast_divination(int severity, const char* cause)
}
}
-static void _miscast_necromancy(int severity, const char* cause)
+// XXX: Monster divination miscasts.
+void MiscastEffect::_divination_mon(int severity)
+{
+}
+
+void MiscastEffect::_necromancy(int severity)
{
- if (you.religion == GOD_KIKUBAAQUDGHA
+ if (target->atype() == ACT_PLAYER && you.religion == GOD_KIKUBAAQUDGHA
&& !player_under_penance() && you.piety >= piety_breakpoint(1)
&& x_chance_in_y(you.piety, 150))
{
@@ -2922,10 +3493,6 @@ static void _miscast_necromancy(int severity, const char* cause)
return;
}
- const god_type god =
- (crawl_state.is_god_acting()) ? crawl_state.which_god_acting()
- : GOD_NO_GOD;
-
switch (severity)
{
case 0:
@@ -2933,41 +3500,50 @@ static void _miscast_necromancy(int severity, const char* cause)
{
case 0:
if (player_can_smell())
- mpr("You smell decay.");
+ all_msg = "You smell decay.";
else if (you.species == SP_MUMMY)
- mpr("Your bandages flutter.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ you_msg = "Your bandages flutter.";
break;
case 1:
- if (!silenced(you.pos()))
- mpr("You hear strange and distant voices.", MSGCH_SOUND);
- else
- mpr("You feel homesick.");
+ if (neither_end_silenced())
+ {
+ all_msg = "You hear strange and distant voices.";
+ msg_ch = MSGCH_SOUND;
+ }
+ else if (target->atype() == ACT_PLAYER)
+ you_msg = "You feel homesick.";
break;
case 2:
- mpr("Pain shoots through your body.");
+ you_msg = "Pain shoots through your body.";
+ // Monster messages needed.
break;
case 3:
- mpr("Your bones ache.");
+ you_msg = "Your bones ache.";
+ // Monster messages needed.
break;
case 4:
- mpr("The world around you seems to dim momentarily.");
+ you_msg = "The world around you seems to dim momentarily.";
+ mon_msg_seen = "@The_monster@ seems to dim momentarily.";
break;
case 5:
- mpr("Strange energies run through your body.");
+ you_msg = "Strange energies run through your body.";
+ // Monster messages needed.
break;
case 6:
- mpr("You shiver with cold.");
+ you_msg = "You shiver with cold.";
+ // Monster messages needed.
break;
case 7:
- mpr("You sense a malignant aura.");
+ you_msg = "You sense a malignant aura.";
+ // Monster messages needed.
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
- mpr("You feel very uncomfortable.");
+ you_msg = "You feel very uncomfortable.";
+ // Monster messages needed.
break;
}
break;
@@ -2976,29 +3552,37 @@ static void _miscast_necromancy(int severity, const char* cause)
switch (random2(3))
{
case 0:
- if (player_res_torment())
+ // Monster messages needed.
+ if (target->res_torment())
{
- mpr("You feel weird for a moment.");
+ you_msg = "You feel weird for a moment.";
+ do_msg();
break;
}
- mpr("Pain shoots through your body!");
- ouch(5 + random2avg(15, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "Pain shoots through your body!";
+ _ouch(5 + random2avg(15, 2));
break;
case 1:
- mpr("You feel horribly lethargic.");
- potion_effect(POT_SLOWING, 15);
+ you_msg = "You feel horribly lethargic.";
+ // Monster messages needed.
+ _potion_effect(POT_SLOWING, 15);
break;
case 2:
// josh declares mummies cannot smell {dlb}
- if (player_can_smell() && you.res_rotting() == 0)
+ if (target->res_rotting() == 0)
{
- mpr("You smell decay."); // identical to a harmless message
- you.rotting++;
+ if (player_can_smell())
+ // identical to a harmless message
+ all_msg = "You smell decay.";
+ if (target->atype() == ACT_PLAYER)
+ you.rotting++;
+ else
+ mon_target->add_ench( mon_enchant(ENCH_ROT, 1, kc) );
}
else if (you.species == SP_MUMMY)
- mpr("Your bandages flutter.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Monster messages needed.
+ you_msg = "Your bandages flutter.";
+ do_msg();
break;
}
break;
@@ -3012,97 +3596,100 @@ static void _miscast_necromancy(int severity, const char* cause)
for (int i = random2(3); i >= 0; --i)
{
- if (create_monster(
- mgen_data::hostile_at(MONS_SHADOW,
- you.pos(), 2, 0, true, god)) != -1)
- {
+ if (_create_monster(MONS_SHADOW, 2, true))
success = true;
- }
}
if (success)
- mpr("Flickering shadows surround you.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ {
+ you_msg = "Flickering shadows surround you.";
+ mon_msg_seen = "Flickering shadows surround @the_monster@.";
+ mon_msg_unseen = "Shadows flicker in the thin air.";
+ }
+ do_msg();
break;
}
case 1:
- if (!player_prot_life() && one_chance_in(3))
+ if (target->atype() == ACT_PLAYER && !player_prot_life()
+ && one_chance_in(3))
{
drain_exp();
break;
} // otherwise it just flows through...
case 2:
- if (player_res_torment())
+ // Monster messages needed.
+ if (target->res_torment())
{
- mpr("You feel weird for a moment.");
+ you_msg = "You feel weird for a moment.";
+ do_msg();
break;
}
- mpr("You convulse helplessly as pain tears through your body!");
- ouch(15 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "You convulse helplessly as pain tears through "
+ "your body!";
+ _ouch(15 + random2avg(23, 2));
break;
}
break;
case 3: // even nastier
- switch (random2(6))
+ // Don't use two last cases for monsters.
+ switch (random2(target->atype() == ACT_PLAYER ? 6 : 4))
{
case 0:
- if (you.is_undead)
+ if (target->holiness() == MH_UNDEAD)
{
- mpr("Something just walked over your grave. No, really!");
+ // Monster messages needed.
+ you_msg = "Something just walked over your grave. No, really!";
+ do_msg();
break;
}
- torment_monsters(you.pos(), 0, TORMENT_GENERIC);
+ torment_monsters(target->pos(), 0, TORMENT_GENERIC);
break;
case 1:
- mpr("You are engulfed in negative energy!");
-
- if (!player_prot_life())
- {
- drain_exp();
- break;
- } // otherwise it just flows through...
+ target->rot(act_source, random2avg(7, 2) + 1, 0);
+ break;
case 2:
- lose_stat(STAT_RANDOM, 1 + random2avg(7, 2), false, cause);
+ if (_create_monster(MONS_SOUL_EATER, 4, true))
+ {
+ // Monster messages needed.
+ you_msg = "Something reaches out for you...";
+ }
+ do_msg();
break;
case 3:
- rot_player( random2avg(7, 2) + 1 );
+ if (_create_monster(MONS_REAPER, 4, true))
+ {
+ // Monster messages needed.
+ you_msg = "Death has come for you...";
+ }
+ do_msg();
break;
case 4:
- if (create_monster(
- mgen_data::hostile_at(MONS_SOUL_EATER,
- you.pos(), 4, 0, true, god)) != -1)
+ mpr("You are engulfed in negative energy!");
+
+ if (!player_prot_life())
{
- mpr("Something reaches out for you...");
- }
- else
- canned_msg(MSG_NOTHING_HAPPENS);
- break;
+ drain_exp();
+ break;
+ } // otherwise it just flows through...
case 5:
- if (create_monster(
- mgen_data::hostile_at(MONS_REAPER,
- you.pos(), 4, 0, true, god)) != -1)
- {
- mpr("Death has come for you...");
- }
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ lose_stat(STAT_RANDOM, 1 + random2avg(7, 2), false, cause);
break;
+
}
break;
}
}
-static void _miscast_transmigration(int severity, const char* cause)
+void MiscastEffect::_transmigration(int severity)
{
switch (severity)
{
@@ -3110,50 +3697,60 @@ static void _miscast_transmigration(int severity, const char* cause)
switch (random2(10))
{
case 0:
- msg::stream << "Your " << your_hand(true)
- << " glow momentarily." << std::endl;
+ _your_hands_glow(target, you_msg, mon_msg_seen);
break;
case 1:
- mpr("The air around you crackles with energy!");
+ you_msg = "The air around you crackles with energy!";
+ mon_msg_seen = "The air around @the_monster@ crackles with"
+ " energy!";
+ mon_msg_unseen = "The thin air crackles with energy!";
break;
case 2:
- mpr("Multicolored lights dance before your eyes!");
+ you_msg = "Multicolored lights dance before your eyes!";
+ // Monster messages needed.
break;
case 3:
- mpr("You feel a strange surge of energy!");
+ you_msg = "You feel a strange surge of energy!";
+ // Monster messages needed.
break;
case 4:
- mpr("Waves of light ripple over your body.");
+ you_msg = "Waves of light ripple over your body.";
+ mon_msg_seen = "Waves of light ripple over @the_monster@'s body.";
+ mon_msg_unseen = "Waves of light ripple in the air.";
break;
case 5:
- mpr("Strange energies run through your body.");
+ you_msg = "Strange energies run through your body.";
+ // Monster messages needed.
break;
case 6:
- mpr("Your skin tingles.");
+ you_msg = "Your skin tingles.";
+ // Monster messages needed.
break;
case 7:
- mpr("Your skin glows momentarily.");
+ you_msg = "Your skin glows momentarily.";
+ mon_msg_seen = "@The_monster@'s body glows momentarily.";
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
if (player_can_smell())
- mpr("You smell something strange.");
+ all_msg = "You smell something strange.";
else if (you.species == SP_MUMMY)
- mpr("Your bandages flutter.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ you_msg = "Your bandages flutter.";
break;
}
+ do_msg();
break;
case 1: // slightly annoying
switch (random2(2))
{
case 0:
- mpr("Your body is twisted painfully.");
- ouch(1 + random2avg(11, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "Your body is twisted painfully.";
+ mon_msg_seen = "@The_monster@'s body twists unnaturally.";
+ _ouch(1 + random2avg(11, 2));
break;
case 1:
random_uselessness();
@@ -3162,123 +3759,147 @@ static void _miscast_transmigration(int severity, const char* cause)
break;
case 2: // much more annoying
- switch (random2(4))
+ // Last case for players only.
+ switch (random2(target->atype() == ACT_PLAYER ? 4 : 3))
{
case 0:
- mpr("Your body is twisted very painfully!");
- ouch(3 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "Your body is twisted very painfully!";
+ mon_msg_seen = "@The_monster@'s body twists and writhes.";
+ _ouch(3 + random2avg(23, 2));
break;
case 1:
- mpr("You feel saturated with unharnessed energies!");
- you.magic_contamination += random2avg(19,3);
+ _potion_effect(POT_PARALYSIS, 10);
break;
case 2:
- potion_effect(POT_PARALYSIS, 10);
+ _potion_effect(POT_CONFUSION, 10);
break;
case 3:
- potion_effect(POT_CONFUSION, 10);
+ mpr("You feel saturated with unharnessed energies!");
+ you.magic_contamination += random2avg(19,3);
break;
}
break;
case 3: // even nastier
+ if (target->atype() == ACT_MONSTER)
+ target->mutate(); // Polymorph the monster, if possible.
switch (random2(3))
{
case 0:
- mpr("Your body is flooded with distortional energies!");
- you.magic_contamination += random2avg(35, 3);
+ if (target->atype() == ACT_PLAYER)
+ {
+ mpr("Your body is flooded with distortional energies!");
+ you.magic_contamination += random2avg(35, 3);
+ }
- ouch(3 + random2avg(18, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ _ouch(3 + random2avg(18, 2));
break;
case 1:
- mpr("You feel very strange.");
- delete_mutation(RANDOM_MUTATION);
- ouch(5 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ if (target->atype() == ACT_PLAYER)
+ {
+ mpr("You feel very strange.");
+ delete_mutation(RANDOM_MUTATION);
+ }
+ _ouch(5 + random2avg(23, 2));
break;
case 2:
- mpr("Your body is distorted in a weirdly horrible way!");
+ if (target->atype() == ACT_PLAYER)
{
+ mpr("Your body is distorted in a weirdly horrible way!");
const bool failMsg = !give_bad_mutation();
if (coinflip())
give_bad_mutation(failMsg);
- ouch(5 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
}
+ _ouch(5 + random2avg(23, 2));
break;
}
break;
}
}
-static void _miscast_fire(int severity, const char* cause)
+void MiscastEffect::_fire(int severity)
{
- bolt beam;
switch (severity)
{
case 0: // just a harmless message
switch (random2(10))
{
case 0:
- msg::stream << "Sparks fly from your " << your_hand(true)
- << '!' << std::endl;
+ you_msg = "Sparks fly from your @hands@!";
+ mon_msg_seen = "Sparks fly from @the_monster@'s @hands@!";
break;
case 1:
- mpr("The air around you burns with energy!");
+ you_msg = "The air around you burns with energy!";
+ mon_msg_seen = "The air around @the_monster@ burns with energy!";
break;
case 2:
- msg::stream << "Wisps of smoke drift from your "
- << your_hand(true) << '.' << std::endl;
+ you_msg = "Wisps of smoke drift from your @hands@.";
+ mon_msg_seen = "Wisps of smoke drift from @the_monster@'s @hands@.";
break;
case 3:
- mpr("You feel a strange surge of energy!");
+ you_msg = "You feel a strange surge of energy!";
+ // Monster messages needed.
break;
case 4:
if (player_can_smell())
- mpr("You smell smoke.");
+ all_msg = "You smell smoke.";
else if (you.species == SP_MUMMY)
- mpr("Your bandages flutter.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ you_msg = "Your bandages flutter.";
break;
case 5:
- mpr("Heat runs through your body.");
+ you_msg = "Heat runs through your body.";
+ // Monster messages needed.
break;
case 6:
- mpr("You feel uncomfortably hot.");
+ you_msg = "You feel uncomfortably hot.";
+ // Monster messages needed.
break;
case 7:
- mpr("Lukewarm flames ripple over your body.");
+ you_msg = "Lukewarm flames ripple over your body.";
+ mon_msg_seen = "Dim flames ripple over @the_monster@'s body.";
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
- if (!silenced(you.pos()))
- mpr("You hear a sizzling sound.", MSGCH_SOUND);
- else
- mpr("You feel like you have heartburn.");
+ if (neither_end_silenced())
+ {
+ all_msg = "You hear a sizzling sound.";
+ msg_ch = MSGCH_SOUND;
+ }
+ else if (target->atype() == ACT_PLAYER)
+ you_msg = "You feel like you have heartburn.";
break;
}
+ do_msg();
break;
case 1: // a bit less harmless stuff
switch (random2(2))
{
case 0:
- msg::stream << "Smoke pours from your "
- << your_hand(true) << "!" << std::endl;
- big_cloud( random_smoke_type(), (cause ? KC_OTHER : KC_YOU),
- you.x_pos, you.y_pos, 20, 7 + random2(7) );
+ you_msg = "Smoke pours from your @hands@!";
+ mon_msg_seen = "Smoke pours from @the_monster@'s @hands@!";
+ mon_msg_unseen = "Smoke appears out of nowhere!";
+
+ do_msg();
+ big_cloud( random_smoke_type(), kc, kt,
+ target->pos().x, target->pos().y, 20, 7 + random2(7) );
break;
case 1:
- mpr("Flames sear your flesh.");
- expose_player_to_element(BEAM_FIRE, 3);
+ you_msg = "Flames sear your flesh.";
+ mon_msg_seen = "Flames sear @the_monster@.";
- if (player_res_fire() < 0)
- ouch(2 + random2avg(13, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ if (target->res_fire() < 0)
+ _ouch(2 + random2avg(13, 2));
+ else
+ do_msg();
+ target->expose_to_element(BEAM_FIRE, 3);
break;
}
@@ -3288,31 +3909,25 @@ static void _miscast_fire(int severity, const char* cause)
switch (random2(2))
{
case 0:
- mpr("You are blasted with fire.");
-
- ouch( check_your_resists( 5 + random2avg(29, 2), BEAM_FIRE ), 0,
- KILLED_BY_WILD_MAGIC, cause );
+ you_msg = "You are blasted with fire.";
+ mon_msg_seen = "@The_monster@ is blasted with fire.";
+ mon_msg_unseen = "A flame briefly burns in thin air.";
- expose_player_to_element(BEAM_FIRE, 5);
+ _ouch(5 + random2avg(29, 2), BEAM_FIRE );
+ target->expose_to_element(BEAM_FIRE, 5);
break;
case 1:
- mpr("You are caught in a fiery explosion!");
- beam.type = dchar_glyph(DCHAR_FIRED_BURST);
- beam.damage = dice_def( 3, 14 );
+ you_msg = "You are caught in a fiery explosion!";
+ mon_msg_seen = "@The_monster@ is caught in a fiery explosion!";
+ mon_msg_unseen = "Fire explodes from out of thin air!";
+
+ beam.type = dchar_glyph(DCHAR_FIRED_BURST);
+ beam.damage = dice_def( 3, 14 );
beam.flavour = BEAM_FIRE;
- beam.target_x = you.x_pos;
- beam.target_y = you.y_pos;
- beam.name = "explosion";
- beam.colour = RED;
- beam.beam_source = NON_MONSTER;
- beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
- beam.aux_source.clear();
- if (cause)
- beam.aux_source = cause;
- beam.ex_size = 1;
- beam.is_explosion = true;
- explosion(beam);
+ beam.name = "explosion";
+ beam.colour = RED;
+ _explosion();
break;
}
break;
@@ -3321,85 +3936,100 @@ static void _miscast_fire(int severity, const char* cause)
switch (random2(3))
{
case 0:
- mpr("You are blasted with searing flames!");
+ you_msg = "You are blasted with searing flames!";
+ mon_msg_seen = "@The_monster@ is blasted with searing flames!";
+ mon_msg_unseen = "A large flame burns hotly for a moment in the "
+ "thin air.";
- ouch( check_your_resists( 9 + random2avg(33, 2), BEAM_FIRE ), 0,
- KILLED_BY_WILD_MAGIC, cause );
+ _ouch(9 + random2avg(33, 2), BEAM_FIRE);
- expose_player_to_element(BEAM_FIRE, 10);
+ target->expose_to_element(BEAM_FIRE, 10);
break;
case 1:
- mpr("There is a sudden and violent explosion of flames!");
- beam.type = dchar_glyph(DCHAR_FIRED_BURST);
- beam.damage = dice_def( 3, 20 );
+ all_msg = "There is a sudden and violent explosion of flames!";
+
+ beam.type = dchar_glyph(DCHAR_FIRED_BURST);
+ beam.damage = dice_def( 3, 20 );
beam.flavour = BEAM_FIRE;
- beam.target_x = you.x_pos;
- beam.target_y = you.y_pos;
- beam.name = "fireball";
- beam.colour = RED;
- beam.beam_source = NON_MONSTER;
- beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
- beam.aux_source.clear();
- if (cause)
- beam.aux_source = cause;
+ beam.name = "fireball";
+ beam.colour = RED;
beam.ex_size = coinflip()?1:2;
- beam.is_explosion = true;
- explosion(beam);
+ _explosion();
break;
case 2:
- mpr("You are covered in liquid flames!");
- you.duration[DUR_LIQUID_FLAMES] += random2avg(7, 3) + 1;
+ {
+ you_msg = "You are covered in liquid flames!";
+ mon_msg_seen = "@The_monster@ is covered in liquid flames!";
+ do_msg();
+
+ int dur = random2avg(7, 3) + 1;
+ if (target->atype() == ACT_PLAYER)
+ you.duration[DUR_LIQUID_FLAMES] += dur;
+ else
+ mon_target->add_ench( mon_enchant(ENCH_STICKY_FLAME, dur, kc) );
break;
+ }
}
break;
}
}
-static void _miscast_ice(int severity, const char* cause)
+void MiscastEffect::_ice(int severity)
{
- bolt beam;
switch (severity)
{
case 0: // just a harmless message
switch (random2(10))
{
case 0:
- mpr("You shiver with cold.");
+ you_msg = "You shiver with cold.";
+ // Monster messages needed.
break;
case 1:
- mpr("A chill runs through your body.");
+ you_msg = "A chill runs through your body.";
+ // Monster messages needed.
break;
case 2:
- msg::stream << "Wisps of condensation drift from your "
- << your_hand(true) << "." << std::endl;
+ you_msg = "Wisps of condensation drift from your @hands@.";
+ mon_msg_seen = "Wisps of condensation drift from @the_monster@'s "
+ "@hands@.";
break;
case 3:
- mpr("You feel a strange surge of energy!");
+ you_msg = "You feel a strange surge of energy!";
+ // Monster messages needed.
break;
case 4:
- msg::stream << "Your " << your_hand(true)
- << " feel numb with cold." << std::endl;
+ you_msg = "Your @hands@ feel numb with cold.";
+ // Monster messages needed.
break;
case 5:
- mpr("A chill runs through your body.");
+ you_msg = "A chill runs through your body.";
+ // Monster messages needed.
break;
case 6:
- mpr("You feel uncomfortably cold.");
+ you_msg = "You feel uncomfortably cold.";
+ // Monster messages needed.
break;
case 7:
- mpr("Frost covers your body.");
+ you_msg = "Frost covers your body.";
+ mon_msg_seen = "Frost covers @the_monster@'s body.";
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
- if (!silenced(you.pos()))
- mpr("You hear a crackling sound.", MSGCH_SOUND);
- else
- mpr("A snowflake lands on your nose.");
+ if (neither_end_silenced())
+ {
+ all_msg = "You hear a crackling sound.";
+ msg_ch = MSGCH_SOUND;
+ }
+ else if (target->atype() == ACT_PLAYER)
+ you_msg = "A snowflake lands on your nose.";
break;
}
+ do_msg();
break;
case 1: // a bit less harmless stuff
@@ -3407,13 +4037,17 @@ static void _miscast_ice(int severity, const char* cause)
{
case 0:
mpr("You feel extremely cold.");
+ // Monster messages needed.
break;
case 1:
- mpr("You are covered in a thin layer of ice.");
- expose_player_to_element(BEAM_COLD, 2);
+ you_msg = "You are covered in a thin layer of ice.";
+ mon_msg_seen = "@The_monster@ is covered in a thin layer of ice.";
- if (player_res_cold() < 0)
- ouch(4 + random2avg(5, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ if (target->res_cold() < 0)
+ _ouch(4 + random2avg(5, 2));
+ else
+ do_msg();
+ target->expose_to_element(BEAM_COLD, 2);
break;
}
break;
@@ -3422,32 +4056,27 @@ static void _miscast_ice(int severity, const char* cause)
switch (random2(2))
{
case 0:
- mpr("Heat is drained from your body.");
+ you_msg = "Heat is drained from your body.";
+ // Monster messages needed.
- ouch(check_your_resists(5 + random2(6) + random2(7), BEAM_COLD), 0,
- KILLED_BY_WILD_MAGIC, cause);
+ _ouch(5 + random2(6) + random2(7), BEAM_COLD);
- expose_player_to_element(BEAM_COLD, 4);
+ target->expose_to_element(BEAM_COLD, 4);
break;
case 1:
- mpr("You are caught in an explosion of ice and frost!");
- beam.type = dchar_glyph(DCHAR_FIRED_BURST);
- beam.damage = dice_def( 3, 11 );
+ you_msg = "You are caught in an explosion of ice and frost!";
+ mon_msg_seen = "@The_monster@ is caught in an explosion of "
+ "ice and frost!";
+ mon_msg_unseen = "Ice and frost explode from out of thin air!";
+
+ beam.type = dchar_glyph(DCHAR_FIRED_BURST);
+ beam.damage = dice_def( 3, 11 );
beam.flavour = BEAM_COLD;
- beam.target_x = you.x_pos;
- beam.target_y = you.y_pos;
- beam.name = "explosion";
- beam.colour = WHITE;
- beam.beam_source = NON_MONSTER;
- beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
- beam.aux_source.clear();
- if (cause)
- beam.aux_source = cause;
- beam.ex_size = 1;
- beam.is_explosion = true;
+ beam.name = "explosion";
+ beam.colour = WHITE;
- explosion(beam);
+ _explosion();
break;
}
break;
@@ -3456,27 +4085,29 @@ static void _miscast_ice(int severity, const char* cause)
switch (random2(2))
{
case 0:
- mpr("You are blasted with ice!");
+ you_msg = "You are blasted with ice!";
+ mon_msg_seen = "@The_monster@ is blasted with ice!";
- ouch(check_your_resists(9 + random2avg(23, 2), BEAM_ICE), 0,
- KILLED_BY_WILD_MAGIC, cause);
+ _ouch(9 + random2avg(23, 2), BEAM_ICE);
- expose_player_to_element(BEAM_COLD, 9);
+ target->expose_to_element(BEAM_COLD, 9);
break;
case 1:
- msg::stream << "Freezing gasses pour from your "
- << your_hand(true) << "!" << std::endl;
- big_cloud(CLOUD_COLD, (cause ? KC_OTHER : KC_YOU),
- you.x_pos, you.y_pos, 20, 8 + random2(4));
+ you_msg = "Freezing gasses pour from your @hands@!";
+ mon_msg_seen = "Freezing gasses pour from @the_monsters@'s "
+ " @hands@!";
+
+ do_msg();
+ big_cloud(CLOUD_COLD, kc, kt,
+ target->pos().x, target->pos().y, 20, 8 + random2(4));
break;
}
break;
}
}
-static void _miscast_earth(int severity, const char* cause)
+void MiscastEffect::_earth(int severity)
{
- bolt beam;
switch (severity)
{
case 0: // just a harmless message
@@ -3484,50 +4115,62 @@ static void _miscast_earth(int severity, const char* cause)
switch (random2(10))
{
case 0:
- mpr("You feel earthy.");
+ you_msg = "You feel earthy.";
+ // Monster messages needed.
break;
case 1:
- mpr("You are showered with tiny particles of grit.");
+ you_msg = "You are showered with tiny particles of grit.";
+ mon_msg_seen = "@The_monster@ is showered with tiny particles "
+ "of grit.";
break;
case 2:
- msg::stream << "Sand pours from your "
- << your_hand(true) << "." << std::endl;
+ you_msg = "Sand pours from your @hands@.";
+ mon_msg_seen = "Sand pours from @the_monster@'s @hands@.";
break;
case 3:
- mpr("You feel a surge of energy from the ground.");
+ you_msg = "You feel a surge of energy from the ground.";
+ // Monster messages needed.
break;
case 4:
- if (!silenced(you.pos()))
- mpr("You hear a distant rumble.", MSGCH_SOUND);
- else
- mpr("You sympathise with the stones.");
+ if (neither_end_silenced())
+ {
+ all_msg = "You hear a distant rumble.";
+ msg_ch = MSGCH_SOUND;
+ }
+ else if (target->atype() == ACT_PLAYER)
+ you_msg = "You sympathise with the stones.";
break;
case 5:
- mpr("You feel gritty.");
+ you_msg = "You feel gritty.";
+ // Monster messages needed.
break;
case 6:
- mpr("You feel momentarily lethargic.");
+ you_msg = "You feel momentarily lethargic.";
+ // Monster messages needed.
break;
case 7:
- mpr("Motes of dust swirl before your eyes.");
+ you_msg = "Motes of dust swirl before your eyes.";
+ // Monster messages needed.
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
- mprf("Your %s warm.",
- (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR)
- ? "lowest portion feels" :
- (!transform_changed_physiology() ?
- (player_mutation_level(MUT_HOOVES)) ? "hooves feel" :
- (player_mutation_level(MUT_TALONS)) ? "talons feel" :
- (you.species == SP_NAGA) ? "underbelly feels" :
- (you.species == SP_MERFOLK
- && player_is_swimming()) ? "tail feels"
- : "feet feel"
- : "feet feel"));
+ {
+ bool pluralized = true;
+ std::string feet = you.foot_name(true, &pluralized);
+ std::ostringstream str;
+
+ str << "Your " << feet << (pluralized ? " feel" : " feels")
+ << " warm";
+
+ you_msg = str.str();
+ // Monster messages needed.
break;
}
+ }
+ do_msg();
break;
case 2: // slightly less harmless stuff
@@ -3537,17 +4180,23 @@ static void _miscast_earth(int severity, const char* cause)
switch (random2(3))
{
case 0:
- mpr("You are hit by flying rocks!");
+ you_msg = "You are hit by flying rocks!";
+ mon_msg_seen = "@The_monster@ is hit by flying rocks!";
+ mon_msg_unseen = "Flying rocks appear out of thin air!";
break;
case 1:
- mpr("You are blasted with sand!");
+ you_msg = "You are blasted with sand!";
+ mon_msg_seen = "@The_monster@ is blasted with sand!";
+ mon_msg_unseen = "A minature sandstorm briefly appears!";
break;
case 2:
- mpr("Rocks fall onto you out of nowhere!");
+ you_msg = "Rocks fall onto you out of nowhere!";
+ mon_msg_seen = "Rocks fall onto @the_monster@ out of "
+ "nowhere!";
+ mon_msg_unseen = "Rocks fall out of nowhere!";
break;
}
- ouch( random2avg(13,2) + 10 - random2(1 + player_AC()),
- 0, KILLED_BY_WILD_MAGIC, cause);
+ _ouch(random2avg(13,2) + 10 - random2(1 + target->armour_class()));
break;
}
break;
@@ -3556,12 +4205,14 @@ static void _miscast_earth(int severity, const char* cause)
switch (random2(1))
{
case 0:
- mpr("You are caught in an explosion of flying shrapnel!");
+ you_msg = "You are caught in an explosion of flying "
+ "shrapnel!";
+ mon_msg_seen = "@The_monster@ is caught in an explosion of "
+ "flying shrapnel!";
+ mon_msg_unseen = "Flying shrapnel explodes from the thin air!";
beam.type = dchar_glyph(DCHAR_FIRED_BURST);
beam.damage = dice_def( 3, 15 );
beam.flavour = BEAM_FRAG;
- beam.target_x = you.x_pos;
- beam.target_y = you.y_pos;
beam.name = "explosion";
beam.colour = CYAN;
@@ -3570,141 +4221,170 @@ static void _miscast_earth(int severity, const char* cause)
if (one_chance_in(5))
beam.colour = LIGHTCYAN;
- beam.beam_source = NON_MONSTER;
- beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
- beam.aux_source.clear();
- if (cause)
- beam.aux_source = cause;
- beam.ex_size = 1;
- beam.is_explosion = true;
-
- explosion(beam);
+ _explosion();
break;
}
break;
}
}
-static void _miscast_air(int severity, const char* cause)
+void MiscastEffect::_air(int severity)
{
- bolt beam;
switch (severity)
{
case 0: // just a harmless message
switch (random2(10))
{
case 0:
- mpr("Ouch! You gave yourself an electric shock.");
+ you_msg = "Ouch! You gave yourself an electric shock.";
+ // Monster messages needed.
break;
case 1:
- mpr("You feel momentarily weightless.");
+ you_msg = "You feel momentarily weightless.";
+ // Monster messages needed.
break;
case 2:
- msg::stream << "Wisps of vapour drift from your "
- << your_hand(true) << "." << std::endl;
+ you_msg = "Wisps of vapour drift from your @hands@.";
+ mon_msg_seen = "Wisps of vapour drift from @the_monster@'s "
+ "@hands@.";
break;
case 3:
- mpr("You feel a strange surge of energy!");
+ you_msg = "You feel a strange surge of energy!";
+ // Monster messages needed.
break;
case 4:
- mpr("You feel electric!");
+ you_msg = "You feel electric!";
+ // Monster messages needed.
break;
case 5:
- msg::stream << "Sparks of electricity dance between your "
- << your_hand(true) << "." << std::endl;
+ {
+ bool pluralized = true;
+ target->hand_name(true, &pluralized);
+
+ if (pluralized)
+ {
+ you_msg = "Sparks of electricity dance between your "
+ "@hands@.";
+ mon_msg_seen = "Sparks of electricity dance between "
+ "@the_monster@'s @hands@.";
+ }
+ else
+ {
+ you_msg = "Sparks of electricity dance over your "
+ "@hand@.";
+ mon_msg_seen = "Sparks of electricity dance over "
+ "@the_monster@'s @hand@.";
+ }
break;
+ }
case 6:
- mpr("You are blasted with air!");
+ you_msg = "You are blasted with air!";
+ // Monster messages needed.
break;
case 7:
- if (!silenced(you.pos()))
- mpr("You hear a whooshing sound.", MSGCH_SOUND);
+ if (neither_end_silenced())
+ {
+ all_msg = "You hear a whooshing sound.";
+ msg_ch = MSGCH_SOUND;
+ }
else if (player_can_smell())
- mpr("You smell ozone.");
+ all_msg = "You smell ozone.";
else if (you.species == SP_MUMMY)
- mpr("Your bandages flutter.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ you_msg = "Your bandages flutter.";
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
- if (!silenced(you.pos()))
- mpr("You hear a crackling sound.", MSGCH_SOUND);
+ if (neither_end_silenced())
+ {
+ all_msg = "You hear a crackling sound.";
+ msg_ch = MSGCH_SOUND;
+ }
else if (player_can_smell())
- mpr("You smell something musty.");
+ all_msg = "You smell something musty.";
else if (you.species == SP_MUMMY)
- mpr("Your bandages flutter.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ you_msg = "Your bandages flutter.";
break;
}
+ do_msg();
break;
case 1: // a bit less harmless stuff
switch (random2(2))
{
case 0:
- mpr("There is a short, sharp shower of sparks.");
+ you_msg = "There is a short, sharp shower of sparks.";
+ mon_msg_seen = "@The_monster@ is briefly showered in sparks.";
break;
case 1:
- mprf("The wind %s around you!",
- silenced(you.pos()) ? "whips" : "howls");
+ if (silenced(you.pos()))
+ all_msg = "The wind whips around you!";
+ else
+ all_msg = "The wind howls around you!";
break;
}
+ do_msg();
break;
case 2: // rather less harmless stuff
switch (random2(2))
{
case 0:
- mpr("Electricity courses through your body.");
- ouch(check_your_resists(4 + random2avg(9, 2), BEAM_ELECTRICITY), 0,
- KILLED_BY_WILD_MAGIC, cause);
+ you_msg = "Electricity courses through your body.";
+ // Monster messages needed.
+ _ouch(4 + random2avg(9, 2), BEAM_ELECTRICITY);
break;
case 1:
- msg::stream << "Noxious gasses pour from your "
- << your_hand(true) << "!" << std::endl;
- big_cloud(CLOUD_STINK, (cause ? KC_OTHER : KC_YOU),
- you.x_pos, you.y_pos, 20, 9 + random2(4));
+ you_msg = "Noxious gasses pour from your @hands@!";
+ mon_msg_seen = "Noxious gasses pour from @the_monster@'s "
+ "@hands@!";
+ mon_msg_unseen = "Noxious gasses appear from out of thin air!";
+
+ do_msg();
+ big_cloud(CLOUD_STINK, kc, kt,
+ target->pos().x, target->pos().y, 20, 9 + random2(4));
break;
}
break;
- case 3: // less harmless stuff
+ case 3: // musch less harmless stuff
switch (random2(2))
{
case 0:
- mpr("You are caught in an explosion of electrical discharges!");
- beam.type = dchar_glyph(DCHAR_FIRED_BURST);
- beam.damage = dice_def( 3, 8 );
+ you_msg = "You are caught in an explosion of electrical "
+ "discharges!";
+ mon_msg_seen = "@The_monster@ is caught in an explosion of "
+ "electrical discharges!";
+ mon_msg_unseen = "Elecectrical discharges explodes from out of "
+ "thin air!";
+
+ beam.type = dchar_glyph(DCHAR_FIRED_BURST);
+ beam.damage = dice_def( 3, 8 );
beam.flavour = BEAM_ELECTRICITY;
- beam.target_x = you.x_pos;
- beam.target_y = you.y_pos;
- beam.name = "explosion";
- beam.colour = LIGHTBLUE;
- beam.beam_source = NON_MONSTER;
- beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
- beam.aux_source.clear();
- if (cause)
- beam.aux_source = cause;
+ beam.name = "explosion";
+ beam.colour = LIGHTBLUE;
beam.ex_size = one_chance_in(4)?1:2;
- beam.is_explosion = true;
- explosion(beam);
+ _explosion();
break;
case 1:
- msg::stream << "Venomous gasses pour from your "
- << your_hand(true) << "!" << std::endl;
- big_cloud( CLOUD_POISON, (cause ? KC_OTHER : KC_YOU),
- you.x_pos, you.y_pos, 20, 8 + random2(5) );
+ you_msg = "Venomous gasses pour from your @hands@!";
+ mon_msg_seen = "Venomous gasses pour from @the_monster@'s "
+ "@hands@!";
+ mon_msg_unseen = "Venomous gasses pour forth from the thin air!";
+
+ do_msg();
+ big_cloud( CLOUD_POISON, kc, kt,
+ target->pos().x, target->pos().y, 20, 8 + random2(5) );
break;
}
}
}
-static void _miscast_poison(int severity, const char* cause)
+// XXX MATT
+void MiscastEffect::_poison(int severity)
{
switch (severity)
{
@@ -3712,83 +4392,101 @@ static void _miscast_poison(int severity, const char* cause)
switch (random2(10))
{
case 0:
- mpr("You feel mildly nauseous.");
+ you_msg = "You feel mildly nauseous.";
+ // Monster messages needed.
break;
case 1:
- mpr("You feel slightly ill.");
+ you_msg = "You feel slightly ill.";
+ // Monster messages needed.
break;
case 2:
- msg::stream << "Wisps of poison gas drift from your "
- << your_hand(true) << "." << std::endl;
+ you_msg = "Wisps of poison gas drift from your @hands@.";
+ mon_msg_seen = "Wisps of poison gas drift from @the_monster@'s "
+ "@hands@.";
break;
case 3:
- mpr("You feel a strange surge of energy!");
+ you_msg = "You feel a strange surge of energy!";
+ // Monster messages needed.
break;
case 4:
- mpr("You feel faint for a moment.");
+ you_msg = "You feel faint for a moment.";
+ // Monster messages needed.
break;
case 5:
- mpr("You feel sick.");
+ you_msg = "You feel sick.";
+ // Monster messages needed.
break;
case 6:
- mpr("You feel odd.");
+ you_msg = "You feel odd.";
+ // Monster messages needed.
break;
case 7:
- mpr("You feel weak for a moment.");
+ you_msg = "You feel weak for a moment.";
+ // Monster messages needed.
break;
case 8:
- canned_msg(MSG_NOTHING_HAPPENS);
+ // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
+ // care of elsewhere.
break;
case 9:
- if (!silenced(you.pos()))
- mpr("You hear a slurping sound.", MSGCH_SOUND);
+ if (neither_end_silenced())
+ {
+ all_msg = "You hear a slurping sound.";
+ msg_ch = MSGCH_SOUND;
+ }
else if (you.species != SP_MUMMY)
- mpr("You taste almonds.");
- else
- canned_msg(MSG_NOTHING_HAPPENS);
+ you_msg = "You taste almonds.";
break;
}
+ do_msg();
break;
case 1: // a bit less harmless stuff
switch (random2(2))
{
case 0:
- if (player_res_poison())
- canned_msg(MSG_NOTHING_HAPPENS);
- else
+ if (target->res_poison() <= 0)
{
- mpr("You feel sick.");
- poison_player( 2 + random2(3) );
+ you_msg = "You feel sick.";
+ // Monster messages needed.
+ target->poison( act_source, 2 + random2(3) );
}
+ do_msg();
break;
case 1:
- msg::stream << "Noxious gasses pour from your "
- << your_hand(true) << "!" << std::endl;
- place_cloud(CLOUD_STINK, you.pos(),
- 2 + random2(4), (cause ? KC_OTHER : KC_YOU) );
+ you_msg = "Noxious gasses pour from your @hands@!";
+ mon_msg_seen = "Noxious gasses pour from @the_monster@'s "
+ "@hands@!";
+ mon_msg_unseen = "Noxious gasses pour forth from the thin air!";
+ place_cloud(CLOUD_STINK, target->pos(), 2 + random2(4), kc, kt );
break;
}
break;
case 2: // rather less harmless stuff
- switch (random2(3))
+ // Don't use last case for monsters.
+ switch (random2(target->atype() == ACT_PLAYER ? 3 : 2))
{
case 0:
- if (player_res_poison())
- canned_msg(MSG_NOTHING_HAPPENS);
- else
+ if (target->res_poison() <= 0)
{
- mpr("You feel very sick.");
- poison_player( 3 + random2avg(9, 2) );
+ you_msg = "You feel very sick.";
+ // Monster messages needed.
+ target->poison( act_source, 3 + random2avg(9, 2) );
}
+ do_msg();
break;
case 1:
- mpr("Noxious gasses pour from your hands!");
- big_cloud(CLOUD_STINK, (cause ? KC_OTHER : KC_YOU),
- you.x_pos, you.y_pos, 20, 8 + random2(5));
+ you_msg = "Noxious gasses pour from your @hands@!";
+ mon_msg_seen = "Noxious gasses pour from @the_monster@'s "
+ "@hands@!";
+ mon_msg_unseen = "Noxious gasses pour forth from the thin air!";
+
+ do_msg();
+ big_cloud(CLOUD_STINK, kc, kt,
+ target->pos().x, target->pos().y, 20, 8 + random2(5));
break;
case 2:
@@ -3801,22 +4499,26 @@ static void _miscast_poison(int severity, const char* cause)
break;
case 3: // less harmless stuff
- switch (random2(3))
+ // Don't use last case for monsters.
+ switch (random2(target->atype() == ACT_PLAYER ? 3 : 2))
{
case 0:
- if (player_res_poison())
- canned_msg(MSG_NOTHING_HAPPENS);
- else
+ if (target->res_poison() <= 0)
{
- mpr("You feel incredibly sick.");
- poison_player( 10 + random2avg(19, 2) );
+ you_msg = "You feel incredibly sick.";
+ // Monster messages needed.
+ target->poison( act_source, 10 + random2avg(19, 2) );
}
+ do_msg();
break;
case 1:
- msg::stream << "Venomous gasses pour from your "
- << your_hand(true) << "!" << std::endl;
- big_cloud(CLOUD_POISON, (cause ? KC_OTHER : KC_YOU),
- you.x_pos, you.y_pos, 20, 7 + random2(7));
+ you_msg = "Venomous gasses pour from your @hands@!";
+ mon_msg_seen = "Venomous gasses pour from @the_monster@'s @hands@!";
+ mon_msg_unseen = "Venomous gasses pour forth from the thin air!";
+
+ do_msg();
+ big_cloud(CLOUD_POISON, kc, kt,
+ target->pos().x, target->pos().y, 20, 7 + random2(7));
break;
case 2:
if (player_res_poison())
@@ -3829,71 +4531,6 @@ static void _miscast_poison(int severity, const char* cause)
}
}
-// sp_type: The type of the spell.
-// mag_pow: The overall power of the spell or effect (i.e. its level).
-// mag_fail: The degree to which you failed.
-// force_effect: This forces a certain severity of effect to occur. It
-// can be disabled by being set to 100.
-//
-// If a god is making you miscast, any monsters produced will count as
-// god gifts.
-void miscast_effect(unsigned int sp_type, int mag_pow, int mag_fail,
- int force_effect, const char *cause)
-{
- if (sp_type == SPTYP_RANDOM)
- sp_type = 1 << (random2(SPTYP_LAST_EXPONENT));
-
- int sever = (mag_pow*mag_fail*(10+mag_pow)/7 * WILD_MAGIC_NASTINESS)/100;
-
- if (force_effect == 100 && random2(40) > sever && random2(40) > sever)
- {
- canned_msg(MSG_NOTHING_HAPPENS);
- return;
- }
-
- if (cause == NULL || strlen(cause) == 0)
- cause = "spell miscasting";
-
- sever /= 100;
-
-#if DEBUG_DIAGNOSTICS
- const int old_fail = sever;
-#endif
-
- sever = random2(sever);
-
- if (sever > 3)
- sever = 3;
- else if (sever < 0)
- sever = 0;
-
-#if DEBUG_DIAGNOSTICS
- mprf(MSGCH_DIAGNOSTICS, "Sptype: %u, failure1: %d, failure2: %d",
- sp_type, old_fail, sever );
-#endif
-
- if (force_effect != 100)
- sever = force_effect;
-
- switch (sp_type)
- {
- case SPTYP_CONJURATION: _miscast_conjuration(sever, cause); break;
- case SPTYP_ENCHANTMENT: _miscast_enchantment(sever, cause); break;
- case SPTYP_TRANSLOCATION: _miscast_translocation(sever, cause); break;
- case SPTYP_SUMMONING: _miscast_summoning(sever, cause); break;
- case SPTYP_DIVINATION: _miscast_divination(sever, cause); break;
- case SPTYP_NECROMANCY: _miscast_necromancy(sever, cause); break;
- case SPTYP_TRANSMIGRATION: _miscast_transmigration(sever, cause); break;
- case SPTYP_FIRE: _miscast_fire(sever, cause); break;
- case SPTYP_ICE: _miscast_ice(sever, cause); break;
- case SPTYP_EARTH: _miscast_earth(sever, cause); break;
- case SPTYP_AIR: _miscast_air(sever, cause); break;
- case SPTYP_POISON: _miscast_poison(sever, cause); break;
- }
-
- xom_is_stimulated(sever);
-}
-
const char* failure_rate_to_string( int fail )
{
return
diff --git a/crawl-ref/source/spl-cast.h b/crawl-ref/source/spl-cast.h
index a2fbf69c53..71c40b38fe 100644
--- a/crawl-ref/source/spl-cast.h
+++ b/crawl-ref/source/spl-cast.h
@@ -71,14 +71,6 @@ void inspect_spells();
* *********************************************************************** */
spret_type your_spells(spell_type spell, int powc = 0, bool allow_fail = true);
-// last updated 12may2000 {dlb}
-/* ***********************************************************************
- * called from: acr - decks - fight - it_use2 - it_use3 - item_use - items -
- * misc - mstuff2 - religion - spell - spl-book - spells4
- * *********************************************************************** */
-void miscast_effect(unsigned int sp_type, int mag_pow, int mag_fail,
- int force_effect, const char *cause = NULL);
-
const char* failure_rate_to_string( int fail );
int spell_power_colour(spell_type spell);
diff --git a/crawl-ref/source/spl-mis.h b/crawl-ref/source/spl-mis.h
new file mode 100644
index 0000000000..ec6c06ff7e
--- /dev/null
+++ b/crawl-ref/source/spl-mis.h
@@ -0,0 +1,126 @@
+/*
+ * File: spl-mis.h
+ * Summary: Spell miscast class.
+ * Written by: Matthew Cline
+ *
+ * Modified for Crawl Reference by $Author$ on $Date: 2008-06-28 22:
+16:39 -0700 (Sat, 28 Jun 2008) $
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+#ifndef SPL_MIS_H
+#define SPL_MIS_H
+
+// last updated 23jul2008 {mpc}
+/* ***********************************************************************
+ * called from: decks - effects - fight - item_use - it_use2 - it_use3 -
+ * item_use - monstuff - religion - spells2 - spells4 -
+ * spl-book - spl-cast - traps - xom
+ * *********************************************************************** */
+
+#include "enum.h"
+
+#include "beam.h"
+#include "mpr.h"
+#include "spl-util.h"
+
+#define ZOT_TRAP_MISCAST (NON_MONSTER + 1)
+#define WIELD_MISCAST (NON_MONSTER + 2)
+#define MELEE_MISCAST (NON_MONSTER + 3)
+#define MISC_KNOWN_MISCAST (NON_MONSTER + 4)
+#define MISC_UNKNOWN_MISCAST (NON_MONSTER + 5)
+
+enum nothing_happens_when_type
+{
+ NH_DEFAULT,
+ NH_NEVER,
+ NH_ALWAYS
+};
+
+class actor;
+
+class MiscastEffect
+{
+public:
+ MiscastEffect(actor* _target, int _source, spell_type _spell, int _pow,
+ int _fail, std::string _cause = "",
+ nothing_happens_when_type _nothing_happens = NH_DEFAULT);
+ MiscastEffect(actor *_target, int _source, spschool_flag_type _school,
+ int _level, std::string _cause,
+ nothing_happens_when_type _nothing_happens = NH_DEFAULT);
+ MiscastEffect(actor *_target, int _source, spschool_flag_type _school,
+ int _pow, int _fail, std::string _cause,
+ nothing_happens_when_type _nothing_happens = NH_DEFAULT);
+
+ void do_miscast();
+
+private:
+ actor* target;
+ int source;
+
+ std::string cause;
+
+ spell_type spell;
+ spschool_flag_type school;
+
+ int pow;
+ int fail;
+ int level;
+
+private:
+ kill_category kc;
+ killer_type kt;
+
+ monsters* mon_target;
+ monsters* mon_source;
+
+ nothing_happens_when_type nothing_happens_when;
+
+ int kill_source;
+ actor* act_source;
+
+ bool source_known;
+ bool target_known;
+
+ bolt beam;
+
+ std::string all_msg;
+ std::string you_msg;
+ std::string mon_msg;
+ std::string mon_msg_seen;
+ std::string mon_msg_unseen;
+
+ msg_channel_type msg_ch;
+
+private:
+ void init();
+ std::string get_default_cause();
+
+ bool neither_end_silenced();
+
+ void do_msg(bool suppress_nothing_happens = false);
+ void _ouch(int dam, beam_type flavour = BEAM_NONE);
+ void _explosion();
+ void _potion_effect(int pot_eff, int pow);
+ bool _create_monster(monster_type what, int abj_deg, bool alert = false);
+ void send_abyss();
+
+ void _conjuration(int severity);
+ void _enchantment(int severity);
+ void _translocation(int severity);
+ void _summoning(int severity);
+ void _divination_you(int severity);
+ void _divination_mon(int severity);
+ void _necromancy(int severity);
+ void _transmigration(int severity);
+ void _fire(int severity);
+ void _ice(int severity);
+ void _earth(int severity);
+ void _air(int severity);
+ void _poison(int severity);
+};
+
+#endif
diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc
index 73d0b16f84..9b6f978ebd 100644
--- a/crawl-ref/source/spl-util.cc
+++ b/crawl-ref/source/spl-util.cc
@@ -54,9 +54,9 @@ static int spell_list[NUM_SPELLS];
static struct spell_desc *_seekspell(spell_type spellid);
static bool _cloud_helper(int (*func)(int, int, int, int, cloud_type,
- kill_category),
+ kill_category, killer_type),
int x, int y, int pow, int spread_rate,
- cloud_type ctype, kill_category );
+ cloud_type ctype, kill_category, killer_type );
//
// BEGIN PUBLIC FUNCTIONS
@@ -134,6 +134,52 @@ spell_type spell_by_name(std::string name, bool partial_match)
: SPELL_NO_SPELL);
}
+spschool_flag_type school_by_name(std::string name)
+{
+ spschool_flag_type short_match, long_match;
+ int short_matches, long_matches;
+
+ short_match = long_match = SPTYP_NONE;
+ short_matches = long_matches = 0;
+
+ for (int i = 0; i <= SPTYP_RANDOM; i++)
+ {
+ spschool_flag_type type = (spschool_flag_type) (1 << i);
+
+ const char* short_name = spelltype_short_name(type);
+ const char* long_name = spelltype_long_name(type);
+
+ if (strcasecmp(short_name, name.c_str()) == 0)
+ return type;
+ if (strcasecmp(long_name, name.c_str()) == 0)
+ return type;
+
+ if (strcasestr(short_name, name.c_str()))
+ {
+ short_match = type;
+ short_matches++;
+ }
+ if (strcasestr(long_name, name.c_str()))
+ {
+ long_match = type;
+ long_matches++;
+ }
+ }
+
+ if (short_matches != 1 && long_matches != 1)
+ return SPTYP_NONE;
+
+ if (short_matches == 1 && long_matches != 1)
+ return short_match;
+ if (short_matches != 1 && long_matches == 1)
+ return long_match;
+
+ if (short_match == long_match)
+ return short_match;
+
+ return SPTYP_NONE;
+}
+
int get_spell_slot_by_letter( char letter )
{
ASSERT( isalpha( letter ) );
@@ -558,10 +604,11 @@ int apply_area_within_radius( cell_func cf, const coord_def& where,
// to do a (shallow) breadth-first-search of the dungeon floor.
// This ought to work okay for small clouds.
void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
- kill_category),
+ kill_category, killer_type),
int x, int y,
int pow, int number, cloud_type ctype,
- kill_category whose, int spread_rate )
+ kill_category whose, killer_type killer,
+ int spread_rate )
{
int spread, clouds_left = number;
int good_squares = 0, neighbours[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -569,7 +616,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
bool x_first;
if (clouds_left && _cloud_helper(func, x, y, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
clouds_left--;
if (!clouds_left)
@@ -585,7 +632,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
if (x_first)
{
if (clouds_left && _cloud_helper(func, x + dx, y, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -593,7 +640,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
}
if (clouds_left && _cloud_helper(func, x - dx, y, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -601,7 +648,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
}
if (clouds_left && _cloud_helper(func, x, y + dy, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -609,7 +656,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
}
if (clouds_left && _cloud_helper(func, x, y - dy, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -619,7 +666,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
else
{
if (clouds_left && _cloud_helper(func, x, y + dy, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -627,7 +674,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
}
if (clouds_left && _cloud_helper(func, x, y - dy, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -635,7 +682,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
}
if (clouds_left && _cloud_helper(func, x + dx, y, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -643,7 +690,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
}
if (clouds_left && _cloud_helper(func, x - dx, y, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -653,7 +700,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
// Mow diagonals; we could randomize dx & dy again here.
if (clouds_left && _cloud_helper(func, x + dx, y + dy, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -661,7 +708,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
}
if (clouds_left && _cloud_helper(func, x - dx, y + dy, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -669,7 +716,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
}
if (clouds_left && _cloud_helper(func, x + dx, y - dy, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -677,7 +724,7 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
}
if (clouds_left && _cloud_helper(func, x - dx, y - dy, pow, spread_rate,
- ctype, whose))
+ ctype, whose, killer))
{
clouds_left--;
good_squares++;
@@ -699,36 +746,36 @@ void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
switch (i)
{
case 0:
- apply_area_cloud(func, x + dx, y, pow, spread, ctype, whose,
+ apply_area_cloud(func, x + dx, y, pow, spread, ctype, whose, killer,
spread_rate);
break;
case 1:
- apply_area_cloud(func, x - dx, y, pow, spread, ctype, whose,
+ apply_area_cloud(func, x - dx, y, pow, spread, ctype, whose, killer,
spread_rate);
break;
case 2:
- apply_area_cloud(func, x, y + dy, pow, spread, ctype, whose,
+ apply_area_cloud(func, x, y + dy, pow, spread, ctype, whose, killer,
spread_rate);
break;
case 3:
- apply_area_cloud(func, x, y - dy, pow, spread, ctype, whose,
+ apply_area_cloud(func, x, y - dy, pow, spread, ctype, whose, killer,
spread_rate);
break;
case 4:
apply_area_cloud(func, x + dx, y + dy, pow, spread, ctype, whose,
- spread_rate);
+ killer, spread_rate);
break;
case 5:
apply_area_cloud(func, x - dx, y + dy, pow, spread, ctype, whose,
- spread_rate);
+ killer, spread_rate);
break;
case 6:
apply_area_cloud(func, x + dx, y - dy, pow, spread, ctype, whose,
- spread_rate);
+ killer, spread_rate);
break;
case 7:
apply_area_cloud(func, x - dx, y - dy, pow, spread, ctype, whose,
- spread_rate);
+ killer, spread_rate);
break;
}
}
@@ -793,6 +840,45 @@ const char* spelltype_short_name( int which_spelltype )
return ("Erth");
case SPTYP_AIR:
return ("Air");
+ case SPTYP_RANDOM:
+ return ("Rndm");
+ default:
+ return "Bug";
+ }
+}
+
+const char* spelltype_long_name( int which_spelltype )
+{
+ switch (which_spelltype)
+ {
+ case SPTYP_CONJURATION:
+ return ("Conjuration");
+ case SPTYP_ENCHANTMENT:
+ return ("Enchantment");
+ case SPTYP_FIRE:
+ return ("Fire");
+ case SPTYP_ICE:
+ return ("Ice");
+ case SPTYP_TRANSMIGRATION:
+ return ("Transmigration");
+ case SPTYP_NECROMANCY:
+ return ("Necromancy");
+ case SPTYP_HOLY:
+ return ("Holy");
+ case SPTYP_SUMMONING:
+ return ("Summoning");
+ case SPTYP_DIVINATION:
+ return ("Divination");
+ case SPTYP_TRANSLOCATION:
+ return ("Translocation");
+ case SPTYP_POISON:
+ return ("Poison");
+ case SPTYP_EARTH:
+ return ("Earth");
+ case SPTYP_AIR:
+ return ("Air");
+ case SPTYP_RANDOM:
+ return ("Random");
default:
return "Bug";
}
@@ -882,13 +968,14 @@ bool is_valid_spell(spell_type spell)
}
static bool _cloud_helper(int (*func)(int, int, int, int, cloud_type,
- kill_category),
+ kill_category, killer_type),
int x, int y, int pow, int spread_rate,
- cloud_type ctype, kill_category whose )
+ cloud_type ctype, kill_category whose,
+ killer_type killer )
{
if (!grid_is_solid(grd[x][y]) && env.cgrid[x][y] == EMPTY_CLOUD)
{
- func(x, y, pow, spread_rate, ctype, whose);
+ func(x, y, pow, spread_rate, ctype, whose, killer);
return (true);
}
diff --git a/crawl-ref/source/spl-util.h b/crawl-ref/source/spl-util.h
index 315e84c697..3734b8d2d4 100644
--- a/crawl-ref/source/spl-util.h
+++ b/crawl-ref/source/spl-util.h
@@ -66,6 +66,8 @@ void init_spell_descs(void);
void init_spell_name_cache();
spell_type spell_by_name(std::string name, bool partial_match = false);
+spschool_flag_type school_by_name(std::string name);
+
int get_spell_slot_by_letter( char letter );
spell_type get_spell_by_letter( char letter );
@@ -95,6 +97,7 @@ int count_bits( unsigned int bits );
const char *spell_title(spell_type which_spell);
const char* spelltype_short_name( int which_spelltype );
+const char* spelltype_long_name( int which_spelltype );
typedef int cell_func(coord_def where, int pow, int aux);
int apply_area_visible(cell_func cf, int power,
@@ -120,9 +123,10 @@ bool spell_direction( dist &spelld, bolt &pbolt,
bool cancel_at_self = false );
void apply_area_cloud(int (*func) (int, int, int, int, cloud_type,
- kill_category),
+ kill_category, killer_type),
int x, int y, int pow, int number, cloud_type ctype,
- kill_category kc, int spread_rate = -1);
+ kill_category kc, killer_type killer,
+ int spread_rate = -1);
const char *spelltype_name(unsigned int which_spelltype);
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index d33daf981b..d165de7b09 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1648,7 +1648,8 @@ static void tag_construct_level(writer &th)
marshallByte(th, env.cloud[i].type);
marshallShort(th, env.cloud[i].decay);
marshallByte(th, (char) env.cloud[i].spread_rate);
- marshallShort(th, env.cloud[i].whose);
+ marshallByte(th, env.cloud[i].whose);
+ marshallByte(th, env.cloud[i].killer);
}
// how many shops?
@@ -1984,7 +1985,8 @@ static void tag_read_level( reader &th, char minorVersion )
env.cloud[i].type = static_cast<cloud_type>(unmarshallByte(th));
env.cloud[i].decay = unmarshallShort(th);
env.cloud[i].spread_rate = (unsigned char) unmarshallByte(th);
- env.cloud[i].whose = static_cast<kill_category>(unmarshallShort(th));
+ env.cloud[i].whose = static_cast<kill_category>(unmarshallByte(th));
+ env.cloud[i].killer = static_cast<killer_type>(unmarshallByte(th));
}
// how many shops?
diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc
index b154f9fdf2..ce581054d5 100644
--- a/crawl-ref/source/traps.cc
+++ b/crawl-ref/source/traps.cc
@@ -35,7 +35,7 @@
#include "randart.h"
#include "skills.h"
#include "spells3.h"
-#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "terrain.h"
#include "transfor.h"
@@ -498,8 +498,8 @@ void handle_traps(trap_type trt, int i, bool trap_known)
default:
mpr((trap_known) ? "You enter the Zot trap."
: "Oh no! You have blundered into a Zot trap!");
- miscast_effect( SPTYP_RANDOM, random2(30) + you.your_level,
- 75 + random2(100), 3, "a Zot trap" );
+ MiscastEffect( &you, ZOT_TRAP_MISCAST, SPTYP_RANDOM,
+ 3, "a Zot trap" );
break;
}
learned_something_new(TUT_SEEN_TRAP, you.x_pos, you.y_pos);
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index d91f1e42a8..bd25195742 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -29,6 +29,7 @@
#include "religion.h"
#include "spells2.h"
#include "spl-cast.h"
+#include "spl-mis.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
@@ -739,7 +740,8 @@ static bool _xom_is_bad(int sever)
{
god_speaks(GOD_XOM, _get_xom_speech("zero miscast effect").c_str());
- miscast_effect(SPTYP_RANDOM, 0, 0, 0, "the mischief of Xom");
+ MiscastEffect(&you, -GOD_XOM, SPTYP_RANDOM, 0,
+ "the mischief of Xom");
done = true;
}
@@ -747,7 +749,7 @@ static bool _xom_is_bad(int sever)
{
god_speaks(GOD_XOM, _get_xom_speech("minor miscast effect").c_str());
- miscast_effect(SPTYP_RANDOM, 0, 0, random2(2),
+ MiscastEffect(&you, -GOD_XOM, SPTYP_RANDOM, random2(2),
"the capriciousness of Xom");
done = true;
@@ -765,7 +767,7 @@ static bool _xom_is_bad(int sever)
{
god_speaks(GOD_XOM, _get_xom_speech("medium miscast effect").c_str());
- miscast_effect(SPTYP_RANDOM, 0, 0, random2(3),
+ MiscastEffect(&you, -GOD_XOM, SPTYP_RANDOM, random2(3),
"the capriciousness of Xom");
done = true;
@@ -894,10 +896,11 @@ static bool _xom_is_bad(int sever)
}
else if (x_chance_in_y(11, sever))
{
- god_speaks(GOD_XOM, _get_xom_speech("major miscast effect").c_str());
+ god_speaks(GOD_XOM,
+ _get_xom_speech("major miscast effect").c_str());
- miscast_effect(SPTYP_RANDOM, 0, 0, random2(4),
- "the severe capriciousness of Xom");
+ MiscastEffect(&you, -GOD_XOM, SPTYP_RANDOM, random2(4),
+ "the severe capriciousness of Xom");
done = true;
}