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
CE6FLTWU5PYFBSGVTIJXQXRMHOIHQ3VJCKHQVIMUUAIFHQ73X7NAC
VDWXI5MMXZLJXWWPZPXJZ2YZIR2OMPQO3VIJO2HMTF4TPYJB2MDQC
EAAACIJUVSBDOB6S73O4NFSMRDLFLQTFO7SXWWALGMVDZTQTHQBQC
YPALSPBPRHBZ6AA7Q2JVYWM53XIPB536EJGHUMESY4GKF4XFILZQC
ND3T5LCZATC63EVQ6SLI7XXMSUL7XICJDNLH3UCYUDEFWTA3N5MQC
TRZAZJJA5VQBJ65SO5H5DNSILIZEJHIZCBYEBHEATCT6ZSMWIFKQC
4MPLCIJZL4YNUWK2RTKNE6N4UWNBMO5WDRKW737ENVE3RKV5LCRAC
KN5WFFRSNGHIGI5IUYRBOA4R4K7XK3AEAAMN6ELDFTSYKPN7QX7AC
HSRRNAU5UAYC6B6IQWGJPFROMZBTJICPCH6DJVZDHDTAGOQ6IOYAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
6ZZO2QBB46RZM6OXVS7OIKC5M3SEAULSSJFXW5PJG556JDKKUHWAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
BWAQ3FHBBM6G3K3KYP75CRTR343RDQZJRYX5ZGYUEXYBAC3APDLAC
ZA7XPDPN44QXOAE5UKRQKMCJCC4IOFTW24CWRFIBKNJBCS7MRR5AC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
LP3U7LC6QK6TCMLAYTRGZ2CDZAHPM6VWDT6NPE5ET4WBBZVHBDXQC
JYCMD6WMNHXA53K4LLKVTNX6PLRLU25F6J2TYMPQXM2ENAE66NIAC
WJSQFRBUSDKGMQLKIBDVXTWJQHIL45GVBAYXB43AG3NACXYE3BBQC
RQFPW4BTIVE72VTJJAPQ6SA67IRSNUEAB3CBWN5RXPEDSYWM5ROAC
P2ZCF3BBG523ZEOD6XQA4X5YEHBTWH3IM33YVHXP2SQ5POXZIH4QC
2VOD7XONHR3G2JGZGXOPHNR2AN7WUQZFR5KJH5ZY4P4G67H3RCSQC
BRGAZR5AXWC2IALBVXO5SB354IRQEIRHSK55RZPGFI4AGIOD4LUQC
RGY2525RQH7SSGM6ZVI7CZL4WMNFZK2WRABOSIWRKQYYOU2RWN4QC
X76YXE6RFL7QY5WL6MSSS44WHVA5FQMDQY3XTYP2UL6UZB4E6XMQC
DMRXDEKHHBQNY37NPGZFAGUQPALWFANGGK4CUWIOQUPSLM2JBNFQC
RVST2QHYJ757ZHK4AUJ5NGPDZ44AD6RVFVXYPKQIBJXZBDNUCHXQC
CXIMQKHAORTQT6MN77TTYKK6IFIF6STKQWIMNAF54CFXAAQ5BKFAC
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
void throw_anything(int slot = -1);
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()
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);
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);
}
}
find_next_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;
case CONTROL('P'):
find_prev_ammo();
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;
}
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)
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)
}
static bool choose_fire_target(dist &target, int &item)
{
announce_ammo(item);
message_current_target();
fire_target_behaviour beh(item);
direction( target, DIR_NONE, TARG_ENEMY, false, true, NULL, &beh );
if (you.duration[DUR_BERSERKER])
if (inv_count() < 1)
{
// canned_msg(MSG_NOTHING_CARRIED); // Hmmm...
err = "You aren't carrying anything.";
return ENDOFPACK;
}
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)
int item = get_fire_item_index();
// 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;
}
// 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)
const item_def *weapon = you.weapon();
if (!weapon || !is_range_weapon(*weapon))
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').",
}
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 );
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))
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;
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();
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 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.
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.
Use the '(' command if you want to change your quiver without
firing.