summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-07-29 22:59:35 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-07-29 22:59:35 +0000
commit63036c9e5ed0103475fea0c6710317f15e8cdb24 (patch)
treec6e731b631741fc069a6baeb80bf15c58458e9e0 /crawl-ref/source
parente744cede0540585248737db8e27a8320e5476955 (diff)
downloadcrawl-ref-63036c9e5ed0103475fea0c6710317f15e8cdb24.tar.gz
crawl-ref-63036c9e5ed0103475fea0c6710317f15e8cdb24.zip
Implemented monster spell miscasts. Spell miscasting is now handled
by the MiscastEffect class, which has helper methods to make most of the non-helper code agnostic with respect to whether the miscaster is the player or a monster. Mummy death curses now affect monsters, and Zot traps now directly affect friendly and good-neutral monsters. In wizard mode you can force the player or a monster to miscast by targeting it and pressing 'M'. Todo/issues/notes: * Clouds now have a killer_type in addition to a kill_category. * There aren't any divination monster miscast effects yet. * Many of the harmless message-only miscast effects are missing monster messages. * If a monster actually miscasts a spell (not getting a mummy death curse or setting off a Zot trap) and this kills both the monster and the player then the wrong monster will be listed in hiscore entry. Since monsters can't do true spell miscasts yet, this can wait. * There was old, non-functioning code making Zot traps heal, haste or turn invisible hostile monsters that triggered it. I fixed it and then commented it out. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@6723 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-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;
}