summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-15 23:46:58 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-15 23:46:58 +0000
commit6c1c71a64485cb196aaa21082d04246bfe922466 (patch)
treec369625e01d61cb00b9f30f38dd0e10b8d0134cf
parent3c019579930be9cdff59094b613b68575f895bae (diff)
downloadcrawl-ref-6c1c71a64485cb196aaa21082d04246bfe922466.tar.gz
crawl-ref-6c1c71a64485cb196aaa21082d04246bfe922466.zip
Implement FR 1936340: add a shortcut for butchering (a)ll corpses in a
stack. Does not yet differentiate between butchering and bottling (for Vampires), and if several butcher/sacrifice delays have been chained and are now interrupted, you only get the "not switching back to xyz" message if the interruption happens while butchering the last corpse. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5068 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/delay.cc148
-rw-r--r--crawl-ref/source/enum.h1
-rw-r--r--crawl-ref/source/food.cc406
-rw-r--r--crawl-ref/source/initfile.cc1
-rw-r--r--crawl-ref/source/stuff.cc7
-rw-r--r--crawl-ref/source/tutorial.cc2
6 files changed, 360 insertions, 205 deletions
diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc
index 8aa6fcfcec..2f8c170abc 100644
--- a/crawl-ref/source/delay.cc
+++ b/crawl-ref/source/delay.cc
@@ -286,11 +286,11 @@ void start_delay( delay_type type, int turns, int parm1, int parm2 )
delay_queue_item delay;
- delay.type = type;
+ delay.type = type;
delay.duration = turns;
- delay.parm1 = parm1;
- delay.parm2 = parm2;
- delay.started = false;
+ delay.parm1 = parm1;
+ delay.parm2 = parm2;
+ delay.started = false;
// Handle zero-turn delays (possible with butchering).
if (turns == 0)
@@ -307,7 +307,7 @@ void start_delay( delay_type type, int turns, int parm1, int parm2 )
void stop_delay( bool stop_stair_travel )
/*********************/
{
- if ( you.delay_queue.empty() )
+ if (you.delay_queue.empty())
return;
delay_queue_item delay = you.delay_queue.front();
@@ -315,9 +315,10 @@ void stop_delay( bool stop_stair_travel )
ASSERT(!crawl_state.is_repeating_cmd() || delay.type == DELAY_MACRO);
const bool butcher_swap_warn =
- (delay.type == DELAY_BUTCHER
- && you.delay_queue.size() >= 2
- && you.delay_queue[1].type == DELAY_WEAPON_SWAP);
+ ((delay.type == DELAY_BUTCHER
+ || delay.type == DELAY_OFFER_CORPSE)
+ && you.delay_queue.size() >= 2
+ && you.delay_queue[1].type == DELAY_WEAPON_SWAP);
const int butcher_swap_weapon =
butcher_swap_warn? you.delay_queue[1].parm1 : -10;
@@ -334,20 +335,25 @@ void stop_delay( bool stop_stair_travel )
{
case DELAY_BUTCHER:
// Corpse keeps track of work in plus2 field, see handle_delay() -- bwr
+ // FIXME: Also print this message for interruptions in chained
+ // butchery/sacrifice session.
if (butcher_swap_warn)
{
std::string weapon;
if (butcher_swap_weapon == -1)
weapon = "unarmed combat";
else
+ {
weapon = "your " +
you.inv[butcher_swap_weapon].name(DESC_BASENAME);
+ }
mprf(MSGCH_WARN, "You stop butchering the corpse; not switching "
"back to %s.",
weapon.c_str());
}
else
mpr( "You stop butchering the corpse." );
+
pop_delay();
break;
@@ -462,10 +468,17 @@ void stop_delay( bool stop_stair_travel )
}
break;
+ case DELAY_OFFER_CORPSE: // one turn
+#ifdef DEBUG_DIAGNOSTICS
+ mpr("Stop sacrificing.");
+#endif
+ pop_delay();
+ break;
+
case DELAY_WEAPON_SWAP: // one turn... too much trouble
case DELAY_DROP_ITEM: // one turn... only used for easy armour drops
- case DELAY_UNINTERRUPTIBLE: // never stoppable
case DELAY_JEWELLERY_ON: // one turn
+ case DELAY_UNINTERRUPTIBLE: // never stoppable
default:
break;
}
@@ -476,8 +489,11 @@ void stop_delay( bool stop_stair_travel )
void stop_butcher_delay()
{
- if (current_delay_action() == DELAY_BUTCHER)
+ if (current_delay_action() == DELAY_BUTCHER
+ || current_delay_action() == DELAY_OFFER_CORPSE)
+ {
stop_delay();
+ }
}
bool you_are_delayed( void )
@@ -588,9 +604,9 @@ void handle_delay( void )
delay_queue_item &delay = you.delay_queue.front();
- if ( !delay.started )
+ if (!delay.started)
{
- switch ( delay.type )
+ switch (delay.type)
{
case DELAY_ARMOUR_ON:
mpr("You start putting on your armour.", MSGCH_MULTITURN_ACTION);
@@ -599,9 +615,16 @@ void handle_delay( void )
mpr("You start removing your armour.", MSGCH_MULTITURN_ACTION);
break;
case DELAY_BUTCHER:
- mprf(MSGCH_MULTITURN_ACTION, "You start %s the corpse.",
- can_bottle_blood_from_corpse(mitm[delay.parm1].plus)?
- "bottling blood from" : "butchering");
+ mprf(MSGCH_MULTITURN_ACTION, "You start %s the %s.",
+ can_bottle_blood_from_corpse(mitm[delay.parm1].plus) ?
+ "bottling blood from" : "butchering",
+ mitm[delay.parm1].name(DESC_PLAIN).c_str());
+
+ if (you.duration[DUR_PRAYER]
+ && god_hates_butchery(you.religion))
+ {
+ did_god_conduct(DID_DEDICATED_BUTCHERY, 10);
+ }
break;
case DELAY_MEMORISE:
mpr("You start memorising the spell.", MSGCH_MULTITURN_ACTION);
@@ -649,14 +672,14 @@ void handle_delay( void )
// First check cases where delay may no longer be valid:
// XXX: need to handle passwall when monster digs -- bwr
- if (delay.type == DELAY_BUTCHER)
+ if (delay.type == DELAY_BUTCHER || delay.type == DELAY_OFFER_CORPSE)
{
// A monster may have raised the corpse you're chopping up! -- bwr
// Note that a monster could have raised the corpse and another
// monster could die and create a corpse with the same ID number...
// However, it would not be at the player's square like the
// original and that's why we do it this way.
- if (is_valid_item( mitm[ delay.parm1 ] )
+ if (is_valid_item(mitm[ delay.parm1 ])
&& mitm[ delay.parm1 ].base_type == OBJ_CORPSES
&& mitm[ delay.parm1 ].x == you.x_pos
&& mitm[ delay.parm1 ].y == you.y_pos )
@@ -664,19 +687,41 @@ void handle_delay( void )
if (mitm[ delay.parm1 ].sub_type == CORPSE_SKELETON)
{
mpr("The corpse rots away into a skeleton!");
- if (player_mutation_level(MUT_SAPROVOROUS) == 3)
- xom_check_corpse_waste();
+ if (delay.type == DELAY_BUTCHER)
+ {
+ if (player_mutation_level(MUT_SAPROVOROUS) == 3)
+ xom_check_corpse_waste();
+ else
+ xom_is_stimulated(32);
+ delay.duration = 0;
+ }
else
- xom_is_stimulated(32);
- delay.duration = 0;
+ {
+ // don't attempt to offer a skeleton
+ pop_delay();
+
+ // Chain onto the next delay.
+ handle_delay();
+ return;
+ }
}
else
{
- // special < 100 is the rottenness check
- if ( (mitm[delay.parm1].special < 100) &&
- (delay.parm2 >= 100) )
+ // Only give the rotting message if the corpse wasn't
+ // previously rotten. (special < 100 is the rottenness check)
+ if (food_is_rotten(mitm[delay.parm1]) && delay.parm2 >= 100)
{
mpr("The corpse rots.", MSGCH_ROTTEN_MEAT);
+ if (delay.type == DELAY_OFFER_CORPSE)
+ {
+ // don't attempt to offer a rotten corpse
+ pop_delay();
+
+ // Chain onto the next delay.
+ handle_delay();
+ return;
+ }
+
delay.parm2 = 99; // don't give the message twice
if (you.is_undead != US_UNDEAD
@@ -697,6 +742,16 @@ void handle_delay( void )
mitm[ delay.parm1 ].plus2++;
}
}
+ else if (delay.type == DELAY_OFFER_CORPSE)
+ {
+ mprf("Corpse %d no longer valid!", delay.parm1);
+ // don't attempt to offer an invalid item
+ pop_delay();
+
+ // Chain onto the next delay.
+ handle_delay();
+ return;
+ }
else
{
// corpse is no longer valid! End the butchering normally
@@ -704,8 +759,14 @@ void handle_delay( void )
// back to their main weapon if necessary.
delay.duration = 0;
}
+
+ if (delay.type == DELAY_OFFER_CORPSE && !you.duration[DUR_PRAYER]
+ && do_autopray())
+ {
+ return;
+ }
}
- if ( delay.type == DELAY_MULTIDROP )
+ else if (delay.type == DELAY_MULTIDROP)
{
// Throw away invalid items; items usually go invalid because
// of chunks rotting away.
@@ -713,7 +774,9 @@ void handle_delay( void )
// Don't look for gold in inventory
&& items_for_multidrop[0].slot != PROMPT_GOT_SPECIAL
&& !is_valid_item(you.inv[ items_for_multidrop[0].slot ]))
+ {
items_for_multidrop.erase( items_for_multidrop.begin() );
+ }
if ( items_for_multidrop.empty() )
{
@@ -722,10 +785,8 @@ void handle_delay( void )
return;
}
}
-
- if ( delay.type == DELAY_RECITE)
+ else if (delay.type == DELAY_RECITE)
{
-
if (check_recital_audience() < 1 // maybe you've lost your audience
|| Options.hp_warning && you.hp*Options.hp_warning <= you.hp_max
&& delay.parm2*Options.hp_warning > you.hp_max
@@ -796,7 +857,7 @@ void handle_delay( void )
mpr("This corpse has started to rot.", MSGCH_ROTTEN_MEAT);
xom_check_corpse_waste();
stop_delay();
- break;
+ return;
}
mprf(MSGCH_MULTITURN_ACTION, "You continue drinking.");
vampire_nutrition_per_turn(corpse, 0);
@@ -990,17 +1051,22 @@ static void finish_delay(const delay_queue_item &delay)
}
else
{
- mprf("You finish %s the corpse into pieces.",
+ mprf("You finish %s the %s into pieces.",
(you.has_usable_claws()
- || player_mutation_level(MUT_FANGS) == 3) ?
- "ripping" : "chopping");
+ || player_mutation_level(MUT_FANGS) == 3) ? "ripping"
+ : "chopping",
+ mitm[delay.parm1].name(DESC_PLAIN).c_str());
if (is_good_god(you.religion) && is_player_same_species(item.plus))
+ {
simple_god_message(" expects more respect for your departed "
"relatives.");
+ }
else if (you.religion == GOD_ZIN && mons_intel(item.plus) >= I_NORMAL)
+ {
simple_god_message(" expects more respect for this departed "
"soul.");
+ }
if (you.species == SP_VAMPIRE && you.experience_level < 6
&& mons_has_blood(item.plus)
@@ -1029,6 +1095,17 @@ static void finish_delay(const delay_queue_item &delay)
break;
}
+ case DELAY_OFFER_CORPSE:
+ {
+ if (!you.duration[DUR_PRAYER] && !do_autopray())
+ {
+ stop_delay();
+ return;
+ }
+
+ offer_corpse(delay.parm1);
+ break;
+ }
case DELAY_DROP_ITEM:
// Note: checking if item is droppable is assumed to
// be done before setting up this delay... this includes
@@ -1639,9 +1716,10 @@ activity_interrupt_type get_activity_interrupt(const std::string &name)
static const char *delay_names[] =
{
"not_delayed", "eat", "vampire_feed", "armour_on", "armour_off",
- "jewellery_on", "memorise", "butcher", "weapon_swap", "passwall",
- "drop_item", "multidrop", "ascending_stairs", "descending_stairs", "recite",
- "run", "rest", "travel", "macro", "interruptible", "uninterruptible",
+ "jewellery_on", "memorise", "butcher", "offer_corpse", "weapon_swap",
+ "passwall", "drop_item", "multidrop", "ascending_stairs",
+ "descending_stairs", "recite", "run", "rest", "travel", "macro",
+ "interruptible", "uninterruptible"
};
// Gets a delay given its name.
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 7abdfa5d21..107ccceaae 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -708,6 +708,7 @@ enum delay_type
DELAY_JEWELLERY_ON,
DELAY_MEMORISE,
DELAY_BUTCHER,
+ DELAY_OFFER_CORPSE,
DELAY_WEAPON_SWAP, // for easy_butcher
DELAY_PASSWALL,
DELAY_DROP_ITEM,
diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc
index be6770421d..108d823b7b 100644
--- a/crawl-ref/source/food.cc
+++ b/crawl-ref/source/food.cc
@@ -55,14 +55,14 @@
#include "tutorial.h"
#include "xom.h"
-static int _determine_chunk_effect(int which_chunk_type, bool rotten_chunk);
-static void _eat_chunk( int chunk_effect, bool cannibal, int mon_intel = 0);
-static void _eating(unsigned char item_class, int item_type);
-static void _describe_food_change(int hunger_increment);
-static bool _food_change(bool suppress_message);
-static bool _vampire_consume_corpse(int slot, bool invent);
-static void _heal_from_food(int hp_amt, int mp_amt, bool unrot,
- bool restore_str);
+static int _determine_chunk_effect(int which_chunk_type, bool rotten_chunk);
+static void _eat_chunk( int chunk_effect, bool cannibal, int mon_intel = 0);
+static void _eating(unsigned char item_class, int item_type);
+static void _describe_food_change(int hunger_increment);
+static bool _food_change(bool suppress_message);
+static bool _vampire_consume_corpse(int slot, bool invent);
+static void _heal_from_food(int hp_amt, int mp_amt, bool unrot,
+ bool restore_str);
/*
**************************************************
@@ -178,10 +178,15 @@ static bool _find_butchering_implement( bool fallback )
mprf(MSGCH_WARN,
"You're wielding a weapon of distortion, will not autoswap "
"for butchering.");
- return false;
+ return (false);
}
+ // no switching necessary
+ if (can_cut_meat( *wpn ))
+ return (false);
}
+ int old_weapon = you.equip[EQ_WEAPON];
+
// look for a butchering implement in your pack
for (int i = 0; i < ENDOFPACK; ++i)
{
@@ -201,70 +206,168 @@ static bool _find_butchering_implement( bool fallback )
}
}
- if ( !fallback )
+ if (!fallback)
return false;
// if we didn't swap above, then we still can't cut...let's call
// wield_weapon() in the "prompt the user" way...
// prompt for new weapon
- int old_weapon = you.equip[EQ_WEAPON];
- mpr( "What would you like to use?", MSGCH_PROMPT );
+ mpr("What would you like to use?", MSGCH_PROMPT);
wield_weapon( false );
// let's see if the user did something...
return (you.equip[EQ_WEAPON] != old_weapon);
}
-bool butchery(int which_corpse)
+static bool _prepare_butchery(bool can_butcher, bool barehand_butcher,
+ bool wpn_switch, bool removed_gloves,
+ bool new_cursed)
{
- bool new_cursed = false;
- int old_weapon = you.equip[EQ_WEAPON];
- int old_gloves = you.equip[EQ_GLOVES];
+ // No preparation necessary.
+ if (can_butcher)
+ return (true);
- const transformation_type transform =
- static_cast<transformation_type>(you.attribute[ATTR_TRANSFORMATION]);
+ // We don't want auto-switching.
+ if (!Options.easy_butcher)
+ return (false);
- // Xom probably likes this, occasionally
- // Vampires' fangs are optimised for biting, not for tearing flesh.
- // Other species with this mutation still might benefit from this.
- bool teeth_butcher = (player_mutation_level(MUT_FANGS) == 3
- && you.species != SP_VAMPIRE);
+ // If you can butcher by taking off your gloves, don't prompt.
+ if (removed_gloves)
+ {
+ // Actually take off the gloves; this creates a
+ // delay. We assume later on that gloves have a 1-turn
+ // takeoff delay!
+ takeoff_armour(you.equip[EQ_GLOVES]);
+ barehand_butcher = true;
+ }
- bool barehand_butcher = (transform_can_butcher_barehanded(transform)
- || you.has_claws()) && you.equip[EQ_GLOVES] == -1;
+ // note that if barehanded then the user selected '-' when
+ // switching weapons
+ if (!barehand_butcher && (!wpn_switch
+ || you.weapon() == NULL
+ || !can_cut_meat(*you.weapon())))
+ {
+ // still can't butcher. Early out
+ if ( you.weapon() == NULL )
+ {
+ if (you.equip[EQ_GLOVES] == -1)
+ mpr("What, with your bare hands?");
+ else
+ mpr("Your gloves aren't that sharp!");
+ }
+ else
+ mpr("Maybe you should try using a sharper implement.");
- bool gloved_butcher = you.has_claws() && (you.equip[EQ_GLOVES] != -1
- && !item_cursed(you.inv[you.equip[EQ_GLOVES]]));
+ // Switch back to old weapon.
+ if (!new_cursed && wpn_switch)
+ start_delay( DELAY_WEAPON_SWAP, 1, you.equip[EQ_WEAPON] );
- bool can_butcher = teeth_butcher || barehand_butcher
- || you.equip[EQ_WEAPON] != -1
- && can_cut_meat(you.inv[you.equip[EQ_WEAPON]]);
+ return (false);
+ }
+ you.turn_is_over = true;
+ // switched to a good butchering tool
+ return (true);
+}
+
+static bool _butcher_corpse(int corpse_id)
+{
+ ASSERT(corpse_id != -1);
+
+ const bool rotten = food_is_rotten(mitm[corpse_id]);
+ const bool can_sac = you.duration[DUR_PRAYER]
+ && god_likes_butchery(you.religion);
+
+ if (can_sac && !rotten)
+ {
+ start_delay(DELAY_OFFER_CORPSE, 1, corpse_id);
+ }
+ else
+ {
+ if (can_sac && rotten)
+ {
+ simple_god_message(coinflip() ? " refuses to accept that"
+ " mouldy sacrifice!"
+ : " demands fresh blood!",
+ you.religion);
+ }
+
+ // If we didn't switch weapons, we get in one turn of butchery;
+ // otherwise the work has to happen in the delay.
+// if (!wpn_switch && !removed_gloves)
+// ++mitm[corpse_id].plus2;
+
+ int work_req = 4 - mitm[corpse_id].plus2;
+ if (work_req < 0)
+ work_req = 0;
+
+ start_delay(DELAY_BUTCHER, work_req, corpse_id,
+ mitm[corpse_id].special);
+ }
+
+ you.turn_is_over = true;
+ return true;
+}
+
+static void _terminate_butchery(bool wpn_switch, bool removed_gloves,
+ bool new_cursed, int old_weapon, int old_gloves)
+{
+ // switch weapon back
+ if (!new_cursed && wpn_switch)
+ start_delay( DELAY_WEAPON_SWAP, 1, old_weapon );
+
+ // put on the removed gloves
+ if (removed_gloves)
+ start_delay( DELAY_ARMOUR_ON, 1, old_gloves );
+
+ you.turn_is_over = true;
+}
+
+bool butchery(int which_corpse)
+{
if (igrd[you.x_pos][you.y_pos] == NON_ITEM)
{
mpr("There isn't anything here!");
return (false);
}
- if (!Options.easy_butcher && !can_butcher)
+ if (you.flight_mode() == FL_LEVITATE)
{
- mpr("Maybe you should try using a sharper implement.");
+ mpr("You can't reach the floor from up here.");
return (false);
}
- if (you.flight_mode() == FL_LEVITATE)
+ const transformation_type transform =
+ static_cast<transformation_type>(you.attribute[ATTR_TRANSFORMATION]);
+
+ // Vampires' fangs are optimised for biting, not for tearing flesh.
+ // Other species with this mutation still might benefit from this.
+ bool teeth_butcher = (player_mutation_level(MUT_FANGS) == 3
+ && you.species != SP_VAMPIRE);
+
+ bool barehand_butcher = (transform_can_butcher_barehanded(transform)
+ || you.has_claws()) && you.equip[EQ_GLOVES] == -1;
+
+ bool gloved_butcher = (you.has_claws() && you.equip[EQ_GLOVES] != -1
+ && !item_cursed(you.inv[you.equip[EQ_GLOVES]]));
+
+ bool can_butcher = teeth_butcher || barehand_butcher
+ || you.equip[EQ_WEAPON] != -1
+ && can_cut_meat(you.inv[you.equip[EQ_WEAPON]]);
+
+ if (!Options.easy_butcher && !can_butcher)
{
- mpr("You can't reach the floor from up here.");
+ mpr("Maybe you should try using a sharper implement.");
return (false);
}
// It makes more sense that you first find out if there's anything
// to butcher, *then* decide to actually butcher it.
// The old code did it the other way.
- if ( !can_butcher && you.duration[DUR_BERSERKER] )
+ if (!can_butcher && you.duration[DUR_BERSERKER])
{
- mpr ("You are too berserk to search for a butchering tool!");
+ mpr("You are too berserk to search for a butchering tool!");
return (false);
}
@@ -274,8 +377,8 @@ bool butchery(int which_corpse)
bool prechosen = (which_corpse != -1);
for (int o = igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link)
{
- if (mitm[o].base_type == OBJ_CORPSES &&
- mitm[o].sub_type == CORPSE_BODY)
+ if (mitm[o].base_type == OBJ_CORPSES
+ && mitm[o].sub_type == CORPSE_BODY)
{
corpse_id = o;
num_corpses++;
@@ -285,165 +388,127 @@ bool butchery(int which_corpse)
break;
}
}
- // pre-chosen corpse not found?
- if (prechosen && corpse_id != which_corpse)
- prechosen = false;
-
- bool canceled_butcher = false;
- // Now pick what you want to butcher. This is only a problem
- // if there are several corpses on the square.
- if ( num_corpses == 0 )
+ if (num_corpses == 0)
{
mprf("There isn't anything to %s here.",
you.species == SP_VAMPIRE && you.experience_level > 5 ? "bottle"
- : "butcher");
- return false;
+ : "butcher");
+ return (false);
}
- else if ( !prechosen
- && (num_corpses > 1 || Options.always_confirm_butcher) )
+
+ int old_weapon = you.equip[EQ_WEAPON];
+ int old_gloves = you.equip[EQ_GLOVES];
+
+ bool wpn_switch = false;
+ bool removed_gloves = false;
+ bool new_cursed = false;
+
+ if (!can_butcher)
{
- corpse_id = -1;
- for (int o=igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link)
- {
- if ( (mitm[o].base_type != OBJ_CORPSES) ||
- (mitm[o].sub_type != CORPSE_BODY) )
- continue;
+ // Try to find a butchering implement.
+ wpn_switch = _find_butchering_implement(!gloved_butcher);
+ removed_gloves = gloved_butcher && !wpn_switch;
- // offer the possibility of butchering
- snprintf(info, INFO_SIZE, "%s %s?",
- can_bottle_blood_from_corpse(mitm[o].plus)? "Bottle" : "Butcher",
- mitm[o].name(DESC_NOCAP_A).c_str());
+ if (wpn_switch)
+ {
+ new_cursed = ( you.weapon() != NULL
+ && you.weapon()->base_type == OBJ_WEAPONS
+ && item_cursed(*you.weapon()) );
+ }
+ }
- const int result = yesnoquit(info, true, 'N', false, false, 'C', 'D');
- if ( result == -1 )
- {
- canceled_butcher = true;
- corpse_id = -1;
- break;
- }
- else if ( result == 1 )
- {
- corpse_id = o;
- break;
- }
- // continue loop for 0
+ // Butcher pre-chosen corpse, if found, or if there is only one corpse.
+ bool success = false;
+ if (prechosen && corpse_id == which_corpse
+ || num_corpses == 1 && !Options.always_confirm_butcher)
+ {
+ if (!_prepare_butchery(can_butcher, barehand_butcher, wpn_switch,
+ removed_gloves, new_cursed))
+ {
+ return (false);
}
+ success = _butcher_corpse(corpse_id);
+ _terminate_butchery(wpn_switch, removed_gloves, new_cursed,
+ old_weapon, old_gloves);
+
+ return success;
}
- // Do the actual butchery, if we found a good corpse.
- if ( corpse_id != -1 )
+ // Now pick what you want to butcher. This is only a problem
+ // if there are several corpses on the square.
+ bool butcher_all = false;
+ for (int o = igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link)
{
- const bool can_sac = you.duration[DUR_PRAYER]
- && god_likes_butchery(you.religion);
- bool removed_gloves = false;
- bool wpn_switch = false;
+ if (mitm[o].base_type != OBJ_CORPSES
+ || mitm[o].sub_type != CORPSE_BODY)
+ {
+ continue;
+ }
- if ( Options.easy_butcher && !can_butcher )
+ if (butcher_all)
+ corpse_id = o;
+ else
{
- // Try to find a butchering implement.
- // If you can butcher by taking off your gloves, don't prompt.
- wpn_switch = _find_butchering_implement(!gloved_butcher);
- removed_gloves = gloved_butcher && !wpn_switch;
- if ( removed_gloves )
+ corpse_id = -1;
+
+ // Shall we butcher this corpse?
+ snprintf(info, INFO_SIZE, "%s %s?",
+ can_bottle_blood_from_corpse(mitm[o].plus) ? "Bottle"
+ : "Butcher",
+ mitm[o].name(DESC_NOCAP_A).c_str());
+
+ const int result = yesnoquit(info, true, 'N', true, false,
+ 'C', 'D');
+
+ if (result == -1) // (q)uit
{
- // Actually take off the gloves; this creates a
- // delay. We assume later on that gloves have a 1-turn
- // takeoff delay!
- takeoff_armour(old_gloves);
- barehand_butcher = true;
+ canned_msg(MSG_OK);
+ _terminate_butchery(wpn_switch, removed_gloves, new_cursed,
+ old_weapon, old_gloves);
+ return (false);
}
- if ( wpn_switch )
+ else if (result == 0) // (n)o
{
- new_cursed =
- (you.weapon() != NULL) &&
- (you.weapon()->base_type == OBJ_WEAPONS) &&
- item_cursed( *you.weapon() );
+ continue;
}
-
- // note that if barehanded then the user selected '-' when
- // switching weapons
-
- if (!barehand_butcher && (!wpn_switch ||
- you.weapon() == NULL ||
- !can_cut_meat(*you.weapon())))
+ else if (result == 1 || result == 2) // (y)es, (a)ll
{
- // still can't butcher. Early out
- if ( you.weapon() == NULL )
+ if (!_prepare_butchery(can_butcher, barehand_butcher,
+ wpn_switch, removed_gloves, new_cursed))
{
- if (you.equip[EQ_GLOVES] == -1)
- mpr("What, with your bare hands?");
- else
- mpr("Your gloves aren't that sharp!");
+ return (false);
}
- else
- mpr("Maybe you should try using a sharper implement.");
-
- if ( !new_cursed && wpn_switch )
- start_delay( DELAY_WEAPON_SWAP, 1, old_weapon );
+ corpse_id = o;
- return false;
+ if (result == 2) // (a)ll
+ butcher_all = true;
}
-
- // switched to a good butchering knife
- can_butcher = true;
}
- if ( can_butcher )
+ if (corpse_id != -1)
{
- const bool rotten = food_is_rotten(mitm[corpse_id]);
- if (can_sac && !rotten)
- offer_corpse(corpse_id);
- else
- {
- if (can_sac && rotten)
- {
- simple_god_message(coinflip() ?
- " refuses to accept that mouldy "
- "sacrifice!" :
- " demands fresh blood!", you.religion);
- }
+ if (_butcher_corpse(corpse_id))
+ success = true;
- // If we didn't switch weapons, we get in one turn of butchery;
- // otherwise the work has to happen in the delay.
- if (!wpn_switch && !removed_gloves)
- ++mitm[corpse_id].plus2;
-
- int work_req = 4 - mitm[corpse_id].plus2;
- if (work_req < 0)
- work_req = 0;
-
- start_delay(DELAY_BUTCHER, work_req, corpse_id,
- mitm[corpse_id].special);
-
- if (you.duration[DUR_PRAYER]
- && god_hates_butchery(you.religion))
- {
- did_god_conduct(DID_DEDICATED_BUTCHERY, 10);
- }
- }
+ if (!butcher_all)
+ break;
}
-
- // switch weapon back
- if (!new_cursed && wpn_switch)
- start_delay( DELAY_WEAPON_SWAP, 1, old_weapon );
-
- // put on the removed gloves
- if ( removed_gloves )
- start_delay( DELAY_ARMOUR_ON, 1, old_gloves );
-
- you.turn_is_over = true;
- return true;
}
- if (canceled_butcher)
- canned_msg(MSG_OK);
- else
+ if (!butcher_all && corpse_id == -1)
+ {
mprf("There isn't anything else to %s here.",
- you.species == SP_VAMPIRE && you.experience_level >= 6 ?
- "bottle" : "butcher");
+ you.species == SP_VAMPIRE && you.experience_level >= 6 ?
+ "bottle" : "butcher");
+ }
+ else
+ {
+ _terminate_butchery(wpn_switch, removed_gloves, new_cursed,
+ old_weapon, old_gloves);
+ }
- return false;
+ return success;
} // end butchery()
void lua_push_items(lua_State *ls, int link)
@@ -694,16 +759,20 @@ static bool _food_change(bool suppress_message)
msg += "feel devoid of blood!";
else
msg += "are starving!";
+ mpr(msg.c_str(), MSGCH_FOOD, less_hungry);
learned_something_new(TUT_YOU_STARVING);
you.check_awaken(500);
break;
+
case HS_NEAR_STARVING:
if (you.species == SP_VAMPIRE)
msg += "feel almost devoid of blood!";
else
msg += "are near starving!";
+ mpr(msg.c_str(), MSGCH_FOOD, less_hungry);
learned_something_new(TUT_YOU_HUNGRY);
break;
+
case HS_VERY_HUNGRY:
case HS_HUNGRY:
msg += "are feeling ";
@@ -711,12 +780,13 @@ static bool _food_change(bool suppress_message)
msg += "very ";
msg += _how_hungry();
msg += ".";
+ mpr(msg.c_str(), MSGCH_FOOD, less_hungry);
learned_something_new(TUT_YOU_HUNGRY);
break;
+
default:
return (state_changed);
}
- mpr(msg.c_str(), MSGCH_FOOD, less_hungry);
}
}
@@ -864,7 +934,9 @@ int eat_from_floor()
<< ' ' << ((item.quantity > 1) ? "one of " : "")
<< item.name(DESC_NOCAP_A) << '?';
- const int ans = yesnoquit( prompt.str().c_str(), true, 0, false, 'E' );
+ const int ans = yesnoquit( prompt.str().c_str(), true, 0, false, false,
+ 'E' );
+
if ( ans == -1 ) // quit
return -1;
else if ( ans == 1 ) // yes
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index d2e44d7d14..7e168db497 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -493,6 +493,7 @@ void game_options::set_default_activity_interrupts()
"interrupt_recite = teleport",
"interrupt_uninterruptible =",
"interrupt_weapon_swap =",
+ "interrupt_offer_corpse = interrupt_butcher, hungry",
NULL
};
diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc
index 92c46482ac..c9be50c2ed 100644
--- a/crawl-ref/source/stuff.cc
+++ b/crawl-ref/source/stuff.cc
@@ -979,11 +979,14 @@ static std::string _list_alternative_yes(char yes1, char yes2,
}
static const char* _list_allowed_keys(char yes1, char yes2,
- bool lowered = false)
+ bool lowered = false,
+ bool allow_all = false)
{
std::string result = " [";
result += (lowered ? "y" : "Y");
result += _list_alternative_yes(yes1, yes2, lowered);
+ if (allow_all)
+ result += (lowered? "/a" : "/A");
result += (lowered ? "/n/q" : "/N/Q");
result += "]";
@@ -1000,7 +1003,7 @@ int yesnoquit( const char* str, bool safe, int safeanswer, bool allow_all,
std::string prompt = make_stringf("%s%s ", str ? str : "Buggy prompt?",
_list_allowed_keys(alt_yes, alt_yes2,
- safe));
+ safe, allow_all));
while (true)
{
diff --git a/crawl-ref/source/tutorial.cc b/crawl-ref/source/tutorial.cc
index c7765e2412..f2480f9445 100644
--- a/crawl-ref/source/tutorial.cc
+++ b/crawl-ref/source/tutorial.cc
@@ -857,7 +857,7 @@ void tutorial_healing_reminder()
learned_something_new(TUT_NEED_POISON_HEALING);
}
else if (Options.tut_seen_invisible > 0
- && you.num_turns < Options.tut_seen_invisible - 20)
+ && you.num_turns < Options.tut_seen_invisible + 20)
{
// If we recently encountered an invisible monster, we need a
// special message.