diff options
author | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-05-03 22:04:54 +0000 |
---|---|---|
committer | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-05-03 22:04:54 +0000 |
commit | 3ede9fff7fa316a1d441a840533613226b720e8a (patch) | |
tree | 26b9d64c81d50d4a162b45bd9a5455b5d67343ab /crawl-ref/source | |
parent | f40a57bf2ed015c5e1489c966987878f3d62d450 (diff) | |
download | crawl-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')
-rw-r--r-- | crawl-ref/source/acr.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/cmd-keys.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/cmd-name.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/command.cc | 12 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/spl-cast.cc | 176 | ||||
-rw-r--r-- | crawl-ref/source/spl-cast.h | 5 | ||||
-rw-r--r-- | crawl-ref/source/spl-data.h | 4 |
8 files changed, 156 insertions, 48 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 27c39d4abb..48f977a3d0 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -1668,6 +1668,7 @@ void process_command( command_type cmd ) } case CMD_CAST_SPELL: + case CMD_FORCE_CAST_SPELL: if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BAT) { canned_msg(MSG_PRESENT_FORM); @@ -1684,7 +1685,7 @@ void process_command( command_type cmd ) if (Options.tutorial_left) Options.tut_spell_counter++; - if (!cast_a_spell()) + if (!cast_a_spell(cmd == CMD_CAST_SPELL)) flush_input_buffer( FLUSH_ON_FAILURE ); break; diff --git a/crawl-ref/source/cmd-keys.h b/crawl-ref/source/cmd-keys.h index aa5d660355..579fd57b24 100644 --- a/crawl-ref/source/cmd-keys.h +++ b/crawl-ref/source/cmd-keys.h @@ -42,6 +42,7 @@ {'w', CMD_WIELD_WEAPON}, {'x', CMD_LOOK_AROUND}, {'z', CMD_CAST_SPELL}, +{'Z', CMD_FORCE_CAST_SPELL}, {'B', CMD_RUN_DOWN_LEFT}, {'H', CMD_RUN_LEFT}, {'J', CMD_RUN_DOWN}, @@ -75,7 +76,6 @@ {'T', CMD_REMOVE_ARMOUR}, {'W', CMD_WEAR_ARMOUR}, {'X', CMD_DISPLAY_MAP}, -{'Z', CMD_ZAP_WAND}, {'.', CMD_MOVE_NOWHERE}, {CK_CLEAR, CMD_MOVE_NOWHERE}, {'<', CMD_GO_UPSTAIRS}, diff --git a/crawl-ref/source/cmd-name.h b/crawl-ref/source/cmd-name.h index 9b91471cb8..7667397bdd 100644 --- a/crawl-ref/source/cmd-name.h +++ b/crawl-ref/source/cmd-name.h @@ -58,6 +58,7 @@ {CMD_LIST_GOLD, "CMD_LIST_GOLD"}, {CMD_ZAP_WAND, "CMD_ZAP_WAND"}, {CMD_CAST_SPELL, "CMD_CAST_SPELL"}, +{CMD_FORCE_CAST_SPELL, "CMD_FORCE_CAST_SPELL"}, {CMD_MEMORISE_SPELL, "CMD_MEMORISE_SPELL"}, {CMD_USE_ABILITY, "CMD_USE_ABILITY"}, {CMD_PRAY, "CMD_PRAY"}, diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index 05f6638b41..2d6fecde38 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -462,7 +462,7 @@ static void _adjust_ability(void) const int keyin = get_ch(); - if ( keyin == '?' || keyin == '*' ) + if (keyin == '?' || keyin == '*') { selected = choose_ability_menu(talents); } @@ -477,7 +477,7 @@ static void _adjust_ability(void) // Try to find the hotkey. for (unsigned int i = 0; i < talents.size(); ++i) { - if ( talents[i].hotkey == keyin ) + if (talents[i].hotkey == keyin) { selected = static_cast<int>(i); break; @@ -485,7 +485,7 @@ static void _adjust_ability(void) } // If we can't, cancel out. - if ( selected < 0 ) + if (selected < 0) { mpr("No such ability."); return; @@ -2145,7 +2145,8 @@ static void _add_formatted_keyhelp(column_composer &cols) "<h>Other Gameplay Actions:\n" "<w>a</w> : use special Ability (<w>a!</w> for help)\n" "<w>p</w> : Pray (<w>^</w> and <w>^!</w> for help)\n" - "<w>z</w> : cast a spell\n" + "<w>z</w> : cast a spell, fails if no visible monsters in range\n" + "<w>Z</w> : cast a spell\n" "<w>I</w> : list all spells\n" "<w>t</w> : tell allies (<w>tt</w> to shout)\n" "<w>`</w> : re-do previous command\n" @@ -2220,7 +2221,6 @@ static void _add_formatted_keyhelp(column_composer &cols) interact += " (tries floor first)\n" "<w>q</w> : Quaff a potion\n" - "<w>Z</w> : Zap a wand\n" "<w>r</w> : Read a scroll or book\n" "<w>M</w> : Memorise a spell from a book\n" "<w>w</w> : Wield an item ( <w>-</w> for none)\n" @@ -2303,7 +2303,7 @@ static void _add_formatted_tutorial_help(column_composer &cols) "with the wielded weapon or barehanded.\n" "For ranged attacks use either\n" "<w>f</w> to launch missiles (like arrows)\n" - "<w>z</w> to cast spells (<w>z?</w> lists spells).\n", + "<w>z</w>/<w>Z</w> to cast spells (<w>z?</w> lists spells).\n", cols.add_formatted( 0, text.str(), diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 43f52dc1e3..973c475fb0 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -484,6 +484,7 @@ enum command_type CMD_LIST_GOLD, CMD_ZAP_WAND, CMD_CAST_SPELL, + CMD_FORCE_CAST_SPELL, CMD_MEMORISE_SPELL, CMD_USE_ABILITY, CMD_PRAY, 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>"; + } } diff --git a/crawl-ref/source/spl-cast.h b/crawl-ref/source/spl-cast.h index 681c3aa958..5167719fe0 100644 --- a/crawl-ref/source/spl-cast.h +++ b/crawl-ref/source/spl-cast.h @@ -46,7 +46,8 @@ enum spret_type SPRET_SUCCESS }; -int list_spells(bool toggle_with_I = true, bool viewing = false); +int list_spells(bool toggle_with_I = true, bool viewing = false, + int minRange = -1); int spell_fail( spell_type spell ); int calc_spell_power(spell_type spell, bool apply_intel, bool fail_rate_chk = false); @@ -63,7 +64,7 @@ void exercise_spell( spell_type spell_ex, bool spc, bool divide ); /* *********************************************************************** * called from: acr * *********************************************************************** */ -bool cast_a_spell( void ); +bool cast_a_spell( bool check_range ); bool maybe_identify_staff( item_def &item, spell_type spell = SPELL_NO_SPELL ); diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h index ac3122a5ab..805e74ff1f 100644 --- a/crawl-ref/source/spl-data.h +++ b/crawl-ref/source/spl-data.h @@ -814,7 +814,7 @@ SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF, 4, 200, - LOS_RADIUS, LOS_RADIUS, + LOS_RADIUS, LOS_RADIUS, 0, NULL, true, @@ -840,7 +840,7 @@ SPFLAG_AREA | SPFLAG_NEUTRAL, 4, 0, - -1, -1, + -1, -1, 0, NULL, false, |