summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/item_use.cc
diff options
context:
space:
mode:
authorpauldubois <pauldubois@c06c8d41-db1a-0410-9941-cceddc491573>2008-02-29 09:46:50 +0000
committerpauldubois <pauldubois@c06c8d41-db1a-0410-9941-cceddc491573>2008-02-29 09:46:50 +0000
commit917c8e96d491847ee8c15ca60a621b551b8f06c6 (patch)
tree9cebacfea82c14b5b41213e564ca280b51f72416 /crawl-ref/source/item_use.cc
parent32ed1823706542ae3cc6bb8086beca1d81e46caf (diff)
downloadcrawl-ref-917c8e96d491847ee8c15ca60a621b551b8f06c6.tar.gz
crawl-ref-917c8e96d491847ee8c15ca60a621b551b8f06c6.zip
FR 1900612
Patch 1901093 Merge 't' functionality into 'f'. Firing interface allows selection of inventory item by hitting 'i'. Items selected through the inventory interface will not be quivered. Firing interface prints "Firing", "Throwing", "Awkwardly throwing" depending on the item selected. In-game documentation and manual updated. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3482 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/item_use.cc')
-rw-r--r--crawl-ref/source/item_use.cc347
1 files changed, 213 insertions, 134 deletions
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: