diff options
Diffstat (limited to 'crawl-ref/source')
-rw-r--r-- | crawl-ref/source/debug.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/delay.cc | 108 | ||||
-rw-r--r-- | crawl-ref/source/delay.h | 13 | ||||
-rw-r--r-- | crawl-ref/source/describe.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/effects.cc | 13 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/food.cc | 394 | ||||
-rw-r--r-- | crawl-ref/source/food.h | 5 | ||||
-rw-r--r-- | crawl-ref/source/initfile.cc | 1 | ||||
-rw-r--r-- | crawl-ref/source/item_use.cc | 13 | ||||
-rw-r--r-- | crawl-ref/source/itemprop.cc | 10 | ||||
-rw-r--r-- | crawl-ref/source/itemprop.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/items.cc | 23 | ||||
-rw-r--r-- | crawl-ref/source/libgui.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/makeitem.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/misc.cc | 34 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 8 | ||||
-rw-r--r-- | crawl-ref/source/religion.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/spells3.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/spells4.cc | 6 |
20 files changed, 372 insertions, 279 deletions
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 0aa7ca040b..25c355d1be 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -1245,11 +1245,8 @@ void create_spec_object() case OBJ_POTIONS: mitm[thing_created].quantity = 12; - if (mitm[thing_created].sub_type == POT_BLOOD - || mitm[thing_created].sub_type == POT_BLOOD_COAGULATED) - { + if (is_blood_potion(mitm[thing_created])) init_stack_blood_potions(mitm[thing_created]); - } break; case OBJ_FOOD: diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc index 9b168c5a62..18227db3f8 100644 --- a/crawl-ref/source/delay.cc +++ b/crawl-ref/source/delay.cc @@ -312,9 +312,9 @@ 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 + && 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; @@ -408,6 +408,33 @@ void stop_delay( bool stop_stair_travel ) // this to be stoppable, with partial food items implemented. -- bwr break; + case DELAY_FEED_VAMPIRE: + { + mpr( "You stop draining the corpse." ); + + item_def &corpse = (delay.parm1 ? you.inv[delay.parm2] + : mitm[delay.parm2]); + + if (!mons_skeleton( corpse.plus )) + { + if (delay.parm1) + dec_inv_item_quantity( delay.parm2, 1 ); + else + dec_mitm_item_quantity( delay.parm2, 1 ); + } + else + { + mpr("All blood oozes out of the corpse!"); + bleed_onto_floor(you.x_pos, you.y_pos, corpse.plus, delay.duration, + false); + corpse.sub_type = CORPSE_SKELETON; + corpse.special = 90; + corpse.colour = LIGHTGREY; + } + did_god_conduct(DID_DRINK_BLOOD, 8); + pop_delay(); + break; + } case DELAY_ARMOUR_ON: case DELAY_ARMOUR_OFF: // These two have the default action of not being interruptible, @@ -484,6 +511,15 @@ bool is_being_butchered(const item_def &item) return (false); } +bool is_vampire_feeding() +{ + if (!you_are_delayed()) + return (false); + + const delay_queue_item &delay = you.delay_queue.front(); + return (delay.type == DELAY_FEED_VAMPIRE); +} + // check whether there are monsters who might be influenced by Recite // return 0, if no monsters found // return 1, if eligible audience found @@ -576,6 +612,13 @@ void handle_delay( void ) if (apply_area_visible(recite_to_monsters, delay.parm1)) viewwindow(true, false); break; + case DELAY_FEED_VAMPIRE: + { + item_def &corpse = (delay.parm1 ? you.inv[delay.parm2] + : mitm[delay.parm2]); + vampire_nutrition_per_turn(corpse, -1); + break; + } default: break; } @@ -740,9 +783,22 @@ void handle_delay( void ) items_for_multidrop.erase( items_for_multidrop.begin() ); break; case DELAY_EAT: - mprf(MSGCH_MULTITURN_ACTION, "You continue %sing.", - you.species == SP_VAMPIRE ? "drink" : "eat"); + mpr("You continue eating.", MSGCH_MULTITURN_ACTION); + break; + case DELAY_FEED_VAMPIRE: + { + item_def &corpse = (delay.parm1 ? you.inv[delay.parm2] + : mitm[delay.parm2]); + if (food_is_rotten(corpse)) + { + mpr("This corpse has started to rot.", MSGCH_ROTTEN_MEAT); + stop_delay(); + break; + } + mprf(MSGCH_MULTITURN_ACTION, "You continue drinking."); + vampire_nutrition_per_turn(corpse, 0); break; + } default: break; } @@ -822,14 +878,37 @@ static void finish_delay(const delay_queue_item &delay) break; } case DELAY_EAT: - mprf("You finish %sing.", - you.species == SP_VAMPIRE ? "drink" : "eat"); + mprf("You finish eating."); // For chunks, warn the player if they're not getting much // nutrition. if (delay.parm1) chunk_nutrition_message(delay.parm1); break; + case DELAY_FEED_VAMPIRE: + { + mprf("You finish drinking."); + did_god_conduct(DID_DRINK_BLOOD, 8); + + item_def &corpse = (delay.parm1 ? you.inv[delay.parm2] + : mitm[delay.parm2]); + vampire_nutrition_per_turn(corpse, 1); + + if (!mons_skeleton( corpse.plus )) + { + if (delay.parm1) + dec_inv_item_quantity( delay.parm2, 1 ); + else + dec_mitm_item_quantity( delay.parm2, 1 ); + } + else if (!one_chance_in(4)) + { + corpse.sub_type = CORPSE_SKELETON; + corpse.special = 90; + corpse.colour = LIGHTGREY; + } + break; + } case DELAY_MEMORISE: mpr( "You finish memorising." ); add_spell_to_memory( static_cast<spell_type>( delay.parm1 ) ); @@ -1325,10 +1404,11 @@ static int userdef_interrupt_activity( const delay_queue_item &idelay, return (true); } - if (delay == DELAY_MACRO && - clua.callbooleanfn(true, "c_interrupt_macro", - "sA", interrupt_name, &at)) + if (delay == DELAY_MACRO && clua.callbooleanfn(true, "c_interrupt_macro", + "sA", interrupt_name, &at)) + { return (true); + } #endif return (false); @@ -1346,8 +1426,8 @@ static bool should_stop_activity(const delay_queue_item &item, if (userd) return (userd == 1); - return (ai == AI_FORCE_INTERRUPT || - (Options.activity_interrupts[item.type][ai])); + return (ai == AI_FORCE_INTERRUPT + || Options.activity_interrupts[item.type][ai]); } inline static void monster_warning(activity_interrupt_type ai, @@ -1547,8 +1627,8 @@ activity_interrupt_type get_activity_interrupt(const std::string &name) static const char *delay_names[] = { - "not_delayed", "eat", "armour_on", "armour_off", "jewellery_on", - "memorise", "butcher", "weapon_swap", "passwall", + "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", }; diff --git a/crawl-ref/source/delay.h b/crawl-ref/source/delay.h index 7c00e1bd5f..44df52435c 100644 --- a/crawl-ref/source/delay.h +++ b/crawl-ref/source/delay.h @@ -1,7 +1,7 @@ /* * File: delay.h * Summary: Functions for handling multi-turn actions. - * + * * Modified for Crawl Reference by $Author$ on $Date$ * * Change History (most recent first): @@ -44,7 +44,7 @@ struct activity_interrupt_data : apt(AIP_STRING), data(s), context() { } - activity_interrupt_data(const std::string &s) + activity_interrupt_data(const std::string &s) : apt(AIP_STRING), data(s.c_str()), context() { } @@ -72,13 +72,14 @@ struct ait_hp_loss void start_delay( delay_type type, int turns, int parm1 = 0, int parm2 = 0 ); void stop_delay( bool stop_stair_travel = false ); -bool you_are_delayed( void ); -delay_type current_delay_action( void ); +bool you_are_delayed( void ); +delay_type current_delay_action( void ); int check_recital_audience( void ); void handle_delay( void ); bool is_run_delay(int delay); bool is_being_butchered(const item_def &item); +bool is_vampire_feeding( void ); void stop_butcher_delay(); const char *activity_interrupt_name(activity_interrupt_type ai); @@ -88,8 +89,8 @@ const char *delay_name(int delay); delay_type get_delay(const std::string &); void perform_activity(); -bool interrupt_activity( activity_interrupt_type ai, - const activity_interrupt_data &a +bool interrupt_activity( activity_interrupt_type ai, + const activity_interrupt_data &a = activity_interrupt_data() ); #endif diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index 1820735b53..efc3a0eeb3 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -1699,8 +1699,7 @@ std::string get_item_description( const item_def &item, bool verbose, case OBJ_POTIONS: #ifdef DEBUG_BLOOD_POTIONS // list content of timer vector for blood potions - if (item.sub_type == POT_BLOOD - || item.sub_type == POT_BLOOD_COAGULATED) + if (is_blood_potion(item)) { item_def stack = static_cast<item_def>(item); CrawlHashTable &props = stack.props; diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index e55da931e8..e5cf28d11c 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -1632,12 +1632,8 @@ bool acquirement(object_class_type class_wanted, int agent, else if (quant > 1) thing.quantity = quant; - if (thing.base_type == OBJ_POTIONS - && (thing.sub_type == POT_BLOOD - || thing.sub_type == POT_BLOOD_COAGULATED)) - { + if (is_blood_potion(thing)) init_stack_blood_potions(thing); - } // remove curse flag from item do_uncurse_item( thing ); @@ -2288,15 +2284,10 @@ static bool food_item_needs_time_check(item_def &item) } if (item.base_type == OBJ_FOOD && item.sub_type != FOOD_CHUNK) - { return false; - } - if (item.base_type == OBJ_POTIONS && item.sub_type != POT_BLOOD - && item.sub_type != POT_BLOOD_COAGULATED) - { + if (item.base_type == OBJ_POTIONS && !is_blood_potion(item)) return false; - } return true; } diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index aa28986432..b73aca2c8e 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -699,6 +699,7 @@ enum delay_type { DELAY_NOT_DELAYED, DELAY_EAT, + DELAY_FEED_VAMPIRE, DELAY_ARMOUR_ON, DELAY_ARMOUR_OFF, DELAY_JEWELLERY_ON, diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index 48d2eefd65..77b99b3569 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -55,15 +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 mons_type, int mass, - int chunk_type, bool rotten); -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); /* ************************************************** @@ -91,10 +90,10 @@ void make_hungry( int hunger_amount, bool suppress_msg ) you.hunger = 0; // so we don't get two messages, ever. - bool state_message = food_change(false); + bool state_message = _food_change(false); if (!suppress_msg && !state_message) - describe_food_change( -hunger_amount ); + _describe_food_change( -hunger_amount ); } // end make_hungry() void lessen_hunger( int satiated_amount, bool suppress_msg ) @@ -108,10 +107,10 @@ void lessen_hunger( int satiated_amount, bool suppress_msg ) you.hunger = 12000; // so we don't get two messages, ever - bool state_message = food_change(false); + bool state_message = _food_change(false); if (!suppress_msg && !state_message) - describe_food_change(satiated_amount); + _describe_food_change(satiated_amount); } // end lessen_hunger() void set_hunger( int new_hunger_level, bool suppress_msg ) @@ -163,7 +162,7 @@ void weapon_switch( int targ ) // look for a butchering implement. If fallback is true, // prompt the user if no obvious options exist. // Returns whether a weapon was switched. -static bool find_butchering_implement( bool fallback ) +static bool _find_butchering_implement( bool fallback ) { // If wielding a distortion weapon, never attempt to switch away // automatically. @@ -341,7 +340,7 @@ bool butchery(int which_corpse) { // 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); + wpn_switch = _find_butchering_implement(!gloved_butcher); removed_gloves = gloved_butcher && !wpn_switch; if ( removed_gloves ) { @@ -476,7 +475,7 @@ void lua_push_inv_items(lua_State *ls = NULL) } } -static bool userdef_eat_food() +static bool _userdef_eat_food() { #ifdef CLUA_BINDINGS lua_push_floor_items(clua.state()); @@ -579,7 +578,7 @@ bool eat_food(bool run_hook, int slot) // If user hook ran, we don't know whether something // was eaten or not... - if (run_hook && userdef_eat_food()) + if (run_hook && _userdef_eat_food()) return (false); if (igrd[you.x_pos][you.y_pos] != NON_ITEM && slot == -1) @@ -601,7 +600,7 @@ bool eat_food(bool run_hook, int slot) * * ************************************************** */ -static std::string how_hungry() +static std::string _how_hungry() { if (you.hunger_state > HS_SATIATED) return ("full"); @@ -610,7 +609,7 @@ static std::string how_hungry() return ("hungry"); } -static bool food_change(bool suppress_message) +static bool _food_change(bool suppress_message) { char newstate = HS_ENGORGED; bool state_changed = false; @@ -672,6 +671,13 @@ static bool food_change(bool suppress_message) "much longer.", MSGCH_WARN); // give more time because suddenly stopping flying can be lethal you.duration[DUR_TRANSFORMATION] = 5; + if (is_vampire_feeding()) + stop_delay(); + } + if (newstate == HS_ENGORGED && is_vampire_feeding()) // Alive + { + mpr("You can't stomach any more blood right now."); + stop_delay(); } } @@ -700,7 +706,7 @@ static bool food_change(bool suppress_message) msg += "are feeling "; if (you.hunger_state == HS_VERY_HUNGRY) msg += "very "; - msg += how_hungry(); + msg += _how_hungry(); msg += "."; learned_something_new(TUT_YOU_HUNGRY); break; @@ -715,7 +721,7 @@ static bool food_change(bool suppress_message) } // end food_change() // food_increment is positive for eating, negative for hungering -static void describe_food_change(int food_increment) +static void _describe_food_change(int food_increment) { int magnitude = (food_increment > 0)?food_increment:(-food_increment); std::string msg; @@ -737,7 +743,7 @@ static void describe_food_change(int food_increment) else msg += "less "; - msg += how_hungry().c_str(); + msg += _how_hungry().c_str(); msg += "."; mpr(msg.c_str()); } // end describe_food_change() @@ -759,28 +765,7 @@ void eat_from_inventory(int which_inventory_slot) item_def& food(you.inv[which_inventory_slot]); if (food.base_type == OBJ_CORPSES && food.sub_type == CORPSE_BODY) { - if (you.species != SP_VAMPIRE) - return; - - const int mons_type = food.plus; - const bool rotten = food_is_rotten(food); - const int chunk_type - = determine_chunk_effect(mons_corpse_effect( mons_type ), rotten); - const int mass = mons_weight(food.plus)/150; - - if (!vampire_consume_corpse(mons_type, mass, chunk_type, rotten)) - return; - - if (!mons_skeleton( mons_type ) || one_chance_in(4)) - { - dec_inv_item_quantity( which_inventory_slot, 1 ); - } - else - { - food.sub_type = CORPSE_SKELETON; - food.special = 90; - food.colour = LIGHTGREY; - } + _vampire_consume_corpse(which_inventory_slot, true); return; } else if (food.sub_type == FOOD_CHUNK) @@ -794,10 +779,11 @@ void eat_from_inventory(int which_inventory_slot) if (rotten && !_player_can_eat_rotten_meat(true)) return; - eat_chunk(determine_chunk_effect(chunk_type, rotten), cannibal, intel); + _eat_chunk(_determine_chunk_effect(chunk_type, rotten), cannibal, + intel); } else - eating( food.base_type, food.sub_type ); + _eating( food.base_type, food.sub_type ); dec_inv_item_quantity( which_inventory_slot, 1 ); } // end eat_from_inventory() @@ -807,28 +793,12 @@ void eat_floor_item(int item_link) item_def& food(mitm[item_link]); if (food.base_type == OBJ_CORPSES && food.sub_type == CORPSE_BODY) { - const int mons_type = food.plus; - const bool rotten = food_is_rotten(food); - const int chunk_type - = determine_chunk_effect(mons_corpse_effect( mons_type ), rotten); - const int mass = mons_weight(food.plus)/150; - - if (!vampire_consume_corpse(mons_type, mass, chunk_type, rotten)) + if (you.species != SP_VAMPIRE) return; - if (!mons_skeleton( mons_type ) || one_chance_in(4)) - { - dec_mitm_item_quantity( item_link, 1 ); - } - else - { - food.sub_type = CORPSE_SKELETON; - food.special = 90; - food.colour = LIGHTGREY; - } - // dec_mitm_item_quantity( item_link, 1 ); + if (_vampire_consume_corpse(item_link, false)) + you.turn_is_over = true; - you.turn_is_over = 1; return; } else if (food.sub_type == FOOD_CHUNK) @@ -841,10 +811,11 @@ void eat_floor_item(int item_link) if (rotten && !_player_can_eat_rotten_meat(true)) return; - eat_chunk(determine_chunk_effect(chunk_type, rotten), cannibal, intel); + _eat_chunk(_determine_chunk_effect(chunk_type, rotten), cannibal, + intel); } else - eating( food.base_type, food.sub_type ); + _eating( food.base_type, food.sub_type ); you.turn_is_over = true; @@ -925,7 +896,7 @@ int eat_from_floor() return (false); } -static const char *chunk_flavour_phrase(bool likes_chunks) +static const char *_chunk_flavour_phrase(bool likes_chunks) { const char *phrase = likes_chunks? "tastes great." : "tastes terrible."; @@ -957,7 +928,7 @@ void chunk_nutrition_message(int nutrition) mpr("That was not very filling."); } -static int apply_herbivore_chunk_effects(int nutrition) +static int _apply_herbivore_chunk_effects(int nutrition) { int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); @@ -967,14 +938,14 @@ static int apply_herbivore_chunk_effects(int nutrition) return (nutrition); } -static int chunk_nutrition(bool likes_chunks) +static int _chunk_nutrition(bool likes_chunks) { int nutrition = CHUNK_BASE_NUTRITION; if (likes_chunks || you.hunger_state < HS_SATIATED) { - return (likes_chunks? nutrition - : apply_herbivore_chunk_effects(nutrition)); + return (likes_chunks ? nutrition + : _apply_herbivore_chunk_effects(nutrition)); } const int gourmand = @@ -994,22 +965,22 @@ static int chunk_nutrition(bool likes_chunks) epercent); #endif - return (apply_herbivore_chunk_effects(effective_nutrition)); + return (_apply_herbivore_chunk_effects(effective_nutrition)); } -static void say_chunk_flavour(bool likes_chunks) +static void _say_chunk_flavour(bool likes_chunks) { - mprf("This raw flesh %s", chunk_flavour_phrase(likes_chunks)); + mprf("This raw flesh %s", _chunk_flavour_phrase(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, int mon_intel ) +// through food::_determine_chunk_effect() first {dlb}: +static void _eat_chunk( int chunk_effect, bool cannibal, int mon_intel ) { bool likes_chunks = (you.omnivorous() || player_mutation_level(MUT_CARNIVOROUS)); - int nutrition = chunk_nutrition(likes_chunks); + 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; @@ -1057,7 +1028,7 @@ static void eat_chunk( int chunk_effect, bool cannibal, int mon_intel ) (chunk_effect == CE_ROTTEN) ? "rotting " : ""); if (you.species == SP_GHOUL) - heal_from_food(hp_amt, 0, !one_chance_in(4), one_chance_in(5)); + _heal_from_food(hp_amt, 0, !one_chance_in(4), one_chance_in(5)); do_eat = true; } @@ -1076,11 +1047,13 @@ static void eat_chunk( int chunk_effect, bool cannibal, int mon_intel ) 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); + { + _heal_from_food((!one_chance_in(5)? hp_amt : 0), 0, + !one_chance_in(3), false); + } } else - say_chunk_flavour(likes_chunks); + _say_chunk_flavour(likes_chunks); do_eat = true; break; @@ -1101,7 +1074,7 @@ static void eat_chunk( int chunk_effect, bool cannibal, int mon_intel ) return; } // end eat_chunk() -static void eating(unsigned char item_class, int item_type) +static void _eating(unsigned char item_class, int item_type) { int temp_rand; // probability determination {dlb} int food_value = 0; @@ -1363,6 +1336,142 @@ static void eating(unsigned char item_class, int item_type) return; } // end eating() +// Divide full nutrition by duration, so that each turn you get the same +// amount of nutrition. Also, experimentally regenerate 1 hp per feeding turn +// - this is likely too strong. +// feeding is -1 at start, 1 when finishing, and 0 else +void vampire_nutrition_per_turn(const item_def &corpse, int feeding) +{ + const int mons_type = corpse.plus; + const int chunk_type = _determine_chunk_effect( + mons_corpse_effect(mons_type), false); + + // This is the exact formula of corpse nutrition for chunk lovers + const int max_chunks = mons_weight(mons_type)/150; + int chunk_amount = 1 + max_chunks/2; + chunk_amount = stepdown_value( chunk_amount, 4, 4, 12, 12 ); + + int food_value = CHUNK_BASE_NUTRITION; +// int mass = CHUNK_BASE_NUTRITION * chunk_amount; + const int duration = 1 + chunk_amount/2; + bool start_feeding = false; + bool during_feeding = false; + bool end_feeding = false; + + if (feeding < 0) + start_feeding = true; + else if (feeding > 0) + end_feeding = true; + else + during_feeding = true; + + switch (mons_type) + { + case MONS_HUMAN: + { + food_value += random2avg((you.experience_level * 10)/duration, 2); + int hp_amt = 1 + you.experience_level/2; + + + if (!end_feeding) + { + if (start_feeding) + mpr("This warm blood tastes really delicious!"); + + // Human blood gives extra healing during feeding. + if (hp_amt >= duration) + hp_amt /= duration; + else if (random2(duration) < hp_amt) + hp_amt = 1; + + _heal_from_food(hp_amt, 0, one_chance_in(duration/2), + one_chance_in(duration)); + } + else + { + // Give the remainder of healing at the end. + if (hp_amt > duration) + { + _heal_from_food(hp_amt % duration, 0, + one_chance_in(duration/2), + one_chance_in(duration)); + } + } + break; + } + case MONS_ELF: + { + food_value += random2avg((you.experience_level * 10)/duration, 2); + + if (end_feeding) + { + // Elven blood gives mana at the end of feeding. + const int mp_amt = 1 + random2(3); + _heal_from_food(1, mp_amt, one_chance_in(duration/2), + one_chance_in(duration)); + } + else if (start_feeding) + mpr("This warm blood tastes magically delicious!"); + break; + } + default: + switch (chunk_type) + { + case CE_CLEAN: + if (start_feeding) + mpr("This warm blood tastes delicious!"); + else if (end_feeding) + _heal_from_food(1, 0, one_chance_in(duration), false); + break; + case CE_CONTAMINATED: + food_value = CHUNK_BASE_NUTRITION/2; + if (start_feeding) + mpr("Somehow this blood was not very filling!"); + else if (end_feeding) + _heal_from_food(1, 0, one_chance_in(duration), false); + break; + case CE_POISONOUS: + make_hungry(CHUNK_BASE_NUTRITION/2, false); + // Always print this message - maybe you lost poison res. + // due to feeding. + mpr("Blech - this blood tastes nasty!"); + if (poison_player( 1 + random2(3) )) + xom_is_stimulated(random2(128)); + stop_delay(); + return; + case CE_MUTAGEN_RANDOM: + food_value = CHUNK_BASE_NUTRITION/2; + if (start_feeding) + mpr("This blood tastes really weird!"); + mutate(RANDOM_MUTATION); + did_god_conduct( DID_DELIBERATE_MUTATING, 10); + xom_is_stimulated(100); + if (end_feeding) + _heal_from_food(1, 0, false, false); + break; + case CE_MUTAGEN_BAD: + food_value = CHUNK_BASE_NUTRITION/2; + if (start_feeding) + mpr("This blood tastes *really* weird."); + give_bad_mutation(); + did_god_conduct( DID_DELIBERATE_MUTATING, 10); + xom_is_stimulated(random2(200)); + if (end_feeding) + _heal_from_food(1, 0, false, false); + break; + case CE_HCL: + rot_player( 5 + random2(5) ); + if (disease_player( 50 + random2(100) )) + xom_is_stimulated(random2(100)); + stop_delay(); + break; + } + } + + if (!end_feeding) + lessen_hunger(food_value / duration, !start_feeding); +} + bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid, bool check_hunger) { @@ -1553,7 +1662,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid, // see if you can follow along here -- except for the Amulet of the Gourmand // addition (long missing and requested), what follows is an expansion of how // chunks were handled in the codebase up to this date ... {dlb} -static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk) +static int _determine_chunk_effect(int which_chunk_type, bool rotten_chunk) { int this_chunk_effect = which_chunk_type; @@ -1657,110 +1766,43 @@ static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk) return (this_chunk_effect); } // end determine_chunk_effect() -static bool vampire_consume_corpse(const int mons_type, const int max_chunks, - const int chunk_type, const bool rotten) +static bool _vampire_consume_corpse(const int slot, bool invent) { - if (!mons_has_blood(mons_type)) + ASSERT(you.species == SP_VAMPIRE); + + item_def &corpse = (invent ? you.inv[slot] + : mitm[slot]); + + ASSERT(corpse.base_type == OBJ_CORPSES); + ASSERT(corpse.sub_type == CORPSE_BODY); + + if (!mons_has_blood(corpse.plus)) { mpr( "There is no blood in this body!" ); return false; } - // This is the exact formula of corpse nutrition for chunk lovers - int chunk_amount = 1 + random2(max_chunks); - chunk_amount = stepdown_value( chunk_amount, 4, 4, 12, 12 ); - int mass = CHUNK_BASE_NUTRITION * chunk_amount; - - int food_value = 0, hp_amt = 0, mp_amt = 0; - - if (rotten) + if (food_is_rotten(corpse)) { - if (wearing_amulet(AMU_THE_GOURMAND)) - { - food_value = mass/2 + random2(you.experience_level * 5); - mpr("Slurp."); - did_god_conduct(DID_DRINK_BLOOD, 8); - } - else - { - mpr("It's not fresh enough."); - return false; - } - } - else - { - hp_amt++; - - switch (mons_type) - { - case MONS_HUMAN: - food_value = mass + random2avg(you.experience_level * 10, 2); - mpr( "This warm blood tastes really delicious!" ); - hp_amt += 1 + random2(1 + you.experience_level); - break; - - case MONS_ELF: - food_value = mass + random2avg(you.experience_level * 10, 2); - mpr( "This warm blood tastes magically delicious!" ); - mp_amt += 1 + random2(3); - break; - - default: - switch (chunk_type) - { - case CE_CLEAN: - food_value = mass; - mpr( "This warm blood tastes delicious!" ); - break; - case CE_CONTAMINATED: - food_value = mass / (random2(3) + 1); - mpr( "Somehow this blood was not very filling!" ); - break; - case CE_POISONOUS: - food_value = -random2(mass/2); - mpr( "Blech - this blood tastes nasty!" ); - if (poison_player( 3 + random2(4) )) - xom_is_stimulated(random2(128)); - break; - case CE_MUTAGEN_RANDOM: - food_value = random2(mass); - mpr( "This blood tastes really weird!" ); - mutate(RANDOM_MUTATION); - did_god_conduct( DID_DELIBERATE_MUTATING, 10); - xom_is_stimulated(100); - break; - case CE_MUTAGEN_BAD: - food_value = random2(mass/2); - mpr("This blood tastes *really* weird."); - give_bad_mutation(); - did_god_conduct( DID_DELIBERATE_MUTATING, 10); - 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; - } - } - did_god_conduct(DID_DRINK_BLOOD, 8); + mpr("It's not fresh enough."); + return false; } - heal_from_food(hp_amt, mp_amt, - !rotten && one_chance_in(4), one_chance_in(3)); - - lessen_hunger( food_value, true ); - describe_food_change(food_value); - // The delay for eating a chunk (mass 1000) is 2 // Here the base nutrition value equals that of chunks, - // but the delay should be greater. - start_delay( DELAY_EAT, mass / 400 ); + // but the delay should be smaller. + const int max_chunks = mons_weight(corpse.plus)/150; + int chunk_amount = 1 + max_chunks/2; + chunk_amount = stepdown_value( chunk_amount, 4, 4, 12, 12 ); + + start_delay( DELAY_FEED_VAMPIRE, 1 + chunk_amount/2, + (int) invent, slot ); + return true; -} // end vampire_consume_corpse() +} -static void heal_from_food(int hp_amt, int mp_amt, bool unrot, - bool restore_str) +static void _heal_from_food(int hp_amt, int mp_amt, bool unrot, + bool restore_str) { if (hp_amt > 0) inc_hp(hp_amt, false); @@ -1779,7 +1821,7 @@ static void heal_from_food(int hp_amt, int mp_amt, bool unrot, calc_hp(); calc_mp(); -} // end heal_from_food() +} int you_max_hunger() { diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h index e925531f28..7887258d44 100644 --- a/crawl-ref/source/food.h +++ b/crawl-ref/source/food.h @@ -83,7 +83,7 @@ void set_hunger(int new_hunger_level, bool suppress_msg); * *********************************************************************** */ void weapon_switch( int targ ); -bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, +bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid = false, bool check_hunger = true); void eat_floor_item(int item_link); @@ -96,6 +96,9 @@ bool prompt_eat_from_inventory(int slot = -1); void chunk_nutrition_message(int nutrition); +void vampire_nutrition_per_turn(const item_def &corpse, + int feeding = 0); + int you_max_hunger(); int you_min_hunger(); diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index 58df77173b..bf37c491d2 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -477,6 +477,7 @@ void game_options::set_default_activity_interrupts() "interrupt_jewellery_on = interrupt_armour_on", "interrupt_memorise = interrupt_armour_on, stat", "interrupt_butcher = interrupt_armour_on, teleport, stat", + "interrupt_vampire_feed = interrupt_butcher", "interrupt_passwall = interrupt_butcher", "interrupt_multidrop = interrupt_butcher", "interrupt_macro = interrupt_multidrop", diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index 2bb7f66607..a6c10853d4 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -3505,11 +3505,19 @@ void drink( int slot ) const bool alreadyknown = item_type_known(you.inv[item_slot]); + if (you.hunger_state == HS_ENGORGED && alreadyknown + && (is_blood_potion(you.inv[item_slot]) + || you.inv[item_slot].sub_type == POT_PORRIDGE)) + { + mpr("You are much too full right now."); + return; + } + // The "> 1" part is to reduce the amount of times that Xom is // stimulated when you are a low-level 1 trying your first unknown // potions on monsters. const bool dangerous = - player_in_a_dangerous_place() && (you.experience_level > 1); + (player_in_a_dangerous_place() && you.experience_level > 1); if (potion_effect(static_cast<potion_type>(you.inv[item_slot].sub_type), 40, alreadyknown)) @@ -3531,8 +3539,7 @@ void drink( int slot ) xom_is_stimulated(255); } - if (you.inv[item_slot].sub_type == POT_BLOOD - || you.inv[item_slot].sub_type == POT_BLOOD_COAGULATED) + if (is_blood_potion(you.inv[item_slot])) { // always drink oldest potion remove_oldest_blood_potion(you.inv[item_slot]); diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc index 27c2bfe7b2..4108fb0738 100644 --- a/crawl-ref/source/itemprop.cc +++ b/crawl-ref/source/itemprop.cc @@ -28,6 +28,7 @@ #include "food.h" #include "items.h" #include "itemprop.h" +#include "it_use2.h" #include "macro.h" #include "mon-util.h" #include "notes.h" @@ -2156,6 +2157,15 @@ bool food_is_veg( const item_def &item ) return (Food_prop[ Food_index[item.sub_type] ].herb_mod > 0); } +bool is_blood_potion( const item_def &item) +{ + if (item.base_type != OBJ_POTIONS) + return false; + + return (item.sub_type == POT_BLOOD + || item.sub_type == POT_BLOOD_COAGULATED); +} + // returns food value for one turn of eating int food_value( const item_def &item ) { diff --git a/crawl-ref/source/itemprop.h b/crawl-ref/source/itemprop.h index 4d09609ce1..d24246a64d 100644 --- a/crawl-ref/source/itemprop.h +++ b/crawl-ref/source/itemprop.h @@ -710,6 +710,7 @@ int ring_has_pluses( const item_def &item ); // food functions: bool food_is_meat( const item_def &item ); bool food_is_veg( const item_def &item ); +bool is_blood_potion( const item_def &item ); int food_value( const item_def &item ); int food_turns( const item_def &item ); bool can_cut_meat( const item_def &item ); diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index 66823ea7c1..be4702016d 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -1533,12 +1533,9 @@ int move_item_to_player( int obj, int quant_got, bool quiet ) you.inv[m].inscription = mitm[obj].inscription; } - if (mitm[obj].base_type == OBJ_POTIONS - && (mitm[obj].sub_type == POT_BLOOD - || mitm[obj].sub_type == POT_BLOOD_COAGULATED)) - { + if (is_blood_potion(mitm[obj])) pick_up_blood_potions_stack(mitm[obj], quant_got); - } + inc_inv_item_quantity( m, quant_got ); dec_mitm_item_quantity( obj, quant_got ); burden_change(); @@ -1592,9 +1589,7 @@ int move_item_to_player( int obj, int quant_got, bool quiet ) check_note_item(item); item.quantity = quant_got; - if (mitm[obj].base_type == OBJ_POTIONS - && (mitm[obj].sub_type == POT_BLOOD - || mitm[obj].sub_type == POT_BLOOD_COAGULATED)) + if (is_blood_potion(mitm[obj])) { if (quant_got != mitm[obj].quantity) { @@ -1759,9 +1754,7 @@ bool copy_item_to_grid( const item_def &item, int x_plos, int y_plos, { inc_mitm_item_quantity( i, quant_drop ); - if (item.base_type == OBJ_POTIONS - && (item.sub_type == POT_BLOOD - || item.sub_type == POT_BLOOD_COAGULATED)) + if (is_blood_potion(item)) { item_def help = item; drop_blood_potions_stack(help, quant_drop, x_plos, y_plos); @@ -1799,9 +1792,7 @@ bool copy_item_to_grid( const item_def &item, int x_plos, int y_plos, } move_item_to_grid( &new_item, x_plos, y_plos ); - if (item.base_type == OBJ_POTIONS - && (item.sub_type == POT_BLOOD - || item.sub_type == POT_BLOOD_COAGULATED) + if (is_blood_potion(item) && item.quantity != quant_drop) // partial drop only { // since only the oldest potions have been dropped, @@ -1923,9 +1914,7 @@ bool drop_item( int item_dropped, int quant_drop, bool try_offer ) else if (strstr(you.inv[item_dropped].inscription.c_str(), "=s") != 0) StashTrack.add_stash(); - if (you.inv[item_dropped].base_type == OBJ_POTIONS - && (you.inv[item_dropped].sub_type == POT_BLOOD - || you.inv[item_dropped].sub_type == POT_BLOOD_COAGULATED) + if (is_blood_potion(you.inv[item_dropped]) && you.inv[item_dropped].quantity != quant_drop) { // oldest potions have been dropped diff --git a/crawl-ref/source/libgui.cc b/crawl-ref/source/libgui.cc index c1c6a7ce6c..517e14f059 100644 --- a/crawl-ref/source/libgui.cc +++ b/crawl-ref/source/libgui.cc @@ -1474,9 +1474,7 @@ static int _handle_mouse_motion(int mouse_x, int mouse_y, bool init) if (wielded) desc += EOL "[Ctrl-L-Click] Unwield"; else if ( item_type_known(item) - && (item.sub_type == POT_BLOOD - || item.sub_type - == POT_BLOOD_COAGULATED) + && is_blood_potion(item) && player_knows_spell( SPELL_SUBLIMATION_OF_BLOOD) ) { diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc index 0ccdd227c6..bf0a595bb2 100644 --- a/crawl-ref/source/makeitem.cc +++ b/crawl-ref/source/makeitem.cc @@ -2361,7 +2361,7 @@ static void _generate_potion_item(item_def& item, int force_type, item.sub_type = stype; } - if (item.sub_type == POT_BLOOD || item.sub_type == POT_BLOOD_COAGULATED) + if (is_blood_potion(item)) init_stack_blood_potions(item); } diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 18316ca38f..0c1dd4faa9 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -164,9 +164,7 @@ void turn_corpse_into_chunks( item_def &item ) // initialize blood potions with a vector of timers void init_stack_blood_potions(item_def &stack, int age) { - ASSERT(stack.base_type == OBJ_POTIONS); - ASSERT(stack.sub_type == POT_BLOOD - || stack.sub_type == POT_BLOOD_COAGULATED); + ASSERT(is_blood_potion(stack)); CrawlHashTable &props = stack.props; props.clear(); // sanity measure @@ -218,10 +216,7 @@ void maybe_coagulate_blood_potions_floor(int obj) { item_def &blood = mitm[obj]; ASSERT(is_valid_item(blood)); - ASSERT(blood.base_type == OBJ_POTIONS); - - ASSERT(blood.sub_type == POT_BLOOD - || blood.sub_type == POT_BLOOD_COAGULATED); + ASSERT(is_blood_potion(blood)); CrawlHashTable &props = blood.props; if (!props.exists("timer")) @@ -420,10 +415,7 @@ static void _potion_stack_changed_message(item_def &potion, int num_changed, bool maybe_coagulate_blood_potions_inv(item_def &blood) { ASSERT(is_valid_item(blood)); - ASSERT(blood.base_type == OBJ_POTIONS); - - ASSERT(blood.sub_type == POT_BLOOD - || blood.sub_type == POT_BLOOD_COAGULATED); + ASSERT(is_blood_potion(blood)); CrawlHashTable &props = blood.props; if (!props.exists("timer")) @@ -728,10 +720,7 @@ bool maybe_coagulate_blood_potions_inv(item_def &blood) long remove_oldest_blood_potion(item_def &stack) { ASSERT(is_valid_item(stack)); - ASSERT(stack.base_type == OBJ_POTIONS); - - ASSERT (stack.sub_type == POT_BLOOD - || stack.sub_type == POT_BLOOD_COAGULATED); + ASSERT(is_blood_potion(stack)); CrawlHashTable &props = stack.props; if (!props.exists("timer")) @@ -751,10 +740,7 @@ long remove_oldest_blood_potion(item_def &stack) void remove_newest_blood_potion(item_def &stack, int quant) { ASSERT(is_valid_item(stack)); - ASSERT(stack.base_type == OBJ_POTIONS); - - ASSERT (stack.sub_type == POT_BLOOD - || stack.sub_type == POT_BLOOD_COAGULATED); + ASSERT(is_blood_potion(stack)); CrawlHashTable &props = stack.props; if (!props.exists("timer")) @@ -794,9 +780,7 @@ void drop_blood_potions_stack(item_def &stack, int quant, int x, int y) return; ASSERT(quant > 0 && quant <= stack.quantity); - ASSERT(stack.base_type == OBJ_POTIONS); - ASSERT(stack.sub_type == POT_BLOOD - || stack.sub_type == POT_BLOOD_COAGULATED); + ASSERT(is_blood_potion(stack)); CrawlHashTable &props = stack.props; if (!props.exists("timer")) @@ -847,9 +831,7 @@ void pick_up_blood_potions_stack(item_def &stack, int quant) if (!is_valid_item(stack)) return; - ASSERT(stack.base_type == OBJ_POTIONS); - ASSERT(stack.sub_type == POT_BLOOD - || stack.sub_type == POT_BLOOD_COAGULATED); + ASSERT(is_blood_potion(stack)); CrawlHashTable &props = stack.props; if (!props.exists("timer")) @@ -966,7 +948,7 @@ void split_potions_into_decay( int obj, int amount, bool need_msg ) you.wield_change = true; you.redraw_quiver = true; - if (potion.sub_type == POT_BLOOD || potion.sub_type == POT_BLOOD_COAGULATED) + if (is_blood_potion(potion)) { // We're being nice here, and only decay the *oldest* potions. for (int i = 0; i < amount; i++) diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 7d73b0cdc4..0d3f6d01bb 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -2663,7 +2663,7 @@ monsters *choose_random_monster_on_level(int weight, chosen = mon; } } - + return chosen; } @@ -3505,12 +3505,8 @@ static bool _handle_potion(monsters *monster, bolt & beem) { if (dec_mitm_item_quantity( monster->inv[MSLOT_POTION], 1 )) monster->inv[MSLOT_POTION] = NON_ITEM; - else if (mitm[monster->inv[MSLOT_POTION]].sub_type == POT_BLOOD - || mitm[monster->inv[MSLOT_POTION]].sub_type - == POT_BLOOD_COAGULATED) - { + else if (is_blood_potion(mitm[monster->inv[MSLOT_POTION]])) remove_oldest_blood_potion(mitm[monster->inv[MSLOT_POTION]]); - } if (ident != ID_UNKNOWN_TYPE && was_visible) set_ident_type(OBJ_POTIONS, potion_type, ident); diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index 3cfa93071e..7ab5ce1ce7 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -2565,8 +2565,7 @@ bool is_evil_item(const item_def& item) retval = (item.sub_type == SCR_TORMENT); break; case OBJ_POTIONS: - retval = (item.sub_type == POT_BLOOD - || item.sub_type == POT_BLOOD_COAGULATED); + retval = is_blood_potion(item); break; case OBJ_BOOKS: retval = (item.sub_type == BOOK_NECROMANCY diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index b5fb8a8bea..36dd8baf38 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -342,9 +342,7 @@ void sublimation(int power) dec_inv_item_quantity( wielded, 1 ); } - else if (you.inv[wielded].base_type == OBJ_POTIONS - && (you.inv[wielded].sub_type == POT_BLOOD - || you.inv[wielded].sub_type == POT_BLOOD_COAGULATED)) + else if (is_blood_potion(you.inv[wielded])) { mprf("The blood within %s frothes and boils.", you.inv[wielded].quantity == 1 ? "the flask you are holding" diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc index 315edf07c4..e2ff3ab3c1 100644 --- a/crawl-ref/source/spells4.cc +++ b/crawl-ref/source/spells4.cc @@ -1662,11 +1662,9 @@ bool cast_evaporate(int pow, bolt& beem, int potion) fire_beam(beem); // both old and new code use up a potion: - if (you.inv[potion].sub_type == POT_BLOOD - || you.inv[potion].sub_type == POT_BLOOD_COAGULATED) - { + if (is_blood_potion(you.inv[potion])) remove_oldest_blood_potion(you.inv[potion]); - } + dec_inv_item_quantity( potion, 1 ); return (true); |