summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-01-06 21:20:56 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-01-06 21:20:56 +0000
commita2df2a7e984468efba235d355daa9d00ed54103f (patch)
tree2c8884c9881cb3672df74d73d25ff863389377ce /crawl-ref/source
parentef970c20a9d2ecb98d5838d779c1790a449d0f33 (diff)
downloadcrawl-ref-a2df2a7e984468efba235d355daa9d00ed54103f.tar.gz
crawl-ref-a2df2a7e984468efba235d355daa9d00ed54103f.zip
Greatly improve eating interface, as suggested in FRs 1923273 and 2018733.
When you now press 'e' the following takes place: 1) If you can eat chunks, the game builds a list out of all chunks on the floor and in your inventory, sorted by age [1], and prompts you to eat them [2]. 2) If none are found, or you decline all of them you get prompted for non-chunk food items on the floor. 3) Prompt for non-chunk food in your inventory. 4) Open up the food menu of your inventory. Because of the way lua works, there's currently a problem that in the early stages (1-3) "q" (now also accepts Escape) will cause to skip ahead to the next stage rather than leaving the process entirely, which is of course less than optimal. I also added two new options [1] prefer_safe_chunks (defaults to true) which will offer clean chunks before contaminated ones, even if the latter happens to be older [2] easy_eat_chunks (defaults to false) which causes the prompting to be skipped for safe (i.e. clean) chunks, so you will automatically eat the oldest chunk that applies. This is ignored for undead characters. I also got rid of the outdated safechnk.lua and chnkdata.lua seeing how chunk effects are no longer spoily information. Added a new wizmode command: Ctrl-H, which allows you to set your character's hunger state. (Hopefully this will make Vampire testing easier.) Also fix 2488374: "Controlled Flight being named upon levitation even if its type is already known. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@8282 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/acr.cc34
-rw-r--r--crawl-ref/source/clua.cc82
-rw-r--r--crawl-ref/source/command.cc6
-rw-r--r--crawl-ref/source/dat/lua/chnkdata.lua35
-rw-r--r--crawl-ref/source/dat/lua/eat.lua107
-rw-r--r--crawl-ref/source/dat/lua/safechnk.lua37
-rw-r--r--crawl-ref/source/externs.h2
-rw-r--r--crawl-ref/source/food.cc488
-rw-r--r--crawl-ref/source/food.h10
-rw-r--r--crawl-ref/source/initfile.cc4
-rw-r--r--crawl-ref/source/invent.cc2
-rw-r--r--crawl-ref/source/it_use2.cc2
-rw-r--r--crawl-ref/source/item_use.cc53
-rw-r--r--crawl-ref/source/itemname.cc7
-rw-r--r--crawl-ref/source/items.cc10
-rw-r--r--crawl-ref/source/items.h1
-rw-r--r--crawl-ref/source/monplace.cc2
-rw-r--r--crawl-ref/source/player.cc16
18 files changed, 617 insertions, 281 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 70fe2f2155..e017f96054 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -652,6 +652,40 @@ static void _do_wizard_command(int wiz_command, bool silent_fail)
you.redraw_hit_points = true;
break;
+ case CONTROL('H'):
+ mpr( "Set hunger state to s(T)arving, (N)ear starving, (H)ungry, (S)atiated, (F)ull or (E)ngorged?", MSGCH_PROMPT );
+ tmp = tolower(getch());
+
+ // Values taken from food.cc.
+ switch (tmp)
+ {
+ case 't':
+ you.hunger = 500;
+ break;
+ case 'n':
+ you.hunger = 1200;
+ break;
+ case 'h':
+ you.hunger = 2400;
+ break;
+ case 's':
+ you.hunger = 5000;
+ break;
+ case 'f':
+ you.hunger = 8000;
+ break;
+ case 'e':
+ you.hunger = 12000;
+ break;
+ default:
+ canned_msg( MSG_OK );
+ break;
+ }
+ food_change();
+ if (you.species == SP_GHOUL && you.hunger_state >= HS_SATIATED)
+ mpr("Ghouls can never be full or above!");
+ break;
+
case 'b':
// wizards can always blink, with no restrictions or
// magical contamination.
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc
index 2514255c2f..8ee34fb06a 100644
--- a/crawl-ref/source/clua.cc
+++ b/crawl-ref/source/clua.cc
@@ -1127,8 +1127,6 @@ static int l_item_drop(lua_State *ls)
return (1);
}
-static int item_on_floor(const item_def &item, const coord_def& where);
-
static item_def *dmx_get_item(lua_State *ls, int ndx, int subndx)
{
if (lua_istable(ls, ndx))
@@ -1615,9 +1613,7 @@ void luaopen_item(lua_State *ls)
}
/////////////////////////////////////////////////////////////////////
-// Food information. Some of this information is spoily (such as whether
-// a given chunk is poisonous), but that can't be helped.
-//
+// Food information.
static int food_do_eat(lua_State *ls)
{
@@ -1628,13 +1624,23 @@ static int food_do_eat(lua_State *ls)
return (1);
}
+static int food_prompt_eat_chunks(lua_State *ls)
+{
+ int eaten = 0;
+ if (!you.turn_is_over)
+ eaten = eat_chunks();
+
+ lua_pushboolean(ls, (eaten != 0));
+ return (1);
+}
+
static int food_prompt_floor(lua_State *ls)
{
int eaten = 0;
if (!you.turn_is_over)
{
eaten = eat_from_floor();
- if ( eaten == 1 )
+ if (eaten == 1)
burden_change();
}
lua_pushboolean(ls, (eaten != 0));
@@ -1645,7 +1651,16 @@ static int food_prompt_inventory(lua_State *ls)
{
bool eaten = false;
if (!you.turn_is_over)
- eaten = prompt_eat_from_inventory();
+ eaten = eat_from_inventory();
+ lua_pushboolean(ls, eaten);
+ return (1);
+}
+
+static int food_prompt_inventory_menu(lua_State *ls)
+{
+ bool eaten = false;
+ if (!you.turn_is_over)
+ eaten = prompt_eat_inventory_item();
lua_pushboolean(ls, eaten);
return (1);
}
@@ -1667,30 +1682,16 @@ static int food_can_eat(lua_State *ls)
return (1);
}
-static int item_on_floor(const item_def &item, const coord_def& where)
-{
- // Check if the item is on the floor and reachable
- for (int link = igrd(where); link != NON_ITEM; link = mitm[link].link)
- {
- if (&mitm[link] == &item)
- return (link);
- }
- return (NON_ITEM);
-}
-
static bool eat_item(const item_def &item)
{
if (in_inventory(item))
{
- eat_from_inventory(item.link);
- burden_change();
- you.turn_is_over = true;
-
+ eat_inventory_item(item.link);
return (true);
}
else
{
- int ilink = item_on_floor(item, you.pos());
+ int ilink = item_on_floor(item, you.pos());
if (ilink != NON_ITEM)
{
@@ -1733,6 +1734,20 @@ static int food_rotting(lua_State *ls)
return (1);
}
+static int food_dangerous(lua_State *ls)
+{
+ LUA_ITEM(item, 1);
+
+ bool dangerous = false;
+ if (item)
+ {
+ dangerous = (is_poisonous(*item) || is_mutagenic(*item)
+ || causes_rot(*item) || is_forbidden_food(*item));
+ }
+ lua_pushboolean(ls, dangerous);
+ return (1);
+}
+
static int food_ischunk(lua_State *ls)
{
LUA_ITEM(item, 1);
@@ -1744,13 +1759,16 @@ static int food_ischunk(lua_State *ls)
static const struct luaL_reg food_lib[] =
{
- { "do_eat", food_do_eat },
- { "prompt_floor", food_prompt_floor },
- { "prompt_inventory", food_prompt_inventory },
- { "can_eat", food_can_eat },
- { "eat", food_eat },
- { "rotting", food_rotting },
- { "ischunk", food_ischunk },
+ { "do_eat", food_do_eat },
+ { "prompt_eat_chunks", food_prompt_eat_chunks },
+ { "prompt_floor", food_prompt_floor },
+ { "prompt_inventory", food_prompt_inventory },
+ { "prompt_inv_menu", food_prompt_inventory_menu },
+ { "can_eat", food_can_eat },
+ { "eat", food_eat },
+ { "rotting", food_rotting },
+ { "dangerous", food_dangerous },
+ { "ischunk", food_ischunk },
{ NULL, NULL },
};
@@ -2395,7 +2413,7 @@ static option_handler handlers[] =
{ "dos_use_background_intensity", &Options.dos_use_background_intensity,
option_hboolean },
{ "menu_colour_prefix_class", &Options.menu_colour_prefix_class,
- option_hboolean },
+ option_hboolean }
};
static const option_handler *get_handler(const char *optname)
@@ -2403,7 +2421,7 @@ static const option_handler *get_handler(const char *optname)
if (optname)
{
for (int i = 0, count = sizeof(handlers) / sizeof(*handlers);
- i < count; ++i)
+ i < count; ++i)
{
if (!strcmp(handlers[i].option, optname))
return &handlers[i];
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index 3b9755018f..e44ff784d6 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -98,8 +98,7 @@ static const char *features[] = {
static std::string _get_version_information(void)
{
- std::string result = "This is <w>";
- result += CRAWL " " VERSION "</w> (";
+ std::string result = "This is <w>" CRAWL " " VERSION "</w> (";
#ifdef BUILD_REVISION
result += "r" + number_to_string(svn_revision()) + ", ";
#endif
@@ -154,7 +153,7 @@ static std::string _get_version_changes(void)
help = buf;
// Give up if you encounter an older version.
- if (help.find("Stone Soup 0.3.4") != std::string::npos)
+ if (help.find("Stone Soup 0.4") != std::string::npos)
break;
if (help.find("Highlights") != std::string::npos)
@@ -2315,6 +2314,7 @@ int list_wizard_commands(bool do_redraw_screen)
"<w>c</w> : card effect\n"
"<w>Ctrl-G</w> : save ghost (bones file)\n"
"<w>h</w>/<w>H</w> : heal yourself (super-Heal)\n"
+ "<w>Ctrl-H</w> : set hunger state\n"
"<w>X</w> : make Xom do something now\n"
"<w>z</w>/<w>Z</w> : cast spell by number/name\n"
"\n"
diff --git a/crawl-ref/source/dat/lua/chnkdata.lua b/crawl-ref/source/dat/lua/chnkdata.lua
deleted file mode 100644
index bfc93be699..0000000000
--- a/crawl-ref/source/dat/lua/chnkdata.lua
+++ /dev/null
@@ -1,35 +0,0 @@
--- SPOILER WARNING
---
--- This file contains spoiler information. Do not read or use this file if you
--- don't want to be spoiled. Further, the Lua code in this file may use this
--- spoily information to take actions on your behalf. If you don't want
--- automatic exploitation of spoilers, don't use this.
---
----------------------------------------------------------------------------
--- chnkdata.lua:
--- Raw data on chunks of meat, auto-extracted from mon-data.h.
---
--- To use this, add this line to your init.txt:
--- lua_file = lua/chnkdata.lua
---
--- This file has no directly usable functions, but is needed by gourmand.lua
--- and enables auto_eat_chunks in eat.lua.
----------------------------------------------------------------------------
-
-sc_cont = {"program bug","ettin","goblin","jackal","manticore","orc","ugly thing","two-headed ogre","hobgoblin","ogre","troll","orc warrior","orc wizard","orc knight","minotaur","beast","iron devil","orc sorcerer","","","hell knight","necromancer","wizard","orc priest","orc high priest","human","gnoll","earth elemental","fire elemental","air elemental","Ice Fiend","Shadow Fiend","spectral warrior","pulsating lump","rock troll","stone giant","flayed ghost","insubstantial wisp","vapour","ogre-mage","dancing weapon","elf","war dog","grey rat","giant mosquito","fire giant","frost giant","firedrake","deep troll","giant blowfly","swamp dragon","swamp drake","hill giant","giant cockroach","white imp","lemure","ufetubus","manes","midge","neqoxec","hellwing","smoke demon","ynoxinul","Executioner","Blue Death","Balrug","Cacodemon","demonic crawler","sun demon","shadow imp","shadow wraith","Mnoleg","Lom Lobon","Cerebov","Gloorx Vloq","orc warlord","deep elf soldier","deep elf fighter","deep elf knight","deep elf mage","deep elf summoner","deep elf conjurer","deep elf priest","deep elf high priest","deep elf demonologist","deep elf annihilator","deep elf sorcerer","deep elf death mage","Terence","Jessica","Ijyb","Sigmund","Blork the orc","Edmund","Psyche","Erolcha","Donald","Urug","Michael","Joseph","Snorg","Erica","Josephine","Harold","Norbert","Jozef","Agnes","Maud","Louise","Francis","Frances","Rupert","Wayne","Duane","Xtahua","Norris","Frederick","Margery","Boris","Geryon","Dispater","Asmodeus","Antaeus","Ereshkigal","vault guard","Killer Klown","ball lightning","orb of fire","boggart","quicksilver dragon","iron dragon","skeletal warrior","","&","warg","","","komodo dragon"}
-sc_pois = {"killer bee","killer bee larva","quasit","scorpion","yellow wasp","giant beetle","kobold","queen bee","kobold demonologist","big kobold","wolf spider","brain worm","boulder beetle","giant mite","hydra","mottled dragon","brown snake","death yak","bumblebee","redback","spiny worm","golden dragon","elephant slug","green rat","orange rat","black snake","giant centipede","iron troll","naga","yellow snake","red wasp","soldier ant","queen ant","ant larva","spiny frog","orange demon","Green Death","giant amoeba","giant slug","giant snail","boring beetle","naga mage","naga warrior","brown ooze","azure jelly","death ooze","acid blob","ooze","shining eye","greater naga","eye of devastation","gila monster"}
-sc_hcl = {"necrophage","ghoul"}
-sc_mut = {"guardian naga","eye of draining","giant orange brain","great orb of eyes","glowing shapeshifter","shapeshifter","very ugly thing"}
-
-function sc_to_hash(list)
- local hash = { }
- for _, i in ipairs(list) do
- hash[i] = true
- end
- return hash
-end
-
-sc_cont = sc_to_hash( sc_cont )
-sc_pois = sc_to_hash( sc_pois )
-sc_hcl = sc_to_hash( sc_hcl )
-sc_mut = sc_to_hash( sc_mut )
diff --git a/crawl-ref/source/dat/lua/eat.lua b/crawl-ref/source/dat/lua/eat.lua
index c29f043456..ff335f1a8c 100644
--- a/crawl-ref/source/dat/lua/eat.lua
+++ b/crawl-ref/source/dat/lua/eat.lua
@@ -1,108 +1,39 @@
---------------------------------------------------------------------------
-- eat.lua:
--- Prompts to eat chunks from inventory.
+-- Prompts to eat food in the following order:
+-- 1) for chunks on the floor *and* in inventory, sorted by age
+-- 2) for non-chunks on the floor
+-- 3) for non-chunks in inventory
+-- 4) opens the food menu of your inventory
--
-- To use this, add this line to your init.txt:
-- lua_file = lua/eat.lua
--
-- See c_eat in this file if you want to tweak eating behaviour further.
---------------------------------------------------------------------------
-function prompt_eat(i)
- local iname = item.name_coloured(i, "a")
- if item.quantity(i) > 1 then
- iname = "one of " .. iname
- end
- crawl.mpr("Eat " .. iname .. "?", "prompt")
-
- local res
- res = crawl.getch()
- if res == 27 then
- res = "escape"
- elseif res < 32 or res > 127 then
- res = ""
- else
- res = string.lower(string.format("%c", res))
- end
- return res
-end
-
-function chunk_maybe_safe(chunk)
- local rot = food.rotting(chunk)
- local race = you.race()
-
- if rot then
- return you.saprovorous() > 0
- end
-
- return true
-end
-
-function is_chunk_safe(chunk)
- local rot = food.rotting(chunk)
- local race = you.race()
-
- -- Check if the user has sourced safechunk.lua and chnkdata.lua
- if not (sc_cont and sc_pois and sc_hcl and sc_mut and sc_safechunk) then
- return false
- end
-
- local cname = item.name(chunk)
- local mon
- _, _, mon = string.find(cname, "chunk of (.+) flesh")
-
- return sc_safechunk(rot, race, mon)
-end
-- Called by Crawl. Note that once Crawl sees a c_eat function, it bypasses the
-- built-in (e)at command altogether.
--
-function c_eat(floor, inv)
- -- To enable auto_eat_chunks, you also need to source chnkdata.lua and
- -- safechunk.lua. WARNING: These files contain spoily information.
- local auto_eat_chunks = options.auto_eat_chunks == "yes" or
- options.auto_eat_chunks == "true"
-
- if auto_eat_chunks then
- local all = { }
- for _, it in ipairs(floor) do table.insert(all, it) end
- for _, it in ipairs(inv) do table.insert(all, it) end
-
- for _, it in ipairs(all) do
- if food.ischunk(it) and food.can_eat(it) and is_chunk_safe(it) then
- local iname = item.name(it, "a")
- if item.quantity(it) > 1 then
- iname = "one of " .. iname
- end
- crawl.mpr("Eating " .. iname)
- food.eat(it)
- return
- end
- end
+function c_eat()
+ -- Prompt to eat chunks off floor/inventory, sorted by age.
+ -- Returns true if the player chose to eat a chunk.
+ if food.prompt_eat_chunks() then
+ return
end
- -- Prompt to eat chunks off the floor. Returns true if the player chose
- -- to eat a chunk.
+ -- Prompt to eat a non-chunk off the floor. Returns true if the player
+ -- ate something.
if food.prompt_floor() then
return
end
-
- for i, it in ipairs(inv) do
- -- If we have chunks in inventory that the player can eat, prompt.
- if food.ischunk(it) and food.can_eat(it) and chunk_maybe_safe(it) then
- local answer = prompt_eat(it)
- if answer == "q" then
- break
- end
- if answer == "escape" then
- return
- end
- if answer == "y" or answer == "e" then
- food.eat(it)
- return
- end
- end
+
+ -- Prompt to eat a non-chunk from the inventory. Returns true if the player
+ -- ate something.
+ if food.prompt_inventory() then
+ return
end
- -- Allow the player to choose a snack from inventory
- food.prompt_inventory()
+ -- Allow the player to choose a snack from inventory.
+ food.prompt_inv_menu()
end
diff --git a/crawl-ref/source/dat/lua/safechnk.lua b/crawl-ref/source/dat/lua/safechnk.lua
deleted file mode 100644
index 447981f141..0000000000
--- a/crawl-ref/source/dat/lua/safechnk.lua
+++ /dev/null
@@ -1,37 +0,0 @@
--- SPOILER WARNING
---
--- This file contains spoiler information. Do not read or use this file if you
--- don't want to be spoiled. Further, the Lua code in this file may use this
--- spoily information to take actions on your behalf. If you don't want
--- automatic exploitation of spoilers, don't use this.
---
----------------------------------------------------------------------------
--- safechunk.lua:
--- Determines whether a chunk of meat is safe for your character to eat.
---
--- To use this, add this line to your init.txt:
--- lua_file = lua/safechunk.lua
---
--- This file has no directly usable functions, but is needed by gourmand.lua
--- and enables auto_eat_chunks in eat.lua.
----------------------------------------------------------------------------
-
-function sc_safechunk(rot, race, mon)
- if rot then
- if you.saprovorous() < 2 then
- return false
- end
- end
-
- if sc_pois[mon] and you.res_poison() > 0 then
- return true
- end
-
- if sc_hcl[mon] or sc_mut[mon] then
- return race == "Ghoul"
- end
-
- -- Only contaminated and clean chunks remain, in theory. We'll accept
- -- either
- return true
-end
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 737290714a..7dc87f11a9 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1947,6 +1947,8 @@ public:
bool prompt_for_swap; // Prompt to switch back from butchering
// tool if hostile monsters are around.
bool list_rotten; // list slots for rotting corpses/chunks
+ bool prefer_safe_chunks; // prefer clean chunks to contaminated ones
+ bool easy_eat_chunks; // make 'e' auto-eat the oldest safe chunk
bool default_target; // start targeting on a real target
bool autopickup_no_burden; // don't autopickup if it changes burden
diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc
index ece51f4295..1f2e9e4175 100644
--- a/crawl-ref/source/food.cc
+++ b/crawl-ref/source/food.cc
@@ -58,7 +58,6 @@ static int _determine_chunk_effect(int which_chunk_type, bool rotten_chunk);
static void _eat_chunk(int chunk_effect, bool cannibal, int mon_intel = 0);
static void _eating(unsigned char item_class, int item_type);
static void _describe_food_change(int hunger_increment);
-static bool _food_change(bool suppress_message);
static bool _vampire_consume_corpse(int slot, bool invent);
static void _heal_from_food(int hp_amt, int mp_amt = 0, bool unrot = false,
bool restore_str = false);
@@ -89,7 +88,7 @@ void make_hungry(int hunger_amount, bool suppress_msg,
you.hunger = 0;
// So we don't get two messages, ever.
- bool state_message = _food_change(false);
+ bool state_message = food_change();
if (!suppress_msg && !state_message)
_describe_food_change( -hunger_amount );
@@ -106,7 +105,7 @@ void lessen_hunger(int satiated_amount, bool suppress_msg)
you.hunger = 12000;
// So we don't get two messages, ever.
- bool state_message = _food_change(false);
+ bool state_message = food_change();
if (!suppress_msg && !state_message)
_describe_food_change(satiated_amount);
@@ -654,6 +653,7 @@ bool butchery(int which_corpse)
}
break;
+ case ESCAPE:
case 'q':
canned_msg(MSG_OK);
_terminate_butchery(wpn_switch, removed_gloves, old_weapon,
@@ -742,7 +742,7 @@ static bool _userdef_eat_food()
#endif
}
-bool prompt_eat_from_inventory(int slot)
+bool prompt_eat_inventory_item(int slot)
{
if (inv_count() < 1)
{
@@ -800,7 +800,7 @@ bool prompt_eat_from_inventory(int slot)
return (false);
}
- eat_from_inventory(which_inventory_slot);
+ eat_inventory_item(which_inventory_slot);
burden_change();
you.turn_is_over = true;
@@ -833,14 +833,14 @@ bool eat_food(bool run_hook, int slot)
if (igrd(you.pos()) != NON_ITEM && slot == -1)
{
- const int res = eat_from_floor();
+ const int res = eat_from_floor(false);
if (res == 1)
return (true);
if (res == -1)
return (false);
}
- return (prompt_eat_from_inventory(slot));
+ return (prompt_eat_inventory_item(slot));
}
/*
@@ -869,7 +869,7 @@ static bool _player_has_enough_food()
if (is_mutagenic(item))
continue;
- if (causes_rot(item) && you.species != SP_GHOUL)
+ if (causes_rot(item))
continue;
// Vampires can only drain corpses.
@@ -918,7 +918,7 @@ static std::string _how_hungry()
return ("hungry");
}
-static bool _food_change(bool suppress_message)
+bool food_change(bool suppress_message)
{
char newstate = HS_ENGORGED;
bool state_changed = false;
@@ -927,7 +927,7 @@ static bool _food_change(bool suppress_message)
you.hunger = std::max(you_min_hunger(), you.hunger);
you.hunger = std::min(you_max_hunger(), you.hunger);
- // get new hunger state
+ // Get new hunger state.
if (you.hunger <= 1000)
newstate = HS_STARVING;
else if (you.hunger <= 1533)
@@ -989,7 +989,6 @@ static bool _food_change(bool suppress_message)
print_stats();
mpr("You can't stomach any more blood right now.");
}
-
}
if (!suppress_message)
@@ -1092,15 +1091,17 @@ static bool _player_can_eat_rotten_meat(bool need_msg = false)
}
// Should really be merged into function below. -- FIXME
-void eat_from_inventory(int which_inventory_slot)
+void eat_inventory_item(int which_inventory_slot)
{
item_def& food(you.inv[which_inventory_slot]);
if (food.base_type == OBJ_CORPSES && food.sub_type == CORPSE_BODY)
{
_vampire_consume_corpse(which_inventory_slot, true);
+ you.turn_is_over = true;
return;
}
- else if (food.sub_type == FOOD_CHUNK)
+
+ if (food.sub_type == FOOD_CHUNK)
{
const int mons_type = food.plus;
const bool cannibal = is_player_same_species(mons_type);
@@ -1117,6 +1118,7 @@ void eat_from_inventory(int which_inventory_slot)
else
_eating( food.base_type, food.sub_type );
+ you.turn_is_over = true;
dec_inv_item_quantity( which_inventory_slot, 1 );
}
@@ -1154,22 +1156,79 @@ void eat_floor_item(int item_link)
dec_mitm_item_quantity( item_link, 1 );
}
+static bool _is_bad_food(item_def food)
+{
+ return (is_poisonous(food) || is_mutagenic(food)
+ || is_forbidden_food(food) || causes_rot(food));
+}
+
+// Returns which of two food items is older (true for first, else false).
+struct compare_by_freshness
+{
+ bool operator()(item_def *food1, item_def *food2)
+ {
+ ASSERT(food1->base_type == OBJ_CORPSES || food1->base_type == OBJ_FOOD);
+ ASSERT(food2->base_type == OBJ_CORPSES || food2->base_type == OBJ_FOOD);
+ ASSERT(food1->base_type == food2->base_type);
+
+ if (is_inedible(*food1))
+ return (false);
+
+ if (is_inedible(*food2))
+ return (true);
+
+ if (food1->base_type == OBJ_FOOD)
+ {
+ // Prefer chunks to non-chunks. (Herbivores handled above.)
+ if (food1->sub_type != FOOD_CHUNK && food2->sub_type == FOOD_CHUNK)
+ return (false);
+ if (food2->sub_type != FOOD_CHUNK && food1->sub_type == FOOD_CHUNK)
+ return (true);
+ }
+
+ // Both food types are edible (not rotten, or player is Saprovore).
+ if (food1->base_type == OBJ_CORPSES
+ || food1->sub_type == FOOD_CHUNK && food2->sub_type == FOOD_CHUNK)
+ {
+ // Always offer poisonous/mutagenic chunks last.
+ if (_is_bad_food(*food1) && !_is_bad_food(*food2))
+ return (false);
+ if (_is_bad_food(*food2) && !_is_bad_food(*food1))
+ return (true);
+
+ if (Options.prefer_safe_chunks)
+ {
+ // Offer non-contaminated chunks first.
+ if (is_contaminated(*food1) && !is_contaminated(*food2))
+ return (false);
+ if (is_contaminated(*food2) && !is_contaminated(*food1))
+ return (true);
+ }
+ }
+
+ return (food1->special < food2->special);
+ }
+};
+
// Returns -1 for cancel, 1 for eaten, 0 for not eaten.
-int eat_from_floor()
+int eat_from_floor(bool skip_chunks)
{
if (you.flight_mode() == FL_LEVITATE)
- return 0;
+ return (0);
+
+ // Corpses should have been handled before.
+ if (you.species == SP_VAMPIRE && skip_chunks)
+ return (0);
bool need_more = false;
int unusable_corpse = 0;
int inedible_food = 0;
item_def wonteat;
bool found_valid = false;
+
+ std::vector<item_def *> food_items;
for (stack_iterator si(you.pos()); si; ++si )
{
- if (you.species != SP_VAMPIRE && si->base_type != OBJ_FOOD)
- continue;
-
if (you.species == SP_VAMPIRE)
{
if (si->base_type != OBJ_CORPSES || si->sub_type != CORPSE_BODY)
@@ -1181,7 +1240,18 @@ int eat_from_floor()
continue;
}
}
- else if (food_is_rotten(*si) && !_player_can_eat_rotten_meat())
+ else
+ {
+ if (si->base_type != OBJ_FOOD)
+ continue;
+
+ // Chunks should have been handled before.
+ if (skip_chunks && si->sub_type == FOOD_CHUNK)
+ continue;
+ }
+
+ if (!skip_chunks && food_is_rotten(*si)
+ && !_player_can_eat_rotten_meat())
{
unusable_corpse++;
continue;
@@ -1207,40 +1277,56 @@ int eat_from_floor()
}
found_valid = true;
- std::string item_name = get_message_colour_tags(*si, DESC_NOCAP_A,
- MSGCH_PROMPT);
-
- mprf(MSGCH_PROMPT, "%s %s%s? (ye/n/q/i?)",
- (you.species == SP_VAMPIRE ? "Drink blood from" : "Eat"),
- ((si->quantity > 1) ? "one of " : ""),
- item_name.c_str());
+ food_items.push_back(&(*si));
+ }
- int keyin = tolower(getchm(KC_CONFIRM));
- switch (keyin)
+ if (found_valid)
+ {
+ std::sort(food_items.begin(), food_items.end(), compare_by_freshness());
+ for (unsigned int i = 0; i < food_items.size(); ++i)
{
- case 'q':
- canned_msg(MSG_OK);
- return -1;
- case 'e':
- case 'y':
- if (can_ingest(si->base_type, si->sub_type, false))
+ item_def *item = food_items[i];
+ std::string item_name = get_message_colour_tags(*item, DESC_NOCAP_A,
+ MSGCH_PROMPT);
+
+ mprf(MSGCH_PROMPT, "%s %s%s? (ye/n/q/i?)",
+ (you.species == SP_VAMPIRE ? "Drink blood from" : "Eat"),
+ ((item->quantity > 1) ? "one of " : ""),
+ item_name.c_str());
+
+ int keyin = tolower(getchm(KC_CONFIRM));
+ switch (keyin)
{
- eat_floor_item(si->index());
- return 1;
+ case ESCAPE:
+ case 'q':
+ canned_msg(MSG_OK);
+ return -1;
+ case 'e':
+ case 'y':
+ if (can_ingest(item->base_type, item->sub_type, false))
+ {
+ int ilink = item_on_floor(*item, you.pos());
+
+ if (ilink != NON_ITEM)
+ {
+ eat_floor_item(ilink);
+ return (true);
+ }
+ return (false);
+ }
+ need_more = true;
+ break;
+ case 'i':
+ case '?':
+ // Directly skip ahead to inventory.
+ return (0);
+ default:
+ // Else no: try next one.
+ break;
}
- need_more = true;
- break;
- case 'i':
- case '?':
- // Directly skip ahead to inventory.
- return (0);
- default:
- // Else no: try next one.
- break;
}
}
-
- if (!found_valid)
+ else
{
// Give a message about why these food items can not actually be eaten.
if (unusable_corpse)
@@ -1279,6 +1365,275 @@ int eat_from_floor()
return (0);
}
+bool eat_from_inventory()
+{
+ // Corpses should have been handled before.
+ if (you.species == SP_VAMPIRE)
+ return 0;
+
+ int unusable_corpse = 0;
+ int inedible_food = 0;
+ item_def *wonteat;
+ bool found_valid = false;
+
+ std::vector<item_def *> food_items;
+ for (int i = 0; i < ENDOFPACK; ++i)
+ {
+ if (!is_valid_item(you.inv[i]))
+ continue;
+
+ item_def *item = &you.inv[i];
+ if (you.species == SP_VAMPIRE)
+ {
+ if (item->base_type != OBJ_CORPSES || item->sub_type != CORPSE_BODY)
+ continue;
+
+ if (!mons_has_blood(item->plus))
+ {
+ unusable_corpse++;
+ continue;
+ }
+ }
+ else
+ {
+ // Chunks should have been handled before.
+ if (item->base_type != OBJ_FOOD || item->sub_type == FOOD_CHUNK)
+ continue;
+ }
+
+ if (food_is_rotten(*item) && !_player_can_eat_rotten_meat())
+ {
+ unusable_corpse++;
+ continue;
+ }
+ else if (!can_ingest(item->base_type, item->sub_type, true))
+ {
+ if (!inedible_food)
+ {
+ wonteat = item;
+ inedible_food++;
+ }
+ else
+ {
+ // Increase only if we're dealing with different subtypes.
+ // FIXME: Use a common check for herbivorous/carnivorous
+ // dislikes, for e.g. "Blech! You need blood!"
+ ASSERT(is_valid_item(*wonteat));
+ if (wonteat->sub_type != item->sub_type)
+ inedible_food++;
+ }
+ continue;
+ }
+
+ found_valid = true;
+ food_items.push_back(item);
+ }
+
+ if (found_valid)
+ {
+ std::sort(food_items.begin(), food_items.end(), compare_by_freshness());
+ for (unsigned int i = 0; i < food_items.size(); ++i)
+ {
+ item_def *item = food_items[i];
+ std::string item_name = get_message_colour_tags(*item, DESC_NOCAP_A,
+ MSGCH_PROMPT);
+
+ mprf(MSGCH_PROMPT, "%s %s%s? (ye/n/q)",
+ (you.species == SP_VAMPIRE ? "Drink blood from" : "Eat"),
+ ((item->quantity > 1) ? "one of " : ""),
+ item_name.c_str());
+
+ int keyin = tolower(getchm(KC_CONFIRM));
+ switch (keyin)
+ {
+ case ESCAPE:
+ case 'q':
+ canned_msg(MSG_OK);
+ return (false);
+ case 'e':
+ case 'y':
+ if (can_ingest(item->base_type, item->sub_type, false))
+ {
+ eat_inventory_item(item->link);
+ return (true);
+ }
+ break;
+ default:
+ // Else no: try next one.
+ break;
+ }
+ }
+ }
+ else
+ {
+ // 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);
+ }
+ else if (inedible_food)
+ {
+ if (inedible_food == 1)
+ {
+ ASSERT(is_valid_item(*wonteat));
+ // Use the normal cannot ingest message.
+ if (can_ingest(wonteat->base_type, wonteat->sub_type, false))
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Error: Can eat %s after all?",
+ wonteat->name(DESC_PLAIN).c_str() );
+ }
+ }
+ else // Several different food items.
+ mpr("You refuse to eat these food items.");
+ }
+ }
+
+ return (false);
+}
+
+bool eat_chunks()
+{
+ // Herbivores cannot eat chunks.
+ if (player_mutation_level(MUT_HERBIVOROUS) == 3)
+ return (false);
+
+ bool found_valid = false;
+ std::vector<item_def *> chunks;
+
+ // First search the stash on the floor, unless levitating.
+ if (you.flight_mode() != FL_LEVITATE)
+ {
+ for (stack_iterator si(you.pos()); si; ++si)
+ {
+ if (you.species == SP_VAMPIRE)
+ {
+ if (si->base_type != OBJ_CORPSES || si->sub_type != CORPSE_BODY)
+ continue;
+
+ if (!mons_has_blood(si->plus))
+ continue;
+ }
+ else if (si->base_type != OBJ_FOOD || si->sub_type != FOOD_CHUNK)
+ continue;
+
+ if (food_is_rotten(*si) && !_player_can_eat_rotten_meat())
+ continue;
+
+ found_valid = true;
+ chunks.push_back(&(*si));
+ }
+ }
+
+ // Then search through the inventory.
+ for (int i = 0; i < ENDOFPACK; ++i)
+ {
+ if (!is_valid_item(you.inv[i]))
+ continue;
+
+ item_def *item = &you.inv[i];
+ if (you.species == SP_VAMPIRE)
+ {
+ if (item->base_type != OBJ_CORPSES || item->sub_type != CORPSE_BODY)
+ continue;
+
+ if (!mons_has_blood(item->plus))
+ continue;
+ }
+ else if (item->base_type != OBJ_FOOD || item->sub_type != FOOD_CHUNK)
+ continue;
+
+ if (food_is_rotten(*item) && !_player_can_eat_rotten_meat())
+ continue;
+
+ found_valid = true;
+ chunks.push_back(item);
+ }
+
+ if (found_valid)
+ {
+ std::sort(chunks.begin(), chunks.end(), compare_by_freshness());
+ for (unsigned int i = 0; i < chunks.size(); ++i)
+ {
+ bool autoeat = false;
+ item_def *item = chunks[i];
+ std::string item_name = get_message_colour_tags(*item,
+ DESC_NOCAP_A,
+ MSGCH_PROMPT);
+
+ // Excempt undead from auto-eating since:
+ // * Mummies don't eat.
+ // * Vampire feeding takes a lot more time than eating a chunk
+ // and may have unintended consequences.
+ // * Ghouls may want to wait until chunks become rotten.
+ if (Options.easy_eat_chunks && !you.is_undead
+ && !_is_bad_food(*item) && !is_contaminated(*item))
+ {
+ // If this chunk is safe to eat, just do so without prompting.
+ autoeat = true;
+ }
+ else
+ {
+ mprf(MSGCH_PROMPT, "%s %s%s? (ye/n/q)",
+ (you.species == SP_VAMPIRE ? "Drink blood from" : "Eat"),
+ ((item->quantity > 1) ? "one of " : ""),
+ item_name.c_str());
+ }
+
+ int keyin = autoeat ? 'y' : tolower(getchm(KC_CONFIRM));
+ switch (keyin)
+ {
+ case ESCAPE:
+ case 'q':
+ canned_msg(MSG_OK);
+ return (false);
+ case 'e':
+ case 'y':
+ if (can_ingest(item->base_type, item->sub_type, false))
+ {
+ if (autoeat)
+ {
+ mprf("%s %s%s.",
+ (you.species == SP_VAMPIRE ? "Drinking blood from"
+ : "Eating"),
+ ((item->quantity > 1) ? "one of " : ""),
+ item_name.c_str());
+ }
+
+ if (in_inventory(*item))
+ {
+ eat_inventory_item(item->link);
+ return (true);
+ }
+ else
+ {
+ int ilink = item_on_floor(*item, you.pos());
+
+ if (ilink != NON_ITEM)
+ {
+ eat_floor_item(ilink);
+ return (true);
+ }
+ return (false);
+ }
+ }
+ break;
+ default:
+ // Else no: try next one.
+ break;
+ }
+ }
+ }
+
+ return (false);
+}
+
static const char *_chunk_flavour_phrase(bool likes_chunks)
{
const char *phrase =
@@ -1358,8 +1713,8 @@ static void _say_chunk_flavour(bool likes_chunks)
// through food::_determine_chunk_effect() first. {dlb}:
static void _eat_chunk(int chunk_effect, bool cannibal, int mon_intel)
{
- bool likes_chunks = (you.omnivorous() ||
- player_mutation_level(MUT_CARNIVOROUS));
+ bool likes_chunks = (you.omnivorous()
+ || player_mutation_level(MUT_CARNIVOROUS));
int nutrition = _chunk_nutrition(likes_chunks);
int hp_amt = 0;
bool suppress_msg = false; // do we display the chunk nutrition message?
@@ -1939,6 +2294,10 @@ bool is_mutagenic(const item_def &food)
if (food.base_type != OBJ_FOOD && food.base_type != OBJ_CORPSES)
return (false);
+ // Has no effect on ghouls.
+ if (you.species == SP_GHOUL)
+ return (false);
+
return (mons_corpse_effect(food.plus) == CE_MUTAGEN_RANDOM);
}
@@ -1948,6 +2307,10 @@ bool is_contaminated(const item_def &food)
if (food.base_type != OBJ_FOOD && food.base_type != OBJ_CORPSES)
return (false);
+ // Has no (bad) effect on ghouls.
+ if (you.species == SP_GHOUL)
+ return (false);
+
return (mons_corpse_effect(food.plus) == CE_CONTAMINATED);
}
@@ -1957,6 +2320,10 @@ bool causes_rot(const item_def &food)
if (food.base_type != OBJ_FOOD && food.base_type != OBJ_CORPSES)
return (false);
+ // Has no effect on ghouls.
+ if (you.species == SP_GHOUL)
+ return (false);
+
return (mons_corpse_effect(food.plus) == CE_HCL);
}
@@ -2065,6 +2432,29 @@ bool is_preferred_food(const item_def &food)
return (false);
}
+bool is_forbidden_food(const item_def &food)
+{
+ if (food.base_type != OBJ_CORPSES
+ && (food.base_type != OBJ_FOOD || food.sub_type != FOOD_CHUNK))
+ {
+ return (false);
+ }
+
+ // Some gods frown upon cannibalistic behaviour.
+ if (god_hates_cannibalism(you.religion)
+ && is_player_same_species(food.plus))
+ {
+ return (true);
+ }
+
+ // Zin doesn't like it if you eat beings with a soul.
+ if (you.religion == GOD_ZIN && mons_class_intel(food.plus) >= I_NORMAL)
+ return (true);
+
+ // Everything else is allowed.
+ return (false);
+}
+
bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid,
bool check_hunger)
{
diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h
index e89bde824f..8ce977e6ee 100644
--- a/crawl-ref/source/food.h
+++ b/crawl-ref/source/food.h
@@ -85,17 +85,21 @@ bool is_contaminated(const item_def &food);
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 can_ingest(int what_isit, int kindof_thing, bool suppress_msg,
bool reqid = false, bool check_hunger = true);
void eat_floor_item(int item_link);
-int eat_from_floor();
+int eat_from_floor(bool skip_chunks = true);
+bool eat_from_inventory();
+bool eat_chunks();
-void eat_from_inventory(int which_inventory_slot);
+bool food_change(bool suppress_message = false);
+void eat_inventory_item(int which_inventory_slot);
-bool prompt_eat_from_inventory(int slot = -1);
+bool prompt_eat_inventory_item(int slot = -1);
void chunk_nutrition_message(int nutrition);
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index e99036a00c..3bf7c2f180 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -686,6 +686,8 @@ void game_options::reset_options()
chunks_autopickup = true;
prompt_for_swap = true;
list_rotten = true;
+ prefer_safe_chunks = true;
+ easy_eat_chunks = false;
easy_confirm = CONFIRM_SAFE_EASY;
easy_quit_item_prompts = true;
allow_self_target = CONFIRM_PROMPT;
@@ -2081,6 +2083,8 @@ void game_options::read_option_line(const std::string &str, bool runscript)
else BOOL_OPTION(chunks_autopickup);
else BOOL_OPTION(prompt_for_swap);
else BOOL_OPTION(list_rotten);
+ else BOOL_OPTION(prefer_safe_chunks);
+ else BOOL_OPTION(easy_eat_chunks);
else if (key == "lua_file" && runscript)
{
#ifdef CLUA_BINDINGS
diff --git a/crawl-ref/source/invent.cc b/crawl-ref/source/invent.cc
index bfb7f24e57..5c63d757d9 100644
--- a/crawl-ref/source/invent.cc
+++ b/crawl-ref/source/invent.cc
@@ -1151,9 +1151,11 @@ std::vector<SelItem> prompt_invent_items(
}
if (ret != PROMPT_ABORT)
+ {
items.push_back(
SelItem( ret, count,
ret != PROMPT_GOT_SPECIAL ? &you.inv[ret] : NULL ) );
+ }
return items;
}
diff --git a/crawl-ref/source/it_use2.cc b/crawl-ref/source/it_use2.cc
index 35ed8900f0..2f61b26f41 100644
--- a/crawl-ref/source/it_use2.cc
+++ b/crawl-ref/source/it_use2.cc
@@ -177,7 +177,7 @@ bool potion_effect( potion_type pot_eff, int pow, bool was_known )
&& !extrinsic_amulet_effect(AMU_CONTROLLED_FLIGHT))
{
item_def& amu(you.inv[you.equip[EQ_AMULET]]);
- if (!is_artefact(amu))
+ if (!is_artefact(amu) && !item_type_known(amu))
{
set_ident_type(amu.base_type, amu.sub_type, ID_KNOWN_TYPE);
set_ident_flags(amu, ISFLAG_KNOW_PROPERTIES);
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index 0e90ed318f..731d10567b 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -2786,33 +2786,45 @@ void jewellery_wear_effects(item_def &item)
break;
case RING_STRENGTH:
- modify_stat(STAT_STRENGTH, item.plus, false, item);
- if (item.plus != 0 && !artefact)
- ident = ID_KNOWN_TYPE;
- learn_pluses = true;
+ if (item.plus)
+ {
+ modify_stat(STAT_STRENGTH, item.plus, false, item);
+
+ if (artefact)
+ fake_rap = RAP_STRENGTH;
+ else
+ ident = ID_KNOWN_TYPE;
- if (Options.autoinscribe_randarts && is_random_artefact(item))
- add_autoinscription( item, randart_auto_inscription(item));
+ learn_pluses = true;
+ }
break;
case RING_DEXTERITY:
- modify_stat(STAT_DEXTERITY, item.plus, false, item);
- if (item.plus != 0 && !artefact)
- ident = ID_KNOWN_TYPE;
- learn_pluses = true;
+ if (item.plus)
+ {
+ modify_stat(STAT_DEXTERITY, item.plus, false, item);
+
+ if (artefact)
+ fake_rap = RAP_DEXTERITY;
+ else
+ ident = ID_KNOWN_TYPE;
- if (Options.autoinscribe_randarts && is_random_artefact(item))
- add_autoinscription( item, randart_auto_inscription(item));
+ learn_pluses = true;
+ }
break;
case RING_INTELLIGENCE:
- modify_stat(STAT_INTELLIGENCE, item.plus, false, item);
- if (item.plus != 0 && !artefact)
- ident = ID_KNOWN_TYPE;
- learn_pluses = true;
+ if (item.plus)
+ {
+ modify_stat(STAT_INTELLIGENCE, item.plus, false, item);
- if (Options.autoinscribe_randarts && is_random_artefact(item))
- add_autoinscription( item, randart_auto_inscription(item));
+ if (artefact)
+ fake_rap = RAP_INTELLIGENCE;
+ else
+ ident = ID_KNOWN_TYPE;
+
+ learn_pluses = true;
+ }
break;
case RING_MAGICAL_POWER:
@@ -2874,7 +2886,7 @@ void jewellery_wear_effects(item_def &item)
}
// Artefacts have completely different appearance than base types
- // so we don't allow them to make the base types known
+ // so we don't allow them to make the base types known.
if (artefact)
{
use_randart(item);
@@ -4814,6 +4826,9 @@ void use_randart(item_def &item, bool unmeld)
if (proprt[RAP_NOISES])
you.special_wield = SPWLD_NOISE;
+ if (!alreadyknown && Options.autoinscribe_randarts)
+ add_autoinscription(item, randart_auto_inscription(item));
+
if (!alreadyknown && dangerous)
{
// Xom loves it when you use an unknown random artefact and
diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc
index 064880c298..6d9d551378 100644
--- a/crawl-ref/source/itemname.cc
+++ b/crawl-ref/source/itemname.cc
@@ -2622,13 +2622,8 @@ static const std::string _item_prefix(const item_def &item, bool temp,
}
// intentional fall-through
case OBJ_FOOD:
- if ((item.base_type == OBJ_CORPSES || item.sub_type == FOOD_CHUNK)
- && (is_good_god(you.religion) && is_player_same_species(item.plus)
- || you.religion == GOD_ZIN
- && mons_class_intel(item.plus) >= I_NORMAL))
- {
+ if (is_forbidden_food(item))
prefixes.push_back("evil_eating");
- }
if (is_inedible(item))
prefixes.push_back("inedible");
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index f5b0788492..a05a5d8e9e 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -2443,6 +2443,16 @@ item_def *find_floor_item(object_class_type cls, int sub_type)
return (NULL);
}
+int item_on_floor(const item_def &item, const coord_def& where)
+{
+ // Check if the item is on the floor and reachable.
+ for (int link = igrd(where); link != NON_ITEM; link = mitm[link].link)
+ if (&mitm[link] == &item)
+ return (link);
+
+ return (NON_ITEM);
+}
+
static bool _find_subtype_by_name(item_def &item,
object_class_type base_type, int ntypes,
const std::string &name)
diff --git a/crawl-ref/source/items.h b/crawl-ref/source/items.h
index 959f2efd0a..1770c8032f 100644
--- a/crawl-ref/source/items.h
+++ b/crawl-ref/source/items.h
@@ -50,6 +50,7 @@ bool items_stack( const item_def &item1, const item_def &item2,
item_def find_item_type(object_class_type base_type, std::string name);
item_def *find_floor_item(object_class_type cls, int sub_type);
+int item_on_floor(const item_def &item, const coord_def& where);
void init_item( int item );
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 02a943bc1a..d1ace875bf 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -1121,6 +1121,8 @@ static int _place_monster_aux(const mgen_data &mg,
menv[id].attitude = ATT_HOSTILE;
menv[id].behaviour = mg.behaviour;
+ // Statues cannot sleep (nor wander but it means they are a bit
+ // more aware of the player than they'd be otherwise).
if (mons_is_statue(mg.cls))
menv[id].behaviour = BEH_WANDER;
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 7860aa7d4d..41f86f9ace 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -1059,18 +1059,18 @@ int player_regen(void)
{
switch (you.hunger_state)
{
- case HS_STARVING:
+ case HS_STARVING:
return (0); // No regeneration for starving vampires!
- case HS_NEAR_STARVING:
- case HS_VERY_HUNGRY:
- case HS_HUNGRY:
+ case HS_NEAR_STARVING:
+ case HS_VERY_HUNGRY:
+ case HS_HUNGRY:
return (rr / 2);
- case HS_SATIATED:
+ case HS_SATIATED:
return (rr);
- case HS_FULL:
- case HS_VERY_FULL:
+ case HS_FULL:
+ case HS_VERY_FULL:
return (rr + 10);
- case HS_ENGORGED:
+ case HS_ENGORGED:
return (rr + 20);
}
}