diff options
Diffstat (limited to 'crawl-ref/source/food.cc')
-rw-r--r-- | crawl-ref/source/food.cc | 378 |
1 files changed, 178 insertions, 200 deletions
diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index 63866f3099..1dc360886b 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -14,8 +14,6 @@ #include "AppHdr.h" #include "food.h" -#include <sstream> - #include <string.h> // required for abs() {dlb}: #include <stdlib.h> @@ -48,14 +46,13 @@ #include "religion.h" #include "skills2.h" #include "spells2.h" -#include "state.h" #include "stuff.h" #include "transfor.h" #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 ); +static void eat_chunk( int chunk_effect ); +static void ghoul_consume_flesh(int chunk_type); 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); @@ -194,8 +191,9 @@ static bool find_butchering_implement( bool fallback ) return (you.equip[EQ_WEAPON] != old_weapon); } -bool butchery() +bool butchery(void) { + bool wpn_switch = false; bool new_cursed = false; int old_weapon = you.equip[EQ_WEAPON]; int old_gloves = you.equip[EQ_GLOVES]; @@ -243,59 +241,30 @@ bool butchery() return (false); } - // First determine how many things there are to butcher. - int num_corpses = 0; - int 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) - { - corpse_id = o; - num_corpses++; - } - } - 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 ) + bool found_nonzero_corpses = false; + for (int objl = igrd[you.x_pos][you.y_pos]; objl != NON_ITEM; + objl = mitm[objl].link) { - mpr("There isn't anything to dissect here."); - return false; - } - else if ( num_corpses > 1 || Options.always_confirm_butcher ) - { - corpse_id = -1; - for (int o=igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link) + if ( (mitm[objl].base_type != OBJ_CORPSES) || + (mitm[objl].sub_type != CORPSE_BODY) ) + continue; + + found_nonzero_corpses = true; + + // offer the possibility of butchering + snprintf(info, INFO_SIZE, "Butcher %s?", + mitm[objl].name(DESC_NOCAP_A).c_str()); + const int answer = yesnoquit( info, true, 'n', false ); + if ( answer == -1 ) { - if ( (mitm[o].base_type != OBJ_CORPSES) || - (mitm[o].sub_type != CORPSE_BODY) ) - continue; - - // offer the possibility of butchering - std::string prompt = "Butcher " + mitm[o].name(DESC_NOCAP_A) + '?'; - const int answer = yesnoquit( prompt.c_str(), true, 'n', false ); - if ( answer == 1 ) - { - corpse_id = o; - break; - } - else if ( answer == -1 ) - { - canceled_butcher = true; - corpse_id = -1; - break; - } + canceled_butcher = true; + break; } - } - - // Do the actual butchery, if we found a good corpse. - if ( corpse_id != -1 ) - { + if ( answer == 0 ) + continue; + bool removed_gloves = false; - bool wpn_switch = false; if ( Options.easy_butcher && !can_butcher ) { @@ -348,35 +317,41 @@ bool butchery() if ( can_butcher ) { - bool rotten = (mitm[corpse_id].special < 100); + // we actually butcher now + if ( teeth_butcher || barehand_butcher ) + mpr("You start tearing the corpse apart."); + else + mpr("You start hacking away."); + + bool rotten = (mitm[objl].special < 100); if (you.duration[DUR_PRAYER] && !rotten && god_likes_butchery(you.religion)) { - offer_corpse(corpse_id); - destroy_item(corpse_id); + offer_corpse(objl); + destroy_item(objl); } else { if (you.duration[DUR_PRAYER] && rotten && god_likes_butchery(you.religion) ) { - simple_god_message(coinflip() ? - " refuses to accept that mouldy " - "sacrifice!" : - " demands fresh blood!", you.religion); + if (coinflip()) + simple_god_message(" refuses to accept that mouldy " + "sacrifice!", you.religion); + else + simple_god_message(" 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; + ++mitm[objl].plus2; - int work_req = 4 - mitm[corpse_id].plus2; + int work_req = 4 - mitm[objl].plus2; if (work_req < 0) work_req = 0; - start_delay(DELAY_BUTCHER, work_req, corpse_id, - mitm[corpse_id].special); + start_delay(DELAY_BUTCHER, work_req, objl, mitm[objl].special); if (you.duration[DUR_PRAYER] && god_hates_butchery(you.religion)) @@ -401,8 +376,14 @@ bool butchery() if (canceled_butcher) canned_msg(MSG_OK); else - mpr("There isn't anything else to dissect here."); + mprf("There isn't anything %sto dissect here.", + found_nonzero_corpses? "else " : ""); + if (!new_cursed && wpn_switch) // should never happen + { + weapon_switch( old_weapon ); + } + return false; } // end butchery() @@ -510,31 +491,24 @@ bool eat_food(bool run_hook) if (you.is_undead == US_UNDEAD) { mpr("You can't eat."); - crawl_state.zero_turns_taken(); return (false); } if (you.hunger >= 11000) { mpr("You're too full to eat anything."); - crawl_state.zero_turns_taken(); return (false); } // If user hook ran, we don't know whether something // was eaten or not... if (run_hook && userdef_eat_food()) - { return (false); - } if (igrd[you.x_pos][you.y_pos] != NON_ITEM) { - const int res = eat_from_floor(); - if ( res == 1 ) - return true; - if ( res == -1 ) - return false; + if (eat_from_floor()) + return (true); } return (prompt_eat_from_inventory()); @@ -599,7 +573,6 @@ static bool food_change(bool suppress_message) case HS_STARVING: mpr("You are starving!", MSGCH_FOOD); learned_something_new(TUT_YOU_STARVING); - you.check_awaken(500); break; case HS_HUNGRY: mpr("You are feeling hungry.", MSGCH_FOOD); @@ -652,7 +625,9 @@ static void describe_food_change(int food_increment) static bool prompt_eat_chunk(const item_def &item, bool rotten) { - if (rotten && !you.mutation[MUT_SAPROVOROUS] + if (rotten && you.species != SP_GHOUL && you.species != SP_KOBOLD + && you.species != SP_TROLL && you.species != SP_OGRE + && you.species != SP_HILL_ORC && !yesno("Are you sure you want to eat this rotten meat?", false, 'n')) { @@ -693,14 +668,13 @@ void eat_from_inventory(int which_inventory_slot) // this is a bit easier to read... most compilers should // handle this the same -- bwr const int mons_type = you.inv[ which_inventory_slot ].plus; - const bool cannibal = is_player_same_species(mons_type); const int chunk_type = mons_corpse_effect( mons_type ); const bool rotten = (you.inv[which_inventory_slot].special < 100); if (!prompt_eat_chunk(you.inv[which_inventory_slot], rotten)) return; - eat_chunk( determine_chunk_effect( chunk_type, rotten ), cannibal ); + eat_chunk( determine_chunk_effect( chunk_type, rotten ) ); } else { @@ -742,11 +716,10 @@ void eat_floor_item(int item_link) else if (mitm[item_link].sub_type == FOOD_CHUNK) { const int chunk_type = mons_corpse_effect( mitm[item_link].plus ); - const bool cannibal = is_player_same_species( mitm[item_link].plus ); const bool rotten = (mitm[item_link].special < 100); if (!prompt_eat_chunk(mitm[item_link], rotten)) return; - eat_chunk( determine_chunk_effect( chunk_type, rotten ), cannibal ); + eat_chunk( determine_chunk_effect( chunk_type, rotten ) ); } else { @@ -758,11 +731,10 @@ void eat_floor_item(int item_link) dec_mitm_item_quantity( item_link, 1 ); } -// return -1 for cancel, 1 for eaten, 0 for not eaten -int eat_from_floor() +bool eat_from_floor(void) { if (you.flight_mode() == FL_LEVITATE) - return 0; + return (false); bool need_more = false; for (int o = igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link) @@ -776,21 +748,37 @@ int eat_from_floor() (item.base_type != OBJ_CORPSES || item.sub_type != CORPSE_BODY)) continue; - std::ostringstream prompt; - prompt << (you.species == SP_VAMPIRE ? "Drink blood from" : "Eat") - << ' ' << ((item.quantity > 1) ? "one of " : "") - << item.name(DESC_NOCAP_A) << '?'; - const int ans = yesnoquit( prompt.str().c_str(), true, 0, false ); - if ( ans == -1 ) // quit - return -1; - else if ( ans == 1 ) + mprf( MSGCH_PROMPT, + "%s %s%s?", you.species == SP_VAMPIRE ? "Drink blood from" : "Eat", + (item.quantity > 1) ? "one of " : "", + item.name(DESC_NOCAP_A).c_str() ); + + // If we're prompting now, we don't need a -more- when + // breaking out, because the prompt serves as a -more-. Of + // course, the prompt can re-set need_more to true. + need_more = false; + + unsigned char keyin = tolower( getch() ); + + if (keyin == 0) + { + getch(); + keyin = 0; + } + + if (keyin == 'q') + return (false); + + if (keyin == 'y') { - if (can_ingest(item.base_type, item.sub_type, false)) + if (!can_ingest( item.base_type, item.sub_type, false )) { - eat_floor_item(o); - return 1; + need_more = true; + continue; } - need_more = true; + + eat_floor_item(o); + return (true); } } @@ -879,99 +867,90 @@ static void say_chunk_flavour(bool likes_chunks) // never called directly - chunk_effect values must pass // through food::determine_chunk_effect() first {dlb}: -static void eat_chunk( int chunk_effect, bool cannibal ) +static void eat_chunk( int chunk_effect ) { - bool likes_chunks = (you.omnivorous() || - you.mutation[MUT_CARNIVOROUS]); - int nutrition = chunk_nutrition(likes_chunks); - int hp_amt = 0; - bool suppress_msg = false; // do we display the chunk nutrition message? - bool do_eat = false; + bool likes_chunks = (you.species == SP_OGRE || you.species == SP_TROLL || + you.mutation[MUT_CARNIVOROUS] > 0); if (you.species == SP_GHOUL) { - nutrition = CHUNK_BASE_NUTRITION; - hp_amt = 1 + random2(5) + random2(1 + you.experience_level); - suppress_msg = true; + ghoul_consume_flesh(chunk_effect); + start_delay( DELAY_EAT, 2 ); + lessen_hunger( CHUNK_BASE_NUTRITION, true ); } - - switch (chunk_effect) + else { - case CE_MUTAGEN_RANDOM: - mpr("This meat tastes really weird."); - mutate(RANDOM_MUTATION); - xom_is_stimulated(100); - break; - - case CE_MUTAGEN_BAD: - mpr("This meat tastes *really* weird."); - give_bad_mutation(); - xom_is_stimulated(random2(200)); - break; - - case CE_HCL: - rot_player( 10 + random2(10) ); - if (disease_player( 50 + random2(100) )) - xom_is_stimulated(random2(100)); - break; + switch (chunk_effect) + { + case CE_MUTAGEN_RANDOM: + mpr("This meat tastes really weird."); + mutate(RANDOM_MUTATION); + xom_is_stimulated(100); + break; - case CE_POISONOUS: - mpr("Yeeuch - this meat is poisonous!"); - if (poison_player( 3 + random2(4) )) - xom_is_stimulated(random2(128)); - break; + case CE_MUTAGEN_BAD: + mpr("This meat tastes *really* weird."); + give_bad_mutation(); + xom_is_stimulated(random2(200)); + break; - case CE_ROTTEN: - case CE_CONTAMINATED: - if (you.mutation[MUT_SAPROVOROUS] == 3) - { - mprf("This %sflesh tastes delicious!", - (chunk_effect == CE_ROTTEN) ? "rotting " : ""); + case CE_HCL: + rot_player( 10 + random2(10) ); + if (disease_player( 50 + random2(100) )) + xom_is_stimulated(random2(100)); + break; - if (you.species == SP_GHOUL) - heal_from_food(hp_amt, 0, !one_chance_in(4), - one_chance_in(5)); + case CE_POISONOUS: + mpr("Yeeuch - this meat is poisonous!"); + if (poison_player( 3 + random2(4) )) + xom_is_stimulated(random2(128)); + break; - do_eat = true; - } - else - { + case CE_ROTTEN: + case CE_CONTAMINATED: mpr("There is something wrong with this meat."); if (disease_player( 50 + random2(100) )) xom_is_stimulated(random2(100)); - } - break; + break; - case CE_CLEAN: - { - if (you.mutation[MUT_SAPROVOROUS] == 3) + // note that this is the only case that takes time and forces redraw + case CE_CLEAN: { - mpr("This raw flesh tastes good."); - - if (you.species == SP_GHOUL) - heal_from_food((!one_chance_in(5)) ? hp_amt : 0, 0, - !one_chance_in(3), false); - } - else say_chunk_flavour(likes_chunks); - - do_eat = true; - break; - } + const int nutrition = chunk_nutrition(likes_chunks); + start_delay( DELAY_EAT, 2, nutrition ); + lessen_hunger( nutrition, true ); + break; + } + } } - if (cannibal) - did_god_conduct( DID_CANNIBALISM, 10 ); - - if (do_eat) + return; +} // end eat_chunk() + +static void ghoul_consume_flesh(int chunk_type) +{ + int hp_amt = 1 + random2(5) + random2(1 + you.experience_level); + + if (chunk_type != CE_ROTTEN && chunk_type != CE_CONTAMINATED) { - start_delay( DELAY_EAT, 2, (suppress_msg) ? 0 : nutrition ); - lessen_hunger( nutrition, true ); + mpr("This raw flesh tastes good."); + + heal_from_food((!one_chance_in(5)) ? hp_amt : 0, 0, + !one_chance_in(3), false); } + else + { + if (chunk_type == CE_ROTTEN) + mpr("This rotting flesh tastes delicious!"); + else // CE_CONTAMINATED or CE_HCL + mpr("This flesh tastes delicious!"); - return; -} // end eat_chunk() + heal_from_food(hp_amt, 0, + !one_chance_in(4), one_chance_in(5)); + } +} // end ghoul_consume_flesh() static void eating(unsigned char item_class, int item_type) { @@ -1279,7 +1258,8 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid, bool ur_chunkslover = ( (check_hunger? you.hunger_state <= HS_HUNGRY : true) || wearing_amulet(AMU_THE_GOURMAND, !reqid) - || you.omnivorous() + || you.species == SP_OGRE + || you.species == SP_TROLL || you.mutation[MUT_CARNIVOROUS]); switch (what_isit) @@ -1410,6 +1390,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid, // understood why liches are hungry and not true undead beings ... {dlb}: static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk) { + const int poison_resistance_level = player_res_poison(); int this_chunk_effect = which_chunk_type; // determine the initial effect of eating a particular chunk {dlb}: @@ -1425,36 +1406,36 @@ static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk) break; case CE_POISONOUS: - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH - || player_res_poison() > 0 && you.species != SP_VAMPIRE) + if (you.species == SP_GHOUL + || you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH + || poison_resistance_level > 0 && you.species != SP_VAMPIRE) { this_chunk_effect = CE_CLEAN; } break; case CE_CONTAMINATED: - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH - && you.mutation[MUT_SAPROVOROUS] < 3) - { + if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH) this_chunk_effect = CE_CLEAN; - } else { - switch (you.mutation[MUT_SAPROVOROUS]) + switch (you.species) { - case 1: - if (!one_chance_in(15)) - this_chunk_effect = CE_CLEAN; + case SP_GHOUL: + // Doing this here causes a odd message later. -- bwr + // this_chunk_effect = CE_ROTTEN; break; - case 2: + case SP_KOBOLD: + case SP_TROLL: if (!one_chance_in(45)) this_chunk_effect = CE_CLEAN; break; - case 3: - // Doing this here causes a odd message later. -- bwr - // this_chunk_effect = CE_ROTTEN; + case SP_HILL_ORC: + case SP_OGRE: + if (!one_chance_in(15)) + this_chunk_effect = CE_CLEAN; break; default: @@ -1489,41 +1470,38 @@ static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk) // one last chance for some species to safely eat rotten food {dlb}: if (this_chunk_effect == CE_ROTTEN) { - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH - && you.mutation[MUT_SAPROVOROUS] < 3) - { + if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH) this_chunk_effect = CE_CLEAN; - } else { - switch (you.mutation[MUT_SAPROVOROUS]) + switch (you.species) { - case 1: - if (!one_chance_in(5)) + case SP_KOBOLD: + case SP_TROLL: + if (!one_chance_in(15)) this_chunk_effect = CE_CLEAN; break; - - case 2: - if (!one_chance_in(15)) + case SP_HILL_ORC: + case SP_OGRE: + if (!one_chance_in(5)) this_chunk_effect = CE_CLEAN; break; - default: break; } } } - // The amulet of the gourmand will permit consumption of - // contaminated meat as though it were "clean" meat - level 3 - // saprovores get rotting meat effect from clean chunks, since they - // love rotting meat. + // the amulet of the gourmad will permit consumption of + // contaminated meat as though it were "clean" meat - ghouls get + // rotting meat effect from clean chunks, since they love rotting + // meat. if (wearing_amulet(AMU_THE_GOURMAND) && random2(GOURMAND_MAX) < you.duration[DUR_GOURMAND]) { - if (you.mutation[MUT_SAPROVOROUS] == 3) + if (you.species == SP_GHOUL) { - // [dshaligram] Level 3 saprovores relish contaminated meat. + // [dshaligram] Ghouls relish contaminated meat. if (this_chunk_effect == CE_CLEAN) this_chunk_effect = CE_CONTAMINATED; } @@ -1596,7 +1574,7 @@ static bool vampire_consume_corpse(int mons_type, int mass, else if (wearing_amulet(AMU_THE_GOURMAND)) { food_value = mass/3 + random2(you.experience_level * 5); - mpr("Slurp."); + mpr("Slurps."); did_god_conduct(DID_DRINK_BLOOD, 8); } else |