summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/spl-cast.cc
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-05-03 22:04:54 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-05-03 22:04:54 +0000
commit3ede9fff7fa316a1d441a840533613226b720e8a (patch)
tree26b9d64c81d50d4a162b45bd9a5455b5d67343ab /crawl-ref/source/spl-cast.cc
parentf40a57bf2ed015c5e1489c966987878f3d62d450 (diff)
downloadcrawl-ref-3ede9fff7fa316a1d441a840533613226b720e8a.tar.gz
crawl-ref-3ede9fff7fa316a1d441a840533613226b720e8a.zip
Some spellcasting modifications, as discussed on c-r-d.
* Spells are marked grey if you lack the necessary magic or if there are no visible monsters within range. * z bails out if there are no monsters in range * Z is the same as the old z behaviour * Wands now need to be e(V)oked. Feedback welcome! git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@9727 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/spl-cast.cc')
-rw-r--r--crawl-ref/source/spl-cast.cc176
1 files changed, 140 insertions, 36 deletions
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index 4bdc390c61..6c700ea721 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -57,6 +57,9 @@ REVISION("$Rev$");
#include <conio.h>
#endif
+static int _calc_spell_range(spell_type spell, int power = 0,
+ bool real_cast = false);
+
static bool _surge_identify_boosters(spell_type spell)
{
const unsigned int typeflags = get_spell_disciplines(spell);
@@ -66,12 +69,12 @@ static bool _surge_identify_boosters(spell_type spell)
// Note that robes of the Archmagi identify on wearing,
// so that's less of an issue.
const item_def* wpn = player_weapon();
- if ( wpn == NULL ||
- wpn->base_type != OBJ_STAVES ||
- item_ident(*wpn, ISFLAG_KNOW_PROPERTIES) )
+ if (wpn == NULL
+ || wpn->base_type != OBJ_STAVES
+ || item_ident(*wpn, ISFLAG_KNOW_PROPERTIES))
{
int num_unknown = 0;
- for ( int i = EQ_LEFT_RING; i <= EQ_RIGHT_RING; ++i )
+ for (int i = EQ_LEFT_RING; i <= EQ_RIGHT_RING; ++i)
{
if (you.equip[i] != -1 &&
!item_ident(you.inv[you.equip[i]], ISFLAG_KNOW_PROPERTIES))
@@ -82,10 +85,10 @@ static bool _surge_identify_boosters(spell_type spell)
// We can also identify cases with two unknown rings, both
// of fire (or both of ice)...let's skip it.
- if ( num_unknown == 1 )
+ if (num_unknown == 1)
{
- for ( int i = EQ_LEFT_RING; i <= EQ_RIGHT_RING; ++i )
- if ( you.equip[i] != -1 )
+ for (int i = EQ_LEFT_RING; i <= EQ_RIGHT_RING; ++i)
+ if (player_wearing_slot(i))
{
item_def& ring = you.inv[you.equip[i]];
if (!item_ident(ring, ISFLAG_KNOW_PROPERTIES)
@@ -127,10 +130,12 @@ static void _surge_power(spell_type spell)
}
}
-static std::string _spell_base_description(spell_type spell)
+static std::string _spell_base_description(spell_type spell, bool grey = false)
{
std::ostringstream desc;
+ if (grey)
+ desc << "<darkgrey>";
desc << std::left;
// spell name
@@ -138,7 +143,7 @@ static std::string _spell_base_description(spell_type spell)
// spell schools
bool already = false;
- for ( int i = 0; i <= SPTYP_LAST_EXPONENT; ++i)
+ for (int i = 0; i <= SPTYP_LAST_EXPONENT; ++i)
{
if (spell_typematch(spell, (1<<i)))
{
@@ -149,21 +154,25 @@ static std::string _spell_base_description(spell_type spell)
}
}
- const int so_far = desc.str().length();
- if ( so_far < 60 )
+ const int so_far = desc.str().length() - (grey ? 10 : 0);
+ if (so_far < 60)
desc << std::string(60 - so_far, ' ');
// spell fail rate, level
desc << std::setw(12) << failure_rate_to_string(spell_fail(spell))
<< spell_difficulty(spell);
+ if (grey)
+ desc << "</darkgrey>";
return desc.str();
}
-static std::string _spell_extra_description(spell_type spell)
+static std::string _spell_extra_description(spell_type spell, bool grey = false)
{
std::ostringstream desc;
+ if (grey)
+ desc << "<darkgrey>";
desc << std::left;
// spell name
@@ -177,10 +186,42 @@ static std::string _spell_extra_description(spell_type spell)
<< std::setw(12) << spell_hunger_string(spell)
<< spell_difficulty(spell);
+ if (grey)
+ desc << "</darkgrey>";
+
return desc.str();
}
-int list_spells(bool toggle_with_I, bool viewing)
+static bool _spell_no_hostile_in_range(spell_type spell, int minRange)
+{
+ if (minRange < 0)
+ return (false);
+
+ switch (spell)
+ {
+ case SPELL_APPORTATION:
+ case SPELL_PROJECTED_NOISE:
+ // These don't target monsters.
+ return (false);
+ default:
+ break;
+ }
+
+ // The healing spells.
+ if (testbits(get_spell_flags(spell), SPFLAG_HELPFUL))
+ return (false);
+
+ const int range = _calc_spell_range(spell);
+ if (range < 0)
+ return (false);
+
+ if (range < minRange)
+ return (true);
+
+ return (false);
+}
+
+int list_spells(bool toggle_with_I, bool viewing, int minRange)
{
ToggleableMenu spell_menu(MF_SINGLESELECT | MF_ANYPRINTABLE
| MF_ALWAYS_SHOW_MORE | MF_ALLOW_FORMATTING);
@@ -221,15 +262,26 @@ int list_spells(bool toggle_with_I, bool viewing)
more_str += "to toggle spell view.";
spell_menu.set_more(formatted_string(more_str));
+ bool grey = false; // Needs to be greyed out?
for (int i = 0; i < 52; ++i)
{
const char letter = index_to_letter(i);
const spell_type spell = get_spell_by_letter(letter);
+ if (!viewing)
+ {
+ if (spell_mana(spell) > you.magic_points
+ || _spell_no_hostile_in_range(spell, minRange))
+ {
+ grey = true;
+ }
+ else
+ grey = false;
+ }
if (spell != SPELL_NO_SPELL)
{
ToggleableMenuEntry* me =
- new ToggleableMenuEntry(_spell_base_description(spell),
- _spell_extra_description(spell),
+ new ToggleableMenuEntry(_spell_base_description(spell, grey),
+ _spell_extra_description(spell, grey),
MEL_ITEM, 1, letter);
spell_menu.add_entry(me);
}
@@ -550,8 +602,39 @@ void inspect_spells()
list_spells(true, true);
}
+static int _get_dist_to_nearest_monster()
+{
+ int minRange = LOS_RADIUS + 1;
+ for (radius_iterator ri(you.pos(), LOS_RADIUS, true, false, true); ri; ++ri)
+ {
+ if (!in_bounds(*ri))
+ continue;
+
+ if (!see_grid(*ri))
+ continue;
+
+ const monsters *mon = monster_at(*ri);
+ if (mon == NULL)
+ continue;
+
+ if (!player_monster_visible(mon)
+ || mons_is_unknown_mimic(mon))
+ {
+ continue;
+ }
+
+ if (mons_wont_attack(mon))
+ continue;
+
+ int dist = grid_distance(you.pos(), *ri);
+ if (dist < minRange)
+ minRange = dist;
+ }
+ return (minRange);
+}
+
// Returns false if spell failed, and true otherwise.
-bool cast_a_spell()
+bool cast_a_spell(bool check_range)
{
if (!you.spell_no)
{
@@ -574,6 +657,14 @@ bool cast_a_spell()
return (false);
}
+ if (you.magic_points < 1)
+ {
+ mpr("You don't have enough magic to cast spells.");
+ return (false);
+ }
+
+ const int minRange = (check_range ? _get_dist_to_nearest_monster() : -1);
+
int keyin = 0; // silence stupid compilers
while (true)
@@ -584,7 +675,7 @@ bool cast_a_spell()
if (keyin == '?' || keyin == '*')
{
- keyin = list_spells();
+ keyin = list_spells(true, false, minRange);
if (!keyin)
keyin = ESCAPE;
@@ -621,12 +712,18 @@ bool cast_a_spell()
return (false);
}
- if (spell_mana( spell ) > you.magic_points)
+ if (spell_mana(spell) > you.magic_points)
{
mpr("You don't have enough magic to cast that spell.");
return (false);
}
+ if (_spell_no_hostile_in_range(spell, minRange))
+ {
+ mpr("There are no visible monsters within range! (Use <w>Z</w> to cast anyway.)");
+ return (false);
+ }
+
if (you.is_undead != US_UNDEAD && you.species != SP_VAMPIRE
&& (you.hunger_state == HS_STARVING
|| you.hunger <= spell_hunger( spell )))
@@ -1047,11 +1144,7 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail)
const bool dont_cancel_me = testbits(flags, SPFLAG_AREA);
-
- // FIXME: Code duplication (see similar line below).
- int range_power = (powc == 0 ? calc_spell_power(spell, true) : powc);
-
- const int range = spell_range(spell, range_power, false);
+ const int range = _calc_spell_range(spell, powc, false);
if (!spell_direction(spd, beam, dir, targ, range,
needs_path, true, dont_cancel_me, prompt,
@@ -1060,14 +1153,14 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail)
return (SPRET_ABORT);
}
- beam.range = spell_range(spell, range_power, true);
+ beam.range = _calc_spell_range(spell, powc, true);
if (testbits(flags, SPFLAG_NOT_SELF) && spd.isMe)
{
if (spell == SPELL_TELEPORT_OTHER || spell == SPELL_POLYMORPH_OTHER
|| spell == SPELL_BANISHMENT)
{
- mpr( "Sorry, this spell works on others only." );
+ mpr("Sorry, this spell works on others only.");
}
else
canned_msg(MSG_UNTHINKING_ACT);
@@ -2165,14 +2258,14 @@ const char* spell_hunger_string( spell_type spell )
int spell_power_colour(spell_type spell)
{
const int powercap = spell_power_cap(spell);
- if ( powercap == 0 )
+ if (powercap == 0)
return DARKGREY;
const int power = calc_spell_power(spell, true);
- if ( power >= powercap )
+ if (power >= powercap)
return WHITE;
- if ( power * 3 < powercap )
+ if (power * 3 < powercap)
return RED;
- if ( power * 3 < powercap * 2 )
+ if (power * 3 < powercap * 2)
return YELLOW;
return GREEN;
}
@@ -2199,23 +2292,34 @@ std::string spell_power_string(spell_type spell)
{
const int numbars = spell_power_bars(spell);
const int capbars = _power_to_barcount(spell_power_cap(spell));
- ASSERT( numbars <= capbars );
- if ( numbars < 0 )
+ ASSERT(numbars <= capbars);
+ if (numbars < 0)
return "N/A";
else
return std::string(numbars, '#') + std::string(capbars - numbars, '.');
}
+static int _calc_spell_range(spell_type spell, int power, bool real_cast)
+{
+ if (power == 0)
+ power = calc_spell_power(spell, true);
+ const int range = spell_range(spell, power, real_cast);
+
+ return (range);
+}
+
std::string spell_range_string(spell_type spell)
{
- const int cap = spell_power_cap(spell);
- const int power = calc_spell_power(spell, true);
- const int range = spell_range(spell, power, false);
+ const int cap = spell_power_cap(spell);
+ const int range = _calc_spell_range(spell);
const int maxrange = spell_range(spell, cap, false);
+
if (range < 0)
return "N/A";
else
+ {
return std::string("@") + std::string(range, '.')
- + "<darkgrey>" + std::string(maxrange - range, '.')
- + "</darkgrey>";
+ + "<darkgrey>" + std::string(maxrange - range, '.')
+ + "</darkgrey>";
+ }
}