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
UET576SVCGS2TXEDRTO7BUTOTLJ77MYHIVZJCDWGH2BAXYMKG6DAC
LSAVA5BJQO4Z2MYXVQOM4AOXTCLKDNQMOS3DZ4SDNO4LI422LA3AC
RQR4PTMGQLTRWLYRU3KXIIDGND7FBORESJWMWFVD3WYU5SISZXAAC
HMC247EGUJ3Q25DQ3VKUCIGLIO4SZORFQQWAPAF6S2WLQY3WU5TQC
NA4FODOSLO724T7EKFP5SNYHVOHGLGSBGL3LFYHVT54JUUTDGU7QC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
VOXLOCDUHOAFIKRTSISYMOA2QFY3TSHQGR7BKGGQ2VZ5BUUKUQYAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
JJULXW764V5C2HJKZNWQAEWB6QM5YZADD7ZCE35LYTBFEM6PMYCAC
YV5KGOLCV7DBD6P4ARYQDLVO4AAH7NDJPF6PNASLQSRAKJRVO4YAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
GKA3ZGZ2P6F22FDNSYNQDMCS3N7HNZD5QCOSQ6VJRAU2K5U4YYTQC
JCWJWGMQIKQGSSFJUQRKNIWW3HBOJSHYDTOPPE5BWOJTIJTDYUTAC
ARVJY7XPMCHI4IAQMD2VUWTAXQLCRNVSM2MK3YT4S4WHQYFTLEMAC
YOZHWGKGPWZGHQYNMMBHNGDO2UEVIHPOR6UF3SEZPIYWVMBGWBOAC
UVJBHQ5KGUIEFRHKTYQPKSXYDUDKTRAXINUXGJJJ6QGNCR6JO7ZAC
4EZVKDQA5GM3QDTNTCKEKGH4F6LGAYNLBT756PXODKZ2B7C4ZVHAC
PUFMMCAH4X5Z25VMUNTWJLRG4NSUGNK45WY4I7NJ2GQXBGBK6SAAC
P2ZCF3BBG523ZEOD6XQA4X5YEHBTWH3IM33YVHXP2SQ5POXZIH4QC
Q3XHNSHW6FI4JCXSEABATRFBJPMCF7PXNG2K6ZQTRRPVMIZFHUBQC
3ZWALZFSTSIVYXY4BAY6ANGINTDACZC6RSSJTEMQSTSUIE66YOBQC
RM2JXW3ATVYRYHF3NMG5ALGI64OJ7IP2F3MDUDPUT5TBKSSN4KVQC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
5R4WV4H5SNIM5WU2X33JJ63HIEGKCXN2HELZ6FRRKKANPLMRLF3QC
ZMED4SUEZTGX762DHBTMAZYNJZDV7RFFKMELFSTCM4KZFX553H5AC
MBBPLL4SZUB3JUUYQYLZW7S5OXRCEGJX3WWADOQXGHWQ7BIKCY5QC
7Q4H6B62UZACQOUDHCHPMPBYEBXM5GVQINIHVHM4KLRENSH6VGTAC
VXWHZPSSJAOUIBJVCYGYOHILZFVDDVKUY5JMFFCQSYCXL3NAZIKAC
5TG5LXU4DX65KMWCZ7YJHOB3VAETQAVBUHEUSQTPMA327XV2HQWAC
ACDPN464TK2LKLHSDN3YVRHAPF7WLSLLU3UHIYEXKFDEZPEU3XSQC
O2GH2BHUL4XXIIJSMKNV2NIC4KQACE6HLMUL4KEUDFNFEAGMZSZAC
74LQ7JXVLAFSHLI7LCBKFX47CNTYSKGUQSXNX5FCIUIGCC2JTR3QC
MMND435BVG6KUGRUEMSHBQX27FRASBK5HJ6OSKLPON2LOG63L75QC
DLVXY6DBP65B3RGWW4PNBEBPBNHNM3LSRYD36F3XDARFY7SPSJYAC
264FLET5STFALEWUDOEFCR273Y5CY2WZDHL56WHZUAQ635RUN6MAC
2WVP47RBNL5OVYMAZH7TKRYD7F2TGSZ5X74PWVGAYCQP26G3JUHQC
5S3CAGZSAQC3CYFPM5TQFPHW5IE2OZRVFJMICQZXHBZRGKFMNPRQC
ARORC5GJNHLAPL2MJ3PUYIAR55ETDDAPXYSYH4OBMXHADNWSGYPAC
QGVAXJZXG2HUCLELWAN6LJJOBSP2BS6TIZMPJTDOAGI2E2SUCOCQC
NJYEH3GBN6OXEMHKOTHVJNIPHXIVW3ZFCLIHYV7I5NFNJZACOYEQC
L6YPJVODN32IYLEZQQZE2ENH3XDAZ63IQIDX3PB4CJEK3A4NUNSAC
PSLBTBSCSC65MRX6TEGGFNKPXLP4OE2FZYGMM6VRJTBXTTGMP5UQC
CY63M5CMG4LYSCOK6QPRLFJEWCB3OMULUZBZCCJDJ6VGPOYDHZ6AC
5HBRQ2QZTFBQE2Z2CFADUI2D52LO5Z5CNHXHA7BJP3LGO7FJPUCQC
BBQWA33DPXWEDYOOPO45VAYD4JQDZQVMZSEJ4RUI5LLC733IMIIQC
GZ4FB5VKL4C22KK3GSKQPLJYMRGLFXUDCOBNEBC2OKK6KVZL3OSQC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
MLZSEZWNNZMSIDQNAAIOJJR4K7VSVJICL5SAGHD3ROM7SYDVZABAC
23PFLB2E4QHL5SF3Q2YV5FXRH6MFHENEU2ACVC572ZCYDXCBZVQAC
6GSGCC5JQJ5NOKX36UHRNOCXNHDBS2A2TDMAR34UBOGWE2DORXIQC
SGR2P5BGJIJHVSSQYQHWS4ORLVHQBZTDES3D4BFC6SVAQXSKENNQC
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);
bool butchery(int which_corpse)
static bool _prepare_butchery(bool can_butcher, bool barehand_butcher,
bool wpn_switch, bool removed_gloves,
bool new_cursed)
{
// No preparation necessary.
if (can_butcher)
return (true);
// We don't want auto-switching.
if (!Options.easy_butcher)
return (false);
// 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;
}
// 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.");
// Switch back to old weapon.
if (!new_cursed && wpn_switch)
start_delay( DELAY_WEAPON_SWAP, 1, 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)
bool new_cursed = false;
int old_weapon = you.equip[EQ_WEAPON];
int old_gloves = you.equip[EQ_GLOVES];
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;
// 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);
start_delay(DELAY_BUTCHER, work_req, corpse_id,
mitm[corpse_id].special);
}
you.turn_is_over = true;
return true;
}
bool barehand_butcher = (transform_can_butcher_barehanded(transform)
|| you.has_claws()) && you.equip[EQ_GLOVES] == -1;
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 );
if (you.flight_mode() == FL_LEVITATE)
// 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)
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)
corpse_id = -1;
for (int o=igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link)
// Try to find a butchering implement.
wpn_switch = _find_butchering_implement(!gloved_butcher);
removed_gloves = gloved_butcher && !wpn_switch;
if (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());
// 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);
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
}
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;
}
// 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);
// 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
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 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;
if (_butcher_corpse(corpse_id))
success = true;
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;
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);
}
(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);
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);
}
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;
}
// 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)
|| player_mutation_level(MUT_FANGS) == 3) ?
"ripping" : "chopping");
|| player_mutation_level(MUT_FANGS) == 3) ? "ripping"
: "chopping",
mitm[delay.parm1].name(DESC_PLAIN).c_str());
"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"