summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authorpauldubois <pauldubois@c06c8d41-db1a-0410-9941-cceddc491573>2008-04-11 10:55:40 +0000
committerpauldubois <pauldubois@c06c8d41-db1a-0410-9941-cceddc491573>2008-04-11 10:55:40 +0000
commita0065e7a7d5c55f0cf93c758f26afa9a86b16572 (patch)
tree74d513f5d251dd57f5b64c5ffb85703c4e08c70a /crawl-ref
parent172fd76cadb63cb41be2758b044b3f16c29a5fbf (diff)
downloadcrawl-ref-a0065e7a7d5c55f0cf93c758f26afa9a86b16572.tar.gz
crawl-ref-a0065e7a7d5c55f0cf93c758f26afa9a86b16572.zip
+ allocate and initialize
+ _fire_prompt_for_item returns -1, not ENDOFPACK + remove _fire_get_noitem_reason() + remove get_current_fire_item() + fix get_next_fire_item + remove _get_fire_order() + remove _fire_item_matches() + verify: no use of ENDOFPACK, use -1 + on_item_fired - implement: tags stuff + bug: wielding sling with stones = empty quiver - bug: wield sling, no quiver, pick up stones: should quiver + bug: wield sling, pick up stones: update # stones + bug: wield sling, stones quivered, drop stones: should update - feature: explicitly dropping all of ammo stack should remove it from quiver - move get_next_fire_item into quiver.cc? - remove: fire_quiver_best - remove: you.quiver - rename: you.quiver_change -> you.redraw_quiver - test no item because of fire_order_begin, =f, etc - find better place for on_weapon_changed - polish Qv: display, the command change - PROBLEM: cast_portal_projectile uses empty quiver slot? (test this) git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@4191 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/acr.cc16
-rw-r--r--crawl-ref/source/command.cc19
-rw-r--r--crawl-ref/source/debug.cc7
-rw-r--r--crawl-ref/source/externs.h2
-rw-r--r--crawl-ref/source/item_use.cc259
-rw-r--r--crawl-ref/source/item_use.h4
-rw-r--r--crawl-ref/source/items.cc8
-rw-r--r--crawl-ref/source/player.cc21
-rw-r--r--crawl-ref/source/quiver.cc192
-rw-r--r--crawl-ref/source/quiver.h15
-rw-r--r--crawl-ref/source/spells3.cc3
-rw-r--r--crawl-ref/source/spells4.cc12
-rw-r--r--crawl-ref/source/spl-cast.cc12
13 files changed, 261 insertions, 309 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 89d6fcc0a1..f91bc481fa 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -115,6 +115,7 @@
#include "output.h"
#include "overmap.h"
#include "player.h"
+#include "quiver.h"
#include "randart.h"
#include "religion.h"
#include "shopping.h"
@@ -2383,16 +2384,13 @@ void process_command( command_type cmd )
case CMD_CYCLE_QUIVER_FORWARD:
{
- if (Options.fire_quiver_best)
+ int cur;
+ you.m_quiver->get_desired_item(NULL, &cur);
+ const int next = get_next_fire_item(cur, +1);
+ if (next != -1)
{
- mpr("Use fire_quiver_best=false if you want manual quiver control.");
- break;
- }
- const int cur = you.quiver[get_quiver_type()];
- if (cur != ENDOFPACK)
- {
- const int next = get_next_fire_item(cur, +1);
- you.quiver[get_quiver_type()] = next;
+ // kind of a hacky way to get quiver to change
+ you.m_quiver->on_item_fired(you.inv[next]);
you.quiver_change = true;
}
break;
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index 922ac5b504..04834336d9 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -42,6 +42,7 @@
#include "mon-util.h"
#include "ouch.h"
#include "player.h"
+#include "quiver.h"
#include "religion.h"
#include "spl-cast.h"
#include "spl-util.h"
@@ -511,16 +512,26 @@ void list_weapons(void)
// Now we print out the current default fire weapon
wstring = "Firing : ";
- const int item = get_current_fire_item();
+ const item_def* item;
+ int slot;
+ you.m_quiver->get_desired_item(&item, &slot);
colour = MSGCOL_BLACK;
- if (item == ENDOFPACK)
+ if (slot == -1 && !is_valid_item(*item))
+ {
wstring += " nothing";
+ }
+ else if (slot == -1)
+ {
+ wstring += "-) ";
+ wstring += you.inv[slot].name(DESC_PLAIN);
+ wstring += " (empty)";
+ }
else
{
- wstring += you.inv[item].name(DESC_INVENTORY_EQUIP);
+ wstring += you.inv[slot].name(DESC_INVENTORY_EQUIP);
colour = menu_colour(wstring,
- menu_colour_item_prefix(you.inv[item]),
+ menu_colour_item_prefix(you.inv[slot]),
"equip");
}
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 50ded9bba9..b685550733 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -81,6 +81,7 @@
#include "output.h"
#include "place.h"
#include "player.h"
+#include "quiver.h"
#include "randart.h"
#include "religion.h"
#include "skills.h"
@@ -2585,7 +2586,7 @@ static bool fsim_ranged_combat(FILE *out, int wskill, int mi,
long hits = 0L;
int maxdam = 0;
- const int thrown = missile_slot == -1? get_current_fire_item() : missile_slot;
+ const int thrown = missile_slot == -1 ? you.m_quiver->get_fire_item() : missile_slot;
if (thrown == ENDOFPACK || thrown == -1)
{
mprf("No suitable missiles for combat simulation.");
@@ -2737,9 +2738,9 @@ static std::string fsim_weapon(int missile_slot)
if (is_range_weapon(weapon))
{
const int missile =
- missile_slot == -1? get_current_fire_item() :
+ missile_slot == -1? you.m_quiver->get_fire_item() :
missile_slot;
- if (missile < ENDOFPACK)
+ if (missile < ENDOFPACK && missile >= 0)
return item_buf + " with "
+ you.inv[missile].name(DESC_PLAIN);
}
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index b5634ac6e3..dc11da94f0 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -76,6 +76,7 @@ struct item_def;
class melee_attack;
struct coord_def;
class level_id;
+class player_quiver;
class actor
{
@@ -755,6 +756,7 @@ public:
std::set<std::string> uniq_map_names;
PlaceInfo global_info;
+ player_quiver* m_quiver;
protected:
FixedVector<PlaceInfo, NUM_BRANCHES> branch_info;
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index 966c8cd1ac..5070a8ad6c 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -61,6 +61,7 @@
#include "mon-util.h"
#include "ouch.h"
#include "player.h"
+#include "quiver.h"
#include "randart.h"
#include "religion.h"
#include "shopping.h"
@@ -87,7 +88,6 @@ static bool _handle_enchant_armour( int item_slot = -1 );
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.
@@ -1199,145 +1199,14 @@ bool takeoff_armour(int item)
return true;
} // end takeoff_armour()
-// Helper for _get_fire_order
-static bool _fire_item_matches(const item_def &item, unsigned fire_type)
-{
- if (!is_valid_item(item))
- return (false);
-
- if (you.attribute[ATTR_HELD])
- {
- if (item.base_type == OBJ_MISSILES)
- {
- const item_def *weapon = you.weapon();
- if (weapon && weapon->sub_type == WPN_BLOWGUN
- && item.launched_by(*weapon))
- {
- return (true);
- }
- }
- return (false);
- }
-
- if (fire_type & FIRE_INSCRIBED)
- if (item.inscription.find("+f", 0) != std::string::npos)
- return true;
-
- if (item.base_type == OBJ_MISSILES)
- {
- if ((fire_type & FIRE_DART) && item.sub_type == MI_DART)
- return (true);
- if ((fire_type & FIRE_STONE) && item.sub_type == MI_STONE)
- return (true);
- if ((fire_type & FIRE_JAVELIN) && item.sub_type == MI_JAVELIN)
- return (true);
- if ((fire_type & FIRE_ROCK) && item.sub_type == MI_LARGE_ROCK)
- return (true);
- if ((fire_type & FIRE_NET) && item.sub_type == MI_THROWING_NET)
- return (true);
-
- if (fire_type & FIRE_LAUNCHER)
- {
- const item_def *weapon = you.weapon();
- if (weapon && item.launched_by(*weapon))
- return (true);
- }
- }
- else if (item.base_type == OBJ_WEAPONS
- && is_throwable(item, you.body_size()))
- {
- if ((fire_type & FIRE_RETURNING) && item.special == SPWPN_RETURNING
- && item_ident(item, ISFLAG_KNOW_TYPE))
- {
- return (true);
- }
- if ((fire_type & FIRE_DAGGER) && item.sub_type == WPN_DAGGER)
- return (true);
- if ((fire_type & FIRE_SPEAR) && item.sub_type == WPN_SPEAR)
- return (true);
- if ((fire_type & FIRE_HAND_AXE) && item.sub_type == WPN_HAND_AXE)
- return (true);
- if ((fire_type & FIRE_CLUB) && item.sub_type == WPN_CLUB)
- return (true);
- }
- return (false);
-}
-
-quiver_type get_quiver_type()
-{
- const int wielded = you.equip[EQ_WEAPON];
- if (wielded == -1)
- return (QUIVER_THROW);
-
- item_def &weapon = you.inv[wielded];
-
- if (weapon.base_type != OBJ_WEAPONS)
- return (QUIVER_THROW);
-
- switch (weapon.sub_type)
- {
- case WPN_BLOWGUN:
- return (QUIVER_BLOWGUN);
- case WPN_SLING:
- return (QUIVER_SLING);
- case WPN_BOW:
- case WPN_LONGBOW:
- return (QUIVER_BOW);
- case WPN_CROSSBOW:
- return (QUIVER_CROSSBOW);
- case WPN_HAND_CROSSBOW:
- return (QUIVER_HAND_CROSSBOW);
- default:
- return (QUIVER_THROW);
- }
-
-}
-
-// Not free, but not a performance issue either.
-static bool Hack_Ignore_F_Inscription = false; // only for "why can't I fire" feedback
-static void _get_fire_order(std::vector<int>& fire_order)
-{
- for (int i_inv=Options.fire_items_start; i_inv<ENDOFPACK; i_inv++)
- {
- const item_def& item = you.inv[i_inv];
- if (!is_valid_item(item))
- continue;
- if (you.equip[EQ_WEAPON] == i_inv)
- continue;
-
- // =f prevents item from being in fire order
- if (!Hack_Ignore_F_Inscription &&
- strstr(item.inscription.c_str(), "=f"))
- continue;
-
- for (unsigned int i_flags=0;
- i_flags<Options.fire_order.size();
- i_flags++)
- {
- if (_fire_item_matches(item, Options.fire_order[i_flags]))
- {
- fire_order.push_back( (i_flags<<16) | (i_inv & 0xffff) );
- break;
- }
- }
- }
-
- std::sort(fire_order.begin(), fire_order.end());
-
- for (unsigned int i=0; i<fire_order.size(); i++)
- {
- fire_order[i] &= 0xffff;
- }
-}
-
int get_next_fire_item(int current, int direction)
{
std::vector<int> fire_order;
- _get_fire_order(fire_order);
+ you.m_quiver->get_fire_order(fire_order);
if (fire_order.size() == 0)
- return ENDOFPACK;
- if (current == ENDOFPACK)
+ return -1;
+ if (current == -1)
return fire_order[0];
for (unsigned i=0; i<fire_order.size(); i++)
@@ -1351,31 +1220,13 @@ int get_next_fire_item(int current, int direction)
return fire_order[0];
}
-int get_current_fire_item()
-{
- std::vector<int> fire_order;
- _get_fire_order(fire_order);
-
- if (fire_order.size() == 0)
- return ENDOFPACK;
-
- if (! Options.fire_quiver_best)
- {
- const int q = you.quiver[get_quiver_type()];
- for (unsigned i = 0; i < fire_order.size(); i++)
- if (q == fire_order[i])
- return q;
- }
- return fire_order[0];
-}
-
class fire_target_behaviour : public targeting_behaviour
{
public:
fire_target_behaviour()
- : item(ENDOFPACK), selected_from_inventory(false), need_prompt(false)
+ : m_slot(-1), selected_from_inventory(false), need_prompt(false)
{
- item = get_current_fire_item();
+ m_slot = you.m_quiver->get_fire_item(&m_noitem_reason);
}
// targeting_behaviour API
@@ -1385,15 +1236,16 @@ public:
void message_ammo_prompt(const std::string* pre_text=0);
public:
- int item;
+ int m_slot;
+ std::string m_noitem_reason;
bool selected_from_inventory;
bool need_prompt;
};
void fire_target_behaviour::message_ammo_prompt(const std::string* pre_text)
{
- const int next_item = get_next_fire_item(item, +1);
- bool no_other_items = (next_item == ENDOFPACK || next_item == item);
+ const int next_item = get_next_fire_item(m_slot, +1);
+ bool no_other_items = (next_item == -1 || next_item == m_slot);
mesclr();
@@ -1401,11 +1253,11 @@ void fire_target_behaviour::message_ammo_prompt(const std::string* pre_text)
mpr(pre_text->c_str());
std::ostringstream msg;
- if (item == ENDOFPACK)
+ if (m_slot == -1)
msg << "Firing ";
else
{
- const item_def& item_def = you.inv[item];
+ const item_def& item_def = you.inv[m_slot];
const launch_retval projected = is_launched(&you, you.weapon(), item_def);
if (projected == LRET_FUMBLED)
@@ -1421,13 +1273,15 @@ void fire_target_behaviour::message_ammo_prompt(const std::string* pre_text)
msg << (no_other_items ? "(i - inventory)" : "(i - inventory. (,) - cycle)")
<< ": ";
- if (item == ENDOFPACK)
- msg << "<red>" << _fire_get_noitem_reason() << "</red>";
+ if (m_slot == -1)
+ {
+ msg << "<red>" << m_noitem_reason << "</red>";
+ }
else
{
const char* color = (selected_from_inventory ? "grey" : "w");
msg << "<" << color << ">"
- << you.inv[item].name(DESC_INVENTORY_EQUIP)
+ << you.inv[m_slot].name(DESC_INVENTORY_EQUIP)
<< "</" << color << ">";
}
@@ -1457,10 +1311,10 @@ command_type fire_target_behaviour::get_command(int key)
case CONTROL('P'):
{
const int direction = (key == CONTROL('P') || key == ')') ? -1 : +1;
- const int next = get_next_fire_item(item, direction);
- if (next != item && next != ENDOFPACK)
+ const int next = get_next_fire_item(m_slot, direction);
+ if (next != m_slot && next != -1)
{
- item = next;
+ m_slot = next;
selected_from_inventory = false;
}
// Do this stuff unconditionally to make the prompt redraw
@@ -1472,10 +1326,10 @@ command_type fire_target_behaviour::get_command(int key)
{
std::string err;
const int selected = _fire_prompt_for_item(err);
- if (selected != ENDOFPACK &&
+ if (selected >= 0 &&
_fire_validate_item(selected, err))
{
- item = selected;
+ m_slot = selected;
selected_from_inventory = true;
}
message_ammo_prompt( err.length() ? &err : NULL );
@@ -1493,27 +1347,27 @@ command_type fire_target_behaviour::get_command(int key)
return targeting_behaviour::get_command(key);
}
-static bool _fire_choose_item_and_target(int& item, dist& target)
+static bool _fire_choose_item_and_target(int& slot, dist& target)
{
fire_target_behaviour beh;
- const bool was_chosen = (item != -1);
+ const bool was_chosen = (slot != -1);
if (was_chosen)
{
- if (you.equip[EQ_WEAPON] == item
- && item_cursed(you.inv[item]))
+ if (you.equip[EQ_WEAPON] == slot
+ && item_cursed(you.inv[slot]))
{
mpr("You can't fire a cursed item!");
return false;
}
- beh.item = item; // force item to be the prechosen one
+ beh.m_slot = slot; // force item to be the prechosen one
}
beh.message_ammo_prompt();
message_current_target(); // XXX: this stuff should be done by direction()
direction( target, DIR_NONE, TARG_ENEMY, -1, false, true, NULL, &beh );
- if (beh.item == ENDOFPACK)
+ if (beh.m_slot == -1)
{
canned_msg(MSG_OK);
return false;
@@ -1528,22 +1382,22 @@ static bool _fire_choose_item_and_target(int& item, dist& target)
// If ammo was chosen via 'fi', it's not supposed to get quivered.
// Otherwise, if the user chose different ammo, quiver it.
// Same for items selected in tile mode.
- if (was_chosen || beh.item != item)
+ if (was_chosen || ! beh.selected_from_inventory)
{
- item = beh.item;
-
- if (! beh.selected_from_inventory)
- {
- you.quiver[get_quiver_type()] = beh.item;
- you.quiver_change = true;
- }
+ you.m_quiver->on_item_fired(you.inv[beh.m_slot]);
+ }
+ else
+ {
+ you.m_quiver->on_item_fired_fi(you.inv[beh.m_slot]);
}
+ you.quiver_change = true;
+ slot = beh.m_slot;
return (true);
}
// Bring up an inventory screen and have user choose an item.
-// Returns an item slot, or ENDOFPACK on abort/failure
+// Returns an item slot, or -1 on abort/failure
// On failure, returns error text, if any.
static int _fire_prompt_for_item(std::string& err)
{
@@ -1551,7 +1405,7 @@ static int _fire_prompt_for_item(std::string& err)
{
// canned_msg(MSG_NOTHING_CARRIED); // Hmmm...
err = "You aren't carrying anything.";
- return ENDOFPACK;
+ return -1;
}
int slot = prompt_invent_item( "Fire/throw which item? (* to show all)",
@@ -1561,7 +1415,7 @@ static int _fire_prompt_for_item(std::string& err)
if (slot == PROMPT_ABORT)
{
err = "Nothing selected.";
- return ENDOFPACK;
+ return -1;
}
return slot;
}
@@ -1615,41 +1469,6 @@ static bool _fire_warn_if_impossible()
return false;
}
-static std::string _fire_get_noitem_reason()
-{
- const int cur_item = get_current_fire_item();
- 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_current_fire_item();
- 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));
- return std::string(buf);
- }
-}
-
// if item == -1, prompt the user.
// if item passed, it will be put into the quiver.
void fire_thing(int item)
diff --git a/crawl-ref/source/item_use.h b/crawl-ref/source/item_use.h
index dcc08cb42e..1ef1bad677 100644
--- a/crawl-ref/source/item_use.h
+++ b/crawl-ref/source/item_use.h
@@ -103,13 +103,9 @@ bool remove_ring(int slot = -1, bool announce = false);
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
-int get_current_fire_item();
int get_next_fire_item(int current, int offset);
void fire_thing(int item=-1);
-
-quiver_type get_quiver_type(void);
-
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: acr
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 2719d1eaaf..52aee95021 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -63,6 +63,7 @@
#include "overmap.h"
#include "place.h"
#include "player.h"
+#include "quiver.h"
#include "randart.h"
#include "religion.h"
#include "shopping.h"
@@ -243,8 +244,7 @@ bool dec_inv_item_quantity( int obj, int amount )
if (you.equip[EQ_WEAPON] == obj)
you.wield_change = true;
- if (you.quiver[get_quiver_type()] == obj)
- you.quiver_change = true;
+ you.m_quiver->on_inv_quantity_change(obj, amount);
if (you.inv[obj].quantity <= amount)
{
@@ -315,9 +315,7 @@ void inc_inv_item_quantity( int obj, int amount )
if (you.equip[EQ_WEAPON] == obj)
you.wield_change = true;
- if (you.quiver[get_quiver_type()] == obj)
- you.quiver_change = true;
-
+ you.m_quiver->on_inv_quantity_change(obj, amount);
you.inv[obj].quantity += amount;
burden_change();
}
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index b6582ebfb1..c4e9cf1ce7 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -55,6 +55,7 @@
#include "ouch.h"
#include "output.h"
#include "place.h"
+#include "quiver.h"
#include "randart.h"
#include "religion.h"
#include "skills.h"
@@ -5287,30 +5288,41 @@ bool actor::can_pass_through(const coord_def &c) const
// player
player::player()
+ : m_quiver(0)
{
init();
- kills = new KillMaster();
+ kills = new KillMaster(); // why isn't this done in init()?
}
player::player(const player &other)
+ : m_quiver(0)
{
init();
+
+ // why doesn't this do a copy_from?
+ player_quiver* saved_quiver = m_quiver;
*this = other;
+ m_quiver = saved_quiver;
kills = new KillMaster(*(other.kills));
+ *m_quiver = *(other.m_quiver);
}
+// why is this not called "operator="?
void player::copy_from(const player &other)
{
if (this == &other)
return;
- KillMaster *_kills = kills;
+ KillMaster *saved_kills = kills;
+ player_quiver* saved_quiver = m_quiver;
*this = other;
- kills = _kills;
+ kills = saved_kills;
*kills = *(other.kills);
+ m_quiver = saved_quiver;
+ *m_quiver = *(other.m_quiver);
}
@@ -5478,6 +5490,9 @@ void player::init()
non_branch_info[i].branch = -1;
non_branch_info[i].assert_validity();
}
+
+ if (m_quiver) delete m_quiver;
+ m_quiver = new player_quiver;
}
player_save_info player_save_info::operator=(const player& rhs)
diff --git a/crawl-ref/source/quiver.cc b/crawl-ref/source/quiver.cc
index 07c6cf32dd..5694acae99 100644
--- a/crawl-ref/source/quiver.cc
+++ b/crawl-ref/source/quiver.cc
@@ -21,9 +21,9 @@
// bool is_valid_item( const item_def &item )
static int _get_pack_slot(const item_def&);
-static ammo_t _get_weapon_ammo_type();
-static bool _item_matches(const item_def &item, fire_type types);
-
+static ammo_t _get_weapon_ammo_type(const item_def*);
+static bool _item_matches(const item_def &item, fire_type types, const item_def* launcher);
+static bool _items_similar(const item_def& a, const item_def& b);
// ----------------------------------------------------------------------
// player_quiver
// ----------------------------------------------------------------------
@@ -42,28 +42,31 @@ void player_quiver::get_desired_item(const item_def** item_out, int* slot_out) c
{
if (m_last_used_type == AMMO_INVALID)
{
- *item_out = NULL;
- *slot_out = -1;
+ if (item_out) *item_out = NULL;
+ if (slot_out) *slot_out = -1;
}
else
{
- *slot_out = _get_pack_slot(m_last_used_of_type[m_last_used_type]);
- if (*slot_out == -1)
+ const int slot = _get_pack_slot(m_last_used_of_type[m_last_used_type]);
+ if (slot == -1)
{
// Not in inv, but caller can at least get the type of the item.
- *item_out = &m_last_used_of_type[m_last_used_type];
+ if (item_out) *item_out = &m_last_used_of_type[m_last_used_type];
}
else
{
// Return the item in inv, since it will have an accurate count
- *item_out = &you.inv[*slot_out];
+ if (item_out) *item_out = &you.inv[slot];
}
+ if (slot_out) *slot_out = slot;
}
}
// Return inv slot of item that should be fired by default.
-// This is the first item displayed in the fire interface.
-int player_quiver::get_default_slot(std::string& no_item_reason) const
+// This differs from get_desired_item; that method can return
+// an item that is not in inventory, while this one cannot.
+// If no item can be found, return the reason why.
+int player_quiver::get_fire_item(std::string* no_item_reason) const
{
int slot;
const item_def* desired_item;
@@ -74,7 +77,7 @@ int player_quiver::get_default_slot(std::string& no_item_reason) const
if (slot == -1)
{
std::vector<int> order;
- _get_fire_order(order, false);
+ _get_fire_order(order, false, you.weapon());
if (order.size())
slot = order[0];
}
@@ -83,23 +86,27 @@ int player_quiver::get_default_slot(std::string& no_item_reason) const
if (slot == -1)
{
std::vector<int> full_fire_order;
- _get_fire_order(full_fire_order, true);
- if (full_fire_order.size() == 0)
+ _get_fire_order(full_fire_order, true, you.weapon());
+ if (no_item_reason == NULL)
+ {
+ // nothing
+ }
+ else if (full_fire_order.size() == 0)
{
- no_item_reason = "No suitable missiles.";
+ *no_item_reason = "No suitable missiles.";
}
else
{
const int skipped_item = full_fire_order[0];
if (skipped_item < Options.fire_items_start)
{
- no_item_reason = make_stringf(
+ *no_item_reason = make_stringf(
"Nothing suitable (fire_items_start = '%c').",
index_to_letter(Options.fire_items_start));
}
else
{
- no_item_reason = make_stringf(
+ *no_item_reason = make_stringf(
"Nothing suitable (ignored '=f'-inscribed item on '%c').",
index_to_letter(skipped_item));
}
@@ -119,40 +126,123 @@ void player_quiver::on_item_fired(const item_def& item)
if (weapon && item.launched_by(*weapon))
{
- const ammo_t t = _get_weapon_ammo_type();
+ const ammo_t t = _get_weapon_ammo_type(weapon);
m_last_used_of_type[t] = item;
- m_last_used_of_type[t].quantity = 1; // ensure it's valid
+ m_last_used_of_type[t].quantity = 1; // 0 makes it invalid :(
+ m_last_used_type = t;
}
else
{
m_last_used_of_type[AMMO_THROW] = item;
m_last_used_of_type[AMMO_THROW].quantity = 1;
+ m_last_used_type = AMMO_THROW;
}
}
-// Notification that ltem was fired with 'f' 't'
-void player_quiver::on_item_thrown(const item_def& item)
+// Notification that ltem was fired with 'f' 'i'
+void player_quiver::on_item_fired_fi(const item_def& item)
{
- m_last_used_of_type[AMMO_THROW] = item;
- m_last_used_of_type[AMMO_THROW].quantity = 1;
+ // currently no difference
+ on_item_fired(item);
}
+// Called when the player might have switched weapons, or might have
+// picked up something interesting.
void player_quiver::on_weapon_changed()
{
- m_last_used_type = _get_weapon_ammo_type();
+ // Only switch m_last_used_type if weapon really changed
+ const item_def* weapon = you.weapon();
+ if (weapon == NULL)
+ {
+ if (m_last_weapon.base_type != OBJ_UNASSIGNED)
+ {
+ m_last_weapon.base_type = OBJ_UNASSIGNED;
+ m_last_used_type = AMMO_THROW;
+ }
+ }
+ else
+ {
+ if (! _items_similar(*weapon, m_last_weapon))
+ {
+ m_last_weapon = *weapon;
+ m_last_used_type = _get_weapon_ammo_type(weapon);
+ }
+ }
+
+ _maybe_fill_empty_slot();
+}
+
+void player_quiver::on_inv_quantity_change(int slot, int amt)
+{
+ if (m_last_used_of_type[m_last_used_type].base_type == OBJ_UNASSIGNED)
+ {
+ // Empty quiver. Maybe we can fill it now?
+ _maybe_fill_empty_slot();
+ you.quiver_change = true;
+ }
+ else if (m_last_used_of_type[m_last_used_type].base_type !=
+ you.inv[slot].base_type)
+ {
+ // Not our current stack; don't bother
+ }
+ else
+ {
+ // Maybe matches current stack. Redraw if so.
+ int qv_slot; get_desired_item(NULL, &qv_slot);
+ if (qv_slot == slot)
+ you.quiver_change = true;
+ }
+}
+
+// If current quiver slot is empty, fill it with something useful.
+void player_quiver::_maybe_fill_empty_slot()
+{
+ const item_def* weapon = you.weapon();
+ const ammo_t slot = _get_weapon_ammo_type(weapon);
+ if (! is_valid_item(m_last_used_of_type[slot]))
+ {
+ // const launch_retval desired_ret =
+ // (weapon && is_range_weapon(*weapon)) ? LRET_LAUNCHED : LRET_THROWN;
+ const launch_retval desired_ret =
+ (slot == AMMO_THROW ? LRET_THROWN : LRET_LAUNCHED);
+ std::vector<int> order; _get_fire_order(order, false, weapon);
+ for (unsigned int i=0; i<order.size(); i++)
+ {
+ if (is_launched(&you, weapon, you.inv[order[i]]) == desired_ret)
+ {
+ m_last_used_of_type[slot] = you.inv[order[i]];
+ m_last_used_of_type[slot].quantity = 1;
+ break;
+ }
+ }
+ }
+}
+
+void player_quiver::get_fire_order(std::vector<int>& v) const
+{
+ _get_fire_order(v, false, you.weapon());
}
-void player_quiver::_get_fire_order(std::vector<int>& order, bool ignore_inscription_etc) const
+// Get a sorted list of items to show in the fire interface.
+//
+// If ignore_inscription_etc, ignore =f and Options.fire_items_start.
+// This is used for generating informational error messages, when the
+// fire order is empty.
+//
+// launcher determines what items match the 'launcher' fire_order type.
+void player_quiver::_get_fire_order(
+ std::vector<int>& order,
+ bool ignore_inscription_etc,
+ const item_def* launcher) const
{
const int inv_start = (ignore_inscription_etc ? 0 : Options.fire_items_start);
// If in a net, cannot throw anything, and can only launch from blowgun
if (you.attribute[ATTR_HELD])
{
- const item_def *weapon = you.weapon();
- if (weapon && weapon->sub_type == WPN_BLOWGUN)
+ if (launcher && launcher->sub_type == WPN_BLOWGUN)
for (int i_inv=inv_start; i_inv<ENDOFPACK; i_inv++)
- if (is_valid_item(you.inv[i_inv]) && you.inv[i_inv].launched_by(*weapon))
+ if (is_valid_item(you.inv[i_inv]) && you.inv[i_inv].launched_by(*launcher))
order.push_back(i_inv);
return;
}
@@ -176,7 +266,7 @@ void player_quiver::_get_fire_order(std::vector<int>& order, bool ignore_inscrip
i_flags<Options.fire_order.size();
i_flags++)
{
- if (_item_matches(item, (fire_type)Options.fire_order[i_flags]))
+ if (_item_matches(item, (fire_type)Options.fire_order[i_flags], launcher))
{
order.push_back( (i_flags<<16) | (i_inv & 0xffff) );
break;
@@ -198,9 +288,9 @@ void player_quiver::_get_fire_order(std::vector<int>& order, bool ignore_inscrip
// Helper for _get_fire_order
// types may actually contain more than one fire_type
-static bool _item_matches(const item_def &item, fire_type types)
+static bool _item_matches(const item_def &item, fire_type types, const item_def* launcher)
{
- ASSERT(!is_valid_item(item));
+ ASSERT(is_valid_item(item));
if (types & FIRE_INSCRIBED)
if (item.inscription.find("+f", 0) != std::string::npos)
@@ -221,8 +311,7 @@ static bool _item_matches(const item_def &item, fire_type types)
if (types & FIRE_LAUNCHER)
{
- const item_def *weapon = you.weapon();
- if (weapon && item.launched_by(*weapon))
+ if (launcher && item.launched_by(*launcher))
return (true);
}
}
@@ -256,7 +345,8 @@ static int _get_pack_slot(const item_def& item)
for (int i=0; i<ENDOFPACK; i++)
{
- if (items_stack(item, you.inv[i]))
+ const item_def& inv_item = you.inv[i];
+ if (inv_item.quantity && _items_similar(item, you.inv[i]))
return i;
}
@@ -266,31 +356,33 @@ static int _get_pack_slot(const item_def& item)
// Return the type of ammo used by the player's equipped weapon,
// or AMMO_THROW if it's not a launcher.
-static ammo_t _get_weapon_ammo_type()
+static ammo_t _get_weapon_ammo_type(const item_def* weapon)
{
- const int wielded = you.equip[EQ_WEAPON];
- if (wielded == -1)
- return (AMMO_THROW);
+ if (weapon == NULL)
+ return AMMO_THROW;
+ if (weapon->base_type != OBJ_WEAPONS)
+ return AMMO_THROW;
- item_def &weapon = you.inv[wielded];
-
- if (weapon.base_type != OBJ_WEAPONS)
- return (AMMO_THROW);
-
- switch (weapon.sub_type)
+ switch (weapon->sub_type)
{
case WPN_BLOWGUN:
- return (AMMO_BLOWGUN);
+ return AMMO_BLOWGUN;
case WPN_SLING:
- return (AMMO_SLING);
+ return AMMO_SLING;
case WPN_BOW:
case WPN_LONGBOW:
- return (AMMO_BOW);
+ return AMMO_BOW;
case WPN_CROSSBOW:
- return (AMMO_CROSSBOW);
+ return AMMO_CROSSBOW;
case WPN_HAND_CROSSBOW:
- return (AMMO_HAND_CROSSBOW);
+ return AMMO_HAND_CROSSBOW;
default:
- return (AMMO_THROW);
+ return AMMO_THROW;
}
}
+
+static bool _items_similar(const item_def& a, const item_def& b)
+{
+ // this is a reasonable implementation for now
+ return items_stack(a, b, true);
+}
diff --git a/crawl-ref/source/quiver.h b/crawl-ref/source/quiver.h
index aee70e74fe..dd76319e1a 100644
--- a/crawl-ref/source/quiver.h
+++ b/crawl-ref/source/quiver.h
@@ -29,17 +29,22 @@ class player_quiver
player_quiver();
void get_desired_item(const item_def** item_out, int* slot_out) const;
- // Returns an item, or a reason why we returned an invalid item
- int get_default_slot(std::string& no_item_reason) const;
- void get_fire_order(std::vector<int>& v) const { _get_fire_order(v, false); }
+ int get_fire_item(std::string* no_item_reason=0) const;
+ void get_fire_order(std::vector<int>& v) const;
void on_item_fired(const item_def&);
- void on_item_thrown(const item_def&);
+ void on_item_fired_fi(const item_def&);
+ void on_inv_quantity_change(int slot, int amt);
void on_weapon_changed();
private:
- void _get_fire_order(std::vector<int>&, bool ignore_inscription_etc) const;
+ void _get_fire_order(std::vector<int>&,
+ bool ignore_inscription_etc,
+ const item_def* launcher) const;
+ void _maybe_fill_empty_slot();
private:
+ item_def m_last_weapon;
+
ammo_t m_last_used_type;
item_def m_last_used_of_type[NUM_AMMO];
};
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index 6ceb3fb857..87b96f7974 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -1101,10 +1101,9 @@ void cast_poison_ammo(void)
mprf("%s %s covered in a thin film of poison.", old_desc,
(you.inv[ammo].quantity == 1) ? "is" : "are");
+ you.quiver_change = true;
if (ammo == you.equip[EQ_WEAPON])
you.wield_change = true;
- else if (ammo == you.quiver[get_quiver_type()])
- you.quiver_change = true;
}
else
{
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index 90ccd5ac9e..cbb771dfaa 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -44,6 +44,7 @@
#include "mstuff2.h"
#include "ouch.h"
#include "player.h"
+#include "quiver.h"
#include "randart.h"
#include "religion.h"
#include "skills.h"
@@ -2424,12 +2425,19 @@ bool cast_portal_projectile(int pow, bolt& beam)
return 0;
}
- const int idx = get_current_fire_item();
- if ( idx == ENDOFPACK )
+ int idx;
+ const item_def* item;
+ you.m_quiver->get_desired_item(&item, &idx);
+ if ( item == NULL )
{
mpr("No suitable missiles.");
return false;
}
+ else if ( idx == -1 )
+ {
+ mpr("No missiles left.");
+ return false;
+ }
throw_it( beam, idx, true, random2(pow/4) );
return true;
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index 05c5ea88a5..24cb234962 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -43,6 +43,7 @@
#include "mutation.h"
#include "ouch.h"
#include "player.h"
+#include "quiver.h"
#include "religion.h"
#include "skills.h"
#include "skills2.h"
@@ -884,12 +885,19 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
const char *prompt = get_spell_target_prompt(spell);
if (spell == SPELL_PORTAL_PROJECTILE)
{
- const int idx = get_current_fire_item();
- if ( idx == ENDOFPACK )
+ const item_def* item;
+ int idx;
+ you.m_quiver->get_desired_item(&item, &idx);
+ if ( item == NULL )
{
mpr("No suitable missiles.");
return (SPRET_ABORT);
}
+ else if ( idx == -1 )
+ {
+ mpr("No missiles left.");
+ return SPRET_ABORT;
+ }
mprf(MSGCH_PROMPT, "Where do you want to aim %s?",
you.inv[idx].name(DESC_NOCAP_YOUR).c_str());
}