diff options
Diffstat (limited to 'crawl-ref')
-rw-r--r-- | crawl-ref/docs/crawl_manual.txt | 21 | ||||
-rw-r--r-- | crawl-ref/source/acr.cc | 42 | ||||
-rw-r--r-- | crawl-ref/source/command.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/item_use.cc | 347 | ||||
-rw-r--r-- | crawl-ref/source/item_use.h | 8 |
6 files changed, 231 insertions, 196 deletions
diff --git a/crawl-ref/docs/crawl_manual.txt b/crawl-ref/docs/crawl_manual.txt index f964d0d4ed..dd66420e93 100644 --- a/crawl-ref/docs/crawl_manual.txt +++ b/crawl-ref/docs/crawl_manual.txt @@ -542,7 +542,7 @@ you might find in the course of your adventures, how these are displayed, and what commands there are to use them: ) weapons (use 'w'ield) -( ammunition (use 't'hrow or 'f'ire) +( ammunition (use 'f'ire) [ armour (use 'W'ear and 'T'ake off) % food (use 'e'at; also 'D'issect for corpses) ? scrolls (use 'r'ead) @@ -663,16 +663,17 @@ thrown; other kinds require you to wield an appropriate device to inflict worthwhile damage. Ammunition has only one "plus" value, which affects both accuracy and damage. -The 'f' command fires a piece of ammunition, chosen from lots suitable -for your weapon and defaulting to your preferred lot (or "quiver"), -typically the last lot you fired. Use the '(' command if you want to -change your quiver without firing. Use the 't' command to throw -anything. +The 'f' command fires or throws a piece of ammunition, typically +chosen from lots suitable for your weapon and defaulting to the last +lot you fired (your "quiver"). -Regardless of their mnemonics, if you are using the right kind of hand -weapon both 'f' and 't' will make you "shoot" the ammunition. -Otherwise, you will "throw" it. At times it is also sensible to throw -weapons like spears, daggers, or hand axes. +The firing interface also allows you to manually select an item to +throw; but it may not be very effective if you lack the correct +launcher. At times it is sensible to throw weapons like spears, +daggers, or hand axes. + +Use the '(' command if you want to change your quiver without +firing. The interface for shooting or throwing things is also used for zapping wands and casting certain spells, and is described in detail in diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index fbbcff2fa5..4023971c9a 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -1902,47 +1902,8 @@ void process_command( command_type cmd ) wield_weapon(false); break; - case CMD_THROW: - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BAT) - { - canned_msg(MSG_PRESENT_FORM); - break; - } - else if (you.attribute[ATTR_HELD]) - { - mpr("You cannot throw anything while held in a net!"); - break; - } - if (Options.tutorial_left) - Options.tut_throw_counter++; - throw_anything(); - break; - case CMD_FIRE: - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BAT) - { - canned_msg(MSG_PRESENT_FORM); - break; - } - else if (you.attribute[ATTR_HELD]) - { - const item_def *weapon = you.weapon(); - if (!weapon || !is_range_weapon(*weapon)) - { - mpr("You cannot throw anything while held in a net!"); - break; - } - else if (weapon->sub_type != WPN_BLOWGUN) - { - mprf("You cannot shoot with your %s while held in a net!", - weapon->name(DESC_BASENAME).c_str()); - break; - } - // else shooting is possible - } - if (Options.tutorial_left) - Options.tut_throw_counter++; - shoot_thing(); + fire_thing(); break; case CMD_WEAR_ARMOUR: @@ -3261,7 +3222,6 @@ command_type keycode_to_command( keycode_type key ) case 'q': return CMD_QUAFF; case 'r': return CMD_READ; case 's': return CMD_SEARCH; - case 't': return CMD_THROW; case 'v': return CMD_EXAMINE_OBJECT; case 'w': return CMD_WIELD_WEAPON; case 'x': return CMD_LOOK_AROUND; diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index f6a42f6382..7f0f9e3f45 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -593,7 +593,9 @@ static const char *targeting_help_1 = static const char *targeting_help_2 = "<h>Firing or throwing a missile:\n" "<w>Ctrl-P</w> : cycle to previous missile.\n" - "<w>Ctrl-N</w> : cycle to next missile.\n"; + "<w>Ctrl-N</w> : cycle to next missile.\n" + "<w>i</w> : choose from inventory.\n" +; // Add the contents of the file fp to the scroller menu m. @@ -1523,8 +1525,7 @@ void list_commands(bool wizard, int hotkey, bool do_redraw_screen) "<w>]</w> : show inventory of equipped items\n" "<w>v</w> : View item description\n" "<w>{</w> : inscribe item\n" - "<w>t</w> : Throw/shoot an item\n" - "<w>f</w> : Fire first available missile\n" + "<w>f</w> : Fire or throw an item\n" "<w>e</w> : Eat food (but tries floor first)\n" "<w>q</w> : Quaff a potion\n" "<w>z</w> : Zap a wand\n" diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 52527c6979..4b003358e2 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -440,7 +440,7 @@ enum command_type CMD_EVOKE, CMD_WIELD_WEAPON, CMD_WEAPON_SWAP, - CMD_THROW, + CMD_THROW, // unused now CMD_FIRE, CMD_WEAR_ARMOUR, CMD_REMOVE_ARMOUR, diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index 710940109a..0348abecfd 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -28,6 +28,7 @@ #include "AppHdr.h" #include "item_use.h" +#include <sstream> #include <string.h> #include <stdlib.h> #include <stdio.h> @@ -82,6 +83,10 @@ static bool drink_fountain(); static bool enchant_armour(); +static int _fire_prompt_for_item(std::string& err); +static bool _fire_validate_item(int selected, std::string& err); +static std::string _fire_get_noitem_reason(); + // Rather messy - we've gathered all the can't-wield logic from wield_weapon() // here. bool can_wield(const item_def *weapon, bool say_reason, @@ -1194,53 +1199,6 @@ bool takeoff_armour(int item) return true; } // end takeoff_armour() -void throw_anything( int slot ) -{ - struct bolt beam; - int throw_slot; - - if (you.duration[DUR_BERSERKER]) - { - canned_msg(MSG_TOO_BERSERK); - return; - } - else if (inv_count() < 1) - { - canned_msg(MSG_NOTHING_CARRIED); - return; - } - - if (slot != -1) - throw_slot = slot; - else - throw_slot = prompt_invent_item( "Throw which item? (* to show all)", - MT_INVLIST, - OBJ_MISSILES, true, true, true, 0, NULL, - OPER_THROW ); - if (throw_slot == PROMPT_ABORT) - { - canned_msg( MSG_OK ); - return; - } - - if (throw_slot == you.equip[EQ_WEAPON] - && (item_cursed( you.inv[you.equip[EQ_WEAPON]] ))) - { - mpr("That thing is stuck to your hand!"); - return; - } - else - { - if ( wearing_slot(throw_slot) ) - { - mpr("You are wearing that object!"); - return; - } - } - - throw_it(beam, throw_slot); -} // end throw_anything() - static bool fire_item_matches(const item_def &item, unsigned fire_type) { if (!is_valid_item(item)) @@ -1399,32 +1357,71 @@ int get_fire_item_index(int start_from, bool forward, bool check_quiver) return (item); } -static void announce_ammo(int item) -{ - mesclr(); - mprf("Firing%s: %s", - get_fire_item_index((item + 1) % ENDOFPACK, true, false) != item? - " (^N/^P - change)" : "", - you.inv[item].name(DESC_INVENTORY_EQUIP).c_str()); -} - class fire_target_behaviour : public targeting_behaviour { public: - fire_target_behaviour(int it) : item(it), need_prompt(false) { } - command_type get_command(int key = -1); - bool should_redraw(); - void announce_new_ammo(bool redraw = true); + fire_target_behaviour() + : item(ENDOFPACK), selected_from_inventory(false), need_prompt(false) + { + item = get_fire_item_index(); + } + + // targeting_behaviour API + virtual command_type get_command(int key = -1); + virtual bool should_redraw(); + + void message_ammo_prompt(const std::string* pre_text=0); public: int item; + bool selected_from_inventory; bool need_prompt; - -private: - void find_next_ammo(); - void find_prev_ammo(); }; +void fire_target_behaviour::message_ammo_prompt(const std::string* pre_text) +{ + bool no_other_items; + { + const int next_item = get_fire_item_index((item + 1) % ENDOFPACK, true, false); + no_other_items = (next_item == ENDOFPACK || next_item == item); + } + + mesclr(); + + if (pre_text) + { + mpr(pre_text->c_str()); + } + + { + std::ostringstream msg; + if (item == ENDOFPACK) msg << "Firing "; + else { + const item_def& item_def = you.inv[item]; + const launch_retval projected = is_launched(&you, you.weapon(), item_def); + if (projected == LRET_FUMBLED) msg << "Awkwardly throwing "; + else if (projected == LRET_LAUNCHED) msg << "Firing "; + else if (projected == LRET_THROWN) msg << "Throwing "; + else msg << "Buggy "; + } + + msg << (no_other_items ? "(i - change)" : "(^n ^p i - change)") + << ": "; + + if (item == ENDOFPACK) { + msg << "<red>" << _fire_get_noitem_reason() << "</red>"; + } else { + const char* color = (selected_from_inventory ? "grey" : "w"); + msg << "<" << color << ">" + << you.inv[item].name(DESC_INVENTORY_EQUIP) + << "</" << color << ">"; + } + + // XXX: use another channel that doesn't spam the message log? + formatted_message_history(msg.str(), MSGCH_PROMPT); + } +} + bool fire_target_behaviour::should_redraw() { if (need_prompt) @@ -1444,15 +1441,38 @@ command_type fire_target_behaviour::get_command(int key) { case '(': case CONTROL('N'): - find_next_ammo(); - break; - case CONTROL('P'): - find_prev_ammo(); + case CONTROL('P'): { + const int direction = (key == CONTROL('N')) ? +1 : -1; + const int start = (item + ENDOFPACK + direction) % ENDOFPACK; + const int next = get_fire_item_index(start, (direction==1), false); + if (next != item && next != ENDOFPACK) + { + item = next; + selected_from_inventory = false; + } + // Do this stuff unconditionally to make the prompt redraw + message_ammo_prompt(); + need_prompt = true; break; + } + + case 'i': { + std::string err; + const int selected = _fire_prompt_for_item(err); + if (selected != ENDOFPACK && + _fire_validate_item(selected, err)) + { + item = selected; + selected_from_inventory = true; + } + message_ammo_prompt( err.length() ? &err : NULL ); + need_prompt = true; + return CMD_NO_CMD; + } case '?': show_targeting_help(); redraw_screen(); - announce_new_ammo(item); + message_ammo_prompt(); need_prompt = true; return (CMD_NO_CMD); } @@ -1460,46 +1480,18 @@ command_type fire_target_behaviour::get_command(int key) return targeting_behaviour::get_command(key); } -void fire_target_behaviour::announce_new_ammo(bool redraw) +static bool _fire_choose_item_and_target(int& item, dist& target) { - announce_ammo(item); - need_prompt = redraw; -} - -void fire_target_behaviour::find_next_ammo() -{ - const int start = (item == ENDOFPACK - 1)? 0 : item + 1; - const int next = get_fire_item_index(start, true, false); - - // We should never get back ENDOFPACK. - if (next != item) - { - item = next; - announce_new_ammo(); - } -} - -void fire_target_behaviour::find_prev_ammo() -{ - const int start = (item == 0)? ENDOFPACK - 1 : item - 1; - const int next = get_fire_item_index(start, false, false); - - // We should never get back ENDOFPACK. - if (next != item) - { - item = next; - announce_new_ammo(); - } -} - -static bool choose_fire_target(dist &target, int &item) -{ - announce_ammo(item); - message_current_target(); - - fire_target_behaviour beh(item); + fire_target_behaviour beh; + beh.message_ammo_prompt(); + message_current_target(); // XXX: this stuff should be done by direction() direction( target, DIR_NONE, TARG_ENEMY, false, true, NULL, &beh ); + if (beh.item == ENDOFPACK) + { + canned_msg(MSG_OK); + return false; + } if (!target.isValid) { if (target.isCancel) @@ -1521,48 +1513,136 @@ static bool choose_fire_target(dist &target, int &item) return (true); } -void shoot_thing(void) +// Bring up an inventory screen and have user choose an item. +// Returns an item slot, or ENDOFPACK on abort/failure +// On failure, returns error text, if any. +static int _fire_prompt_for_item(std::string& err) { - if (you.duration[DUR_BERSERKER]) + if (inv_count() < 1) { - canned_msg(MSG_TOO_BERSERK); - flush_input_buffer( FLUSH_ON_FAILURE ); - return; + // canned_msg(MSG_NOTHING_CARRIED); // Hmmm... + err = "You aren't carrying anything."; + return ENDOFPACK; } - int item = get_fire_item_index(); + int slot = prompt_invent_item( "Fire/throw which item? (* to show all)", + MT_INVLIST, + OBJ_MISSILES, true, true, true, 0, NULL, + OPER_THROW ); + if (slot == PROMPT_ABORT) + { + err = "Nothing selected."; + return ENDOFPACK; + } + return slot; +} + +// Return false and err text if this item can't be fired. +static bool _fire_validate_item(int slot, std::string& err) +{ + if (slot == you.equip[EQ_WEAPON] + && item_cursed(you.inv[slot])) + { + err = "That thing is stuck to your hand!"; + return false; + } + else if ( wearing_slot(slot) ) + { + err = "You are wearing that object!"; + return false; + } + return true; +} - if (item == ENDOFPACK) +// Return true if warning is given +static bool _fire_warn_if_impossible() +{ + if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BAT) { - // Tell the user why we might have skipped their missile - unwind_var<int> unwind_festart(Options.fire_items_start, 0); - unwind_var<bool> unwind_inscription(Hack_Ignore_F_Inscription, true); - const int skipped_item = get_fire_item_index(); - if (skipped_item == ENDOFPACK) + canned_msg(MSG_PRESENT_FORM); + return true; + } + if (you.attribute[ATTR_HELD]) + { + const item_def *weapon = you.weapon(); + if (!weapon || !is_range_weapon(*weapon)) { - mpr("No suitable missiles."); + mpr("You cannot throw anything while held in a net!"); + return true; } - else if (skipped_item < unwind_festart.original_value()) + else if (weapon->sub_type != WPN_BLOWGUN) { - mprf("No suitable missiles (fire_items_start = '%c', " - "ignoring item on '%c').", - index_to_letter(unwind_festart.original_value()), - index_to_letter(skipped_item)); + mprf("You cannot shoot with your %s while held in a net!", + weapon->name(DESC_BASENAME).c_str()); + return true; } - else - { - mprf("No suitable missiles (ignoring '=f'-inscribed item on '%c').", + // else shooting is possible + } + if (you.duration[DUR_BERSERKER]) + { + canned_msg(MSG_TOO_BERSERK); + return true; + } + return false; +} + +static std::string _fire_get_noitem_reason() +{ + const int cur_item = get_fire_item_index(); + if (cur_item != ENDOFPACK) + { + // Shouldn't be calling this if there is a good default item! + return std::string("Buggy."); + } + + // Tell the user why we might have skipped their missile + unwind_var<int> unwind_festart(Options.fire_items_start, 0); + unwind_var<bool> unwind_inscription(Hack_Ignore_F_Inscription, true); + const int skipped_item = get_fire_item_index(); + char buf[200]; + if (skipped_item == ENDOFPACK) + { + return std::string("No suitable missiles."); + } + else if (skipped_item < unwind_festart.original_value()) + { + // no room for showing index_to_letter(skipped_item); + snprintf(buf, 200, + "Nothing suitable (fire_items_start = '%c').", + index_to_letter(unwind_festart.original_value())); + return std::string(buf); + } + else + { + snprintf(buf, 200, + "Nothing suitable (ignored '=f'-inscribed item on '%c').", index_to_letter(skipped_item)); - } - flush_input_buffer( FLUSH_ON_FAILURE ); + return std::string(buf); + } +} + +// if item == -1, prompt the user. +void fire_thing(int item) +{ + if (_fire_warn_if_impossible()) + { + flush_input_buffer( FLUSH_ON_FAILURE ); return; } + + if (Options.tutorial_left) + Options.tut_throw_counter++; dist target; - bolt beam; - if (choose_fire_target(target, item) - && check_warning_inscriptions(you.inv[item], OPER_FIRE)) + if (item == -1) + { + if (! _fire_choose_item_and_target(item, target)) + return; + } + + if (check_warning_inscriptions(you.inv[item], OPER_FIRE)) { + bolt beam; throw_it( beam, item, false, 0, &target ); } } @@ -4602,8 +4682,7 @@ void tile_use_item(int idx, InvAction act) return; case OBJ_MISSILES: - if (check_warning_inscriptions(you.inv[idx], OPER_THROW)) - throw_anything(idx); + fire_thing(idx); return; case OBJ_ARMOUR: diff --git a/crawl-ref/source/item_use.h b/crawl-ref/source/item_use.h index cc1c5b8820..0efea498a3 100644 --- a/crawl-ref/source/item_use.h +++ b/crawl-ref/source/item_use.h @@ -104,15 +104,9 @@ bool remove_ring(int slot = -1, bool announce = false); * *********************************************************************** */ int get_fire_item_index(int start_from = 0, bool forward = true, bool check_quiver = true); -void shoot_thing(void); +void fire_thing(int item=-1); -// last updated 12may2000 {dlb} -/* *********************************************************************** - * called from: acr - * *********************************************************************** */ -void throw_anything(int slot = -1); - quiver_type get_quiver_type(void); // last updated 12may2000 {dlb} |