git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@4191 c06c8d41-db1a-0410-9941-cceddc491573
ENI6P5WUO7DS4Y7EUDCYB4PSNT7CXH2L5JIB5BLZHNMWN4QDXMWQC
TX3LTXGB7TJ2QHLW2TEW6XTCTOW5A3KTZGBPBRTDTUYOZFFT3NLAC
TRCCLE5RJ4VJULBOWOI2WC3RJU7WTEGS7RRQTDQL6W5UU246LKTQC
TM35IHKZZNBCMR3ERBS4EYHGUK5IVCPUT2JUITMT74AYAIUZSYFQC
CWPA3Q5BG7KTTY6GX7CCS26PWC4UHJ47PUCMJX5BOJIP3FSTP2BQC
COLMJH3UIQFF4R5AV642OJK4HHGUIIPLNP5WGKLWWYNJV7ZGPI7AC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
EAAACIJUVSBDOB6S73O4NFSMRDLFLQTFO7SXWWALGMVDZTQTHQBQC
RPGERJQMO2J4ZDYTRHJCLZMXDVSTUOOJURSZ7FPWOUFHTXIV5VIAC
GT7BSR54BVJKHUCLEBTELGBMNBFFDQW52EVC4XKVEMUVG2UGZMDAC
NQIXUYGUIQTKZUB2IQDII7BBDMZ4VN4NUUTGT2ARQBZTDJUMPKRQC
FVT2J6IVMSQZYKQGUHQVGT4ADYM7AWUQ4U7766GBRRFMSR2WBMLAC
AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
DOZORMA366M4HB5JKSS27BMCR6ET7QNZNND2B7KV3NVEEPR5H7EAC
CE6FLTWU5PYFBSGVTIJXQXRMHOIHQ3VJCKHQVIMUUAIFHQ73X7NAC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
LZB2MLE66DKPQPG3BE6IU77HLHYMBQFJTKFJSPKEKZSOSXPXESJQC
4GFCF6N3MZSCHUB77Z3SQYJ3FYR5N3VBW2CGWANLJ74O5FEQH3CQC
YPALSPBPRHBZ6AA7Q2JVYWM53XIPB536EJGHUMESY4GKF4XFILZQC
5HBRQ2QZTFBQE2Z2CFADUI2D52LO5Z5CNHXHA7BJP3LGO7FJPUCQC
45MYNXZEG5E2GIOGVN2JXQFLHC56WTCXPD2SW6S6LZJ643G24JHQC
WL5WZXFJ6TONUQRSHUY4GQ5USU47ILWNN5X2JDQZO4CRJJZSRQIAC
QFM6WJTFHB4KCQYVROAQD4KRAYV2FZKDL5PJZQN5MS7WDYSLJBIAC
HSRRNAU5UAYC6B6IQWGJPFROMZBTJICPCH6DJVZDHDTAGOQ6IOYAC
RQFPW4BTIVE72VTJJAPQ6SA67IRSNUEAB3CBWN5RXPEDSYWM5ROAC
5V47S4NNTHWTSAHV3YLO2VGH7JTUIYJ3GBPDN5ZM4UQALT2ZEXDQC
6K4SRFJRW7762C4M7GOP2J3ZX6UZOAN5ZAOSS6QALFFG4SXRXJKAC
3GLHLYH34NUBL2C5HSECKNVAO4ZFAAYXCW3Q5VZ2PXDDZ4SDD7LQC
ACDPN464TK2LKLHSDN3YVRHAPF7WLSLLU3UHIYEXKFDEZPEU3XSQC
7V6TZHBSKK7AKY3SCYSP27QR2HP5N7HI3FI7V2QL7Y44OKKNI6IAC
E3X5HVN5UN75OMTJA6JFQBNZ54P37NDZLZZF7EFBZZC45KR73YGAC
4MPLCIJZL4YNUWK2RTKNE6N4UWNBMO5WDRKW737ENVE3RKV5LCRAC
R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC
3PY3L3A4QRW3Z5Y7SHO4TMVOOP2VNCO27X2MX4DTOP2SADLBQUOAC
DLVXY6DBP65B3RGWW4PNBEBPBNHNM3LSRYD36F3XDARFY7SPSJYAC
W2KRIXSCRJPS6WDIYTHVF5IRMF3V5DWECRAWUPVTB7VZ6A2BLD4QC
3D6NWJ44UYHLZMD3BOQIWXJUEGITAVCHK6Z2WWDQONVQC4HSBRXQC
XRZPPYWPWUOM4SFNI6BHKH2UKJQNLKOV6Y7XIEPEZXE5QYRT26PAC
2PAHDAPDO6PN4FNGB5N7CQNEGHSE3NOGPXYZMIAOJC4VW34FRVOAC
TRZAZJJA5VQBJ65SO5H5DNSILIZEJHIZCBYEBHEATCT6ZSMWIFKQC
// 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;
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);
// 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
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::_get_fire_order(std::vector<int>& order, bool ignore_inscription_etc) const
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());
}
// 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 wielded = you.equip[EQ_WEAPON];
if (wielded == -1)
return (AMMO_THROW);
item_def &weapon = you.inv[wielded];
if (weapon.base_type != OBJ_WEAPONS)
return (AMMO_THROW);
if (weapon == NULL)
return AMMO_THROW;
if (weapon->base_type != OBJ_WEAPONS)
return AMMO_THROW;
// 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_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];
}
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);
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 = 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]);
}
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 (Options.fire_quiver_best)
{
mpr("Use fire_quiver_best=false if you want manual quiver control.");
break;
}
const int cur = you.quiver[get_quiver_type()];
if (cur != ENDOFPACK)
int cur;
you.m_quiver->get_desired_item(NULL, &cur);
const int next = get_next_fire_item(cur, +1);
if (next != -1)