Anonymous | Login | 2024-04-26 22:06 CEST |
Main | My View | View Issues | Change Log | Wiki | Tavern | News |
Viewing Issue Simple Details [ Jump to Notes ] [ Wiki ] | [ View Advanced ] [ Issue History ] [ Print ] | ||||||
ID | Category | Severity | Reproducibility | Date Submitted | Last Update | ||
0004226 | [DCSS] Implementables | minor | have not tried | 2011-07-06 23:44 | 2011-10-21 03:22 | ||
Reporter | dpeg | View Status | public | ||||
Assigned To | KiloByte | ||||||
Priority | normal | Resolution | done | ||||
Status | closed | Product Branch | 0.10 ancient branch | ||||
Summary | 0004226: Food reform | ||||||
Description |
A request to implement Vintermann's food reform: https://crawl.develz.org/wiki/doku.php?id=dcss:brainstorm:misc:eating#the_proposal [^] That page has a lot of reasoning and explains matters very well. At the bottom is a rather detailed proposal how to go about it. Testing and tweaking will be necessary, but changing the food system like this is a large step in the right direction. |
||||||
Additional Information | |||||||
Tags | No tags attached. | ||||||
Attached Files |
0001-0004226-Food-reform.patch [^] (25,470 bytes) 2011-07-17 08:50 [Show Content] [Hide Content]From e1f038b13534fc4a55c9382e73ee6771e240b01e Mon Sep 17 00:00:00 2001 From: Ryak <ryak2002@hotmail.com> Date: Sun, 17 Jul 2011 01:49:53 -0500 Subject: [PATCH] 0004226: Food reform --- crawl-ref/source/defines.h | 2 +- crawl-ref/source/food.cc | 439 +++++++++++++++++++---------------------- crawl-ref/source/food.h | 3 +- crawl-ref/source/itemname.cc | 3 +- crawl-ref/source/l_food.cc | 3 +- crawl-ref/source/potion.cc | 5 +- crawl-ref/source/travel.cc | 2 +- 7 files changed, 210 insertions(+), 247 deletions(-) diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h index 96bfe29..e29e4fb 100644 --- a/crawl-ref/source/defines.h +++ b/crawl-ref/source/defines.h @@ -182,7 +182,7 @@ const int BASELINE_DELAY = 10; const int GOURMAND_MAX = 200 * BASELINE_DELAY; const int GOURMAND_NUTRITION_BASE = 10 * BASELINE_DELAY; -const int CHUNK_BASE_NUTRITION = 1000; +const int CHUNK_BASE_NUTRITION = 750; const int ICEMAIL_MAX = 10; const int ICEMAIL_TIME = 300 * BASELINE_DELAY; diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index d375745..e40c7d4 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -5,7 +5,7 @@ #include "AppHdr.h" -#include "food.h" + #include <sstream> @@ -52,11 +52,13 @@ #include "travel.h" #include "xom.h" +#include "food.h" + static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, bool rotten_chunk); static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel = 0, bool holy = false); -static void _eating(object_class_type item_class, int item_type); +static void _eat_nonchunk(object_class_type item_class, int item_type); static void _describe_food_change(int hunger_increment); static bool _vampire_consume_corpse(int slot, bool invent); static void _heal_from_food(int hp_amt, int mp_amt = 0, bool unrot = false, @@ -707,6 +709,73 @@ bool eat_food(int slot) // END PUBLIC FUNCTIONS +static int determine_maximum_satiation(int preference) +{ + switch (preference) + { + case -2: return 1533; // near starving + case -1: return 2066; // very hungry + case 0: return 2600; // hungry + case 1: return 7000; // satiated + case 2: return 9000; // full + } + if (preference > 2) + return 11000; // engorged + + return 0; // cannot ever eat +} + +static double determine_satiation_multiplier(int preference) +{ + if (preference <= 0) + return 1 + 0.334 * preference; + else + return 0.8 + 0.2 * preference; +} + +// Returns 1 for herbivores, -1 for carnivores and 0 for either. +static int determine_food_type(int type) +{ + switch (static_cast<food_type>(type)) + { + case FOOD_BREAD_RATION: + case FOOD_PEAR: + case FOOD_APPLE: + case FOOD_CHOKO: + case FOOD_SNOZZCUMBER: + case FOOD_APRICOT: + case FOOD_ORANGE: + case FOOD_BANANA: + case FOOD_STRAWBERRY: + case FOOD_RAMBUTAN: + case FOOD_LEMON: + case FOOD_GRAPE: + case FOOD_SULTANA: + case FOOD_LYCHEE: + return 1; + + case FOOD_CHUNK: + case FOOD_MEAT_RATION: + case FOOD_SAUSAGE: + case FOOD_BEEF_JERKY: + return -1; + + case FOOD_HONEYCOMB: + case FOOD_ROYAL_JELLY: + case FOOD_AMBROSIA: + case FOOD_CHEESE: + case FOOD_PIZZA: + return 0; + + case NUM_FOODS: + mpr("Bad food type", MSGCH_ERROR); + return 0; + } + + mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); + return 0; +} + static bool _player_has_enough_food() { int food_value = 0; @@ -970,7 +1039,7 @@ void eat_inventory_item(int which_inventory_slot) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; dec_inv_item_quantity(which_inventory_slot, 1); @@ -1004,7 +1073,7 @@ void eat_floor_item(int item_link) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; @@ -1060,6 +1129,76 @@ public: } }; +int get_preference_for_food_type(int type, corpse_effect_type effect_type = CE_CLEAN) +{ + int preference = 0; + int saprovorous = player_mutation_level(MUT_SAPROVOROUS); + + // Royal Jelly can always be eaten. It needs a total of +3 to guarentee this + if (static_cast<food_type>(type) == FOOD_ROYAL_JELLY) + preference += 1; + + // permafood gets a +2 bonus + if (static_cast<food_type>(type) != FOOD_CHUNK) + preference += 2; + else + { + // unclean chunks get a penalty (If you are immune to the effect, we will be passed + // clean even if the original chunk wasn't clean [except rotting]) + switch (effect_type) + { + case CE_CLEAN: break; + case CE_CONTAMINATED: + case CE_POISONOUS: + case CE_POISON_CONTAM: + case CE_HCL: + case CE_MUTAGEN_RANDOM: + case CE_MUTAGEN_GOOD: + case CE_MUTAGEN_BAD: preference -= 1; + break; + case CE_ROTTEN: if (saprovorous == 0) + preference -= 2; + else if (saprovorous == 1 || saprovorous == 2) + preference -= 1; + break; + case CE_NOCORPSE: + case CE_RANDOM: + break; + } + } + + int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); + int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); + int food_type = determine_food_type(type); + + // bonus/penalty of your mutation level for matching/conflicting food type + preference += how_herbivorous * food_type; + preference -= how_carnivorous * food_type; + + // gourmand - (only affects chunks) + if (wearing_amulet(AMU_THE_GOURMAND), true) + { + if (you.duration[DUR_GOURMAND] > GOURMAND_MAX) + { + preference++; + + // If you're wearing it and it activates, it should auto-id + const int amulet = you.equip[EQ_AMULET]; + ASSERT(amulet != -1); + if (!item_type_known(you.inv[amulet])) + { + // For artefact amulets, this will tell you its name and + // subtype. Other properties may still be hidden. + set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); + set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); + mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); + } + } + } + + return preference; +} + // Returns -1 for cancel, 1 for eaten, 0 for not eaten. int eat_from_floor(bool skip_chunks) { @@ -1371,14 +1510,7 @@ int prompt_eat_chunks(bool only_auto) if (player_mutation_level(MUT_HERBIVOROUS) == 3) return (0); - // If we *know* the player can eat chunks, doesn't have the gourmand - // effect and isn't hungry, don't prompt for chunks. - if (you.species != SP_VAMPIRE && !player_likes_chunks(true) - && !wearing_amulet(AMU_THE_GOURMAND, false) - && you.hunger_state >= HS_SATIATED) - { - return (0); - } + bool found_valid = false; std::vector<item_def *> chunks; @@ -1406,6 +1538,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*si)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(si->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(&(*si)); } @@ -1436,6 +1572,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*item)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(item->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(item); } @@ -1583,47 +1723,6 @@ void chunk_nutrition_message(int nutrition) mpr("That was not very filling."); } -static int _apply_herbivore_nutrition_effects(int nutrition) -{ - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - - while (how_herbivorous--) - nutrition = nutrition * 80 / 100; - - return (nutrition); -} - -static int _apply_gourmand_nutrition_effects(int nutrition, int gourmand) -{ - return (nutrition * (gourmand + GOURMAND_NUTRITION_BASE) - / (GOURMAND_MAX + GOURMAND_NUTRITION_BASE)); -} - -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_nutrition_effects(nutrition)); - } - - const int gourmand = - wearing_amulet(AMU_THE_GOURMAND) ? you.duration[DUR_GOURMAND] : 0; - const int effective_nutrition = - _apply_gourmand_nutrition_effects(nutrition, gourmand); - -#ifdef DEBUG_DIAGNOSTICS - const int epercent = effective_nutrition * 100 / nutrition; - mprf(MSGCH_DIAGNOSTICS, - "Gourmand factor: %d, chunk base: %d, effective: %d, %%: %d", - gourmand, nutrition, effective_nutrition, epercent); -#endif - - return (_apply_herbivore_nutrition_effects(effective_nutrition)); -} - static void _say_chunk_flavour(bool likes_chunks) { mprf("This raw flesh %s", _chunk_flavour_phrase(likes_chunks)); @@ -1635,10 +1734,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel, bool holy) { bool likes_chunks = player_likes_chunks(true); - int nutrition = _chunk_nutrition(likes_chunks); + int preference = get_preference_for_food_type(FOOD_CHUNK, chunk_effect); + int nutrition = CHUNK_BASE_NUTRITION * determine_satiation_multiplier(preference); int hp_amt = 0; bool suppress_msg = false; // do we display the chunk nutrition message? - bool do_eat = false; + bool do_eat = true; if (you.species == SP_GHOUL) { @@ -1675,6 +1775,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, xom_is_stimulated(random2(128)); break; + case CE_POISON_CONTAM: + mpr("Yeeuch - this meat is poisonous!"); + if (poison_player(3 + random2(4), "", "poisonous meat")) + xom_is_stimulated(random2(128)); + // fall through case CE_ROTTEN: case CE_CONTAMINATED: if (player_mutation_level(MUT_SAPROVOROUS) == 3) @@ -1684,8 +1789,6 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, if (you.species == SP_GHOUL) _heal_from_food(hp_amt, 0, !one_chance_in(4), one_chance_in(5)); - - do_eat = true; } else { @@ -1712,10 +1815,8 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, else _say_chunk_flavour(likes_chunks); - do_eat = true; break; - case CE_POISON_CONTAM: // _determine_chunk_effect should never return this case CE_MUTAGEN_GOOD: case CE_NOCORPSE: case CE_RANDOM: @@ -1738,13 +1839,10 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, } } -static void _eating(object_class_type item_class, int item_type) +static void _eat_nonchunk(object_class_type item_class, int item_type) { int food_value = 0; - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); - int carnivore_modifier = 0; - int herbivore_modifier = 0; + int preference = 0; switch (item_class) { @@ -1754,108 +1852,58 @@ static void _eating(object_class_type item_class, int item_type) { case FOOD_MEAT_RATION: case FOOD_ROYAL_JELLY: - food_value = 5000; + food_value = 4000; break; case FOOD_BREAD_RATION: - food_value = 4400; + food_value = 3500; break; case FOOD_AMBROSIA: - food_value = 2500; + food_value = 2000; break; case FOOD_HONEYCOMB: - food_value = 2000; + food_value = 1600; break; case FOOD_SNOZZCUMBER: // Maybe a nasty side-effect from RD's book? // I'd like that, but I don't dare. (jpeg) case FOOD_PIZZA: case FOOD_BEEF_JERKY: - food_value = 1500; + food_value = 1200; break; case FOOD_CHEESE: case FOOD_SAUSAGE: - food_value = 1200; + food_value = 1000; break; case FOOD_ORANGE: case FOOD_BANANA: case FOOD_LEMON: - food_value = 1000; + food_value = 800; break; case FOOD_PEAR: case FOOD_APPLE: case FOOD_APRICOT: - food_value = 700; - break; - case FOOD_CHOKO: - case FOOD_RAMBUTAN: - case FOOD_LYCHEE: food_value = 600; break; - case FOOD_STRAWBERRY: - food_value = 200; - break; - case FOOD_GRAPE: - food_value = 100; - break; - case FOOD_SULTANA: - food_value = 70; // Will not save you from starvation. - break; - default: - break; - } - - // Next, sustenance modifier for carnivores/herbivores {dlb}: - switch (item_type) - { - case FOOD_MEAT_RATION: - carnivore_modifier = 500; - herbivore_modifier = -1500; - break; - case FOOD_BEEF_JERKY: - case FOOD_SAUSAGE: - carnivore_modifier = 200; - herbivore_modifier = -200; - break; - case FOOD_BREAD_RATION: - carnivore_modifier = -1000; - herbivore_modifier = 500; - break; - case FOOD_BANANA: - case FOOD_ORANGE: - case FOOD_LEMON: - carnivore_modifier = -300; - herbivore_modifier = 300; - break; - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_APRICOT: case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: case FOOD_RAMBUTAN: case FOOD_LYCHEE: - carnivore_modifier = -200; - herbivore_modifier = 200; + food_value = 550; break; case FOOD_STRAWBERRY: - carnivore_modifier = -50; - herbivore_modifier = 50; + food_value = 160; break; case FOOD_GRAPE: + food_value = 80; + break; case FOOD_SULTANA: - carnivore_modifier = -20; - herbivore_modifier = 20; + food_value = 60; // Will not save you from starvation. break; default: - carnivore_modifier = 0; - herbivore_modifier = 0; break; } - // Finally, modify player's hunger level {dlb}: - if (carnivore_modifier && how_carnivorous > 0) - food_value += (carnivore_modifier * how_carnivorous); - - if (herbivore_modifier && how_herbivorous > 0) - food_value += (herbivore_modifier * how_herbivorous); + // multiply the base satiation by a value determined by how much the player likes the food + preference = get_preference_for_food_type(item_type); + food_value *= determine_satiation_multiplier(preference); if (food_value > 0) { @@ -2277,49 +2325,6 @@ bool causes_rot(const item_def &food) return (mons_corpse_effect(food.plus) == CE_HCL); } -// Returns 1 for herbivores, -1 for carnivores and 0 for either. -static int _player_likes_food_type(int type) -{ - switch (static_cast<food_type>(type)) - { - case FOOD_BREAD_RATION: - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: - case FOOD_APRICOT: - case FOOD_ORANGE: - case FOOD_BANANA: - case FOOD_STRAWBERRY: - case FOOD_RAMBUTAN: - case FOOD_LEMON: - case FOOD_GRAPE: - case FOOD_SULTANA: - case FOOD_LYCHEE: - return 1; - - case FOOD_CHUNK: - case FOOD_MEAT_RATION: - case FOOD_SAUSAGE: - case FOOD_BEEF_JERKY: - return -1; - - case FOOD_HONEYCOMB: - case FOOD_ROYAL_JELLY: - case FOOD_AMBROSIA: - case FOOD_CHEESE: - case FOOD_PIZZA: - return 0; - - case NUM_FOODS: - mpr("Bad food type", MSGCH_ERROR); - return 0; - } - - mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); - return 0; -} - // Returns true if an item of basetype FOOD or CORPSES cannot currently // be eaten (respecting species and mutations set). bool is_inedible(const item_def &item) @@ -2386,10 +2391,10 @@ bool is_preferred_food(const item_def &food) return (food_is_rotten(food)); if (player_mutation_level(MUT_CARNIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) < 0); + return (determine_food_type(food.sub_type) < 0); if (player_mutation_level(MUT_HERBIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) > 0); + return (determine_food_type(food.sub_type) > 0); // No food preference. return (false); @@ -2425,38 +2430,15 @@ bool is_forbidden_food(const item_def &food) return (false); } -bool check_amu_the_gourmand(bool reqid) -{ - if (wearing_amulet(AMU_THE_GOURMAND, !reqid)) - { - const int amulet = you.equip[EQ_AMULET]; - - ASSERT(amulet != -1); - - if (!item_type_known(you.inv[amulet])) - { - // For artefact amulets, this will tell you its name and - // subtype. Other properties may still be hidden. - set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); - set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); - mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); - } - - return (true); - } - - return (false); -} - bool can_ingest(const item_def &food, bool suppress_msg, bool reqid, bool check_hunger) { return can_ingest(food.base_type, food.sub_type, suppress_msg, reqid, - check_hunger, food_is_rotten(food)); + check_hunger, mons_corpse_effect(food.plus)); } bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, - bool reqid, bool check_hunger, bool rotten) + bool reqid, bool check_hunger, corpse_effect_type effect_type) { bool survey_says = false; @@ -2485,12 +2467,6 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool ur_carnivorous = player_mutation_level(MUT_CARNIVOROUS) == 3; bool ur_herbivorous = player_mutation_level(MUT_HERBIVOROUS) == 3; - // ur_chunkslover not defined in terms of ur_carnivorous because - // a player could be one and not the other IMHO - 13mar2000 {dlb} - bool ur_chunkslover = ((check_hunger ? you.hunger_state < HS_SATIATED - : true) - || player_likes_chunks(true)); - switch (what_isit) { case OBJ_FOOD: @@ -2502,7 +2478,14 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, return (false); } - const int vorous = _player_likes_food_type(kindof_thing); + const int preference = get_preference_for_food_type(kindof_thing, effect_type); + + // not defined in terms of ur_carnivorous because + // a player could be one and not the other IMHO - 13mar2000 {dlb} + bool willing_to_eat = (check_hunger ? you.hunger <= determine_maximum_satiation(preference) : true); + + int vorous = determine_food_type(kindof_thing); + if (vorous > 0) // Herbivorous food. { if (ur_carnivorous) @@ -2524,13 +2507,10 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } else if (kindof_thing == FOOD_CHUNK) { - if (rotten && !_player_can_eat_rotten_meat(!suppress_msg)) + if (effect_type == CE_ROTTEN && !_player_can_eat_rotten_meat(!suppress_msg)) return (false); - if (ur_chunkslover) - return (true); - - if (check_amu_the_gourmand(reqid)) + if (willing_to_eat) return (true); if (!suppress_msg) @@ -2540,8 +2520,18 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } } // Any food types not specifically handled until here (e.g. meat - // rations for non-herbivores) are okay. - return (true); + // rations for non-herbivores) are okay as long as your preference . + if (willing_to_eat) + { + return (true); + } + else + { + if (!suppress_msg) + mpr("You aren't quite hungry enough to eat that!"); + + return (false); + } } case OBJ_CORPSES: @@ -2636,7 +2626,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, case CE_POISON_CONTAM: if (player_res_poison() <= 0) { - chunktype = CE_POISONOUS; break; } else @@ -2705,28 +2694,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, } } - // 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. - if (wearing_amulet(AMU_THE_GOURMAND) - && x_chance_in_y(you.duration[DUR_GOURMAND], GOURMAND_MAX)) - { - if (player_mutation_level(MUT_SAPROVOROUS) == 3) - { - // [dshaligram] Level 3 saprovores relish contaminated meat. - if (chunktype == CE_CLEAN) - chunktype = CE_CONTAMINATED; - } - else - { - // [dshaligram] New AotG behaviour - contaminated chunks become - // clean, but rotten chunks remain rotten. - if (chunktype == CE_CONTAMINATED) - chunktype = CE_CLEAN; - } - } - return (chunktype); } diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h index e79ba9f..6d00ef5 100644 --- a/crawl-ref/source/food.h +++ b/crawl-ref/source/food.h @@ -60,13 +60,12 @@ bool causes_rot(const item_def &food); bool is_inedible(const item_def &item); bool is_preferred_food(const item_def &food); bool is_forbidden_food(const item_def &food); -bool check_amu_the_gourmand(bool reqid); bool can_ingest(const item_def &food, bool suppress_msg, bool reqid = false, bool check_hunger = true); bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid = false, bool check_hunger = true, - bool rotten = false); + corpse_effect_type effect_type = CE_CLEAN); bool chunk_is_poisonous(int chunktype); void eat_floor_item(int item_link); diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index ddabc86..250bf16 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -20,7 +20,6 @@ #include "artefact.h" #include "colour.h" #include "decks.h" -#include "food.h" #include "goditem.h" #include "invent.h" #include "item_use.h" @@ -42,7 +41,7 @@ #include "stuff.h" #include "env.h" #include "transform.h" - +#include "food.h" static bool _is_random_name_space(char let); static bool _is_random_name_vowel(char let); diff --git a/crawl-ref/source/l_food.cc b/crawl-ref/source/l_food.cc index 089390b..8cbc00e 100644 --- a/crawl-ref/source/l_food.cc +++ b/crawl-ref/source/l_food.cc @@ -3,11 +3,12 @@ #include "cluautil.h" #include "l_libs.h" -#include "food.h" #include "invent.h" #include "itemprop.h" #include "items.h" #include "player.h" +#include "mon-util.h" +#include "food.h" ///////////////////////////////////////////////////////////////////// // Food information. diff --git a/crawl-ref/source/potion.cc b/crawl-ref/source/potion.cc index 4eafd46..8410a96 100644 --- a/crawl-ref/source/potion.cc +++ b/crawl-ref/source/potion.cc @@ -131,14 +131,11 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) const int value = 200; const int herbivorous = player_mutation_level(MUT_HERBIVOROUS); - if (herbivorous < 3 && player_likes_chunks()) + if (herbivorous < 3 && player_likes_chunks(true)) { // Likes it. mpr("This tastes like blood."); lessen_hunger(value, true); - - if (!player_likes_chunks(true)) - check_amu_the_gourmand(false); } else { diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 051077a..a17dff2 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -13,7 +13,6 @@ #include "coordit.h" #include "files.h" #include "fixedarray.h" -#include "food.h" #include "branch.h" #include "command.h" #include "cio.h" @@ -51,6 +50,7 @@ #include "travel.h" #include "hints.h" #include "view.h" +#include "food.h" #include <algorithm> #include <set> -- 1.7.5.GIT 0002-0004226-Food-reform.patch [^] (834 bytes) 2011-07-17 09:05 [Show Content] [Hide Content] From 4e06f20720c9c987100de4348c6a91813fd2ff33 Mon Sep 17 00:00:00 2001 From: Ryak <ryak2002@hotmail.com> Date: Sun, 17 Jul 2011 02:04:45 -0500 Subject: [PATCH 2/2] 0004226: Food reform --- crawl-ref/source/food.cc | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index e40c7d4..e11243c 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -1176,7 +1176,7 @@ int get_preference_for_food_type(int type, corpse_effect_type effect_type = CE_C preference -= how_carnivorous * food_type; // gourmand - (only affects chunks) - if (wearing_amulet(AMU_THE_GOURMAND), true) + if (static_cast<food_type>(type) == FOOD_CHUNK && wearing_amulet(AMU_THE_GOURMAND), true) { if (you.duration[DUR_GOURMAND] > GOURMAND_MAX) { -- 1.7.5.GIT 0001-Applied-Ryak-s-patch-and-fixed-the-rejected-bits.patch [^] (25,559 bytes) 2011-09-06 22:08 [Show Content] [Hide Content] From d6e7ebd3ef2981c65ebb8558eb72ed9d90ee2b65 Mon Sep 17 00:00:00 2001 From: Harald Korneliussen <vintermann@gmail.com> Date: Tue, 6 Sep 2011 21:54:53 +0200 Subject: [PATCH] Applied Ryak's patch and fixed the rejected bits so it works on head --- crawl-ref/source/defines.h | 2 +- crawl-ref/source/food.cc | 440 +++++++++++++++++++---------------------- crawl-ref/source/food.h | 3 +- crawl-ref/source/itemname.cc | 3 +- crawl-ref/source/l_food.cc | 3 +- crawl-ref/source/potion.cc | 5 +- crawl-ref/source/travel.cc | 2 +- 7 files changed, 211 insertions(+), 247 deletions(-) diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h index 96bfe29..e29e4fb 100644 --- a/crawl-ref/source/defines.h +++ b/crawl-ref/source/defines.h @@ -182,7 +182,7 @@ const int BASELINE_DELAY = 10; const int GOURMAND_MAX = 200 * BASELINE_DELAY; const int GOURMAND_NUTRITION_BASE = 10 * BASELINE_DELAY; -const int CHUNK_BASE_NUTRITION = 1000; +const int CHUNK_BASE_NUTRITION = 750; const int ICEMAIL_MAX = 10; const int ICEMAIL_TIME = 300 * BASELINE_DELAY; diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index 2ca2be5..f7b3d21 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -5,7 +5,7 @@ #include "AppHdr.h" -#include "food.h" + #include <sstream> @@ -52,11 +52,13 @@ #include "travel.h" #include "xom.h" +#include "food.h" + static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, bool rotten_chunk); static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel = 0, bool holy = false); -static void _eating(object_class_type item_class, int item_type); +static void _eat_nonchunk(object_class_type item_class, int item_type); static void _describe_food_change(int hunger_increment); static bool _vampire_consume_corpse(int slot, bool invent); static void _heal_from_food(int hp_amt, int mp_amt = 0, bool unrot = false, @@ -707,6 +709,73 @@ bool eat_food(int slot) // END PUBLIC FUNCTIONS +static int determine_maximum_satiation(int preference) +{ + switch (preference) + { + case -2: return 1533; // near starving + case -1: return 2066; // very hungry + case 0: return 2600; // hungry + case 1: return 7000; // satiated + case 2: return 9000; // full + } + if (preference > 2) + return 11000; // engorged + + return 0; // cannot ever eat +} + +static double determine_satiation_multiplier(int preference) +{ + if (preference <= 0) + return 1 + 0.334 * preference; + else + return 0.8 + 0.2 * preference; +} + +// Returns 1 for herbivores, -1 for carnivores and 0 for either. +static int determine_food_type(int type) +{ + switch (static_cast<food_type>(type)) + { + case FOOD_BREAD_RATION: + case FOOD_PEAR: + case FOOD_APPLE: + case FOOD_CHOKO: + case FOOD_SNOZZCUMBER: + case FOOD_APRICOT: + case FOOD_ORANGE: + case FOOD_BANANA: + case FOOD_STRAWBERRY: + case FOOD_RAMBUTAN: + case FOOD_LEMON: + case FOOD_GRAPE: + case FOOD_SULTANA: + case FOOD_LYCHEE: + return 1; + + case FOOD_CHUNK: + case FOOD_MEAT_RATION: + case FOOD_SAUSAGE: + case FOOD_BEEF_JERKY: + return -1; + + case FOOD_HONEYCOMB: + case FOOD_ROYAL_JELLY: + case FOOD_AMBROSIA: + case FOOD_CHEESE: + case FOOD_PIZZA: + return 0; + + case NUM_FOODS: + mpr("Bad food type", MSGCH_ERROR); + return 0; + } + + mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); + return 0; +} + static bool _player_has_enough_food() { int food_value = 0; @@ -970,7 +1039,7 @@ void eat_inventory_item(int which_inventory_slot) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; dec_inv_item_quantity(which_inventory_slot, 1); @@ -1004,7 +1073,7 @@ void eat_floor_item(int item_link) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; @@ -1060,6 +1129,76 @@ public: } }; +int get_preference_for_food_type(int type, corpse_effect_type effect_type = CE_CLEAN) +{ + int preference = 0; + int saprovorous = player_mutation_level(MUT_SAPROVOROUS); + + // Royal Jelly can always be eaten. It needs a total of +3 to guarentee this + if (static_cast<food_type>(type) == FOOD_ROYAL_JELLY) + preference += 1; + + // permafood gets a +2 bonus + if (static_cast<food_type>(type) != FOOD_CHUNK) + preference += 2; + else + { + // unclean chunks get a penalty (If you are immune to the effect, we will be passed + // clean even if the original chunk wasn't clean [except rotting]) + switch (effect_type) + { + case CE_CLEAN: break; + case CE_CONTAMINATED: + case CE_POISONOUS: + case CE_POISON_CONTAM: + case CE_ROT: + case CE_MUTAGEN_RANDOM: + case CE_MUTAGEN_GOOD: + case CE_MUTAGEN_BAD: preference -= 1; + break; + case CE_ROTTEN: if (saprovorous == 0) + preference -= 2; + else if (saprovorous == 1 || saprovorous == 2) + preference -= 1; + break; + case CE_NOCORPSE: + case CE_RANDOM: + break; + } + } + + int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); + int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); + int food_type = determine_food_type(type); + + // bonus/penalty of your mutation level for matching/conflicting food type + preference += how_herbivorous * food_type; + preference -= how_carnivorous * food_type; + + // gourmand - (only affects chunks) + if (wearing_amulet(AMU_THE_GOURMAND), true) + { + if (you.duration[DUR_GOURMAND] > GOURMAND_MAX) + { + preference++; + + // If you're wearing it and it activates, it should auto-id + const int amulet = you.equip[EQ_AMULET]; + ASSERT(amulet != -1); + if (!item_type_known(you.inv[amulet])) + { + // For artefact amulets, this will tell you its name and + // subtype. Other properties may still be hidden. + set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); + set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); + mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); + } + } + } + + return preference; +} + // Returns -1 for cancel, 1 for eaten, 0 for not eaten. int eat_from_floor(bool skip_chunks) { @@ -1371,14 +1510,7 @@ int prompt_eat_chunks(bool only_auto) if (player_mutation_level(MUT_HERBIVOROUS) == 3) return (0); - // If we *know* the player can eat chunks, doesn't have the gourmand - // effect and isn't hungry, don't prompt for chunks. - if (you.species != SP_VAMPIRE && !player_likes_chunks(true) - && !wearing_amulet(AMU_THE_GOURMAND, false) - && you.hunger_state >= HS_SATIATED) - { - return (0); - } + bool found_valid = false; std::vector<item_def *> chunks; @@ -1406,6 +1538,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*si)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(si->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(&(*si)); } @@ -1436,6 +1572,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*item)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(item->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(item); } @@ -1583,47 +1723,6 @@ void chunk_nutrition_message(int nutrition) mpr("That was not very filling."); } -static int _apply_herbivore_nutrition_effects(int nutrition) -{ - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - - while (how_herbivorous--) - nutrition = nutrition * 80 / 100; - - return (nutrition); -} - -static int _apply_gourmand_nutrition_effects(int nutrition, int gourmand) -{ - return (nutrition * (gourmand + GOURMAND_NUTRITION_BASE) - / (GOURMAND_MAX + GOURMAND_NUTRITION_BASE)); -} - -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_nutrition_effects(nutrition)); - } - - const int gourmand = - wearing_amulet(AMU_THE_GOURMAND) ? you.duration[DUR_GOURMAND] : 0; - const int effective_nutrition = - _apply_gourmand_nutrition_effects(nutrition, gourmand); - -#ifdef DEBUG_DIAGNOSTICS - const int epercent = effective_nutrition * 100 / nutrition; - mprf(MSGCH_DIAGNOSTICS, - "Gourmand factor: %d, chunk base: %d, effective: %d, %%: %d", - gourmand, nutrition, effective_nutrition, epercent); -#endif - - return (_apply_herbivore_nutrition_effects(effective_nutrition)); -} - static void _say_chunk_flavour(bool likes_chunks) { mprf("This raw flesh %s", _chunk_flavour_phrase(likes_chunks)); @@ -1635,10 +1734,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel, bool holy) { bool likes_chunks = player_likes_chunks(true); - int nutrition = _chunk_nutrition(likes_chunks); + int preference = get_preference_for_food_type(FOOD_CHUNK, chunk_effect); + int nutrition = CHUNK_BASE_NUTRITION * determine_satiation_multiplier(preference); int hp_amt = 0; bool suppress_msg = false; // do we display the chunk nutrition message? - bool do_eat = false; + bool do_eat = true; if (you.species == SP_GHOUL) { @@ -1675,6 +1775,12 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, xom_is_stimulated(random2(100)); break; + case CE_POISON_CONTAM: + mpr("Yeeuch - this meat is poisonous!"); + if (poison_player(3 + random2(4), "", "poisonous meat")) + xom_is_stimulated(random2(100)); + // Fall through + case CE_ROTTEN: case CE_CONTAMINATED: if (player_mutation_level(MUT_SAPROVOROUS) == 3) @@ -1684,8 +1790,6 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, if (you.species == SP_GHOUL) _heal_from_food(hp_amt, 0, !one_chance_in(4), one_chance_in(5)); - - do_eat = true; } else { @@ -1712,10 +1816,8 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, else _say_chunk_flavour(likes_chunks); - do_eat = true; break; - case CE_POISON_CONTAM: // _determine_chunk_effect should never return this case CE_MUTAGEN_GOOD: case CE_NOCORPSE: case CE_RANDOM: @@ -1738,13 +1840,10 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, } } -static void _eating(object_class_type item_class, int item_type) +static void _eat_nonchunk(object_class_type item_class, int item_type) { int food_value = 0; - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); - int carnivore_modifier = 0; - int herbivore_modifier = 0; + int preference = 0; switch (item_class) { @@ -1754,108 +1853,58 @@ static void _eating(object_class_type item_class, int item_type) { case FOOD_MEAT_RATION: case FOOD_ROYAL_JELLY: - food_value = 5000; + food_value = 4000; break; case FOOD_BREAD_RATION: - food_value = 4400; + food_value = 3500; break; case FOOD_AMBROSIA: - food_value = 2500; + food_value = 2000; break; case FOOD_HONEYCOMB: - food_value = 2000; + food_value = 1600; break; case FOOD_SNOZZCUMBER: // Maybe a nasty side-effect from RD's book? // I'd like that, but I don't dare. (jpeg) case FOOD_PIZZA: case FOOD_BEEF_JERKY: - food_value = 1500; + food_value = 1200; break; case FOOD_CHEESE: case FOOD_SAUSAGE: - food_value = 1200; + food_value = 1000; break; case FOOD_ORANGE: case FOOD_BANANA: case FOOD_LEMON: - food_value = 1000; + food_value = 800; break; case FOOD_PEAR: case FOOD_APPLE: case FOOD_APRICOT: - food_value = 700; - break; - case FOOD_CHOKO: - case FOOD_RAMBUTAN: - case FOOD_LYCHEE: food_value = 600; break; - case FOOD_STRAWBERRY: - food_value = 200; - break; - case FOOD_GRAPE: - food_value = 100; - break; - case FOOD_SULTANA: - food_value = 70; // Will not save you from starvation. - break; - default: - break; - } - - // Next, sustenance modifier for carnivores/herbivores {dlb}: - switch (item_type) - { - case FOOD_MEAT_RATION: - carnivore_modifier = 500; - herbivore_modifier = -1500; - break; - case FOOD_BEEF_JERKY: - case FOOD_SAUSAGE: - carnivore_modifier = 200; - herbivore_modifier = -200; - break; - case FOOD_BREAD_RATION: - carnivore_modifier = -1000; - herbivore_modifier = 500; - break; - case FOOD_BANANA: - case FOOD_ORANGE: - case FOOD_LEMON: - carnivore_modifier = -300; - herbivore_modifier = 300; - break; - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_APRICOT: case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: case FOOD_RAMBUTAN: case FOOD_LYCHEE: - carnivore_modifier = -200; - herbivore_modifier = 200; + food_value = 550; break; case FOOD_STRAWBERRY: - carnivore_modifier = -50; - herbivore_modifier = 50; + food_value = 160; break; case FOOD_GRAPE: + food_value = 80; + break; case FOOD_SULTANA: - carnivore_modifier = -20; - herbivore_modifier = 20; + food_value = 60; // Will not save you from starvation. break; default: - carnivore_modifier = 0; - herbivore_modifier = 0; break; } - // Finally, modify player's hunger level {dlb}: - if (carnivore_modifier && how_carnivorous > 0) - food_value += (carnivore_modifier * how_carnivorous); - - if (herbivore_modifier && how_herbivorous > 0) - food_value += (herbivore_modifier * how_herbivorous); + // multiply the base satiation by a value determined by how much the player likes the food + preference = get_preference_for_food_type(item_type); + food_value *= determine_satiation_multiplier(preference); if (food_value > 0) { @@ -2281,49 +2330,6 @@ bool causes_rot(const item_def &food) return (mons_corpse_effect(food.plus) == CE_ROT); } -// Returns 1 for herbivores, -1 for carnivores and 0 for either. -static int _player_likes_food_type(int type) -{ - switch (static_cast<food_type>(type)) - { - case FOOD_BREAD_RATION: - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: - case FOOD_APRICOT: - case FOOD_ORANGE: - case FOOD_BANANA: - case FOOD_STRAWBERRY: - case FOOD_RAMBUTAN: - case FOOD_LEMON: - case FOOD_GRAPE: - case FOOD_SULTANA: - case FOOD_LYCHEE: - return 1; - - case FOOD_CHUNK: - case FOOD_MEAT_RATION: - case FOOD_SAUSAGE: - case FOOD_BEEF_JERKY: - return -1; - - case FOOD_HONEYCOMB: - case FOOD_ROYAL_JELLY: - case FOOD_AMBROSIA: - case FOOD_CHEESE: - case FOOD_PIZZA: - return 0; - - case NUM_FOODS: - mpr("Bad food type", MSGCH_ERROR); - return 0; - } - - mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); - return 0; -} - // Returns true if an item of basetype FOOD or CORPSES cannot currently // be eaten (respecting species and mutations set). bool is_inedible(const item_def &item) @@ -2390,10 +2396,10 @@ bool is_preferred_food(const item_def &food) return (food_is_rotten(food)); if (player_mutation_level(MUT_CARNIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) < 0); + return (determine_food_type(food.sub_type) < 0); if (player_mutation_level(MUT_HERBIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) > 0); + return (determine_food_type(food.sub_type) > 0); // No food preference. return (false); @@ -2429,38 +2435,15 @@ bool is_forbidden_food(const item_def &food) return (false); } -bool check_amu_the_gourmand(bool reqid) -{ - if (wearing_amulet(AMU_THE_GOURMAND, !reqid)) - { - const int amulet = you.equip[EQ_AMULET]; - - ASSERT(amulet != -1); - - if (!item_type_known(you.inv[amulet])) - { - // For artefact amulets, this will tell you its name and - // subtype. Other properties may still be hidden. - set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); - set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); - mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); - } - - return (true); - } - - return (false); -} - bool can_ingest(const item_def &food, bool suppress_msg, bool reqid, bool check_hunger) { return can_ingest(food.base_type, food.sub_type, suppress_msg, reqid, - check_hunger, food_is_rotten(food)); + check_hunger, mons_corpse_effect(food.plus)); } bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, - bool reqid, bool check_hunger, bool rotten) + bool reqid, bool check_hunger, corpse_effect_type effect_type) { bool survey_says = false; @@ -2489,12 +2472,6 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool ur_carnivorous = player_mutation_level(MUT_CARNIVOROUS) == 3; bool ur_herbivorous = player_mutation_level(MUT_HERBIVOROUS) == 3; - // ur_chunkslover not defined in terms of ur_carnivorous because - // a player could be one and not the other IMHO - 13mar2000 {dlb} - bool ur_chunkslover = ((check_hunger ? you.hunger_state < HS_SATIATED - : true) - || player_likes_chunks(true)); - switch (what_isit) { case OBJ_FOOD: @@ -2506,7 +2483,14 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, return (false); } - const int vorous = _player_likes_food_type(kindof_thing); + const int preference = get_preference_for_food_type(kindof_thing, effect_type); + + // not defined in terms of ur_carnivorous because + // a player could be one and not the other IMHO - 13mar2000 {dlb} + bool willing_to_eat = (check_hunger ? you.hunger <= determine_maximum_satiation(preference) : true); + + int vorous = determine_food_type(kindof_thing); + if (vorous > 0) // Herbivorous food. { if (ur_carnivorous) @@ -2528,13 +2512,10 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } else if (kindof_thing == FOOD_CHUNK) { - if (rotten && !_player_can_eat_rotten_meat(!suppress_msg)) + if (effect_type == CE_ROTTEN && !_player_can_eat_rotten_meat(!suppress_msg)) return (false); - if (ur_chunkslover) - return (true); - - if (check_amu_the_gourmand(reqid)) + if (willing_to_eat) return (true); if (!suppress_msg) @@ -2544,8 +2525,18 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } } // Any food types not specifically handled until here (e.g. meat - // rations for non-herbivores) are okay. - return (true); + // rations for non-herbivores) are okay as long as your preference . + if (willing_to_eat) + { + return (true); + } + else + { + if (!suppress_msg) + mpr("You aren't quite hungry enough to eat that!"); + + return (false); + } } case OBJ_CORPSES: @@ -2640,7 +2631,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, case CE_POISON_CONTAM: if (player_res_poison() <= 0) { - chunktype = CE_POISONOUS; break; } else @@ -2709,28 +2699,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, } } - // 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. - if (wearing_amulet(AMU_THE_GOURMAND) - && x_chance_in_y(you.duration[DUR_GOURMAND], GOURMAND_MAX)) - { - if (player_mutation_level(MUT_SAPROVOROUS) == 3) - { - // [dshaligram] Level 3 saprovores relish contaminated meat. - if (chunktype == CE_CLEAN) - chunktype = CE_CONTAMINATED; - } - else - { - // [dshaligram] New AotG behaviour - contaminated chunks become - // clean, but rotten chunks remain rotten. - if (chunktype == CE_CONTAMINATED) - chunktype = CE_CLEAN; - } - } - return (chunktype); } diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h index e79ba9f..6d00ef5 100644 --- a/crawl-ref/source/food.h +++ b/crawl-ref/source/food.h @@ -60,13 +60,12 @@ bool causes_rot(const item_def &food); bool is_inedible(const item_def &item); bool is_preferred_food(const item_def &food); bool is_forbidden_food(const item_def &food); -bool check_amu_the_gourmand(bool reqid); bool can_ingest(const item_def &food, bool suppress_msg, bool reqid = false, bool check_hunger = true); bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid = false, bool check_hunger = true, - bool rotten = false); + corpse_effect_type effect_type = CE_CLEAN); bool chunk_is_poisonous(int chunktype); void eat_floor_item(int item_link); diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index 3c4aea1..b52b3fc 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -20,7 +20,6 @@ #include "artefact.h" #include "colour.h" #include "decks.h" -#include "food.h" #include "goditem.h" #include "invent.h" #include "item_use.h" @@ -42,7 +41,7 @@ #include "stuff.h" #include "env.h" #include "transform.h" - +#include "food.h" static bool _is_random_name_space(char let); static bool _is_random_name_vowel(char let); diff --git a/crawl-ref/source/l_food.cc b/crawl-ref/source/l_food.cc index 089390b..8cbc00e 100644 --- a/crawl-ref/source/l_food.cc +++ b/crawl-ref/source/l_food.cc @@ -3,11 +3,12 @@ #include "cluautil.h" #include "l_libs.h" -#include "food.h" #include "invent.h" #include "itemprop.h" #include "items.h" #include "player.h" +#include "mon-util.h" +#include "food.h" ///////////////////////////////////////////////////////////////////// // Food information. diff --git a/crawl-ref/source/potion.cc b/crawl-ref/source/potion.cc index 0dbf839..76e98ff 100644 --- a/crawl-ref/source/potion.cc +++ b/crawl-ref/source/potion.cc @@ -133,14 +133,11 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) const int value = 200; const int herbivorous = player_mutation_level(MUT_HERBIVOROUS); - if (herbivorous < 3 && player_likes_chunks()) + if (herbivorous < 3 && player_likes_chunks(true)) { // Likes it. mpr("This tastes like blood."); lessen_hunger(value, true); - - if (!player_likes_chunks(true)) - check_amu_the_gourmand(false); } else { diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index e50876b..854a42b 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -13,7 +13,6 @@ #include "coordit.h" #include "files.h" #include "fixedarray.h" -#include "food.h" #include "branch.h" #include "command.h" #include "cio.h" @@ -51,6 +50,7 @@ #include "travel.h" #include "hints.h" #include "view.h" +#include "food.h" #include <algorithm> #include <set> -- 1.7.4.1 nutri.c [^] (4,460 bytes) 2011-09-06 22:31 0001-0004226-Food-reform-v2.patch [^] (26,670 bytes) 2011-09-30 05:11 [Show Content] [Hide Content] From 592403dc7ec62115870171006014d91007ffeb40 Mon Sep 17 00:00:00 2001 From: Ryak <ryak2002@hotmail.com> Date: Sun, 17 Jul 2011 01:49:53 -0500 Subject: [PATCH] 0004226: Food reform --- crawl-ref/source/food.cc | 447 +++++++++++++++++++---------------------- crawl-ref/source/food.h | 14 +- crawl-ref/source/itemname.cc | 3 +- crawl-ref/source/l_food.cc | 3 +- crawl-ref/source/misc.cc | 2 +- crawl-ref/source/potion.cc | 5 +- crawl-ref/source/travel.cc | 2 +- 7 files changed, 223 insertions(+), 253 deletions(-) diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index 2ca2be5..0d2c3b3 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -5,7 +5,7 @@ #include "AppHdr.h" -#include "food.h" + #include <sstream> @@ -52,11 +52,13 @@ #include "travel.h" #include "xom.h" +#include "food.h" + static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, bool rotten_chunk); static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel = 0, bool holy = false); -static void _eating(object_class_type item_class, int item_type); +static void _eat_nonchunk(object_class_type item_class, int item_type); static void _describe_food_change(int hunger_increment); static bool _vampire_consume_corpse(int slot, bool invent); static void _heal_from_food(int hp_amt, int mp_amt = 0, bool unrot = false, @@ -111,8 +113,8 @@ void lessen_hunger(int satiated_amount, bool suppress_msg) you.hunger += satiated_amount; - if (you.hunger > 12000) - you.hunger = 12000; + if (you.hunger > HUNGER_ENGORGED) + you.hunger = HUNGER_ENGORGED; // So we don't get two messages, ever. bool state_message = food_change(); @@ -707,6 +709,73 @@ bool eat_food(int slot) // END PUBLIC FUNCTIONS +static int determine_maximum_satiation(int preference) +{ + switch (preference) + { + case -2: return HUNGER_NEAR_STARVING; + case -1: return HUNGER_VERY_HUNGRY; + case 0: return HUNGER_HUNGRY; + case 1: return HUNGER_SATIATED; + case 2: return HUNGER_FULL; + } + if (preference > 2) + return HUNGER_VERY_FULL; + + return 0; // cannot ever eat +} + +static float determine_satiation_multiplier(int preference) +{ + if (preference <= 0) + return 1 + 0.334 * preference; + else + return 0.8 + 0.2 * preference; +} + +// Returns 1 for herbivores, -1 for carnivores and 0 for either. +static int determine_plant_content(int type) +{ + switch (type) + { + case FOOD_BREAD_RATION: + case FOOD_PEAR: + case FOOD_APPLE: + case FOOD_CHOKO: + case FOOD_SNOZZCUMBER: + case FOOD_APRICOT: + case FOOD_ORANGE: + case FOOD_BANANA: + case FOOD_STRAWBERRY: + case FOOD_RAMBUTAN: + case FOOD_LEMON: + case FOOD_GRAPE: + case FOOD_SULTANA: + case FOOD_LYCHEE: + return 1; + + case FOOD_CHUNK: + case FOOD_MEAT_RATION: + case FOOD_SAUSAGE: + case FOOD_BEEF_JERKY: + return -1; + + case FOOD_HONEYCOMB: + case FOOD_ROYAL_JELLY: + case FOOD_AMBROSIA: + case FOOD_CHEESE: + case FOOD_PIZZA: + return 0; + + case NUM_FOODS: + mpr("Bad food type", MSGCH_ERROR); + return 0; + } + + mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); + return 0; +} + static bool _player_has_enough_food() { int food_value = 0; @@ -970,7 +1039,7 @@ void eat_inventory_item(int which_inventory_slot) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; dec_inv_item_quantity(which_inventory_slot, 1); @@ -1004,7 +1073,7 @@ void eat_floor_item(int item_link) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; @@ -1060,6 +1129,76 @@ public: } }; +int get_preference_for_food_type(int type, corpse_effect_type effect_type = CE_CLEAN) +{ + int preference = 0; + int saprovorous = player_mutation_level(MUT_SAPROVOROUS); + + // Royal Jelly can always be eaten. It needs a total of +3 to guarentee this + if (type == FOOD_ROYAL_JELLY) + preference += 1; + + // permafood gets a +2 bonus + if (type != FOOD_CHUNK) + preference += 2; + else + { + // unclean chunks get a penalty (If you are immune to the effect, we will be passed + // clean even if the original chunk wasn't clean [except rotting]) + switch (effect_type) + { + case CE_CLEAN: break; + case CE_CONTAMINATED: + case CE_POISONOUS: + case CE_POISON_CONTAM: + case CE_ROT: + case CE_MUTAGEN_RANDOM: + case CE_MUTAGEN_GOOD: + case CE_MUTAGEN_BAD: preference -= 1; + break; + case CE_ROTTEN: if (saprovorous == 0) + preference -= 2; + else if (saprovorous == 1 || saprovorous == 2) + preference -= 1; + break; + case CE_NOCORPSE: + case CE_RANDOM: + break; + } + } + + int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); + int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); + int plant_content = determine_plant_content(type); + + // bonus/penalty of your mutation level for matching/conflicting food type + preference += how_herbivorous * plant_content; + preference -= how_carnivorous * plant_content; + + // gourmand - (only affects chunks) + if (type == FOOD_CHUNK && wearing_amulet(AMU_THE_GOURMAND), true) + { + if (you.duration[DUR_GOURMAND] > GOURMAND_MAX) + { + preference++; + + // If you're wearing it and it activates, it should auto-id + const int amulet = you.equip[EQ_AMULET]; + ASSERT(amulet != -1); + if (!item_type_known(you.inv[amulet])) + { + // For artefact amulets, this will tell you its name and + // subtype. Other properties may still be hidden. + set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); + set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); + mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); + } + } + } + + return preference; +} + // Returns -1 for cancel, 1 for eaten, 0 for not eaten. int eat_from_floor(bool skip_chunks) { @@ -1371,14 +1510,7 @@ int prompt_eat_chunks(bool only_auto) if (player_mutation_level(MUT_HERBIVOROUS) == 3) return (0); - // If we *know* the player can eat chunks, doesn't have the gourmand - // effect and isn't hungry, don't prompt for chunks. - if (you.species != SP_VAMPIRE && !player_likes_chunks(true) - && !wearing_amulet(AMU_THE_GOURMAND, false) - && you.hunger_state >= HS_SATIATED) - { - return (0); - } + bool found_valid = false; std::vector<item_def *> chunks; @@ -1406,6 +1538,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*si)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(si->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(&(*si)); } @@ -1436,6 +1572,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*item)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(item->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(item); } @@ -1583,47 +1723,6 @@ void chunk_nutrition_message(int nutrition) mpr("That was not very filling."); } -static int _apply_herbivore_nutrition_effects(int nutrition) -{ - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - - while (how_herbivorous--) - nutrition = nutrition * 80 / 100; - - return (nutrition); -} - -static int _apply_gourmand_nutrition_effects(int nutrition, int gourmand) -{ - return (nutrition * (gourmand + GOURMAND_NUTRITION_BASE) - / (GOURMAND_MAX + GOURMAND_NUTRITION_BASE)); -} - -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_nutrition_effects(nutrition)); - } - - const int gourmand = - wearing_amulet(AMU_THE_GOURMAND) ? you.duration[DUR_GOURMAND] : 0; - const int effective_nutrition = - _apply_gourmand_nutrition_effects(nutrition, gourmand); - -#ifdef DEBUG_DIAGNOSTICS - const int epercent = effective_nutrition * 100 / nutrition; - mprf(MSGCH_DIAGNOSTICS, - "Gourmand factor: %d, chunk base: %d, effective: %d, %%: %d", - gourmand, nutrition, effective_nutrition, epercent); -#endif - - return (_apply_herbivore_nutrition_effects(effective_nutrition)); -} - static void _say_chunk_flavour(bool likes_chunks) { mprf("This raw flesh %s", _chunk_flavour_phrase(likes_chunks)); @@ -1635,10 +1734,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel, bool holy) { bool likes_chunks = player_likes_chunks(true); - int nutrition = _chunk_nutrition(likes_chunks); + int preference = get_preference_for_food_type(FOOD_CHUNK, chunk_effect); + int nutrition = CHUNK_BASE_NUTRITION * determine_satiation_multiplier(preference); int hp_amt = 0; bool suppress_msg = false; // do we display the chunk nutrition message? - bool do_eat = false; + bool do_eat = true; if (you.species == SP_GHOUL) { @@ -1675,6 +1775,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, xom_is_stimulated(random2(100)); break; + case CE_POISON_CONTAM: + mpr("Yeeuch - this meat is poisonous!"); + if (poison_player(3 + random2(4), "", "poisonous meat")) + xom_is_stimulated(random2(128)); + // fall through case CE_ROTTEN: case CE_CONTAMINATED: if (player_mutation_level(MUT_SAPROVOROUS) == 3) @@ -1684,8 +1789,6 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, if (you.species == SP_GHOUL) _heal_from_food(hp_amt, 0, !one_chance_in(4), one_chance_in(5)); - - do_eat = true; } else { @@ -1712,10 +1815,8 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, else _say_chunk_flavour(likes_chunks); - do_eat = true; break; - case CE_POISON_CONTAM: // _determine_chunk_effect should never return this case CE_MUTAGEN_GOOD: case CE_NOCORPSE: case CE_RANDOM: @@ -1738,13 +1839,10 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, } } -static void _eating(object_class_type item_class, int item_type) +static void _eat_nonchunk(object_class_type item_class, int item_type) { int food_value = 0; - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); - int carnivore_modifier = 0; - int herbivore_modifier = 0; + int preference = 0; switch (item_class) { @@ -1754,108 +1852,58 @@ static void _eating(object_class_type item_class, int item_type) { case FOOD_MEAT_RATION: case FOOD_ROYAL_JELLY: - food_value = 5000; + food_value = 4000; break; case FOOD_BREAD_RATION: - food_value = 4400; + food_value = 3500; break; case FOOD_AMBROSIA: - food_value = 2500; + food_value = 2000; break; case FOOD_HONEYCOMB: - food_value = 2000; + food_value = 1600; break; case FOOD_SNOZZCUMBER: // Maybe a nasty side-effect from RD's book? // I'd like that, but I don't dare. (jpeg) case FOOD_PIZZA: case FOOD_BEEF_JERKY: - food_value = 1500; + food_value = 1200; break; case FOOD_CHEESE: case FOOD_SAUSAGE: - food_value = 1200; + food_value = 1000; break; case FOOD_ORANGE: case FOOD_BANANA: case FOOD_LEMON: - food_value = 1000; + food_value = 800; break; case FOOD_PEAR: case FOOD_APPLE: case FOOD_APRICOT: - food_value = 700; - break; - case FOOD_CHOKO: - case FOOD_RAMBUTAN: - case FOOD_LYCHEE: food_value = 600; break; - case FOOD_STRAWBERRY: - food_value = 200; - break; - case FOOD_GRAPE: - food_value = 100; - break; - case FOOD_SULTANA: - food_value = 70; // Will not save you from starvation. - break; - default: - break; - } - - // Next, sustenance modifier for carnivores/herbivores {dlb}: - switch (item_type) - { - case FOOD_MEAT_RATION: - carnivore_modifier = 500; - herbivore_modifier = -1500; - break; - case FOOD_BEEF_JERKY: - case FOOD_SAUSAGE: - carnivore_modifier = 200; - herbivore_modifier = -200; - break; - case FOOD_BREAD_RATION: - carnivore_modifier = -1000; - herbivore_modifier = 500; - break; - case FOOD_BANANA: - case FOOD_ORANGE: - case FOOD_LEMON: - carnivore_modifier = -300; - herbivore_modifier = 300; - break; - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_APRICOT: case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: case FOOD_RAMBUTAN: case FOOD_LYCHEE: - carnivore_modifier = -200; - herbivore_modifier = 200; + food_value = 550; break; case FOOD_STRAWBERRY: - carnivore_modifier = -50; - herbivore_modifier = 50; + food_value = 160; break; case FOOD_GRAPE: + food_value = 80; + break; case FOOD_SULTANA: - carnivore_modifier = -20; - herbivore_modifier = 20; + food_value = 60; // Will not save you from starvation. break; default: - carnivore_modifier = 0; - herbivore_modifier = 0; break; } - // Finally, modify player's hunger level {dlb}: - if (carnivore_modifier && how_carnivorous > 0) - food_value += (carnivore_modifier * how_carnivorous); - - if (herbivore_modifier && how_herbivorous > 0) - food_value += (herbivore_modifier * how_herbivorous); + // multiply the base satiation by a value determined by how much the player likes the food + preference = get_preference_for_food_type(item_type); + food_value *= determine_satiation_multiplier(preference); if (food_value > 0) { @@ -2281,49 +2329,6 @@ bool causes_rot(const item_def &food) return (mons_corpse_effect(food.plus) == CE_ROT); } -// Returns 1 for herbivores, -1 for carnivores and 0 for either. -static int _player_likes_food_type(int type) -{ - switch (static_cast<food_type>(type)) - { - case FOOD_BREAD_RATION: - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: - case FOOD_APRICOT: - case FOOD_ORANGE: - case FOOD_BANANA: - case FOOD_STRAWBERRY: - case FOOD_RAMBUTAN: - case FOOD_LEMON: - case FOOD_GRAPE: - case FOOD_SULTANA: - case FOOD_LYCHEE: - return 1; - - case FOOD_CHUNK: - case FOOD_MEAT_RATION: - case FOOD_SAUSAGE: - case FOOD_BEEF_JERKY: - return -1; - - case FOOD_HONEYCOMB: - case FOOD_ROYAL_JELLY: - case FOOD_AMBROSIA: - case FOOD_CHEESE: - case FOOD_PIZZA: - return 0; - - case NUM_FOODS: - mpr("Bad food type", MSGCH_ERROR); - return 0; - } - - mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); - return 0; -} - // Returns true if an item of basetype FOOD or CORPSES cannot currently // be eaten (respecting species and mutations set). bool is_inedible(const item_def &item) @@ -2390,10 +2395,10 @@ bool is_preferred_food(const item_def &food) return (food_is_rotten(food)); if (player_mutation_level(MUT_CARNIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) < 0); + return (determine_plant_content(food.sub_type) < 0); if (player_mutation_level(MUT_HERBIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) > 0); + return (determine_plant_content(food.sub_type) > 0); // No food preference. return (false); @@ -2429,38 +2434,15 @@ bool is_forbidden_food(const item_def &food) return (false); } -bool check_amu_the_gourmand(bool reqid) -{ - if (wearing_amulet(AMU_THE_GOURMAND, !reqid)) - { - const int amulet = you.equip[EQ_AMULET]; - - ASSERT(amulet != -1); - - if (!item_type_known(you.inv[amulet])) - { - // For artefact amulets, this will tell you its name and - // subtype. Other properties may still be hidden. - set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); - set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); - mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); - } - - return (true); - } - - return (false); -} - bool can_ingest(const item_def &food, bool suppress_msg, bool reqid, bool check_hunger) { return can_ingest(food.base_type, food.sub_type, suppress_msg, reqid, - check_hunger, food_is_rotten(food)); + check_hunger, mons_corpse_effect(food.plus)); } bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, - bool reqid, bool check_hunger, bool rotten) + bool reqid, bool check_hunger, corpse_effect_type effect_type) { bool survey_says = false; @@ -2489,12 +2471,6 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool ur_carnivorous = player_mutation_level(MUT_CARNIVOROUS) == 3; bool ur_herbivorous = player_mutation_level(MUT_HERBIVOROUS) == 3; - // ur_chunkslover not defined in terms of ur_carnivorous because - // a player could be one and not the other IMHO - 13mar2000 {dlb} - bool ur_chunkslover = ((check_hunger ? you.hunger_state < HS_SATIATED - : true) - || player_likes_chunks(true)); - switch (what_isit) { case OBJ_FOOD: @@ -2506,8 +2482,15 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, return (false); } - const int vorous = _player_likes_food_type(kindof_thing); - if (vorous > 0) // Herbivorous food. + const int preference = get_preference_for_food_type(kindof_thing, effect_type); + + // not defined in terms of ur_carnivorous because + // a player could be one and not the other IMHO - 13mar2000 {dlb} + bool willing_to_eat = (check_hunger ? you.hunger <= determine_maximum_satiation(preference) : true); + + int plant_content = determine_plant_content(kindof_thing); + + if (plant_content > 0) // Herbivorous food. { if (ur_carnivorous) { @@ -2518,7 +2501,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, else return (true); } - else if (vorous < 0) // Carnivorous food. + else if (plant_content < 0) // Carnivorous food. { if (ur_herbivorous) { @@ -2528,13 +2511,10 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } else if (kindof_thing == FOOD_CHUNK) { - if (rotten && !_player_can_eat_rotten_meat(!suppress_msg)) + if (effect_type == CE_ROTTEN && !_player_can_eat_rotten_meat(!suppress_msg)) return (false); - if (ur_chunkslover) - return (true); - - if (check_amu_the_gourmand(reqid)) + if (willing_to_eat) return (true); if (!suppress_msg) @@ -2544,8 +2524,18 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } } // Any food types not specifically handled until here (e.g. meat - // rations for non-herbivores) are okay. - return (true); + // rations for non-herbivores) are okay as long as your preference . + if (willing_to_eat) + { + return (true); + } + else + { + if (!suppress_msg) + mpr("You aren't quite hungry enough to eat that!"); + + return (false); + } } case OBJ_CORPSES: @@ -2640,7 +2630,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, case CE_POISON_CONTAM: if (player_res_poison() <= 0) { - chunktype = CE_POISONOUS; break; } else @@ -2709,28 +2698,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, } } - // 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. - if (wearing_amulet(AMU_THE_GOURMAND) - && x_chance_in_y(you.duration[DUR_GOURMAND], GOURMAND_MAX)) - { - if (player_mutation_level(MUT_SAPROVOROUS) == 3) - { - // [dshaligram] Level 3 saprovores relish contaminated meat. - if (chunktype == CE_CLEAN) - chunktype = CE_CONTAMINATED; - } - else - { - // [dshaligram] New AotG behaviour - contaminated chunks become - // clean, but rotten chunks remain rotten. - if (chunktype == CE_CONTAMINATED) - chunktype = CE_CLEAN; - } - } - return (chunktype); } diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h index e79ba9f..f0551de 100644 --- a/crawl-ref/source/food.h +++ b/crawl-ref/source/food.h @@ -35,8 +35,15 @@ enum food_type NUM_FOODS // 23 }; -#define BERSERK_NUTRITION 700 -#define HUNGER_STARVING 1000 +#define BERSERK_NUTRITION 700 +#define HUNGER_STARVING 1000 +#define HUNGER_NEAR_STARVING 1533 +#define HUNGER_VERY_HUNGRY 2066 +#define HUNGER_HUNGRY 2600 +#define HUNGER_SATIATED 7000 +#define HUNGER_FULL 9000 +#define HUNGER_VERY_FULL 11000 +#define HUNGER_ENGORGED 12000 int count_corpses_in_pack(bool blood_only = false); bool butchery(int which_corpse = -1, bool bottle_blood = false); @@ -60,13 +67,12 @@ bool causes_rot(const item_def &food); bool is_inedible(const item_def &item); bool is_preferred_food(const item_def &food); bool is_forbidden_food(const item_def &food); -bool check_amu_the_gourmand(bool reqid); bool can_ingest(const item_def &food, bool suppress_msg, bool reqid = false, bool check_hunger = true); bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid = false, bool check_hunger = true, - bool rotten = false); + corpse_effect_type effect_type = CE_CLEAN); bool chunk_is_poisonous(int chunktype); void eat_floor_item(int item_link); diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index 07ba699..239c1f2 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -20,7 +20,6 @@ #include "artefact.h" #include "colour.h" #include "decks.h" -#include "food.h" #include "goditem.h" #include "invent.h" #include "item_use.h" @@ -42,7 +41,7 @@ #include "stuff.h" #include "env.h" #include "transform.h" - +#include "food.h" static bool _is_random_name_space(char let); static bool _is_random_name_vowel(char let); diff --git a/crawl-ref/source/l_food.cc b/crawl-ref/source/l_food.cc index 089390b..8cbc00e 100644 --- a/crawl-ref/source/l_food.cc +++ b/crawl-ref/source/l_food.cc @@ -3,11 +3,12 @@ #include "cluautil.h" #include "l_libs.h" -#include "food.h" #include "invent.h" #include "itemprop.h" #include "items.h" #include "player.h" +#include "mon-util.h" +#include "food.h" ///////////////////////////////////////////////////////////////////// // Food information. diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 8b1a332..ed84c6c 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -136,7 +136,7 @@ static void _create_monster_hide(const item_def corpse) int get_max_corpse_chunks(int mons_class) { - return (mons_weight(mons_class) / 150); + return (mons_weight(mons_class) / 300); } void turn_corpse_into_skeleton(item_def &item) diff --git a/crawl-ref/source/potion.cc b/crawl-ref/source/potion.cc index 0dbf839..76e98ff 100644 --- a/crawl-ref/source/potion.cc +++ b/crawl-ref/source/potion.cc @@ -133,14 +133,11 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) const int value = 200; const int herbivorous = player_mutation_level(MUT_HERBIVOROUS); - if (herbivorous < 3 && player_likes_chunks()) + if (herbivorous < 3 && player_likes_chunks(true)) { // Likes it. mpr("This tastes like blood."); lessen_hunger(value, true); - - if (!player_likes_chunks(true)) - check_amu_the_gourmand(false); } else { diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 24b953f..1542d3f 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -13,7 +13,6 @@ #include "coordit.h" #include "files.h" #include "fixedarray.h" -#include "food.h" #include "branch.h" #include "command.h" #include "cio.h" @@ -51,6 +50,7 @@ #include "travel.h" #include "hints.h" #include "view.h" +#include "food.h" #include <algorithm> #include <set> -- 1.7.5.GIT 0001-0004226-Food-reform_v3.patch [^] (27,987 bytes) 2011-10-01 07:05 [Show Content] [Hide Content] From aa044d5550985159fa7790df8a1e81e04b89b3eb Mon Sep 17 00:00:00 2001 From: Ryak <ryak2002@hotmail.com> Date: Sun, 17 Jul 2011 01:49:53 -0500 Subject: [PATCH] 0004226: Food reform --- crawl-ref/source/food.cc | 478 ++++++++++++++++++++---------------------- crawl-ref/source/food.h | 14 +- crawl-ref/source/itemname.cc | 3 +- crawl-ref/source/l_food.cc | 3 +- crawl-ref/source/misc.cc | 2 +- crawl-ref/source/potion.cc | 5 +- crawl-ref/source/travel.cc | 2 +- 7 files changed, 247 insertions(+), 260 deletions(-) diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index 2ca2be5..77ba156 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -5,7 +5,7 @@ #include "AppHdr.h" -#include "food.h" + #include <sstream> @@ -52,11 +52,13 @@ #include "travel.h" #include "xom.h" +#include "food.h" + static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, bool rotten_chunk); static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel = 0, bool holy = false); -static void _eating(object_class_type item_class, int item_type); +static void _eat_nonchunk(object_class_type item_class, int item_type); static void _describe_food_change(int hunger_increment); static bool _vampire_consume_corpse(int slot, bool invent); static void _heal_from_food(int hp_amt, int mp_amt = 0, bool unrot = false, @@ -111,8 +113,8 @@ void lessen_hunger(int satiated_amount, bool suppress_msg) you.hunger += satiated_amount; - if (you.hunger > 12000) - you.hunger = 12000; + if (you.hunger > HUNGER_ENGORGED) + you.hunger = HUNGER_ENGORGED; // So we don't get two messages, ever. bool state_message = food_change(); @@ -707,6 +709,84 @@ bool eat_food(int slot) // END PUBLIC FUNCTIONS +static int determine_maximum_satiation(int preference) +{ + switch (preference) + { + case -2: return HUNGER_NEAR_STARVING; + case -1: return HUNGER_VERY_HUNGRY; + case 0: return HUNGER_HUNGRY; + case 1: return HUNGER_SATIATED; + case 2: return HUNGER_FULL; + } + if (preference > 2) + return HUNGER_VERY_FULL; + + return 0; // cannot ever eat +} + +static float determine_satiation_multiplier(int preference) +{ + if (preference < -2) + { + return 0; + } + switch (preference) + { + case -2: return 0.3334; + case -1: return 0.6667; + case 0: return 1; + case 1: return 1.1; + case 2: return 1.2; + case 3: return 1.5; + case 4: return 2.4; + default: return 3; + } +} + +// Returns 1 for herbivores, -1 for carnivores and 0 for either. +static int determine_plant_content(int type) +{ + switch (type) + { + case FOOD_BREAD_RATION: + case FOOD_PEAR: + case FOOD_APPLE: + case FOOD_CHOKO: + case FOOD_SNOZZCUMBER: + case FOOD_APRICOT: + case FOOD_ORANGE: + case FOOD_BANANA: + case FOOD_STRAWBERRY: + case FOOD_RAMBUTAN: + case FOOD_LEMON: + case FOOD_GRAPE: + case FOOD_SULTANA: + case FOOD_LYCHEE: + return 1; + + case FOOD_CHUNK: + case FOOD_MEAT_RATION: + case FOOD_SAUSAGE: + case FOOD_BEEF_JERKY: + return -1; + + case FOOD_HONEYCOMB: + case FOOD_ROYAL_JELLY: + case FOOD_AMBROSIA: + case FOOD_CHEESE: + case FOOD_PIZZA: + return 0; + + case NUM_FOODS: + mpr("Bad food type", MSGCH_ERROR); + return 0; + } + + mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); + return 0; +} + static bool _player_has_enough_food() { int food_value = 0; @@ -782,19 +862,19 @@ bool food_change(bool suppress_message) you.hunger = std::min(you_max_hunger(), you.hunger); // Get new hunger state. - if (you.hunger <= 1000) + if (you.hunger <= HUNGER_STARVING) newstate = HS_STARVING; - else if (you.hunger <= 1533) + else if (you.hunger <= HUNGER_NEAR_STARVING) newstate = HS_NEAR_STARVING; - else if (you.hunger <= 2066) + else if (you.hunger <= HUNGER_VERY_HUNGRY) newstate = HS_VERY_HUNGRY; - else if (you.hunger <= 2600) + else if (you.hunger <= HUNGER_HUNGRY) newstate = HS_HUNGRY; - else if (you.hunger < 7000) + else if (you.hunger < HUNGER_SATIATED) newstate = HS_SATIATED; - else if (you.hunger < 9000) + else if (you.hunger < HUNGER_FULL) newstate = HS_FULL; - else if (you.hunger < 11000) + else if (you.hunger < HUNGER_VERY_FULL) newstate = HS_VERY_FULL; if (newstate != you.hunger_state) @@ -970,7 +1050,7 @@ void eat_inventory_item(int which_inventory_slot) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; dec_inv_item_quantity(which_inventory_slot, 1); @@ -1004,7 +1084,7 @@ void eat_floor_item(int item_link) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; @@ -1060,6 +1140,82 @@ public: } }; +int get_preference_for_food_type(int type, corpse_effect_type effect_type = CE_CLEAN) +{ + int preference = 0; + int saprovorous = player_mutation_level(MUT_SAPROVOROUS); + + // Royal Jelly can always be eaten. It needs a total of +3 to guarentee this + if (type == FOOD_ROYAL_JELLY) + preference += 1; + + // permafood gets a +2 bonus + if (type != FOOD_CHUNK) + preference += 2; + else + { + // unclean chunks get a penalty (If you are immune to the effect, we will be passed + // clean even if the original chunk wasn't clean [except rotting]) + switch (effect_type) + { + case CE_CLEAN: break; + case CE_CONTAMINATED: + case CE_POISONOUS: + case CE_POISON_CONTAM: + case CE_ROT: + case CE_MUTAGEN_RANDOM: + case CE_MUTAGEN_GOOD: + case CE_MUTAGEN_BAD: preference -= 1; + break; + case CE_ROTTEN: if (saprovorous == 0) + preference -= 2; + else if (saprovorous == 1 || saprovorous == 2) + preference -= 1; + break; + case CE_NOCORPSE: + case CE_RANDOM: + break; + } + } + + int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); + int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); + int plant_content = determine_plant_content(type); + + // bonus/penalty of your mutation level for matching/conflicting food type + preference += how_herbivorous * plant_content; + preference -= how_carnivorous * plant_content; + + // -1 more for "incompatible" permafood. + if (type != FOOD_CHUNK && ((how_herbivorous > 0 && plant_content < 0) || (how_carnivorous > 0 && plant_content > 0))) + { + preference--; + } + + // gourmand - (only affects chunks) + if (type == FOOD_CHUNK && wearing_amulet(AMU_THE_GOURMAND), true) + { + if (you.duration[DUR_GOURMAND] > GOURMAND_MAX) + { + preference++; + + // If you're wearing it and it activates, it should auto-id + const int amulet = you.equip[EQ_AMULET]; + ASSERT(amulet != -1); + if (!item_type_known(you.inv[amulet])) + { + // For artefact amulets, this will tell you its name and + // subtype. Other properties may still be hidden. + set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); + set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); + mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); + } + } + } + + return preference; +} + // Returns -1 for cancel, 1 for eaten, 0 for not eaten. int eat_from_floor(bool skip_chunks) { @@ -1371,14 +1527,7 @@ int prompt_eat_chunks(bool only_auto) if (player_mutation_level(MUT_HERBIVOROUS) == 3) return (0); - // If we *know* the player can eat chunks, doesn't have the gourmand - // effect and isn't hungry, don't prompt for chunks. - if (you.species != SP_VAMPIRE && !player_likes_chunks(true) - && !wearing_amulet(AMU_THE_GOURMAND, false) - && you.hunger_state >= HS_SATIATED) - { - return (0); - } + bool found_valid = false; std::vector<item_def *> chunks; @@ -1406,6 +1555,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*si)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(si->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(&(*si)); } @@ -1436,6 +1589,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*item)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(item->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(item); } @@ -1583,47 +1740,6 @@ void chunk_nutrition_message(int nutrition) mpr("That was not very filling."); } -static int _apply_herbivore_nutrition_effects(int nutrition) -{ - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - - while (how_herbivorous--) - nutrition = nutrition * 80 / 100; - - return (nutrition); -} - -static int _apply_gourmand_nutrition_effects(int nutrition, int gourmand) -{ - return (nutrition * (gourmand + GOURMAND_NUTRITION_BASE) - / (GOURMAND_MAX + GOURMAND_NUTRITION_BASE)); -} - -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_nutrition_effects(nutrition)); - } - - const int gourmand = - wearing_amulet(AMU_THE_GOURMAND) ? you.duration[DUR_GOURMAND] : 0; - const int effective_nutrition = - _apply_gourmand_nutrition_effects(nutrition, gourmand); - -#ifdef DEBUG_DIAGNOSTICS - const int epercent = effective_nutrition * 100 / nutrition; - mprf(MSGCH_DIAGNOSTICS, - "Gourmand factor: %d, chunk base: %d, effective: %d, %%: %d", - gourmand, nutrition, effective_nutrition, epercent); -#endif - - return (_apply_herbivore_nutrition_effects(effective_nutrition)); -} - static void _say_chunk_flavour(bool likes_chunks) { mprf("This raw flesh %s", _chunk_flavour_phrase(likes_chunks)); @@ -1635,10 +1751,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel, bool holy) { bool likes_chunks = player_likes_chunks(true); - int nutrition = _chunk_nutrition(likes_chunks); + int preference = get_preference_for_food_type(FOOD_CHUNK, chunk_effect); + int nutrition = CHUNK_BASE_NUTRITION * determine_satiation_multiplier(preference); int hp_amt = 0; bool suppress_msg = false; // do we display the chunk nutrition message? - bool do_eat = false; + bool do_eat = true; if (you.species == SP_GHOUL) { @@ -1675,6 +1792,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, xom_is_stimulated(random2(100)); break; + case CE_POISON_CONTAM: + mpr("Yeeuch - this meat is poisonous!"); + if (poison_player(3 + random2(4), "", "poisonous meat")) + xom_is_stimulated(random2(128)); + // fall through case CE_ROTTEN: case CE_CONTAMINATED: if (player_mutation_level(MUT_SAPROVOROUS) == 3) @@ -1684,8 +1806,6 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, if (you.species == SP_GHOUL) _heal_from_food(hp_amt, 0, !one_chance_in(4), one_chance_in(5)); - - do_eat = true; } else { @@ -1712,10 +1832,8 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, else _say_chunk_flavour(likes_chunks); - do_eat = true; break; - case CE_POISON_CONTAM: // _determine_chunk_effect should never return this case CE_MUTAGEN_GOOD: case CE_NOCORPSE: case CE_RANDOM: @@ -1738,13 +1856,10 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, } } -static void _eating(object_class_type item_class, int item_type) +static void _eat_nonchunk(object_class_type item_class, int item_type) { int food_value = 0; - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); - int carnivore_modifier = 0; - int herbivore_modifier = 0; + int preference = 0; switch (item_class) { @@ -1754,108 +1869,58 @@ static void _eating(object_class_type item_class, int item_type) { case FOOD_MEAT_RATION: case FOOD_ROYAL_JELLY: - food_value = 5000; + food_value = 4000; break; case FOOD_BREAD_RATION: - food_value = 4400; + food_value = 3666; break; case FOOD_AMBROSIA: - food_value = 2500; + food_value = 2000; break; case FOOD_HONEYCOMB: - food_value = 2000; + food_value = 1666; break; case FOOD_SNOZZCUMBER: // Maybe a nasty side-effect from RD's book? // I'd like that, but I don't dare. (jpeg) case FOOD_PIZZA: case FOOD_BEEF_JERKY: - food_value = 1500; + food_value = 1200; break; case FOOD_CHEESE: case FOOD_SAUSAGE: - food_value = 1200; + food_value = 1000; break; case FOOD_ORANGE: case FOOD_BANANA: case FOOD_LEMON: - food_value = 1000; + food_value = 800; break; case FOOD_PEAR: case FOOD_APPLE: case FOOD_APRICOT: - food_value = 700; - break; - case FOOD_CHOKO: - case FOOD_RAMBUTAN: - case FOOD_LYCHEE: food_value = 600; break; - case FOOD_STRAWBERRY: - food_value = 200; - break; - case FOOD_GRAPE: - food_value = 100; - break; - case FOOD_SULTANA: - food_value = 70; // Will not save you from starvation. - break; - default: - break; - } - - // Next, sustenance modifier for carnivores/herbivores {dlb}: - switch (item_type) - { - case FOOD_MEAT_RATION: - carnivore_modifier = 500; - herbivore_modifier = -1500; - break; - case FOOD_BEEF_JERKY: - case FOOD_SAUSAGE: - carnivore_modifier = 200; - herbivore_modifier = -200; - break; - case FOOD_BREAD_RATION: - carnivore_modifier = -1000; - herbivore_modifier = 500; - break; - case FOOD_BANANA: - case FOOD_ORANGE: - case FOOD_LEMON: - carnivore_modifier = -300; - herbivore_modifier = 300; - break; - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_APRICOT: case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: case FOOD_RAMBUTAN: case FOOD_LYCHEE: - carnivore_modifier = -200; - herbivore_modifier = 200; + food_value = 550; break; case FOOD_STRAWBERRY: - carnivore_modifier = -50; - herbivore_modifier = 50; + food_value = 160; break; case FOOD_GRAPE: + food_value = 80; + break; case FOOD_SULTANA: - carnivore_modifier = -20; - herbivore_modifier = 20; + food_value = 60; // Will not save you from starvation. break; default: - carnivore_modifier = 0; - herbivore_modifier = 0; break; } - // Finally, modify player's hunger level {dlb}: - if (carnivore_modifier && how_carnivorous > 0) - food_value += (carnivore_modifier * how_carnivorous); - - if (herbivore_modifier && how_herbivorous > 0) - food_value += (herbivore_modifier * how_herbivorous); + // multiply the base satiation by a value determined by how much the player likes the food + preference = get_preference_for_food_type(item_type); + food_value *= determine_satiation_multiplier(preference); if (food_value > 0) { @@ -2281,49 +2346,6 @@ bool causes_rot(const item_def &food) return (mons_corpse_effect(food.plus) == CE_ROT); } -// Returns 1 for herbivores, -1 for carnivores and 0 for either. -static int _player_likes_food_type(int type) -{ - switch (static_cast<food_type>(type)) - { - case FOOD_BREAD_RATION: - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: - case FOOD_APRICOT: - case FOOD_ORANGE: - case FOOD_BANANA: - case FOOD_STRAWBERRY: - case FOOD_RAMBUTAN: - case FOOD_LEMON: - case FOOD_GRAPE: - case FOOD_SULTANA: - case FOOD_LYCHEE: - return 1; - - case FOOD_CHUNK: - case FOOD_MEAT_RATION: - case FOOD_SAUSAGE: - case FOOD_BEEF_JERKY: - return -1; - - case FOOD_HONEYCOMB: - case FOOD_ROYAL_JELLY: - case FOOD_AMBROSIA: - case FOOD_CHEESE: - case FOOD_PIZZA: - return 0; - - case NUM_FOODS: - mpr("Bad food type", MSGCH_ERROR); - return 0; - } - - mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); - return 0; -} - // Returns true if an item of basetype FOOD or CORPSES cannot currently // be eaten (respecting species and mutations set). bool is_inedible(const item_def &item) @@ -2390,10 +2412,10 @@ bool is_preferred_food(const item_def &food) return (food_is_rotten(food)); if (player_mutation_level(MUT_CARNIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) < 0); + return (determine_plant_content(food.sub_type) < 0); if (player_mutation_level(MUT_HERBIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) > 0); + return (determine_plant_content(food.sub_type) > 0); // No food preference. return (false); @@ -2429,38 +2451,15 @@ bool is_forbidden_food(const item_def &food) return (false); } -bool check_amu_the_gourmand(bool reqid) -{ - if (wearing_amulet(AMU_THE_GOURMAND, !reqid)) - { - const int amulet = you.equip[EQ_AMULET]; - - ASSERT(amulet != -1); - - if (!item_type_known(you.inv[amulet])) - { - // For artefact amulets, this will tell you its name and - // subtype. Other properties may still be hidden. - set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); - set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); - mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); - } - - return (true); - } - - return (false); -} - bool can_ingest(const item_def &food, bool suppress_msg, bool reqid, bool check_hunger) { return can_ingest(food.base_type, food.sub_type, suppress_msg, reqid, - check_hunger, food_is_rotten(food)); + check_hunger, mons_corpse_effect(food.plus)); } bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, - bool reqid, bool check_hunger, bool rotten) + bool reqid, bool check_hunger, corpse_effect_type effect_type) { bool survey_says = false; @@ -2489,12 +2488,6 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool ur_carnivorous = player_mutation_level(MUT_CARNIVOROUS) == 3; bool ur_herbivorous = player_mutation_level(MUT_HERBIVOROUS) == 3; - // ur_chunkslover not defined in terms of ur_carnivorous because - // a player could be one and not the other IMHO - 13mar2000 {dlb} - bool ur_chunkslover = ((check_hunger ? you.hunger_state < HS_SATIATED - : true) - || player_likes_chunks(true)); - switch (what_isit) { case OBJ_FOOD: @@ -2506,8 +2499,15 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, return (false); } - const int vorous = _player_likes_food_type(kindof_thing); - if (vorous > 0) // Herbivorous food. + const int preference = get_preference_for_food_type(kindof_thing, effect_type); + + // not defined in terms of ur_carnivorous because + // a player could be one and not the other IMHO - 13mar2000 {dlb} + bool willing_to_eat = (check_hunger ? you.hunger <= determine_maximum_satiation(preference) : true); + + int plant_content = determine_plant_content(kindof_thing); + + if (plant_content > 0) // Herbivorous food. { if (ur_carnivorous) { @@ -2518,7 +2518,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, else return (true); } - else if (vorous < 0) // Carnivorous food. + else if (plant_content < 0) // Carnivorous food. { if (ur_herbivorous) { @@ -2528,13 +2528,10 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } else if (kindof_thing == FOOD_CHUNK) { - if (rotten && !_player_can_eat_rotten_meat(!suppress_msg)) + if (effect_type == CE_ROTTEN && !_player_can_eat_rotten_meat(!suppress_msg)) return (false); - if (ur_chunkslover) - return (true); - - if (check_amu_the_gourmand(reqid)) + if (willing_to_eat) return (true); if (!suppress_msg) @@ -2544,8 +2541,18 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } } // Any food types not specifically handled until here (e.g. meat - // rations for non-herbivores) are okay. - return (true); + // rations for non-herbivores) are okay as long as your preference . + if (willing_to_eat) + { + return (true); + } + else + { + if (!suppress_msg) + mpr("You aren't quite hungry enough to eat that!"); + + return (false); + } } case OBJ_CORPSES: @@ -2640,7 +2647,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, case CE_POISON_CONTAM: if (player_res_poison() <= 0) { - chunktype = CE_POISONOUS; break; } else @@ -2709,28 +2715,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, } } - // 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. - if (wearing_amulet(AMU_THE_GOURMAND) - && x_chance_in_y(you.duration[DUR_GOURMAND], GOURMAND_MAX)) - { - if (player_mutation_level(MUT_SAPROVOROUS) == 3) - { - // [dshaligram] Level 3 saprovores relish contaminated meat. - if (chunktype == CE_CLEAN) - chunktype = CE_CONTAMINATED; - } - else - { - // [dshaligram] New AotG behaviour - contaminated chunks become - // clean, but rotten chunks remain rotten. - if (chunktype == CE_CONTAMINATED) - chunktype = CE_CLEAN; - } - } - return (chunktype); } diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h index e79ba9f..f0551de 100644 --- a/crawl-ref/source/food.h +++ b/crawl-ref/source/food.h @@ -35,8 +35,15 @@ enum food_type NUM_FOODS // 23 }; -#define BERSERK_NUTRITION 700 -#define HUNGER_STARVING 1000 +#define BERSERK_NUTRITION 700 +#define HUNGER_STARVING 1000 +#define HUNGER_NEAR_STARVING 1533 +#define HUNGER_VERY_HUNGRY 2066 +#define HUNGER_HUNGRY 2600 +#define HUNGER_SATIATED 7000 +#define HUNGER_FULL 9000 +#define HUNGER_VERY_FULL 11000 +#define HUNGER_ENGORGED 12000 int count_corpses_in_pack(bool blood_only = false); bool butchery(int which_corpse = -1, bool bottle_blood = false); @@ -60,13 +67,12 @@ bool causes_rot(const item_def &food); bool is_inedible(const item_def &item); bool is_preferred_food(const item_def &food); bool is_forbidden_food(const item_def &food); -bool check_amu_the_gourmand(bool reqid); bool can_ingest(const item_def &food, bool suppress_msg, bool reqid = false, bool check_hunger = true); bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid = false, bool check_hunger = true, - bool rotten = false); + corpse_effect_type effect_type = CE_CLEAN); bool chunk_is_poisonous(int chunktype); void eat_floor_item(int item_link); diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index 07ba699..239c1f2 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -20,7 +20,6 @@ #include "artefact.h" #include "colour.h" #include "decks.h" -#include "food.h" #include "goditem.h" #include "invent.h" #include "item_use.h" @@ -42,7 +41,7 @@ #include "stuff.h" #include "env.h" #include "transform.h" - +#include "food.h" static bool _is_random_name_space(char let); static bool _is_random_name_vowel(char let); diff --git a/crawl-ref/source/l_food.cc b/crawl-ref/source/l_food.cc index 089390b..8cbc00e 100644 --- a/crawl-ref/source/l_food.cc +++ b/crawl-ref/source/l_food.cc @@ -3,11 +3,12 @@ #include "cluautil.h" #include "l_libs.h" -#include "food.h" #include "invent.h" #include "itemprop.h" #include "items.h" #include "player.h" +#include "mon-util.h" +#include "food.h" ///////////////////////////////////////////////////////////////////// // Food information. diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 8b1a332..ed84c6c 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -136,7 +136,7 @@ static void _create_monster_hide(const item_def corpse) int get_max_corpse_chunks(int mons_class) { - return (mons_weight(mons_class) / 150); + return (mons_weight(mons_class) / 300); } void turn_corpse_into_skeleton(item_def &item) diff --git a/crawl-ref/source/potion.cc b/crawl-ref/source/potion.cc index 0dbf839..76e98ff 100644 --- a/crawl-ref/source/potion.cc +++ b/crawl-ref/source/potion.cc @@ -133,14 +133,11 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) const int value = 200; const int herbivorous = player_mutation_level(MUT_HERBIVOROUS); - if (herbivorous < 3 && player_likes_chunks()) + if (herbivorous < 3 && player_likes_chunks(true)) { // Likes it. mpr("This tastes like blood."); lessen_hunger(value, true); - - if (!player_likes_chunks(true)) - check_amu_the_gourmand(false); } else { diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 24b953f..1542d3f 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -13,7 +13,6 @@ #include "coordit.h" #include "files.h" #include "fixedarray.h" -#include "food.h" #include "branch.h" #include "command.h" #include "cio.h" @@ -51,6 +50,7 @@ #include "travel.h" #include "hints.h" #include "view.h" +#include "food.h" #include <algorithm> #include <set> -- 1.7.5.GIT 0001-0004226-Food-reform_v4.patch [^] (27,448 bytes) 2011-10-02 22:28 [Show Content] [Hide Content] From 6936ae461403d32414eb2631bf5b4c8882b831c5 Mon Sep 17 00:00:00 2001 From: Ryak <ryak2002@hotmail.com> Date: Sun, 17 Jul 2011 01:49:53 -0500 Subject: [PATCH] 0004226: Food reform --- crawl-ref/source/food.cc | 464 ++++++++++++++++++++---------------------- crawl-ref/source/food.h | 14 +- crawl-ref/source/itemname.cc | 3 +- crawl-ref/source/l_food.cc | 3 +- crawl-ref/source/misc.cc | 2 +- crawl-ref/source/potion.cc | 5 +- crawl-ref/source/travel.cc | 2 +- 7 files changed, 233 insertions(+), 260 deletions(-) diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index 2ca2be5..6a4f3fc 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -5,7 +5,7 @@ #include "AppHdr.h" -#include "food.h" + #include <sstream> @@ -52,11 +52,13 @@ #include "travel.h" #include "xom.h" +#include "food.h" + static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, bool rotten_chunk); static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel = 0, bool holy = false); -static void _eating(object_class_type item_class, int item_type); +static void _eat_nonchunk(object_class_type item_class, int item_type); static void _describe_food_change(int hunger_increment); static bool _vampire_consume_corpse(int slot, bool invent); static void _heal_from_food(int hp_amt, int mp_amt = 0, bool unrot = false, @@ -111,8 +113,8 @@ void lessen_hunger(int satiated_amount, bool suppress_msg) you.hunger += satiated_amount; - if (you.hunger > 12000) - you.hunger = 12000; + if (you.hunger > HUNGER_ENGORGED) + you.hunger = HUNGER_ENGORGED; // So we don't get two messages, ever. bool state_message = food_change(); @@ -707,6 +709,84 @@ bool eat_food(int slot) // END PUBLIC FUNCTIONS +static int determine_maximum_satiation(int preference) +{ + switch (preference) + { + case -2: return HUNGER_NEAR_STARVING; + case -1: return HUNGER_VERY_HUNGRY; + case 0: return HUNGER_HUNGRY; + case 1: return HUNGER_SATIATED; + case 2: return HUNGER_FULL; + } + if (preference > 2) + return HUNGER_VERY_FULL; + + return 0; // cannot ever eat +} + +static float determine_satiation_multiplier(int preference) +{ + if (preference < -2) + { + return 0; + } + switch (preference) + { + case -2: return 0.3334; + case -1: return 0.6667; + case 0: return 1; + case 1: return 1.1; + case 2: return 1.2; + case 3: return 1.5; + case 4: return 2.4; + default: return 3; + } +} + +// Returns 1 for herbivores, -1 for carnivores and 0 for either. +static int determine_plant_content(int type) +{ + switch (type) + { + case FOOD_BREAD_RATION: + case FOOD_PEAR: + case FOOD_APPLE: + case FOOD_CHOKO: + case FOOD_SNOZZCUMBER: + case FOOD_APRICOT: + case FOOD_ORANGE: + case FOOD_BANANA: + case FOOD_STRAWBERRY: + case FOOD_RAMBUTAN: + case FOOD_LEMON: + case FOOD_GRAPE: + case FOOD_SULTANA: + case FOOD_LYCHEE: + return 1; + + case FOOD_CHUNK: + case FOOD_MEAT_RATION: + case FOOD_SAUSAGE: + case FOOD_BEEF_JERKY: + return -1; + + case FOOD_HONEYCOMB: + case FOOD_ROYAL_JELLY: + case FOOD_AMBROSIA: + case FOOD_CHEESE: + case FOOD_PIZZA: + return 0; + + case NUM_FOODS: + mpr("Bad food type", MSGCH_ERROR); + return 0; + } + + mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); + return 0; +} + static bool _player_has_enough_food() { int food_value = 0; @@ -782,19 +862,19 @@ bool food_change(bool suppress_message) you.hunger = std::min(you_max_hunger(), you.hunger); // Get new hunger state. - if (you.hunger <= 1000) + if (you.hunger <= HUNGER_STARVING) newstate = HS_STARVING; - else if (you.hunger <= 1533) + else if (you.hunger <= HUNGER_NEAR_STARVING) newstate = HS_NEAR_STARVING; - else if (you.hunger <= 2066) + else if (you.hunger <= HUNGER_VERY_HUNGRY) newstate = HS_VERY_HUNGRY; - else if (you.hunger <= 2600) + else if (you.hunger <= HUNGER_HUNGRY) newstate = HS_HUNGRY; - else if (you.hunger < 7000) + else if (you.hunger < HUNGER_SATIATED) newstate = HS_SATIATED; - else if (you.hunger < 9000) + else if (you.hunger < HUNGER_FULL) newstate = HS_FULL; - else if (you.hunger < 11000) + else if (you.hunger < HUNGER_VERY_FULL) newstate = HS_VERY_FULL; if (newstate != you.hunger_state) @@ -970,7 +1050,7 @@ void eat_inventory_item(int which_inventory_slot) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; dec_inv_item_quantity(which_inventory_slot, 1); @@ -1004,7 +1084,7 @@ void eat_floor_item(int item_link) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; @@ -1060,6 +1140,68 @@ public: } }; +int get_preference_for_food_type(int type, corpse_effect_type effect_type = CE_CLEAN) +{ + int preference = 0; + int saprovorous = player_mutation_level(MUT_SAPROVOROUS); + int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); + int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); + + int plant_content = determine_plant_content(type); + + // bonus/penalty of your mutation level for matching/conflicting food type + preference += how_herbivorous * plant_content; + preference -= how_carnivorous * plant_content; + + // Royal Jelly can always be eaten. It needs a total of +3 to guarentee this + if (type == FOOD_ROYAL_JELLY) + { + preference += 1; + } + + + if (type != FOOD_CHUNK) + { + // permafood gets a +2 bonus for being delicious unless it is "incompatible" (meat for herbivores or plants for carnivores) + if (!((how_herbivorous > 0 && plant_content < 0) || (how_carnivorous > 0 && plant_content > 0))) + { + preference += 2; + } + } + else + { + // unclean chunks get a penalty (If you are immune to the effect, we will be passed + // clean even if the original chunk wasn't clean [except rotting]) + switch (effect_type) + { + case CE_CLEAN: break; + case CE_CONTAMINATED: + case CE_POISONOUS: + case CE_POISON_CONTAM: + case CE_ROT: + case CE_MUTAGEN_RANDOM: + case CE_MUTAGEN_GOOD: + case CE_MUTAGEN_BAD: preference -= 1; + break; + case CE_ROTTEN: if (saprovorous == 0) + preference -= 2; + else if (saprovorous == 1 || saprovorous == 2) + preference -= 1; + break; + case CE_NOCORPSE: + case CE_RANDOM: + break; + } + + // gourmand - (only affects chunks) + if (you.duration[DUR_GOURMAND] >= GOURMAND_MAX) + { + preference++; + } + } + return preference; +} + // Returns -1 for cancel, 1 for eaten, 0 for not eaten. int eat_from_floor(bool skip_chunks) { @@ -1371,14 +1513,7 @@ int prompt_eat_chunks(bool only_auto) if (player_mutation_level(MUT_HERBIVOROUS) == 3) return (0); - // If we *know* the player can eat chunks, doesn't have the gourmand - // effect and isn't hungry, don't prompt for chunks. - if (you.species != SP_VAMPIRE && !player_likes_chunks(true) - && !wearing_amulet(AMU_THE_GOURMAND, false) - && you.hunger_state >= HS_SATIATED) - { - return (0); - } + bool found_valid = false; std::vector<item_def *> chunks; @@ -1406,6 +1541,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*si)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(si->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(&(*si)); } @@ -1436,6 +1575,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*item)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(item->plus))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(item); } @@ -1583,47 +1726,6 @@ void chunk_nutrition_message(int nutrition) mpr("That was not very filling."); } -static int _apply_herbivore_nutrition_effects(int nutrition) -{ - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - - while (how_herbivorous--) - nutrition = nutrition * 80 / 100; - - return (nutrition); -} - -static int _apply_gourmand_nutrition_effects(int nutrition, int gourmand) -{ - return (nutrition * (gourmand + GOURMAND_NUTRITION_BASE) - / (GOURMAND_MAX + GOURMAND_NUTRITION_BASE)); -} - -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_nutrition_effects(nutrition)); - } - - const int gourmand = - wearing_amulet(AMU_THE_GOURMAND) ? you.duration[DUR_GOURMAND] : 0; - const int effective_nutrition = - _apply_gourmand_nutrition_effects(nutrition, gourmand); - -#ifdef DEBUG_DIAGNOSTICS - const int epercent = effective_nutrition * 100 / nutrition; - mprf(MSGCH_DIAGNOSTICS, - "Gourmand factor: %d, chunk base: %d, effective: %d, %%: %d", - gourmand, nutrition, effective_nutrition, epercent); -#endif - - return (_apply_herbivore_nutrition_effects(effective_nutrition)); -} - static void _say_chunk_flavour(bool likes_chunks) { mprf("This raw flesh %s", _chunk_flavour_phrase(likes_chunks)); @@ -1635,10 +1737,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel, bool holy) { bool likes_chunks = player_likes_chunks(true); - int nutrition = _chunk_nutrition(likes_chunks); + int preference = get_preference_for_food_type(FOOD_CHUNK, chunk_effect); + int nutrition = CHUNK_BASE_NUTRITION * determine_satiation_multiplier(preference); int hp_amt = 0; bool suppress_msg = false; // do we display the chunk nutrition message? - bool do_eat = false; + bool do_eat = true; if (you.species == SP_GHOUL) { @@ -1675,6 +1778,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, xom_is_stimulated(random2(100)); break; + case CE_POISON_CONTAM: + mpr("Yeeuch - this meat is poisonous!"); + if (poison_player(3 + random2(4), "", "poisonous meat")) + xom_is_stimulated(random2(128)); + // fall through case CE_ROTTEN: case CE_CONTAMINATED: if (player_mutation_level(MUT_SAPROVOROUS) == 3) @@ -1684,8 +1792,6 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, if (you.species == SP_GHOUL) _heal_from_food(hp_amt, 0, !one_chance_in(4), one_chance_in(5)); - - do_eat = true; } else { @@ -1712,10 +1818,8 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, else _say_chunk_flavour(likes_chunks); - do_eat = true; break; - case CE_POISON_CONTAM: // _determine_chunk_effect should never return this case CE_MUTAGEN_GOOD: case CE_NOCORPSE: case CE_RANDOM: @@ -1738,13 +1842,10 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, } } -static void _eating(object_class_type item_class, int item_type) +static void _eat_nonchunk(object_class_type item_class, int item_type) { int food_value = 0; - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); - int carnivore_modifier = 0; - int herbivore_modifier = 0; + int preference = 0; switch (item_class) { @@ -1754,108 +1855,58 @@ static void _eating(object_class_type item_class, int item_type) { case FOOD_MEAT_RATION: case FOOD_ROYAL_JELLY: - food_value = 5000; + food_value = 4000; break; case FOOD_BREAD_RATION: - food_value = 4400; + food_value = 3666; break; case FOOD_AMBROSIA: - food_value = 2500; + food_value = 2000; break; case FOOD_HONEYCOMB: - food_value = 2000; + food_value = 1666; break; case FOOD_SNOZZCUMBER: // Maybe a nasty side-effect from RD's book? // I'd like that, but I don't dare. (jpeg) case FOOD_PIZZA: case FOOD_BEEF_JERKY: - food_value = 1500; + food_value = 1200; break; case FOOD_CHEESE: case FOOD_SAUSAGE: - food_value = 1200; + food_value = 1000; break; case FOOD_ORANGE: case FOOD_BANANA: case FOOD_LEMON: - food_value = 1000; + food_value = 800; break; case FOOD_PEAR: case FOOD_APPLE: case FOOD_APRICOT: - food_value = 700; - break; - case FOOD_CHOKO: - case FOOD_RAMBUTAN: - case FOOD_LYCHEE: food_value = 600; break; - case FOOD_STRAWBERRY: - food_value = 200; - break; - case FOOD_GRAPE: - food_value = 100; - break; - case FOOD_SULTANA: - food_value = 70; // Will not save you from starvation. - break; - default: - break; - } - - // Next, sustenance modifier for carnivores/herbivores {dlb}: - switch (item_type) - { - case FOOD_MEAT_RATION: - carnivore_modifier = 500; - herbivore_modifier = -1500; - break; - case FOOD_BEEF_JERKY: - case FOOD_SAUSAGE: - carnivore_modifier = 200; - herbivore_modifier = -200; - break; - case FOOD_BREAD_RATION: - carnivore_modifier = -1000; - herbivore_modifier = 500; - break; - case FOOD_BANANA: - case FOOD_ORANGE: - case FOOD_LEMON: - carnivore_modifier = -300; - herbivore_modifier = 300; - break; - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_APRICOT: case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: case FOOD_RAMBUTAN: case FOOD_LYCHEE: - carnivore_modifier = -200; - herbivore_modifier = 200; + food_value = 550; break; case FOOD_STRAWBERRY: - carnivore_modifier = -50; - herbivore_modifier = 50; + food_value = 160; break; case FOOD_GRAPE: + food_value = 80; + break; case FOOD_SULTANA: - carnivore_modifier = -20; - herbivore_modifier = 20; + food_value = 60; // Will not save you from starvation. break; default: - carnivore_modifier = 0; - herbivore_modifier = 0; break; } - // Finally, modify player's hunger level {dlb}: - if (carnivore_modifier && how_carnivorous > 0) - food_value += (carnivore_modifier * how_carnivorous); - - if (herbivore_modifier && how_herbivorous > 0) - food_value += (herbivore_modifier * how_herbivorous); + // multiply the base satiation by a value determined by how much the player likes the food + preference = get_preference_for_food_type(item_type); + food_value *= determine_satiation_multiplier(preference); if (food_value > 0) { @@ -2281,49 +2332,6 @@ bool causes_rot(const item_def &food) return (mons_corpse_effect(food.plus) == CE_ROT); } -// Returns 1 for herbivores, -1 for carnivores and 0 for either. -static int _player_likes_food_type(int type) -{ - switch (static_cast<food_type>(type)) - { - case FOOD_BREAD_RATION: - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: - case FOOD_APRICOT: - case FOOD_ORANGE: - case FOOD_BANANA: - case FOOD_STRAWBERRY: - case FOOD_RAMBUTAN: - case FOOD_LEMON: - case FOOD_GRAPE: - case FOOD_SULTANA: - case FOOD_LYCHEE: - return 1; - - case FOOD_CHUNK: - case FOOD_MEAT_RATION: - case FOOD_SAUSAGE: - case FOOD_BEEF_JERKY: - return -1; - - case FOOD_HONEYCOMB: - case FOOD_ROYAL_JELLY: - case FOOD_AMBROSIA: - case FOOD_CHEESE: - case FOOD_PIZZA: - return 0; - - case NUM_FOODS: - mpr("Bad food type", MSGCH_ERROR); - return 0; - } - - mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); - return 0; -} - // Returns true if an item of basetype FOOD or CORPSES cannot currently // be eaten (respecting species and mutations set). bool is_inedible(const item_def &item) @@ -2390,10 +2398,10 @@ bool is_preferred_food(const item_def &food) return (food_is_rotten(food)); if (player_mutation_level(MUT_CARNIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) < 0); + return (determine_plant_content(food.sub_type) < 0); if (player_mutation_level(MUT_HERBIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) > 0); + return (determine_plant_content(food.sub_type) > 0); // No food preference. return (false); @@ -2429,38 +2437,15 @@ bool is_forbidden_food(const item_def &food) return (false); } -bool check_amu_the_gourmand(bool reqid) -{ - if (wearing_amulet(AMU_THE_GOURMAND, !reqid)) - { - const int amulet = you.equip[EQ_AMULET]; - - ASSERT(amulet != -1); - - if (!item_type_known(you.inv[amulet])) - { - // For artefact amulets, this will tell you its name and - // subtype. Other properties may still be hidden. - set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); - set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); - mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); - } - - return (true); - } - - return (false); -} - bool can_ingest(const item_def &food, bool suppress_msg, bool reqid, bool check_hunger) { return can_ingest(food.base_type, food.sub_type, suppress_msg, reqid, - check_hunger, food_is_rotten(food)); + check_hunger, mons_corpse_effect(food.plus)); } bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, - bool reqid, bool check_hunger, bool rotten) + bool reqid, bool check_hunger, corpse_effect_type effect_type) { bool survey_says = false; @@ -2489,12 +2474,6 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool ur_carnivorous = player_mutation_level(MUT_CARNIVOROUS) == 3; bool ur_herbivorous = player_mutation_level(MUT_HERBIVOROUS) == 3; - // ur_chunkslover not defined in terms of ur_carnivorous because - // a player could be one and not the other IMHO - 13mar2000 {dlb} - bool ur_chunkslover = ((check_hunger ? you.hunger_state < HS_SATIATED - : true) - || player_likes_chunks(true)); - switch (what_isit) { case OBJ_FOOD: @@ -2506,8 +2485,15 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, return (false); } - const int vorous = _player_likes_food_type(kindof_thing); - if (vorous > 0) // Herbivorous food. + const int preference = get_preference_for_food_type(kindof_thing, effect_type); + + // not defined in terms of ur_carnivorous because + // a player could be one and not the other IMHO - 13mar2000 {dlb} + bool willing_to_eat = (check_hunger ? you.hunger <= determine_maximum_satiation(preference) : true); + + int plant_content = determine_plant_content(kindof_thing); + + if (plant_content > 0) // Herbivorous food. { if (ur_carnivorous) { @@ -2518,7 +2504,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, else return (true); } - else if (vorous < 0) // Carnivorous food. + else if (plant_content < 0) // Carnivorous food. { if (ur_herbivorous) { @@ -2528,13 +2514,10 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } else if (kindof_thing == FOOD_CHUNK) { - if (rotten && !_player_can_eat_rotten_meat(!suppress_msg)) + if (effect_type == CE_ROTTEN && !_player_can_eat_rotten_meat(!suppress_msg)) return (false); - if (ur_chunkslover) - return (true); - - if (check_amu_the_gourmand(reqid)) + if (willing_to_eat) return (true); if (!suppress_msg) @@ -2544,8 +2527,18 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } } // Any food types not specifically handled until here (e.g. meat - // rations for non-herbivores) are okay. - return (true); + // rations for non-herbivores) are okay as long as your preference . + if (willing_to_eat) + { + return (true); + } + else + { + if (!suppress_msg) + mpr("You aren't quite hungry enough to eat that!"); + + return (false); + } } case OBJ_CORPSES: @@ -2640,7 +2633,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, case CE_POISON_CONTAM: if (player_res_poison() <= 0) { - chunktype = CE_POISONOUS; break; } else @@ -2709,28 +2701,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, } } - // 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. - if (wearing_amulet(AMU_THE_GOURMAND) - && x_chance_in_y(you.duration[DUR_GOURMAND], GOURMAND_MAX)) - { - if (player_mutation_level(MUT_SAPROVOROUS) == 3) - { - // [dshaligram] Level 3 saprovores relish contaminated meat. - if (chunktype == CE_CLEAN) - chunktype = CE_CONTAMINATED; - } - else - { - // [dshaligram] New AotG behaviour - contaminated chunks become - // clean, but rotten chunks remain rotten. - if (chunktype == CE_CONTAMINATED) - chunktype = CE_CLEAN; - } - } - return (chunktype); } diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h index e79ba9f..f0551de 100644 --- a/crawl-ref/source/food.h +++ b/crawl-ref/source/food.h @@ -35,8 +35,15 @@ enum food_type NUM_FOODS // 23 }; -#define BERSERK_NUTRITION 700 -#define HUNGER_STARVING 1000 +#define BERSERK_NUTRITION 700 +#define HUNGER_STARVING 1000 +#define HUNGER_NEAR_STARVING 1533 +#define HUNGER_VERY_HUNGRY 2066 +#define HUNGER_HUNGRY 2600 +#define HUNGER_SATIATED 7000 +#define HUNGER_FULL 9000 +#define HUNGER_VERY_FULL 11000 +#define HUNGER_ENGORGED 12000 int count_corpses_in_pack(bool blood_only = false); bool butchery(int which_corpse = -1, bool bottle_blood = false); @@ -60,13 +67,12 @@ bool causes_rot(const item_def &food); bool is_inedible(const item_def &item); bool is_preferred_food(const item_def &food); bool is_forbidden_food(const item_def &food); -bool check_amu_the_gourmand(bool reqid); bool can_ingest(const item_def &food, bool suppress_msg, bool reqid = false, bool check_hunger = true); bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid = false, bool check_hunger = true, - bool rotten = false); + corpse_effect_type effect_type = CE_CLEAN); bool chunk_is_poisonous(int chunktype); void eat_floor_item(int item_link); diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index 07ba699..239c1f2 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -20,7 +20,6 @@ #include "artefact.h" #include "colour.h" #include "decks.h" -#include "food.h" #include "goditem.h" #include "invent.h" #include "item_use.h" @@ -42,7 +41,7 @@ #include "stuff.h" #include "env.h" #include "transform.h" - +#include "food.h" static bool _is_random_name_space(char let); static bool _is_random_name_vowel(char let); diff --git a/crawl-ref/source/l_food.cc b/crawl-ref/source/l_food.cc index 089390b..8cbc00e 100644 --- a/crawl-ref/source/l_food.cc +++ b/crawl-ref/source/l_food.cc @@ -3,11 +3,12 @@ #include "cluautil.h" #include "l_libs.h" -#include "food.h" #include "invent.h" #include "itemprop.h" #include "items.h" #include "player.h" +#include "mon-util.h" +#include "food.h" ///////////////////////////////////////////////////////////////////// // Food information. diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 8b1a332..ed84c6c 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -136,7 +136,7 @@ static void _create_monster_hide(const item_def corpse) int get_max_corpse_chunks(int mons_class) { - return (mons_weight(mons_class) / 150); + return (mons_weight(mons_class) / 300); } void turn_corpse_into_skeleton(item_def &item) diff --git a/crawl-ref/source/potion.cc b/crawl-ref/source/potion.cc index 0dbf839..76e98ff 100644 --- a/crawl-ref/source/potion.cc +++ b/crawl-ref/source/potion.cc @@ -133,14 +133,11 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) const int value = 200; const int herbivorous = player_mutation_level(MUT_HERBIVOROUS); - if (herbivorous < 3 && player_likes_chunks()) + if (herbivorous < 3 && player_likes_chunks(true)) { // Likes it. mpr("This tastes like blood."); lessen_hunger(value, true); - - if (!player_likes_chunks(true)) - check_amu_the_gourmand(false); } else { diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 24b953f..1542d3f 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -13,7 +13,6 @@ #include "coordit.h" #include "files.h" #include "fixedarray.h" -#include "food.h" #include "branch.h" #include "command.h" #include "cio.h" @@ -51,6 +50,7 @@ #include "travel.h" #include "hints.h" #include "view.h" +#include "food.h" #include <algorithm> #include <set> -- 1.7.5.GIT 0001-0004226-Food-reform_v5.patch [^] (26,986 bytes) 2011-10-03 05:09 [Show Content] [Hide Content] From c1830574a6787304133b790f5436e544ac7ea3c0 Mon Sep 17 00:00:00 2001 From: Ryak <ryak2002@hotmail.com> Date: Sun, 17 Jul 2011 01:49:53 -0500 Subject: [PATCH] 0004226: Food reform --- crawl-ref/source/food.cc | 462 +++++++++++++++++++++--------------------- crawl-ref/source/food.h | 12 +- crawl-ref/source/itemname.cc | 3 +- crawl-ref/source/l_food.cc | 3 +- crawl-ref/source/misc.cc | 2 +- crawl-ref/source/potion.cc | 5 +- crawl-ref/source/travel.cc | 2 +- 7 files changed, 241 insertions(+), 248 deletions(-) diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index 2ca2be5..628d164 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -5,7 +5,7 @@ #include "AppHdr.h" -#include "food.h" + #include <sstream> @@ -52,11 +52,13 @@ #include "travel.h" #include "xom.h" +#include "food.h" + static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, bool rotten_chunk); static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel = 0, bool holy = false); -static void _eating(object_class_type item_class, int item_type); +static void _eat_nonchunk(object_class_type item_class, int item_type); static void _describe_food_change(int hunger_increment); static bool _vampire_consume_corpse(int slot, bool invent); static void _heal_from_food(int hp_amt, int mp_amt = 0, bool unrot = false, @@ -111,8 +113,8 @@ void lessen_hunger(int satiated_amount, bool suppress_msg) you.hunger += satiated_amount; - if (you.hunger > 12000) - you.hunger = 12000; + if (you.hunger > HUNGER_ENGORGED) + you.hunger = HUNGER_ENGORGED; // So we don't get two messages, ever. bool state_message = food_change(); @@ -707,6 +709,100 @@ bool eat_food(int slot) // END PUBLIC FUNCTIONS +static int determine_maximum_satiation(int preference) +{ + if (preference < 0) + { + return 0; // cannot ever eat + } + switch (preference) + { + case 0: return HUNGER_NEAR_STARVING; + case 1: return HUNGER_VERY_HUNGRY; + case 2: return HUNGER_HUNGRY; + case 3: return HUNGER_SATIATED; + case 4: return HUNGER_FULL; + default: return HUNGER_VERY_FULL; + } +} + +static float determine_chunk_satiation_multiplier(int preference) +{ + if (preference < 0) + { + return 0; // 3 levels incompatible + } + switch (preference) + { + case 0: return 0.3334; // 2 levels incompatible + case 1: return 0.6667; // 1 level incompatible + case 2: return 1; // basic case + case 3: return 1.1; // 1 level compatible + case 4: return 1.2; // 2 levels compatible + default: return 1.5; // 3 levels compatible + } +} + +static float determine_permafood_satiation_multiplier(int preference) +{ + if (preference < 2) + { + return 0; // 3 levels incompatible + } + switch (preference) + { + case 2: return 0.3334; // 2 levels incompatible + case 3: return 0.6667; // 1 level incompatible + case 4: return 1; // basic case + case 5: return 1.5; // 1 level compatible + case 6: return 2; // 2 levels compatible + default: return 2.5; // 3 levels compatible + } +} + +// Returns 1 for herbivores, -1 for carnivores and 0 for either. +static int determine_plant_content(int type) +{ + switch (type) + { + case FOOD_BREAD_RATION: + case FOOD_PEAR: + case FOOD_APPLE: + case FOOD_CHOKO: + case FOOD_SNOZZCUMBER: + case FOOD_APRICOT: + case FOOD_ORANGE: + case FOOD_BANANA: + case FOOD_STRAWBERRY: + case FOOD_RAMBUTAN: + case FOOD_LEMON: + case FOOD_GRAPE: + case FOOD_SULTANA: + case FOOD_LYCHEE: + return 1; + + case FOOD_CHUNK: + case FOOD_MEAT_RATION: + case FOOD_SAUSAGE: + case FOOD_BEEF_JERKY: + return -1; + + case FOOD_HONEYCOMB: + case FOOD_ROYAL_JELLY: + case FOOD_AMBROSIA: + case FOOD_CHEESE: + case FOOD_PIZZA: + return 0; + + case NUM_FOODS: + mpr("Bad food type", MSGCH_ERROR); + return 0; + } + + mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); + return 0; +} + static bool _player_has_enough_food() { int food_value = 0; @@ -782,19 +878,19 @@ bool food_change(bool suppress_message) you.hunger = std::min(you_max_hunger(), you.hunger); // Get new hunger state. - if (you.hunger <= 1000) + if (you.hunger <= HUNGER_STARVING) newstate = HS_STARVING; - else if (you.hunger <= 1533) + else if (you.hunger <= HUNGER_NEAR_STARVING) newstate = HS_NEAR_STARVING; - else if (you.hunger <= 2066) + else if (you.hunger <= HUNGER_VERY_HUNGRY) newstate = HS_VERY_HUNGRY; - else if (you.hunger <= 2600) + else if (you.hunger <= HUNGER_HUNGRY) newstate = HS_HUNGRY; - else if (you.hunger < 7000) + else if (you.hunger < HUNGER_SATIATED) newstate = HS_SATIATED; - else if (you.hunger < 9000) + else if (you.hunger < HUNGER_FULL) newstate = HS_FULL; - else if (you.hunger < 11000) + else if (you.hunger < HUNGER_VERY_FULL) newstate = HS_VERY_FULL; if (newstate != you.hunger_state) @@ -970,7 +1066,7 @@ void eat_inventory_item(int which_inventory_slot) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; dec_inv_item_quantity(which_inventory_slot, 1); @@ -1004,7 +1100,7 @@ void eat_floor_item(int item_link) intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_nonchunk(food.base_type, food.sub_type); you.turn_is_over = true; @@ -1060,6 +1156,75 @@ public: } }; +int get_preference_for_food_type(int type, corpse_effect_type effect_type = CE_CLEAN, bool is_rotten = false) +{ + int preference = 2; + int saprovorous = player_mutation_level(MUT_SAPROVOROUS); + int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); + int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); + + int plant_content = determine_plant_content(type); + + // bonus/penalty of your mutation level for matching/conflicting food type + preference += how_herbivorous * plant_content; + preference -= how_carnivorous * plant_content; + + // Royal Jelly can always be eaten. It needs a total of +3 to guarentee this + if (type == FOOD_ROYAL_JELLY) + { + preference += 1; + } + + + if (type != FOOD_CHUNK) + { + // permafood gets a +2 bonus for being delicious + preference += 2; + } + else + { + // unclean chunks get a penalty (If you are immune to the effect, we will be passed + // clean even if the original chunk wasn't clean [except rotting]) + switch (effect_type) + { + case CE_CLEAN: break; + case CE_CONTAMINATED: + case CE_POISONOUS: + case CE_POISON_CONTAM: + case CE_ROT: + case CE_MUTAGEN_RANDOM: + case CE_MUTAGEN_GOOD: + case CE_MUTAGEN_BAD: preference -= 1; + break; + case CE_ROTTEN: is_rotten = true; + break; + case CE_NOCORPSE: + case CE_RANDOM: + break; + } + + // handle rotten food + if (is_rotten) + { + if (saprovorous == 0) + { + preference -= 2; + } + else if (saprovorous == 1 || saprovorous == 2) + { + preference -= 1; + } + } + + // gourmand - (only affects chunks) + if (you.duration[DUR_GOURMAND] >= GOURMAND_MAX) + { + preference++; + } + } + return preference; +} + // Returns -1 for cancel, 1 for eaten, 0 for not eaten. int eat_from_floor(bool skip_chunks) { @@ -1371,14 +1536,7 @@ int prompt_eat_chunks(bool only_auto) if (player_mutation_level(MUT_HERBIVOROUS) == 3) return (0); - // If we *know* the player can eat chunks, doesn't have the gourmand - // effect and isn't hungry, don't prompt for chunks. - if (you.species != SP_VAMPIRE && !player_likes_chunks(true) - && !wearing_amulet(AMU_THE_GOURMAND, false) - && you.hunger_state >= HS_SATIATED) - { - return (0); - } + bool found_valid = false; std::vector<item_def *> chunks; @@ -1406,6 +1564,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*si)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(si->plus), food_is_rotten(*si))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(&(*si)); } @@ -1436,6 +1598,10 @@ int prompt_eat_chunks(bool only_auto) if (is_bad_food(*item)) continue; + // You have to be hungry enough to consider eating a chunk + if (determine_maximum_satiation(get_preference_for_food_type(FOOD_CHUNK, mons_corpse_effect(item->plus), food_is_rotten(*item))) <= you.hunger) + continue; + found_valid = true; chunks.push_back(item); } @@ -1583,47 +1749,6 @@ void chunk_nutrition_message(int nutrition) mpr("That was not very filling."); } -static int _apply_herbivore_nutrition_effects(int nutrition) -{ - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - - while (how_herbivorous--) - nutrition = nutrition * 80 / 100; - - return (nutrition); -} - -static int _apply_gourmand_nutrition_effects(int nutrition, int gourmand) -{ - return (nutrition * (gourmand + GOURMAND_NUTRITION_BASE) - / (GOURMAND_MAX + GOURMAND_NUTRITION_BASE)); -} - -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_nutrition_effects(nutrition)); - } - - const int gourmand = - wearing_amulet(AMU_THE_GOURMAND) ? you.duration[DUR_GOURMAND] : 0; - const int effective_nutrition = - _apply_gourmand_nutrition_effects(nutrition, gourmand); - -#ifdef DEBUG_DIAGNOSTICS - const int epercent = effective_nutrition * 100 / nutrition; - mprf(MSGCH_DIAGNOSTICS, - "Gourmand factor: %d, chunk base: %d, effective: %d, %%: %d", - gourmand, nutrition, effective_nutrition, epercent); -#endif - - return (_apply_herbivore_nutrition_effects(effective_nutrition)); -} - static void _say_chunk_flavour(bool likes_chunks) { mprf("This raw flesh %s", _chunk_flavour_phrase(likes_chunks)); @@ -1635,10 +1760,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel, bool holy) { bool likes_chunks = player_likes_chunks(true); - int nutrition = _chunk_nutrition(likes_chunks); + int preference = get_preference_for_food_type(FOOD_CHUNK, chunk_effect); + int nutrition = CHUNK_BASE_NUTRITION * determine_chunk_satiation_multiplier(preference); int hp_amt = 0; bool suppress_msg = false; // do we display the chunk nutrition message? - bool do_eat = false; + bool do_eat = true; if (you.species == SP_GHOUL) { @@ -1675,6 +1801,11 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, xom_is_stimulated(random2(100)); break; + case CE_POISON_CONTAM: + mpr("Yeeuch - this meat is poisonous!"); + if (poison_player(3 + random2(4), "", "poisonous meat")) + xom_is_stimulated(random2(128)); + // fall through case CE_ROTTEN: case CE_CONTAMINATED: if (player_mutation_level(MUT_SAPROVOROUS) == 3) @@ -1684,8 +1815,6 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, if (you.species == SP_GHOUL) _heal_from_food(hp_amt, 0, !one_chance_in(4), one_chance_in(5)); - - do_eat = true; } else { @@ -1712,10 +1841,8 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, else _say_chunk_flavour(likes_chunks); - do_eat = true; break; - case CE_POISON_CONTAM: // _determine_chunk_effect should never return this case CE_MUTAGEN_GOOD: case CE_NOCORPSE: case CE_RANDOM: @@ -1738,13 +1865,10 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, } } -static void _eating(object_class_type item_class, int item_type) +static void _eat_nonchunk(object_class_type item_class, int item_type) { int food_value = 0; - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); - int carnivore_modifier = 0; - int herbivore_modifier = 0; + int preference = 0; switch (item_class) { @@ -1803,59 +1927,9 @@ static void _eating(object_class_type item_class, int item_type) break; } - // Next, sustenance modifier for carnivores/herbivores {dlb}: - switch (item_type) - { - case FOOD_MEAT_RATION: - carnivore_modifier = 500; - herbivore_modifier = -1500; - break; - case FOOD_BEEF_JERKY: - case FOOD_SAUSAGE: - carnivore_modifier = 200; - herbivore_modifier = -200; - break; - case FOOD_BREAD_RATION: - carnivore_modifier = -1000; - herbivore_modifier = 500; - break; - case FOOD_BANANA: - case FOOD_ORANGE: - case FOOD_LEMON: - carnivore_modifier = -300; - herbivore_modifier = 300; - break; - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_APRICOT: - case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: - case FOOD_RAMBUTAN: - case FOOD_LYCHEE: - carnivore_modifier = -200; - herbivore_modifier = 200; - break; - case FOOD_STRAWBERRY: - carnivore_modifier = -50; - herbivore_modifier = 50; - break; - case FOOD_GRAPE: - case FOOD_SULTANA: - carnivore_modifier = -20; - herbivore_modifier = 20; - break; - default: - carnivore_modifier = 0; - herbivore_modifier = 0; - break; - } - - // Finally, modify player's hunger level {dlb}: - if (carnivore_modifier && how_carnivorous > 0) - food_value += (carnivore_modifier * how_carnivorous); - - if (herbivore_modifier && how_herbivorous > 0) - food_value += (herbivore_modifier * how_herbivorous); + // multiply the base satiation by a value determined by how much the player likes the food + preference = get_preference_for_food_type(item_type); + food_value *= determine_permafood_satiation_multiplier(preference); if (food_value > 0) { @@ -2281,49 +2355,6 @@ bool causes_rot(const item_def &food) return (mons_corpse_effect(food.plus) == CE_ROT); } -// Returns 1 for herbivores, -1 for carnivores and 0 for either. -static int _player_likes_food_type(int type) -{ - switch (static_cast<food_type>(type)) - { - case FOOD_BREAD_RATION: - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: - case FOOD_APRICOT: - case FOOD_ORANGE: - case FOOD_BANANA: - case FOOD_STRAWBERRY: - case FOOD_RAMBUTAN: - case FOOD_LEMON: - case FOOD_GRAPE: - case FOOD_SULTANA: - case FOOD_LYCHEE: - return 1; - - case FOOD_CHUNK: - case FOOD_MEAT_RATION: - case FOOD_SAUSAGE: - case FOOD_BEEF_JERKY: - return -1; - - case FOOD_HONEYCOMB: - case FOOD_ROYAL_JELLY: - case FOOD_AMBROSIA: - case FOOD_CHEESE: - case FOOD_PIZZA: - return 0; - - case NUM_FOODS: - mpr("Bad food type", MSGCH_ERROR); - return 0; - } - - mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); - return 0; -} - // Returns true if an item of basetype FOOD or CORPSES cannot currently // be eaten (respecting species and mutations set). bool is_inedible(const item_def &item) @@ -2390,10 +2421,10 @@ bool is_preferred_food(const item_def &food) return (food_is_rotten(food)); if (player_mutation_level(MUT_CARNIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) < 0); + return (determine_plant_content(food.sub_type) < 0); if (player_mutation_level(MUT_HERBIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) > 0); + return (determine_plant_content(food.sub_type) > 0); // No food preference. return (false); @@ -2429,38 +2460,15 @@ bool is_forbidden_food(const item_def &food) return (false); } -bool check_amu_the_gourmand(bool reqid) -{ - if (wearing_amulet(AMU_THE_GOURMAND, !reqid)) - { - const int amulet = you.equip[EQ_AMULET]; - - ASSERT(amulet != -1); - - if (!item_type_known(you.inv[amulet])) - { - // For artefact amulets, this will tell you its name and - // subtype. Other properties may still be hidden. - set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); - set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); - mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); - } - - return (true); - } - - return (false); -} - bool can_ingest(const item_def &food, bool suppress_msg, bool reqid, bool check_hunger) { return can_ingest(food.base_type, food.sub_type, suppress_msg, reqid, - check_hunger, food_is_rotten(food)); + check_hunger, mons_corpse_effect(food.plus), food_is_rotten(food)); } bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, - bool reqid, bool check_hunger, bool rotten) + bool reqid, bool check_hunger, corpse_effect_type effect_type, bool is_rotten) { bool survey_says = false; @@ -2489,12 +2497,6 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool ur_carnivorous = player_mutation_level(MUT_CARNIVOROUS) == 3; bool ur_herbivorous = player_mutation_level(MUT_HERBIVOROUS) == 3; - // ur_chunkslover not defined in terms of ur_carnivorous because - // a player could be one and not the other IMHO - 13mar2000 {dlb} - bool ur_chunkslover = ((check_hunger ? you.hunger_state < HS_SATIATED - : true) - || player_likes_chunks(true)); - switch (what_isit) { case OBJ_FOOD: @@ -2506,8 +2508,14 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, return (false); } - const int vorous = _player_likes_food_type(kindof_thing); - if (vorous > 0) // Herbivorous food. + // First, we calculate how much we like this thing we are considering eating + // Then, based on that, we decide how hungry we would have to be to eat it + const int preference = get_preference_for_food_type(kindof_thing, effect_type, is_rotten); + bool willing_to_eat = (check_hunger ? you.hunger <= determine_maximum_satiation(preference) : true); + + int plant_content = determine_plant_content(kindof_thing); + + if (plant_content > 0) // Herbivorous food. { if (ur_carnivorous) { @@ -2518,7 +2526,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, else return (true); } - else if (vorous < 0) // Carnivorous food. + else if (plant_content < 0) // Carnivorous food. { if (ur_herbivorous) { @@ -2528,13 +2536,10 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } else if (kindof_thing == FOOD_CHUNK) { - if (rotten && !_player_can_eat_rotten_meat(!suppress_msg)) + if (is_rotten && !_player_can_eat_rotten_meat(!suppress_msg)) return (false); - if (ur_chunkslover) - return (true); - - if (check_amu_the_gourmand(reqid)) + if (willing_to_eat) return (true); if (!suppress_msg) @@ -2543,9 +2548,17 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, return (false); } } - // Any food types not specifically handled until here (e.g. meat - // rations for non-herbivores) are okay. - return (true); + if (willing_to_eat) // Food which is neither. + { + return (true); + } + else + { + if (!suppress_msg) + mpr("You aren't quite hungry enough to eat that!"); + + return (false); + } } case OBJ_CORPSES: @@ -2640,7 +2653,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, case CE_POISON_CONTAM: if (player_res_poison() <= 0) { - chunktype = CE_POISONOUS; break; } else @@ -2709,28 +2721,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, } } - // 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. - if (wearing_amulet(AMU_THE_GOURMAND) - && x_chance_in_y(you.duration[DUR_GOURMAND], GOURMAND_MAX)) - { - if (player_mutation_level(MUT_SAPROVOROUS) == 3) - { - // [dshaligram] Level 3 saprovores relish contaminated meat. - if (chunktype == CE_CLEAN) - chunktype = CE_CONTAMINATED; - } - else - { - // [dshaligram] New AotG behaviour - contaminated chunks become - // clean, but rotten chunks remain rotten. - if (chunktype == CE_CONTAMINATED) - chunktype = CE_CLEAN; - } - } - return (chunktype); } diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h index e79ba9f..9e9d1c6 100644 --- a/crawl-ref/source/food.h +++ b/crawl-ref/source/food.h @@ -36,7 +36,14 @@ enum food_type }; #define BERSERK_NUTRITION 700 -#define HUNGER_STARVING 1000 +#define HUNGER_STARVING 1000 +#define HUNGER_NEAR_STARVING 1533 +#define HUNGER_VERY_HUNGRY 2066 +#define HUNGER_HUNGRY 2600 +#define HUNGER_SATIATED 7000 +#define HUNGER_FULL 9000 +#define HUNGER_VERY_FULL 11000 +#define HUNGER_ENGORGED 12000 int count_corpses_in_pack(bool blood_only = false); bool butchery(int which_corpse = -1, bool bottle_blood = false); @@ -60,13 +67,12 @@ bool causes_rot(const item_def &food); bool is_inedible(const item_def &item); bool is_preferred_food(const item_def &food); bool is_forbidden_food(const item_def &food); -bool check_amu_the_gourmand(bool reqid); bool can_ingest(const item_def &food, bool suppress_msg, bool reqid = false, bool check_hunger = true); bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid = false, bool check_hunger = true, - bool rotten = false); + corpse_effect_type effect_type = CE_CLEAN, bool is_rotten = false); bool chunk_is_poisonous(int chunktype); void eat_floor_item(int item_link); diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index 07ba699..239c1f2 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -20,7 +20,6 @@ #include "artefact.h" #include "colour.h" #include "decks.h" -#include "food.h" #include "goditem.h" #include "invent.h" #include "item_use.h" @@ -42,7 +41,7 @@ #include "stuff.h" #include "env.h" #include "transform.h" - +#include "food.h" static bool _is_random_name_space(char let); static bool _is_random_name_vowel(char let); diff --git a/crawl-ref/source/l_food.cc b/crawl-ref/source/l_food.cc index 089390b..8cbc00e 100644 --- a/crawl-ref/source/l_food.cc +++ b/crawl-ref/source/l_food.cc @@ -3,11 +3,12 @@ #include "cluautil.h" #include "l_libs.h" -#include "food.h" #include "invent.h" #include "itemprop.h" #include "items.h" #include "player.h" +#include "mon-util.h" +#include "food.h" ///////////////////////////////////////////////////////////////////// // Food information. diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 8b1a332..ed84c6c 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -136,7 +136,7 @@ static void _create_monster_hide(const item_def corpse) int get_max_corpse_chunks(int mons_class) { - return (mons_weight(mons_class) / 150); + return (mons_weight(mons_class) / 300); } void turn_corpse_into_skeleton(item_def &item) diff --git a/crawl-ref/source/potion.cc b/crawl-ref/source/potion.cc index 0dbf839..76e98ff 100644 --- a/crawl-ref/source/potion.cc +++ b/crawl-ref/source/potion.cc @@ -133,14 +133,11 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) const int value = 200; const int herbivorous = player_mutation_level(MUT_HERBIVOROUS); - if (herbivorous < 3 && player_likes_chunks()) + if (herbivorous < 3 && player_likes_chunks(true)) { // Likes it. mpr("This tastes like blood."); lessen_hunger(value, true); - - if (!player_likes_chunks(true)) - check_amu_the_gourmand(false); } else { diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 24b953f..1542d3f 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -13,7 +13,6 @@ #include "coordit.h" #include "files.h" #include "fixedarray.h" -#include "food.h" #include "branch.h" #include "command.h" #include "cio.h" @@ -51,6 +50,7 @@ #include "travel.h" #include "hints.h" #include "view.h" +#include "food.h" #include <algorithm> #include <set> -- 1.7.5.GIT 0001-Food-reform_v6.patch [^] (36,759 bytes) 2011-10-03 17:24 [Show Content] [Hide Content] From 8ba0595e4f78cb52fc4e5783e2fe3e89780e4efe Mon Sep 17 00:00:00 2001 From: Raphael Langella <raphael.langella@gmail.com> Date: Mon, 3 Oct 2011 15:21:04 +0000 Subject: [PATCH] Food reform (#4226). Based on Ryak's implementation and Vintermann's design. https://crawl.develz.org/wiki/doku.php?id=dcss:brainstorm:misc:eating --- crawl-ref/source/food.cc | 693 ++++++++++++++++++--------------------- crawl-ref/source/food.h | 18 +- crawl-ref/source/main.cc | 2 +- crawl-ref/source/misc.cc | 2 +- crawl-ref/source/player-act.cc | 4 +- crawl-ref/source/potion.cc | 5 +- 6 files changed, 340 insertions(+), 384 deletions(-) diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc index a64b3a5..9d6868e 100644 --- a/crawl-ref/source/food.cc +++ b/crawl-ref/source/food.cc @@ -56,7 +56,7 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, bool rotten_chunk); static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel = 0, bool holy = false); -static void _eating(object_class_type item_class, int item_type); +static void _eat_permafood(int item_type); static void _describe_food_change(int hunger_increment); static bool _vampire_consume_corpse(int slot, bool invent); static void _heal_from_food(int hp_amt, int mp_amt = 0, bool unrot = false, @@ -111,8 +111,8 @@ void lessen_hunger(int satiated_amount, bool suppress_msg) you.hunger += satiated_amount; - if (you.hunger > 12000) - you.hunger = 12000; + if (you.hunger > HUNGER_ENGORGED) + you.hunger = HUNGER_ENGORGED; // So we don't get two messages, ever. bool state_message = food_change(); @@ -709,6 +709,97 @@ bool eat_food(int slot) // END PUBLIC FUNCTIONS +static int _maximum_satiation(int preference) +{ + if (preference < 0) + return 0; // cannot ever eat + + switch (preference) + { + case 0: return HS_NEAR_STARVING; + case 1: return HS_VERY_HUNGRY; + case 2: return HS_HUNGRY; + case 3: return HS_SATIATED; + case 4: return HS_FULL; + default: return HS_VERY_FULL; + } +} + +static float _chunk_satiation_multiplier(int preference) +{ + if (preference < 0) + return 0; // 3 levels incompatible + + switch (preference) + { + case 0: return (1.0 / 3.0); // 2 levels incompatible + case 1: return (2.0 / 3.0); // 1 level incompatible + case 2: return 1; // basic case + case 3: return 1.1; // 1 level compatible + case 4: return 1.2; // 2 levels compatible + default: return 1.5; // 3 levels compatible + } +} + +static float _permafood_satiation_multiplier(int preference) +{ + if (preference < 2) + return 0; // 3 levels incompatible + + switch (preference) + { + case 2: return (1.0 / 3.0); // 2 levels incompatible + case 3: return (2.0 / 3.0); // 1 level incompatible + case 4: return 1; // basic case + case 5: return 1.5; // 1 level compatible + case 6: return 2; // 2 levels compatible + default: return 2.5; // 3 levels compatible + } +} + +// Returns 1 for herbivores, -1 for carnivores and 0 for either. +static int _plant_content(int type) +{ + switch (type) + { + case FOOD_BREAD_RATION: + case FOOD_PEAR: + case FOOD_APPLE: + case FOOD_CHOKO: + case FOOD_SNOZZCUMBER: + case FOOD_APRICOT: + case FOOD_ORANGE: + case FOOD_BANANA: + case FOOD_STRAWBERRY: + case FOOD_RAMBUTAN: + case FOOD_LEMON: + case FOOD_GRAPE: + case FOOD_SULTANA: + case FOOD_LYCHEE: + return 1; + + case FOOD_CHUNK: + case FOOD_MEAT_RATION: + case FOOD_SAUSAGE: + case FOOD_BEEF_JERKY: + return -1; + + case FOOD_HONEYCOMB: + case FOOD_ROYAL_JELLY: + case FOOD_AMBROSIA: + case FOOD_CHEESE: + case FOOD_PIZZA: + return 0; + + case NUM_FOODS: + mpr("Bad food type", MSGCH_ERROR); + return 0; + } + + mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); + return 0; +} + static bool _player_has_enough_food() { int food_value = 0; @@ -784,19 +875,19 @@ bool food_change(bool suppress_message) you.hunger = std::min(you_max_hunger(), you.hunger); // Get new hunger state. - if (you.hunger <= 1000) + if (you.hunger <= HUNGER_STARVING) newstate = HS_STARVING; - else if (you.hunger <= 1533) + else if (you.hunger <= HUNGER_NEAR_STARVING) newstate = HS_NEAR_STARVING; - else if (you.hunger <= 2066) + else if (you.hunger <= HUNGER_VERY_HUNGRY) newstate = HS_VERY_HUNGRY; - else if (you.hunger <= 2600) + else if (you.hunger <= HUNGER_HUNGRY) newstate = HS_HUNGRY; - else if (you.hunger < 7000) + else if (you.hunger < HUNGER_SATIATED) newstate = HS_SATIATED; - else if (you.hunger < 9000) + else if (you.hunger < HUNGER_FULL) newstate = HS_FULL; - else if (you.hunger < 11000) + else if (you.hunger < HUNGER_VERY_FULL) newstate = HS_VERY_FULL; if (newstate != you.hunger_state) @@ -934,17 +1025,6 @@ static void _describe_food_change(int food_increment) mpr(msg.c_str()); } -static bool _player_can_eat_rotten_meat(bool need_msg = false) -{ - if (player_mutation_level(MUT_SAPROVOROUS)) - return (true); - - if (need_msg) - mpr("You refuse to eat that rotten meat."); - - return (false); -} - // Should really be merged into function below. -- FIXME void eat_inventory_item(int which_inventory_slot) { @@ -956,6 +1036,9 @@ void eat_inventory_item(int which_inventory_slot) return; } + if (food.base_type != OBJ_FOOD) + return; + if (food.sub_type == FOOD_CHUNK) { const int mons_type = food.plus; @@ -965,14 +1048,14 @@ void eat_inventory_item(int which_inventory_slot) const bool rotten = food_is_rotten(food); const corpse_effect_type chunk_type = mons_corpse_effect(mons_type); - if (rotten && !_player_can_eat_rotten_meat(true)) + if (!can_ingest(food, true)) return; _eat_chunk(_determine_chunk_effect(chunk_type, rotten), cannibal, intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_permafood(food.sub_type); you.turn_is_over = true; dec_inv_item_quantity(which_inventory_slot, 1); @@ -991,7 +1074,11 @@ void eat_floor_item(int item_link) return; } - else if (food.sub_type == FOOD_CHUNK) + + if (food.base_type != OBJ_FOOD) + return; + + if (food.sub_type == FOOD_CHUNK) { const int intel = mons_class_intel(food.plus) - I_ANIMAL; const bool cannibal = is_player_same_species(food.plus); @@ -999,14 +1086,14 @@ void eat_floor_item(int item_link) const bool holy = (mons_class_holiness(food.plus) == MH_HOLY); const corpse_effect_type chunk_type = mons_corpse_effect(food.plus); - if (rotten && !_player_can_eat_rotten_meat(true)) + if (!can_ingest(food, true)) return; _eat_chunk(_determine_chunk_effect(chunk_type, rotten), cannibal, intel, holy); } else - _eating(food.base_type, food.sub_type); + _eat_permafood(food.sub_type); you.turn_is_over = true; @@ -1062,6 +1149,64 @@ public: } }; +static int _food_preference(int type, + corpse_effect_type effect_type = CE_CLEAN, + bool is_rotten = false) +{ + int preference = 2; + const int saprovorous = player_mutation_level(MUT_SAPROVOROUS); + const int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); + const int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); + + const int plant_content = _plant_content(type); + + // bonus/penalty of your mutation level for matching/conflicting food type + preference += how_herbivorous * plant_content; + preference -= how_carnivorous * plant_content; + + // Royal Jelly can always be eaten. It needs a total of +3 to guarantee this + if (type == FOOD_ROYAL_JELLY) + preference += 1; + + if (type == FOOD_CHUNK) + { + // unclean chunks get a penalty (If you are immune to the effect, clean + // is passed even if the original chunk wasn't clean [except rotting]) + switch (effect_type) + { + case CE_CONTAMINATED: + case CE_POISONOUS: + case CE_POISON_CONTAM: + case CE_ROT: + case CE_MUTAGEN_RANDOM: + case CE_MUTAGEN_GOOD: + case CE_MUTAGEN_BAD: + preference -= 1; + break; + case CE_ROTTEN: + is_rotten = true; + break; + default: + ; + } + + // handle rotten food + if (is_rotten) + preference -= (4 - saprovorous) / 2; + + // gourmand - (only affects chunks) + if (you.duration[DUR_GOURMAND] >= GOURMAND_MAX) + preference++; + } + else + { + // permafood gets a +2 bonus for being delicious + preference += 2; + } + + return preference; +} + // Returns -1 for cancel, 1 for eaten, 0 for not eaten. int eat_from_floor(bool skip_chunks) { @@ -1108,13 +1253,7 @@ int eat_from_floor(bool skip_chunks) continue; } - if (!skip_chunks && food_is_rotten(*si) - && !_player_can_eat_rotten_meat()) - { - unusable_corpse++; - continue; - } - else if (!can_ingest(*si, true)) + if (!can_ingest(*si, true)) { if (!inedible_food) { @@ -1192,14 +1331,8 @@ int eat_from_floor(bool skip_chunks) // Give a message about why these food items can not actually be eaten. if (unusable_corpse) { - if (you.species == SP_VAMPIRE) - { - mprf("%s devoid of blood.", - unusable_corpse == 1 ? "This corpse is" - : "These corpses are"); - } - else - _player_can_eat_rotten_meat(true); + mprf("%s devoid of blood.", + unusable_corpse == 1 ? "This corpse is" : "These corpses are"); need_more = true; } else if (inedible_food) @@ -1268,12 +1401,7 @@ bool eat_from_inventory() if (is_bad_food(*item)) continue; - if (food_is_rotten(*item) && !_player_can_eat_rotten_meat()) - { - unusable_corpse++; - continue; - } - else if (!can_ingest(*item, true)) + if (!can_ingest(*item, true)) { if (!inedible_food) { @@ -1336,14 +1464,9 @@ bool eat_from_inventory() // Give a message about why these food items can not actually be eaten. if (unusable_corpse) { - if (you.species == SP_VAMPIRE) - { - mprf("%s devoid of blood.", - unusable_corpse == 1 ? "The corpse you are carrying is" - : "The corpses you are carrying are"); - } - else - _player_can_eat_rotten_meat(true); + mprf("%s devoid of blood.", + unusable_corpse == 1 ? "The corpse you are carrying is" + : "The corpses you are carrying are"); } else if (inedible_food) { @@ -1373,15 +1496,6 @@ int prompt_eat_chunks(bool only_auto) if (player_mutation_level(MUT_HERBIVOROUS) == 3) return (0); - // If we *know* the player can eat chunks, doesn't have the gourmand - // effect and isn't hungry, don't prompt for chunks. - if (you.species != SP_VAMPIRE && !player_likes_chunks(true) - && !wearing_amulet(AMU_THE_GOURMAND, false) - && you.hunger_state >= HS_SATIATED) - { - return (0); - } - bool found_valid = false; std::vector<item_def *> chunks; @@ -1401,13 +1515,22 @@ int prompt_eat_chunks(bool only_auto) else if (si->base_type != OBJ_FOOD || si->sub_type != FOOD_CHUNK) continue; - if (food_is_rotten(*si) && !_player_can_eat_rotten_meat()) + if (!can_ingest(*si, true)) continue; // Don't prompt for bad food types. if (is_bad_food(*si)) continue; + // You have to be hungry enough to consider eating a chunk + if (you.hunger_state >= _maximum_satiation(_food_preference( + FOOD_CHUNK, + mons_corpse_effect(si->plus), + food_is_rotten(*si)))) + { + continue; + } + found_valid = true; chunks.push_back(&(*si)); } @@ -1431,13 +1554,22 @@ int prompt_eat_chunks(bool only_auto) else if (item->base_type != OBJ_FOOD || item->sub_type != FOOD_CHUNK) continue; - if (food_is_rotten(*item) && !_player_can_eat_rotten_meat()) + if (!can_ingest(*item, true)) continue; // Don't prompt for bad food types. if (is_bad_food(*item)) continue; + // You have to be hungry enough to consider eating a chunk + if (you.hunger_state >= _maximum_satiation(_food_preference( + FOOD_CHUNK, + mons_corpse_effect(item->plus), + food_is_rotten(*item)))) + { + continue; + } + found_valid = true; chunks.push_back(item); } @@ -1585,47 +1717,6 @@ void chunk_nutrition_message(int nutrition) mpr("That was not very filling."); } -static int _apply_herbivore_nutrition_effects(int nutrition) -{ - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - - while (how_herbivorous--) - nutrition = nutrition * 80 / 100; - - return (nutrition); -} - -static int _apply_gourmand_nutrition_effects(int nutrition, int gourmand) -{ - return (nutrition * (gourmand + GOURMAND_NUTRITION_BASE) - / (GOURMAND_MAX + GOURMAND_NUTRITION_BASE)); -} - -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_nutrition_effects(nutrition)); - } - - const int gourmand = - wearing_amulet(AMU_THE_GOURMAND) ? you.duration[DUR_GOURMAND] : 0; - const int effective_nutrition = - _apply_gourmand_nutrition_effects(nutrition, gourmand); - -#ifdef DEBUG_DIAGNOSTICS - const int epercent = effective_nutrition * 100 / nutrition; - mprf(MSGCH_DIAGNOSTICS, - "Gourmand factor: %d, chunk base: %d, effective: %d, %%: %d", - gourmand, nutrition, effective_nutrition, epercent); -#endif - - return (_apply_herbivore_nutrition_effects(effective_nutrition)); -} - static void _say_chunk_flavour(bool likes_chunks) { mprf("This raw flesh %s", _chunk_flavour_phrase(likes_chunks)); @@ -1637,11 +1728,10 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, int mon_intel, bool holy) { bool likes_chunks = player_likes_chunks(true); - int nutrition = _chunk_nutrition(likes_chunks); + int preference = _food_preference(FOOD_CHUNK, chunk_effect); + int nutrition = CHUNK_BASE_NUTRITION * _chunk_satiation_multiplier(preference); int hp_amt = 0; bool suppress_msg = false; // do we display the chunk nutrition message? - bool do_eat = false; - if (you.species == SP_GHOUL) { nutrition = CHUNK_BASE_NUTRITION; @@ -1672,10 +1762,14 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, break; case CE_POISONOUS: + case CE_POISON_CONTAM: mpr("Yeeuch - this meat is poisonous!"); if (poison_player(3 + random2(4), "", "poisonous meat")) xom_is_stimulated(random2(100)); - break; + + if (chunk_effect == CE_POISONOUS) + break; + // else fall through case CE_ROTTEN: case CE_CONTAMINATED: @@ -1686,8 +1780,6 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, if (you.species == SP_GHOUL) _heal_from_food(hp_amt, 0, !one_chance_in(4), one_chance_in(5)); - - do_eat = true; } else { @@ -1714,10 +1806,8 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, else _say_chunk_flavour(likes_chunks); - do_eat = true; break; - case CE_POISON_CONTAM: // _determine_chunk_effect should never return this case CE_MUTAGEN_GOOD: case CE_NOCORPSE: case CE_RANDOM: @@ -1733,155 +1823,94 @@ static void _eat_chunk(corpse_effect_type chunk_effect, bool cannibal, if (holy) did_god_conduct(DID_VIOLATE_HOLY_CORPSE, 2); - if (do_eat) - { - start_delay(DELAY_EAT, 2, (suppress_msg) ? 0 : nutrition, -1); - lessen_hunger(nutrition, true); - } + start_delay(DELAY_EAT, 2, (suppress_msg) ? 0 : nutrition, -1); + lessen_hunger(nutrition, true); + dprf("Eat chunk, nutrition:%d, preference:%d.", nutrition, preference); } -static void _eating(object_class_type item_class, int item_type) +static void _eat_permafood(int item_type) { int food_value = 0; - int how_herbivorous = player_mutation_level(MUT_HERBIVOROUS); - int how_carnivorous = player_mutation_level(MUT_CARNIVOROUS); - int carnivore_modifier = 0; - int herbivore_modifier = 0; - switch (item_class) + // apply base sustenance {dlb}: + switch (item_type) { - case OBJ_FOOD: - // apply base sustenance {dlb}: - switch (item_type) - { - case FOOD_MEAT_RATION: - case FOOD_ROYAL_JELLY: - food_value = 5000; - break; - case FOOD_BREAD_RATION: - food_value = 4400; - break; - case FOOD_AMBROSIA: - food_value = 2500; - break; - case FOOD_HONEYCOMB: - food_value = 2000; - break; - case FOOD_SNOZZCUMBER: // Maybe a nasty side-effect from RD's book? - // I'd like that, but I don't dare. (jpeg) - case FOOD_PIZZA: - case FOOD_BEEF_JERKY: - food_value = 1500; - break; - case FOOD_CHEESE: - case FOOD_SAUSAGE: - food_value = 1200; - break; - case FOOD_ORANGE: - case FOOD_BANANA: - case FOOD_LEMON: - food_value = 1000; - break; - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_APRICOT: - food_value = 700; - break; - case FOOD_CHOKO: - case FOOD_RAMBUTAN: - case FOOD_LYCHEE: - food_value = 600; - break; - case FOOD_STRAWBERRY: - food_value = 200; - break; - case FOOD_GRAPE: - food_value = 100; - break; - case FOOD_SULTANA: - food_value = 70; // Will not save you from starvation. - break; - default: - break; - } + case FOOD_MEAT_RATION: + case FOOD_ROYAL_JELLY: + food_value = 5000; + break; + case FOOD_BREAD_RATION: + food_value = 4400; + break; + case FOOD_AMBROSIA: + food_value = 2500; + break; + case FOOD_HONEYCOMB: + food_value = 2000; + break; + case FOOD_SNOZZCUMBER: // Maybe a nasty side-effect from RD's book? + // I'd like that, but I don't dare. (jpeg) + case FOOD_PIZZA: + case FOOD_BEEF_JERKY: + food_value = 1500; + break; + case FOOD_CHEESE: + case FOOD_SAUSAGE: + food_value = 1200; + break; + case FOOD_ORANGE: + case FOOD_BANANA: + case FOOD_LEMON: + food_value = 1000; + break; + case FOOD_PEAR: + case FOOD_APPLE: + case FOOD_APRICOT: + food_value = 700; + break; + case FOOD_CHOKO: + case FOOD_RAMBUTAN: + case FOOD_LYCHEE: + food_value = 600; + break; + case FOOD_STRAWBERRY: + food_value = 200; + break; + case FOOD_GRAPE: + food_value = 100; + break; + case FOOD_SULTANA: + food_value = 70; // Will not save you from starvation. + break; + default: + break; + } - // Next, sustenance modifier for carnivores/herbivores {dlb}: - switch (item_type) - { - case FOOD_MEAT_RATION: - carnivore_modifier = 500; - herbivore_modifier = -1500; - break; - case FOOD_BEEF_JERKY: - case FOOD_SAUSAGE: - carnivore_modifier = 200; - herbivore_modifier = -200; - break; - case FOOD_BREAD_RATION: - carnivore_modifier = -1000; - herbivore_modifier = 500; - break; - case FOOD_BANANA: - case FOOD_ORANGE: - case FOOD_LEMON: - carnivore_modifier = -300; - herbivore_modifier = 300; - break; - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_APRICOT: - case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: - case FOOD_RAMBUTAN: - case FOOD_LYCHEE: - carnivore_modifier = -200; - herbivore_modifier = 200; - break; - case FOOD_STRAWBERRY: - carnivore_modifier = -50; - herbivore_modifier = 50; - break; - case FOOD_GRAPE: - case FOOD_SULTANA: - carnivore_modifier = -20; - herbivore_modifier = 20; - break; - default: - carnivore_modifier = 0; - herbivore_modifier = 0; - break; - } + // multiply the base satiation by a value determined by how much + // the player likes the food + const int preference = _food_preference(item_type); + food_value *= _permafood_satiation_multiplier(preference); - // Finally, modify player's hunger level {dlb}: - if (carnivore_modifier && how_carnivorous > 0) - food_value += (carnivore_modifier * how_carnivorous); + if (food_value > 0) + { + int duration = 1; + if (item_type == FOOD_MEAT_RATION || item_type == FOOD_BREAD_RATION) + duration = 3; - if (herbivore_modifier && how_herbivorous > 0) - food_value += (herbivore_modifier * how_herbivorous); + start_delay(DELAY_EAT, duration, 0, item_type); + lessen_hunger(food_value, true); + dprf("Eat permafood, nutrition:%d, preference:%d.", food_value, + preference); - if (food_value > 0) + if (player_mutation_level(MUT_FOOD_JELLY) + && x_chance_in_y(food_value, 12000)) { - int duration = 1; - if (item_type == FOOD_MEAT_RATION || item_type == FOOD_BREAD_RATION) - duration = 3; - - start_delay(DELAY_EAT, duration, 0, item_type); - lessen_hunger(food_value, true); - - if (player_mutation_level(MUT_FOOD_JELLY) - && x_chance_in_y(food_value, 12000)) - { - mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, 0, - you.pos(), MHITNOT, 0, you.religion); + mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, 0, + you.pos(), MHITNOT, 0, you.religion); - if (create_monster(mg) != -1) - mprf("A jelly spawns from your body."); - } + if (create_monster(mg) != -1) + mprf("A jelly spawns from your body."); } - break; - - default: - break; } } @@ -2283,49 +2312,6 @@ bool causes_rot(const item_def &food) return (mons_corpse_effect(food.plus) == CE_ROT); } -// Returns 1 for herbivores, -1 for carnivores and 0 for either. -static int _player_likes_food_type(int type) -{ - switch (static_cast<food_type>(type)) - { - case FOOD_BREAD_RATION: - case FOOD_PEAR: - case FOOD_APPLE: - case FOOD_CHOKO: - case FOOD_SNOZZCUMBER: - case FOOD_APRICOT: - case FOOD_ORANGE: - case FOOD_BANANA: - case FOOD_STRAWBERRY: - case FOOD_RAMBUTAN: - case FOOD_LEMON: - case FOOD_GRAPE: - case FOOD_SULTANA: - case FOOD_LYCHEE: - return 1; - - case FOOD_CHUNK: - case FOOD_MEAT_RATION: - case FOOD_SAUSAGE: - case FOOD_BEEF_JERKY: - return -1; - - case FOOD_HONEYCOMB: - case FOOD_ROYAL_JELLY: - case FOOD_AMBROSIA: - case FOOD_CHEESE: - case FOOD_PIZZA: - return 0; - - case NUM_FOODS: - mpr("Bad food type", MSGCH_ERROR); - return 0; - } - - mprf(MSGCH_ERROR, "Couldn't handle food type: %d", type); - return 0; -} - // Returns true if an item of basetype FOOD or CORPSES cannot currently // be eaten (respecting species and mutations set). bool is_inedible(const item_def &item) @@ -2334,17 +2320,8 @@ bool is_inedible(const item_def &item) if (you.is_undead == US_UNDEAD) return (true); - if (food_is_rotten(item) - && !player_mutation_level(MUT_SAPROVOROUS)) - { - return (true); - } - - if (item.base_type == OBJ_FOOD - && !can_ingest(item, true, true, false)) - { + if (item.base_type == OBJ_FOOD && !can_ingest(item, true, true, false)) return (true); - } if (item.base_type == OBJ_CORPSES && (item.sub_type == CORPSE_SKELETON @@ -2392,10 +2369,10 @@ bool is_preferred_food(const item_def &food) return (food_is_rotten(food)); if (player_mutation_level(MUT_CARNIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) < 0); + return (_plant_content(food.sub_type) < 0); if (player_mutation_level(MUT_HERBIVOROUS) == 3) - return (_player_likes_food_type(food.sub_type) > 0); + return (_plant_content(food.sub_type) > 0); // No food preference. return (false); @@ -2431,38 +2408,17 @@ bool is_forbidden_food(const item_def &food) return (false); } -bool check_amu_the_gourmand(bool reqid) -{ - if (wearing_amulet(AMU_THE_GOURMAND, !reqid)) - { - const int amulet = you.equip[EQ_AMULET]; - - ASSERT(amulet != -1); - - if (!item_type_known(you.inv[amulet])) - { - // For artefact amulets, this will tell you its name and - // subtype. Other properties may still be hidden. - set_ident_flags(you.inv[amulet], ISFLAG_KNOW_TYPE); - set_ident_type(OBJ_JEWELLERY, AMU_THE_GOURMAND, ID_KNOWN_TYPE); - mpr(you.inv[amulet].name(DESC_INVENTORY, false).c_str()); - } - - return (true); - } - - return (false); -} - bool can_ingest(const item_def &food, bool suppress_msg, bool reqid, bool check_hunger) { return can_ingest(food.base_type, food.sub_type, suppress_msg, reqid, - check_hunger, food_is_rotten(food)); + check_hunger, mons_corpse_effect(food.plus), + food_is_rotten(food)); } bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, - bool reqid, bool check_hunger, bool rotten) + bool reqid, bool check_hunger, corpse_effect_type effect_type, + bool is_rotten) { bool survey_says = false; @@ -2491,12 +2447,6 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool ur_carnivorous = player_mutation_level(MUT_CARNIVOROUS) == 3; bool ur_herbivorous = player_mutation_level(MUT_HERBIVOROUS) == 3; - // ur_chunkslover not defined in terms of ur_carnivorous because - // a player could be one and not the other IMHO - 13mar2000 {dlb} - bool ur_chunkslover = ((check_hunger ? you.hunger_state < HS_SATIATED - : true) - || player_likes_chunks(true)); - switch (what_isit) { case OBJ_FOOD: @@ -2508,8 +2458,18 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, return (false); } - const int vorous = _player_likes_food_type(kindof_thing); - if (vorous > 0) // Herbivorous food. + // First, we calculate how much we like this thing we are considering eating + // Then, based on that, we decide how hungry we would have to be to eat it + const int preference = _food_preference(kindof_thing, effect_type, + is_rotten); + const bool inedible = preference < (kindof_thing == FOOD_CHUNK ? 0: 2); + const bool willing_to_eat = + (!check_hunger + || you.hunger_state <= _maximum_satiation(preference)); + + const int plant_content = _plant_content(kindof_thing); + + if (plant_content > 0) // Herbivorous food. { if (ur_carnivorous) { @@ -2520,7 +2480,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, else return (true); } - else if (vorous < 0) // Carnivorous food. + else if (plant_content < 0) // Carnivorous food. { if (ur_herbivorous) { @@ -2530,13 +2490,19 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, } else if (kindof_thing == FOOD_CHUNK) { - if (rotten && !_player_can_eat_rotten_meat(!suppress_msg)) + if (inedible) + { + if (!suppress_msg) + { + if (is_rotten) + mpr("You refuse to eat that rotten meat."); + else + mpr("You refuse to eat this disgusting meat."); + } return (false); + } - if (ur_chunkslover) - return (true); - - if (check_amu_the_gourmand(reqid)) + if (willing_to_eat) return (true); if (!suppress_msg) @@ -2545,9 +2511,15 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, return (false); } } - // Any food types not specifically handled until here (e.g. meat - // rations for non-herbivores) are okay. - return (true); + if (willing_to_eat) // Food which is neither. + return (true); + else + { + if (!suppress_msg) + mpr("You aren't quite hungry enough to eat that!"); + + return (false); + } } case OBJ_CORPSES: @@ -2641,10 +2613,7 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, case CE_POISON_CONTAM: if (player_res_poison() <= 0) - { - chunktype = CE_POISONOUS; break; - } else { chunktype = CE_CONTAMINATED; @@ -2711,28 +2680,6 @@ static corpse_effect_type _determine_chunk_effect(corpse_effect_type chunktype, } } - // 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. - if (wearing_amulet(AMU_THE_GOURMAND) - && x_chance_in_y(you.duration[DUR_GOURMAND], GOURMAND_MAX)) - { - if (player_mutation_level(MUT_SAPROVOROUS) == 3) - { - // [dshaligram] Level 3 saprovores relish contaminated meat. - if (chunktype == CE_CLEAN) - chunktype = CE_CONTAMINATED; - } - else - { - // [dshaligram] New AotG behaviour - contaminated chunks become - // clean, but rotten chunks remain rotten. - if (chunktype == CE_CONTAMINATED) - chunktype = CE_CLEAN; - } - } - return (chunktype); } diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h index e79ba9f..608c48e 100644 --- a/crawl-ref/source/food.h +++ b/crawl-ref/source/food.h @@ -7,6 +7,8 @@ #ifndef FOOD_H #define FOOD_H +#include "mon-enum.h" + enum food_type { FOOD_MEAT_RATION, // 0 @@ -36,7 +38,17 @@ enum food_type }; #define BERSERK_NUTRITION 700 -#define HUNGER_STARVING 1000 +enum satiation_threshold +{ + HUNGER_STARVING = 1000, + HUNGER_NEAR_STARVING = 1533, + HUNGER_VERY_HUNGRY = 2066, + HUNGER_HUNGRY = 2600, + HUNGER_SATIATED = 7000, + HUNGER_FULL = 9000, + HUNGER_VERY_FULL = 11000, + HUNGER_ENGORGED = 12000 +}; int count_corpses_in_pack(bool blood_only = false); bool butchery(int which_corpse = -1, bool bottle_blood = false); @@ -60,13 +72,13 @@ bool causes_rot(const item_def &food); bool is_inedible(const item_def &item); bool is_preferred_food(const item_def &food); bool is_forbidden_food(const item_def &food); -bool check_amu_the_gourmand(bool reqid); bool can_ingest(const item_def &food, bool suppress_msg, bool reqid = false, bool check_hunger = true); bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid = false, bool check_hunger = true, - bool rotten = false); + corpse_effect_type effect_type = CE_CLEAN, + bool is_rotten = false); bool chunk_is_poisonous(int chunktype); void eat_floor_item(int item_link); diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc index 4d134ae..108fd1f 100644 --- a/crawl-ref/source/main.cc +++ b/crawl-ref/source/main.cc @@ -2630,7 +2630,7 @@ static void _decrement_durations() slow_player(dur); make_hungry(BERSERK_NUTRITION, true); - you.hunger = std::max(HUNGER_STARVING, you.hunger); + you.hunger = std::max<int>(HUNGER_STARVING, you.hunger); // 1KB: No berserk healing. you.hp = (you.hp + 1) * 2 / 3; diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 8b1a332..ed84c6c 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -136,7 +136,7 @@ static void _create_monster_hide(const item_def corpse) int get_max_corpse_chunks(int mons_class) { - return (mons_weight(mons_class) / 150); + return (mons_weight(mons_class) / 300); } void turn_corpse_into_skeleton(item_def &item) diff --git a/crawl-ref/source/player-act.cc b/crawl-ref/source/player-act.cc index e66b144..f44e4e7 100644 --- a/crawl-ref/source/player-act.cc +++ b/crawl-ref/source/player-act.cc @@ -669,8 +669,8 @@ bool player::can_go_berserk(bool intentional, bool potion) const return (false); } - ASSERT(HUNGER_STARVING + BERSERK_NUTRITION < 2066); - if (you.hunger <= 2066) + ASSERT(HUNGER_STARVING + BERSERK_NUTRITION < HS_VERY_HUNGRY); + if (you.hunger <= HS_VERY_HUNGRY) { if (verbose) mpr("You're too hungry to go berserk."); diff --git a/crawl-ref/source/potion.cc b/crawl-ref/source/potion.cc index 0dbf839..76e98ff 100644 --- a/crawl-ref/source/potion.cc +++ b/crawl-ref/source/potion.cc @@ -133,14 +133,11 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) const int value = 200; const int herbivorous = player_mutation_level(MUT_HERBIVOROUS); - if (herbivorous < 3 && player_likes_chunks()) + if (herbivorous < 3 && player_likes_chunks(true)) { // Likes it. mpr("This tastes like blood."); lessen_hunger(value, true); - - if (!player_likes_chunks(true)) - check_amu_the_gourmand(false); } else { -- 1.7.3.1 |
||||||
|
Relationships | |||||||||||||||||||||
|
Notes | |
(0013841) Ryak (reporter) 2011-07-17 07:43 |
I've got this implemented. It probably needs some balancing. I'm going to run a few test games and see if i can at least make the balance reasonable before posting a patch. |
(0013842) Ryak (reporter) 2011-07-17 08:55 |
(1) New criteria for eating: Instead of two seperate scales as it was proposed (which would be messy and hard to implement cleanly, i used a single scale while providing a bonus to permafood to give similar results as the original proposal. (a)Start at 0 +2 for permafood +1 for royal jelly +1 for gourmand (on chunks only) +-1 for each level of carnivore/herbivore for (in)appropriate food pref nutrition max satiation example -3 Can't eat.... Can't eat.... herbivore 2 + dirty chunk -2 1/3 nutrition near starving herbivore 1 + dirty chunk -1 2/3 nutrition very hungry.. no mutations + dirty chunk 0. 1 nutrition.. hungry....... no mutations + clean chunk 1. 1 nutrition.. satiated..... herbivore 1 + meat ration 2. 6/5 nutrition full......... no mutations + choko 3. 7/5 nutrition no limit..... carnivore 3 + clean chunk 4 8/5 nutrition. no limit..... carnivore 2 + meat ration 5 9/5 nutrition no limit herbivore 3 + bread ration (b) still can't eat meat at herbivore 3 or plants at carnivore 3 ever (2) Amount of nutrition different (a)Permafood base nutrition reduced by 20% - this works out to a 4% net loss of nutrition except for royal jelly which got a slight buff in nutrition (b)chunks base nutrition reduced by 25% - origional proposal suggested reducing the number of chunks, but i think this is a better solution because it has less of an impact on the other uses of chunks. (3) All chunks give nutrition. This provides interesting decisions if you are hungry and only have bad chunks. |
(0013843) Ryak (reporter) 2011-07-17 09:07 |
Second patch is a 1 line fix to an obvious oversight. Despite the fact that i added a comment saying gourmand only worked on chunks, i forgot to actually limit it to chunks. |
(0013844) KiloByte (manager) 2011-07-17 12:32 |
Uhm no, requiring hunger levels below Hungry would bring back the nasty micromanagement we mostly got rid of for berserk. That's a damn bad idea. |
(0013858) Ryak (reporter) 2011-07-17 16:22 |
Huh? thats pretty much straight from the proposal. In my playtesting as a centaur its not really any more micro-managey than before, either. Did you try it? |
(0013880) galehar (administrator) 2011-07-18 12:16 |
I don't see the problem with the very hungry restrictions. Currently, you rarely eat contaminated chunks before very hungry anyway. And if it makes herbivore 1 and 2 rely more often on permafood, well, I guess that's the point. Definitely worth testing it IMHO. However, I'm not sure about shoving permafood and chunks in a single scale. I like dpeg's original design. Your scale is a bit hard to read, so I'm not sure how it compares. Also, reducing nutrition instead of number of chunks doesn't sound like a good idea because it means you'll have to eat more often. Having less source for sublimation of blood is certainly not a problem, and twisted resurrection can be easily boosted to compensate. Anything else? |
(0013952) Ryak (reporter) 2011-07-22 03:38 |
Yeah unfortunately mantis doesnt really let you do formatted text. I made a google doc so its more readable. The effective result is pretty much the same as dpeg's 2 scale proposal, only easier to implement. https://spreadsheets.google.com/spreadsheet/ccc?key=0AnMbfunDtqPCdHlFSmZzQVd1bE82ZnBPZnRoOGdHSkE&hl=en_US [^] |
(0014033) dpeg (administrator) 2011-07-31 18:27 |
Thanks for the patch! I am adding Ryak's version to the wiki page, for easier comparison. (Ryak, please check if I got it right.) Kilobyte: I doubt there will be micromanagement. We should really give it a try -- currently the food system wastes a lot of potential (the meaning of poisonous chunks is trivial, depending on your rP; similar for contaminated chunks; Gourmand trivialises everything; the mutations are binary) -- using a gradient has the potential to make everything a lot better. Ryak: Reducing the number of chunks is a very good step in itself. It already comes up in Vinterman's original proposal. The abuse potential of many-chunk corpses is in principle also around for other corpse uses. (Yes, Twisted Resurrection will need a second look.) |
(0014049) dpeg (administrator) 2011-08-01 22:00 |
I have turned the original proposals into tables as well (wiki), now you can easily compare the proposals. Examples are still missing. |
(0014206) dpeg (administrator) 2011-08-16 22:10 |
I have looked at the two tables for quite some time. ryak's system is a lot simpler. On the other hand, it does not even try to reduce the amount of (chunk) food available, which is not good. I am also not sure what it does with Saprovore and poisonous/mutagenice (which should really work like in the original proposal). That said, I am fine with testing the patch. |
(0014307) galehar (administrator) 2011-08-24 17:59 |
I have started to look into it, but the patch doesn't compile: food.cc:1154: error: ‘CE_HCL’ was not declared in this scope food.cc:1148: warning: enumeration value ‘CE_ROT’ not handled in switch |
(0014308) Kate (developer) 2011-08-24 18:38 edited on: 2011-08-24 18:47 |
I think CE_HCL was renamed to CE_ROT since this patch was made (commit 3758c0c064). |
(0014552) vintermann (reporter) 2011-09-06 20:56 |
This is absolutely wonderful! I actually had worked out in C code how I wanted (my version of) the proposal to work, but I didn't manage/didn't have time to get it integrated properly into food.cc without breaking all sorts of related stuff. If Ryak's done the heavy work of that, it will hopefully be much easier to tweak it as well. Can we have a proper git branch for this, MarvinPA? I have trouble applying the patches attached to this issue, and I'd like to start testing it out as soon as possible. |
(0014553) vintermann (reporter) 2011-09-06 22:33 |
OK, at galehar's suggestion I uploaded my bit of executable pseudocode to illustrate how my messy two-scale system could be implemented :) It's in nutri.c |
(0014630) galehar (administrator) 2011-09-13 11:42 |
I've reviewed Ryak's patch and I'm afraid the code isn't good enough to go in. It has duplications (in determine_maximum_satiation), too many static casts, useless type conversions (calculation in floats, return a double) a variable named food_type (which is a type name) and it doesn't even implement the original design. Some variation in the scales compared to the design is perfectly acceptable, but I really think reducing chunk number is better than reducing nutrition value. So the issue is still open for contribution. Whether to clean up Ryak's code or to come up with a new implementation. |
(0014853) Mental Mouse (reporter) 2011-09-25 23:22 |
If you want to cut chunk numbers, you could eliminate chunks from bats and/or rats (that is, small but numerous). Of course, that can make the starting game difficult for heavy eaters.... |
(0014948) Ryak (reporter) 2011-09-30 03:19 |
I had meant to go back to this and modify it a bit based on your feedback. I'm pretty sure with a few tweaks we should have a better patch. A couple of your comments were things i wanted to go back and change too. |
(0014949) Ryak (reporter) 2011-09-30 04:08 |
Also in my defense with the variable food_type, there was already an existing function which also used a variable by that name. Anyway, i'm renaming it plant_content which is more descriptive anyway. |
(0014950) Ryak (reporter) 2011-09-30 05:09 |
Ok changes from before: (1) removed unnecessary static_casts (2) replaced hunger level magic numbers with defined constants (3) renamed food_type variables to plant_content (4) returned chunk nutrition to normal and reduced chunk number as per the proposal (5) determine_satiation_multiplier returns with the same precision it calculates at (geez a little picky there) Patch Uploaded |
(0014952) ghallberg (reporter) 2011-09-30 08:28 |
I'm not a dev team member but I'm really happy to see things happening here again, looks like you fixed up most of the stuff galehar was worried about too so now I can hopefully get thius in 0.10 :) |
(0014955) galehar (administrator) 2011-09-30 15:35 |
Ryak: I'm sorry that you feel like you have to defend yourself. I was just trying to provide objective feedback about what was in need of improvement. Please, don't take critiques personally. Anyway, you've delivered, the new patch does bring improvements. However, your implementation does bring significant changes to the original design. I've set up a spreadsheet for easy comparison. I filled values based on reading your code and what you've put on the wiki, so there might be mistakes. Let me know if you spot any. https://docs.google.com/spreadsheet/ccc?key=0AqvhLOPFHpiMdGlkWFpybUc5X3VNbmdwQmhNWm9MMkE&hl=en_US [^] This table show that Ryak's simplified scale does not always give results similar to the original. I won't go into a detailed analysis, I think the numbers speak for themselves. I'm not saying the original design is perfect. There might be some simplification and/or improvement. Anyway, the new patch provided by Ryak does 90% of the work. Implementing the original scales should be quite easy. |
(0014956) dpeg (administrator) 2011-09-30 16:13 |
ryak: thanks for keeping the patch alive. galehar: thanks for the spreadsheet. I am worried about the bad performance of plant food under herbivore regime with the new patch. There is a reason why the original proposal is so generous to herbivores: they have a much harder time than carnivores. Flavourwise, I like how Herbivore 2 would make sausages emergency food (a contrast to the patch). |
(0014967) Ryak (reporter) 2011-10-01 02:04 |
You make a good point. Some of the numbers are quite different. i'll give you the benefit of the doubt that you correctly calculated everything. i think i can match the numbers much more closely. I was mainly focusing on the food levels, which generally match the proposal as you can see. I should get a chance to work on this further this weekend and we should have something we can work with. |
(0014968) Ryak (reporter) 2011-10-01 02:08 |
Also, no need to apologize. I took no offense. Your comments were pretty much completely justified. I'll assume you're more used to talking on the tavern where people take offense alot easier ;) |
(0014970) Ryak (reporter) 2011-10-01 03:40 |
I made one small change to get_preference_for_food_type and some different numbers in determine_satiation_multiplier. I used your spreadsheet to make sure everything lined up nicely with vintermann's numbers and they do quite well. I put it in sheet 2 of my above spreadsheet. |
(0014972) Ryak (reporter) 2011-10-01 07:04 edited on: 2011-10-01 07:05 |
Patch uploaded. Numbers can be seen on sheet 2 of my spreadsheet above. |
(0014999) Ryak (reporter) 2011-10-02 22:27 edited on: 2011-10-02 22:35 |
talking to dpeg, he suggested penalizing incompatible foods even harder, so i made it a -2 penalty (implemented by not giving the +2 permafood bonus). Patch uploaded. Numbers are on sheet 3 of my spreadsheet above. |
(0015000) dpeg (administrator) 2011-10-02 23:20 |
galehar: Would you have a look? If you think the numbers are okay and if the code quality is good (I cannot judge), it's ready to go in by my assessment. Is it worth to have the table of former/new nutrition values in the commit message? (I'd think so...) |
(0015001) galehar (administrator) 2011-10-03 00:14 |
Those numbers look spot on. Maybe even better than vintermann's. Will look at the code ASAP. |
(0015002) galehar (administrator) 2011-10-03 00:40 |
a quick look at the code doesn't reveal anything terrifing. I'm a bit worried about changing nutrition value of permafood. It's what we use for spell and abilities food cost and we are used to them. Is this really necessary? (also use spaces instead of tabs) (and why do you insist on moving the #include food.h line?) appart from those details, it's almost good to go. Will have a more thorough look tomorrow. |
(0015004) Ryak (reporter) 2011-10-03 01:55 edited on: 2011-10-03 01:59 |
i moved the #include because it uses corpse_effect_type in one of the method signatures now where it didn't used to. Let me see if i can refactor it a bit to keep the base values where they were but still get the same results. Re: spaces vs tabs. I'm used to my IDE at work autoconverting tabs to spaces. I'll change that too. |
(0015005) Ryak (reporter) 2011-10-03 05:09 edited on: 2011-10-03 05:18 |
Ok, the updated info is on the spreadsheet. Pretty much everything is close to what it was before. Patch uploaded. Changes: (1) Revert base values to what they were before (2) Seperate scales for satiation_multiplier for permafood and chunks (consequence of 1) (3) fix a bug where it wasn't taking into account rotted status of chunks (4) Convert tabs to spaces |
(0015016) galehar (administrator) 2011-10-03 17:31 |
I've started cleaning up and testing the code. I'm almost finished, but there's still some issues. As per design, I've allowed non saprovorous to eat rotten chunk (at greatly reduced nutrition and with systematic sickness), but they don't get sorted properly when prompted (offered before contaminated meat). Due to how _determine_chunk_effect works, contaminated meat gets reduced nutrition only when you actually get the sickness effect (should be always). Also, contaminated and rotten chunks are not cumulative, so they're not worse than white rotten chunk like they should be. This probably needs some refactoring but I don't have the time do it right now. Uploading my current version in case Ryak wants to give it a try. |
(0015024) galehar (administrator) 2011-10-04 00:40 |
It's in. Thanks Ryak! |
(0015113) KiloByte (manager) 2011-10-09 20:25 |
After some testing, the food reform turned out to be a disaster. Especially its stated purpose: "My overall vision: Reduce player hassle, without breaking food clock." has spectacularly failed. Players keep complaining about mad micromanagement required all the time now. Looks like even most ardent proponents seem to have turned back. Galehar for example, the very person who did most of the integration, is said to talk about removing variable thresholds, the main part of the "reform". I say: let's not waste any more time and just revert it outright. The code to do so is on a git branch. |
(0015114) ion_frigate (reporter) 2011-10-10 00:57 |
Might I suggest some more limited reforms, to address the original things (I gather) this reform was trying to get at: * Brown chunks: For a non-saprovore, 3/4 nutrition, sickness 1/9 of the time instead of 1/3. This keeps the expected nutrition gain the same, while reducing the frequency of sickness, which is a really common early-game annoyance that has little gameplay value there. Saprovores stay the same. * Poisonous chunks: give 1/2 nutrition to those without rpois, while obviously poisoning them. Meant as a desperation option, where you have potions of healing but no food. Also makes the cure poison spell have a little more of a point, at least until getting rpois. Basically I don't think the idea of variable nutrition is one that requires micromanagement. Thresholds are horrible, but variable nutrition is fairly intuitive and passive. |
(0015159) Ryak (reporter) 2011-10-11 01:29 |
so now we're stuck back with the original problems of gourmand and carnivore 1 being overpowered and the completely illogical rule that you get no food for chunks which sicken you. We could easily have addressed people's concerns which basically entirely revolved around being able to eat contaminated chunks at very hungry instead of hungry without throwing out the baby with the bathwater. |
(0015162) KiloByte (manager) 2011-10-11 01:31 |
Reverted. |
(0015163) dpeg (administrator) 2011-10-11 01:40 |
Ryak: folks had no patience. I just played another game with your system, and I found it bearable. But if you read the forum entries, players seem to disagree. :( Carnivore 1 is weaker than before (only goes to Full). Nutrition for brown chunks will come. Sorry for this, it surely hurts. We have to live and learn. |
(0015172) Kyrris (reporter) 2011-10-12 02:03 |
It's not illogical, Ryak. You don't get any actual nutrition when you vomit up your dinner. |
(0015174) KiloByte (manager) 2011-10-12 12:39 |
Kyrris: I fully agree with you, and have picked that part only because dpeg insisted. Getting no nutrition when sickened, and the whole amount otherwise, is better than always getting partial amounts: it is less reliable, yet works the same on the average. And there's the increased theme as you point out. |
(0015384) dpeg (administrator) 2011-10-21 03:22 |
The targets are in, using a different approach. Thanks to all who helped! |
Mantis 1.1.8[^] Copyright © 2000 - 2009 Mantis Group |