diff options
author | pauldubois <pauldubois@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-04-11 10:55:40 +0000 |
---|---|---|
committer | pauldubois <pauldubois@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-04-11 10:55:40 +0000 |
commit | a0065e7a7d5c55f0cf93c758f26afa9a86b16572 (patch) | |
tree | 74d513f5d251dd57f5b64c5ffb85703c4e08c70a /crawl-ref/source | |
parent | 172fd76cadb63cb41be2758b044b3f16c29a5fbf (diff) | |
download | crawl-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/source')
-rw-r--r-- | crawl-ref/source/acr.cc | 16 | ||||
-rw-r--r-- | crawl-ref/source/command.cc | 19 | ||||
-rw-r--r-- | crawl-ref/source/debug.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/item_use.cc | 259 | ||||
-rw-r--r-- | crawl-ref/source/item_use.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/items.cc | 8 | ||||
-rw-r--r-- | crawl-ref/source/player.cc | 21 | ||||
-rw-r--r-- | crawl-ref/source/quiver.cc | 192 | ||||
-rw-r--r-- | crawl-ref/source/quiver.h | 15 | ||||
-rw-r--r-- | crawl-ref/source/spells3.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/spells4.cc | 12 | ||||
-rw-r--r-- | crawl-ref/source/spl-cast.cc | 12 |
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()); } |