summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/dat/database/monspeak.txt2
-rw-r--r--crawl-ref/source/debug.cc14
-rw-r--r--crawl-ref/source/describe.cc20
-rw-r--r--crawl-ref/source/effects.cc107
-rw-r--r--crawl-ref/source/item_use.cc17
-rw-r--r--crawl-ref/source/items.cc54
-rw-r--r--crawl-ref/source/libgui.cc19
-rw-r--r--crawl-ref/source/makeitem.cc9
-rw-r--r--crawl-ref/source/misc.cc606
-rw-r--r--crawl-ref/source/misc.h11
-rw-r--r--crawl-ref/source/newgame.cc5
-rw-r--r--crawl-ref/source/player.cc4
-rw-r--r--crawl-ref/source/spells4.cc11
13 files changed, 664 insertions, 215 deletions
diff --git a/crawl-ref/source/dat/database/monspeak.txt b/crawl-ref/source/dat/database/monspeak.txt
index b67de8e3c9..6680635431 100644
--- a/crawl-ref/source/dat/database/monspeak.txt
+++ b/crawl-ref/source/dat/database/monspeak.txt
@@ -2241,7 +2241,7 @@ orc sorcerer
@_wizard_@
w:1
-@_generic_orc_@
+@_generic_orc_speech@
w:1
__NONE
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index b685550733..0f0509b730 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -1244,12 +1244,14 @@ void create_spec_object()
break;
case OBJ_POTIONS:
- if (mitm[thing_created].sub_type == POT_BLOOD)
- mitm[thing_created].special = 1200;
- else if (mitm[thing_created].sub_type == POT_BLOOD_COAGULATED)
- mitm[thing_created].special = 200;
- // intentional fall-through
-
+ mitm[thing_created].quantity = 12;
+ if (mitm[thing_created].sub_type == POT_BLOOD
+ || mitm[thing_created].sub_type == POT_BLOOD_COAGULATED)
+ {
+ init_stack_blood_potions(mitm[thing_created]);
+ }
+ break;
+
case OBJ_FOOD:
case OBJ_SCROLLS:
mitm[thing_created].quantity = 12;
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 0c2bbdfc24..2f487034f4 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -1645,8 +1645,26 @@ std::string get_item_description( const item_def &item, bool verbose,
description << "$This book is beyond your current level of understanding.";
break;
- case OBJ_SCROLLS:
case OBJ_POTIONS:
+#ifdef DEBUG_BLOOD_POTIONS
+ // list content of timer vector for blood potions
+ if (item.sub_type == POT_BLOOD
+ || item.sub_type == POT_BLOOD_COAGULATED)
+ {
+ item_def stack = static_cast<item_def>(item);
+ CrawlHashTable &props = stack.props;
+ ASSERT(props.exists("timer"));
+ CrawlVector &timer = props["timer"].get_vector();
+ ASSERT(!timer.empty());
+
+ description << "$Quantity: " << stack.quantity
+ << " Timer size: " << (int) timer.size();
+ description << "$Timers:$";
+ for (int i = 0; i < timer.size(); i++)
+ description << (timer[i].get_long()) << " ";
+ }
+#endif
+ case OBJ_SCROLLS:
case OBJ_ORBS:
case OBJ_CORPSES:
case OBJ_GOLD:
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index e050246104..d77f3c5a5d 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -1547,12 +1547,11 @@ bool acquirement(object_class_type class_wanted, int agent,
else if (quant > 1)
thing.quantity = quant;
- if (thing.base_type == OBJ_POTIONS)
+ if (thing.base_type == OBJ_POTIONS
+ && (thing.sub_type == POT_BLOOD
+ || thing.sub_type == POT_BLOOD_COAGULATED))
{
- if (thing.sub_type == POT_BLOOD)
- thing.special = 1200;
- else if (thing.sub_type == POT_BLOOD_COAGULATED)
- thing.special = 200;
+ init_stack_blood_potions(thing);
}
// remove curse flag from item
@@ -2213,9 +2212,6 @@ static void rot_inventory_food(long time_delta)
// Update all of the corpses and food chunks in the player's
// inventory {should be moved elsewhere - dlb}
bool burden_changed_by_rot = false;
- int num_total_blood = 0, num_blood_coagulates = 0;
- int affected_potion = -1; // stack of coagulating blood potions
- // (only one possible at a time)
std::vector<char> rotten_items;
for (int i = 0; i < ENDOFPACK; i++)
{
@@ -2225,11 +2221,18 @@ static void rot_inventory_food(long time_delta)
if (!food_item_needs_time_check(you.inv[i]))
continue;
+ if (you.inv[i].base_type == OBJ_POTIONS)
+ {
+ // also handles messaging
+ if (maybe_coagulate_blood_potions_inv(you.inv[i]))
+ burden_changed_by_rot = true;
+ continue;
+ }
+
// food item timed out -> make it disappear
if ((time_delta / 20) >= you.inv[i].special)
{
- if (you.inv[i].base_type == OBJ_FOOD
- || you.inv[i].base_type == OBJ_POTIONS)
+ if (you.inv[i].base_type == OBJ_FOOD)
{
if (you.equip[EQ_WEAPON] == i)
unwield_item();
@@ -2263,18 +2266,8 @@ static void rot_inventory_food(long time_delta)
// if it hasn't disappeared, reduce the rotting timer
you.inv[i].special -= (time_delta / 20);
- if (you.inv[i].base_type == OBJ_POTIONS
- && you.inv[i].sub_type == POT_BLOOD)
- {
- num_total_blood += you.inv[i].quantity;
- if (you.inv[i].special < 200)
- {
- num_blood_coagulates += you.inv[i].quantity;
- affected_potion = i;
- }
- }
- else if (food_is_rotten(you.inv[i])
- && (you.inv[i].special + (time_delta / 20) >= 100 ))
+ if (food_is_rotten(you.inv[i])
+ && (you.inv[i].special + (time_delta / 20) >= 100 ))
{
rotten_items.push_back(index_to_letter( i ));
}
@@ -2339,50 +2332,6 @@ static void rot_inventory_food(long time_delta)
learned_something_new(TUT_ROTTEN_FOOD);
}
- if (num_blood_coagulates)
- {
- ASSERT(affected_potion != -1);
-
- std::string msg = "";
-
- if (num_total_blood == num_blood_coagulates)
- msg += you.inv[affected_potion].name(DESC_CAP_YOUR, false);
-/*
- // this is for later, when part of a stack can coagulate
- else
- {
- if (congealed_blood_num == 1)
- msg += "One of ";
- else
- msg += "Some of ";
-
- msg += you.inv[affected_potion].name(DESC_NOCAP_YOUR, false);
- }
-*/
- msg += " coagulate";
- if (num_blood_coagulates == 1)
- msg += "s";
- msg += ".";
-
- mpr(msg.c_str(), MSGCH_ROTTEN_MEAT);
-
- const bool known_blood = item_type_known(you.inv[affected_potion]);
- you.inv[affected_potion].sub_type = POT_BLOOD_COAGULATED;
- you.inv[affected_potion].plus
- = you.item_description[IDESC_POTIONS][POT_BLOOD_COAGULATED];
- const bool known_coag_blood = item_type_known(you.inv[affected_potion]);
-
- // identify both blood and coagulated blood, if necessary
- if (!known_blood)
- set_ident_type( OBJ_POTIONS, POT_BLOOD, ID_KNOWN_TYPE );
- if (!known_coag_blood)
- {
- set_ident_flags( you.inv[affected_potion], ISFLAG_IDENT_MASK );
- set_ident_type( OBJ_POTIONS, POT_BLOOD_COAGULATED, ID_KNOWN_TYPE );
- mpr(you.inv[affected_potion].name(DESC_INVENTORY, false).c_str());
- }
- }
-
if (burden_changed_by_rot)
{
mpr("Your equipment suddenly weighs less.", MSGCH_ROTTEN_MEAT);
@@ -2879,10 +2828,9 @@ static void _maybe_restart_fountain_flow(const int x, const int y,
const int tries)
{
dungeon_feature_type grid = grd[x][y];
+
if (grid < DNGN_DRY_FOUNTAIN_BLUE || grid > DNGN_DRY_FOUNTAIN_BLOOD)
- {
return;
- }
int t = 0;
while (tries > t++)
@@ -2941,9 +2889,15 @@ void update_corpses(double elapsedTime)
if (!food_item_needs_time_check(it))
continue;
+ if (it.base_type == OBJ_POTIONS)
+ {
+ maybe_coagulate_blood_potions_floor(c);
+ continue;
+ }
+
if (rot_time >= it.special && !is_being_butchered(it))
{
- if (it.base_type == OBJ_FOOD || it.base_type == OBJ_POTIONS)
+ if (it.base_type == OBJ_FOOD)
{
destroy_item(c);
}
@@ -2964,22 +2918,7 @@ void update_corpses(double elapsedTime)
}
else
{
- // potions of blood have a longer rot time
- if (it.base_type != OBJ_POTIONS)
- ASSERT(rot_time < 256);
-
it.special -= rot_time;
-
- if (it.base_type == OBJ_POTIONS
- && it.sub_type == POT_BLOOD
- && it.special < 200)
- {
- ASSERT(rot_time < 1200);
- it.sub_type = POT_BLOOD_COAGULATED;
-
- it.plus
- = you.item_description[IDESC_POTIONS][POT_BLOOD_COAGULATED];
- }
}
}
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index 482291666d..ed787ab125 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -1755,6 +1755,17 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
item.quantity = 1;
item.slot = index_to_letter(item.link);
origin_set_unknown(item);
+ if (item.base_type == OBJ_POTIONS
+ && (item.sub_type == POT_BLOOD
+ || item.sub_type == POT_BLOOD_COAGULATED)
+ && you.inv[throw_2].quantity > 1)
+ {
+ // initialize thrown potion with oldest potion in stack
+ long val = remove_oldest_blood_potion(you.inv[throw_2]);
+ val -= you.num_turns;
+ item.props.clear();
+ init_stack_blood_potions(item, val);
+ }
if (you.duration[DUR_CONF])
{
@@ -3497,6 +3508,12 @@ void drink( int slot )
xom_is_stimulated(255);
}
+ if (you.inv[item_slot].sub_type == POT_BLOOD
+ || you.inv[item_slot].sub_type == POT_BLOOD_COAGULATED)
+ {
+ // always drink oldest potion
+ remove_oldest_blood_potion(you.inv[item_slot]);
+ }
dec_inv_item_quantity( item_slot, 1 );
you.turn_is_over = true;
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index f7aa0a111b..06ccc9d944 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -1530,10 +1530,7 @@ int move_item_to_player( int obj, int quant_got, bool quiet )
&& (mitm[obj].sub_type == POT_BLOOD
|| mitm[obj].sub_type == POT_BLOOD_COAGULATED))
{
- // use average age
- int age = you.inv[m].special * you.inv[m].quantity
- + mitm[obj].special * quant_got;
- you.inv[m].special = age / (you.inv[m].quantity + quant_got);
+ pick_up_blood_potions_stack(mitm[obj], quant_got);
}
inc_inv_item_quantity( m, quant_got );
dec_mitm_item_quantity( obj, quant_got );
@@ -1586,20 +1583,34 @@ int move_item_to_player( int obj, int quant_got, bool quiet )
check_note_item(item);
item.quantity = quant_got;
+ if (mitm[obj].base_type == OBJ_POTIONS
+ && (mitm[obj].sub_type == POT_BLOOD
+ || mitm[obj].sub_type == POT_BLOOD_COAGULATED))
+ {
+ if (quant_got != mitm[obj].quantity)
+ {
+ // remove oldest timers from original stack
+ for (int i = 0; i < quant_got; i++)
+ remove_oldest_blood_potion(mitm[obj]);
+
+ // ... and newest ones from picked up stack
+ remove_newest_blood_potion(item);
+ }
+ }
dec_mitm_item_quantity( obj, quant_got );
you.m_quiver->on_inv_quantity_changed(freeslot, quant_got);
burden_change();
if (!quiet)
mpr( you.inv[freeslot].name(DESC_INVENTORY).c_str() );
-
+
if (Options.tutorial_left)
{
taken_new_item(item.base_type);
if (is_artefact(item) || get_equip_desc( item ) != ISFLAG_NO_DESC)
learned_something_new(TUT_SEEN_RANDART);
}
-
+
if (item.base_type == OBJ_ORBS
&& you.char_direction == GDT_DESCENDING)
{
@@ -1737,17 +1748,16 @@ bool copy_item_to_grid( const item_def &item, int x_plos, int y_plos,
{
if (items_stack( item, mitm[i] ))
{
+ inc_mitm_item_quantity( i, quant_drop );
+
if (item.base_type == OBJ_POTIONS
&& (item.sub_type == POT_BLOOD
|| item.sub_type == POT_BLOOD_COAGULATED))
{
- // calculate average age
- int age = mitm[i].special * mitm[i].quantity
- + item.special * quant_drop;
- mitm[i].special = age / (mitm[i].quantity + quant_drop);
+ item_def help = item;
+ drop_blood_potions_stack(help, quant_drop, x_plos, y_plos);
}
- inc_mitm_item_quantity( i, quant_drop );
-
+
// If the items on the floor already have a nonzero slot,
// leave it as such, otherwise set the slot.
if (mark_dropped && !mitm[i].slot)
@@ -1780,6 +1790,15 @@ bool copy_item_to_grid( const item_def &item, int x_plos, int y_plos,
}
move_item_to_grid( &new_item, x_plos, y_plos );
+ if (item.base_type == OBJ_POTIONS
+ && (item.sub_type == POT_BLOOD
+ || item.sub_type == POT_BLOOD_COAGULATED)
+ && item.quantity != quant_drop) // partial drop only
+ {
+ // since only the oldest potions have been dropped,
+ // remove the newest ones
+ remove_newest_blood_potion(mitm[new_item]);
+ }
return (true);
} // end copy_item_to_grid()
@@ -1893,7 +1912,16 @@ bool drop_item( int item_dropped, int quant_drop, bool try_offer )
}
else if (strstr(you.inv[item_dropped].inscription.c_str(), "=s") != 0)
StashTrack.add_stash();
-
+
+ if (you.inv[item_dropped].base_type == OBJ_POTIONS
+ && (you.inv[item_dropped].sub_type == POT_BLOOD
+ || you.inv[item_dropped].sub_type == POT_BLOOD_COAGULATED)
+ && you.inv[item_dropped].quantity != quant_drop)
+ {
+ // oldest potions have been dropped
+ for (int i = 0; i < quant_drop; i++)
+ remove_oldest_blood_potion(you.inv[item_dropped]);
+ }
dec_inv_item_quantity( item_dropped, quant_drop );
you.turn_is_over = true;
diff --git a/crawl-ref/source/libgui.cc b/crawl-ref/source/libgui.cc
index 73a83f25be..6b005cb167 100644
--- a/crawl-ref/source/libgui.cc
+++ b/crawl-ref/source/libgui.cc
@@ -29,6 +29,7 @@
#include "externs.h"
#include "guic.h"
#include "message.h"
+#include "misc.h"
#include "mon-util.h"
#include "newgame.h"
#include "player.h"
@@ -367,19 +368,19 @@ void GmapUpdate(int x, int y, int what, bool upd_tile)
c = _gmap_to_colour(gmap_col[what & 0xff]);
break;
}
- if (c == Options.tile_monster_col && mgrd[x][y] != NON_MONSTER
- && upd_tile)
+
+ if (c == Options.tile_monster_col && mgrd[x][y] != NON_MONSTER)
{
const int grid = mgrd[x][y];
- if (mons_friendly(&menv[grid]))
+ if (mons_friendly(&menv[grid]) && upd_tile)
c = Options.tile_friendly_col; // colour friendly monsters
- else if (mons_neutral(&menv[grid])
+ else if (mons_neutral(&menv[grid]) && upd_tile
&& Options.tile_neutral_col != Options.tile_monster_col)
{
c = Options.tile_neutral_col; // colour neutral monsters
}
else if (mons_class_flag( menv[grid].type, M_NO_EXP_GAIN ))
- c = Options.tile_plant_col;
+ c = Options.tile_plant_col; // colour zero xp monsters
}
if (c == Options.tile_floor_col || c == Options.tile_item_col)
@@ -1345,8 +1346,12 @@ static int _handle_mouse_motion(int mouse_x, int mouse_y, bool init)
&& item.sub_type != CORPSE_SKELETON
&& !food_is_rotten(item))
{
- // TODO: Differentiate bottle/butcher for vampires.
- desc += EOL "[Shift-L-Click] Chop up (c)";
+ desc += EOL "[Shift-L-Click] ";
+ if (can_bottle_blood_from_corpse( item.plus))
+ desc += "Bottle blood";
+ else
+ desc += "Chop up";
+ desc += " (c)";
if (you.species == SP_VAMPIRE)
desc += EOL "[Shift-R-Click] Drink blood (e)";
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index 586f9b3aa3..efb4afbe4f 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -19,6 +19,7 @@
#include "itemname.h"
#include "itemprop.h"
#include "items.h"
+#include "misc.h"
#include "mon-util.h"
#include "player.h"
#include "randart.h"
@@ -2313,11 +2314,9 @@ static void generate_potion_item(item_def& item, int force_type, int item_level)
}
item.sub_type = stype;
}
-
- if (item.sub_type == POT_BLOOD)
- item.special = 1200;
- else
- item.special = 0;
+
+ if (item.sub_type == POT_BLOOD || item.sub_type == POT_BLOOD_COAGULATED)
+ init_stack_blood_potions(item);
}
static void generate_scroll_item(item_def& item, int force_type,
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index bd124f5d9d..2a64821b6d 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -163,18 +163,32 @@ void turn_corpse_into_chunks( item_def &item )
void init_stack_blood_potions(item_def &stack, int age)
{
ASSERT(stack.base_type == OBJ_POTIONS);
- ASSERT(stack.sub_type == POT_BLOOD);
+ ASSERT(stack.sub_type == POT_BLOOD
+ || stack.sub_type == POT_BLOOD_COAGULATED);
CrawlHashTable &props = stack.props;
+ props.clear(); // sanity measure
props.set_default_flags(SFLAG_CONST_TYPE);
props["timer"].new_vector(SV_LONG);
- CrawlVector &timer = props["timer"];
+ CrawlVector &timer = props["timer"].get_vector();
+ if (age == -1)
+ {
+ if (stack.sub_type == POT_BLOOD)
+ age = 2000;
+ else // coagulated blood
+ age = 500;
+ }
// for a newly created stack, all potions use the same timer
- const long max_age = you.num_turns + (age == -1 ? 1200 : age);
+ const long max_age = you.num_turns + age;
+#ifdef DEBUG_BLOOD_POTIONS
+ mprf(MSGCH_DIAGNOSTICS, "newly created stack will time out at turn %d",
+ max_age);
+#endif
for (int i = 0; i < stack.quantity; i++)
timer.push_back(max_age);
+ stack.special = 0;
ASSERT(timer.size() == stack.quantity);
props.assert_validity();
}
@@ -184,21 +198,23 @@ static void _long_sort(CrawlVector &vec)
{
std::vector<long> help;
while (!vec.empty())
- help.push_back(vec.pop_back());
+ {
+ help.push_back(vec[vec.size()-1].get_long());
+ vec.pop_back();
+ }
std::sort(help.begin(), help.end());
- long val;
while (!help.empty())
{
- val = help[help.size() - 1];
+ vec.push_back(help[help.size()-1]);
help.pop_back();
- vec.push_back(val);
}
}
-void maybe_coagulate_blood_floor(item_def &blood)
+void maybe_coagulate_blood_potions_floor(int obj)
{
+ item_def &blood = mitm[obj];
ASSERT(is_valid_item(blood));
ASSERT(blood.base_type == OBJ_POTIONS);
@@ -206,46 +222,61 @@ void maybe_coagulate_blood_floor(item_def &blood)
|| blood.sub_type == POT_BLOOD_COAGULATED);
CrawlHashTable &props = blood.props;
+ if (!props.exists("timer"))
+ init_stack_blood_potions(blood, blood.special);
+
ASSERT(props.exists("timer"));
- CrawlVector &timer = props["timer"];
- ASSERT(timer.size() == blood.quantity);
+ CrawlVector &timer = props["timer"].get_vector();
ASSERT(!timer.empty());
+ ASSERT(timer.size() == blood.quantity);
// blood.sub_type could be POT_BLOOD or POT_BLOOD_COAGULATED
// -> need different handling
int rot_limit = you.num_turns;
- int coag_limit = you.num_turns + 200; // check 200 turns later
+ int coag_limit = you.num_turns + 500; // check 500 turns later
// first count whether coagulating is even necessary
int rot_count = 0;
int coag_count = 0;
std::vector<long> age_timer;
long current;
- const int size = timer.size();
- for (int i = 0; i < size; i++)
+ while (!timer.empty())
{
- current = timer.pop_back();
- if (rot_limit >= current)
+ current = timer[timer.size()-1].get_long();
+ if (current > coag_limit
+ || blood.sub_type == POT_BLOOD_COAGULATED && current > rot_limit)
+ {
+ // still some time until rotting/coagulating
+ break;
+ }
+
+ timer.pop_back();
+ if (current <= rot_limit)
rot_count++;
- else if (blood.sub_type == POT_BLOOD && coag_limit >= current)
+ else if (blood.sub_type == POT_BLOOD && current <= coag_limit)
{
coag_count++;
age_timer.push_back(current);
}
- else // still some time until rotting/coagulating
- {
- timer.push_back(current);
- _long_sort(timer);
- break;
- }
}
if (!rot_count && !coag_count)
return; // nothing to be done
+#ifdef DEBUG_BLOOD_POTIONS
+ mprf(MSGCH_DIAGNOSTICS, "in maybe_coagulate_blood_potions_FLOOR "
+ "(turns: %d)", you.num_turns);
+
+ mprf(MSGCH_DIAGNOSTICS, "Something happened at pos (%d, %d)!",
+ blood.x, blood.y);
+ mprf(MSGCH_DIAGNOSTICS, "coagulated: %d, rotted: %d, total: %d",
+ coag_count, rot_count, blood.quantity);
+ more();
+#endif
+
if (!coag_count) // some potions rotted away
{
- dec_mitm_item_quantity(blood.link, rot_count);
+ dec_mitm_item_quantity(obj, rot_count);
// timer is already up to date
return;
}
@@ -254,16 +285,19 @@ void maybe_coagulate_blood_floor(item_def &blood)
ASSERT(blood.sub_type == POT_BLOOD);
// now that coagulating is necessary, check square for !coagulated blood
- int o = igrd[blood.x][blood.y];
- while (o != NON_ITEM)
+ ASSERT(blood.x >= 0 && blood.y >= 0);
+ for (int o = igrd[blood.x][blood.y]; o != NON_ITEM; o = mitm[o].link)
{
if (mitm[o].base_type == OBJ_POTIONS
&& mitm[o].sub_type == POT_BLOOD_COAGULATED)
{
// merge with existing stack
CrawlHashTable &props2 = mitm[o].props;
+ if (!props2.exists("timer"))
+ init_stack_blood_potions(mitm[o], mitm[o].special);
+
ASSERT(props2.exists("timer"));
- CrawlVector &timer2 = props2["timer"];
+ CrawlVector &timer2 = props2["timer"].get_vector();
ASSERT(timer2.size() == mitm[o].quantity);
// update timer -> push(pop)
@@ -277,10 +311,9 @@ void maybe_coagulate_blood_floor(item_def &blood)
_long_sort(timer2);
inc_mitm_item_quantity(o, coag_count);
ASSERT(timer2.size() == mitm[o].quantity);
- dec_mitm_item_quantity(blood.link, rot_count + coag_count);
+ dec_mitm_item_quantity(obj, rot_count + coag_count);
return;
}
- o = mitm[o].link;
}
// If we got here nothing was found!
@@ -289,9 +322,11 @@ void maybe_coagulate_blood_floor(item_def &blood)
if (rot_count + coag_count == blood.quantity)
{
ASSERT(timer.empty());
+
// update subtype
blood.sub_type = POT_BLOOD_COAGULATED;
item_colour(blood);
+
// re-fill vector
long val;
while (!age_timer.empty())
@@ -300,14 +335,322 @@ void maybe_coagulate_blood_floor(item_def &blood)
age_timer.pop_back();
timer.push_back(val);
}
- dec_mitm_item_quantity(blood.link, rot_count);
+ dec_mitm_item_quantity(obj, rot_count);
ASSERT(timer.size() == blood.quantity);
+ return;
+ }
+
+ // else, create a new stack of potions
+ int o = get_item_slot( 20 );
+ if (o == NON_ITEM)
+ return;
+
+ item_def &item = mitm[o];
+ item.base_type = OBJ_POTIONS;
+ item.sub_type = POT_BLOOD_COAGULATED;
+ item.quantity = coag_count;
+ item.plus = 0;
+ item.plus2 = 0;
+ item.special = 0;
+ item.flags = 0;
+ item_colour(item);
+
+ CrawlHashTable &props_new = item.props;
+ props_new.set_default_flags(SFLAG_CONST_TYPE);
+ props_new["timer"].new_vector(SV_LONG);
+ CrawlVector &timer_new = props_new["timer"].get_vector();
+
+ long val;
+ while (!age_timer.empty())
+ {
+ val = age_timer[age_timer.size() - 1];
+ age_timer.pop_back();
+ timer_new.push_back(val);
+ }
+
+ ASSERT(timer_new.size() == coag_count);
+ props_new.assert_validity();
+ move_item_to_grid( &o, blood.x, blood.y );
+
+ dec_mitm_item_quantity(obj, rot_count + coag_count);
+ ASSERT(timer.size() == blood.quantity);
+}
+
+static void _coagulating_blood_message(item_def &blood, int num_coagulated)
+{
+ ASSERT(num_coagulated > 0);
+
+ std::string msg;
+ if (blood.quantity == num_coagulated)
+ msg = blood.name(DESC_CAP_YOUR, false);
+ else
+ {
+ if (num_coagulated == 1)
+ msg = "One of ";
+ else
+ msg = "Some of ";
+
+ msg += blood.name(DESC_NOCAP_YOUR, false);
}
+ msg += " coagulate";
+ if (num_coagulated == 1)
+ msg += "s";
+ msg += ".";
+
+ mpr(msg.c_str(), MSGCH_ROTTEN_MEAT);
+}
+
+// returns true if "equipment weighs less" message needed
+// also handles coagulation messages
+bool maybe_coagulate_blood_potions_inv(item_def &blood)
+{
+ ASSERT(is_valid_item(blood));
+ ASSERT(blood.base_type == OBJ_POTIONS);
+
+ ASSERT(blood.sub_type == POT_BLOOD
+ || blood.sub_type == POT_BLOOD_COAGULATED);
+
+ CrawlHashTable &props = blood.props;
+ if (!props.exists("timer"))
+ init_stack_blood_potions(blood, blood.special);
+
+ ASSERT(props.exists("timer"));
+ CrawlVector &timer = props["timer"].get_vector();
+ ASSERT(timer.size() == blood.quantity);
+ ASSERT(!timer.empty());
+
+ // blood.sub_type could be POT_BLOOD or POT_BLOOD_COAGULATED
+ // -> need different handling
+ int rot_limit = you.num_turns;
+ int coag_limit = you.num_turns + 500; // check 500 turns later
+
+ // first count whether coagulating is even necessary
+ int rot_count = 0;
+ int coag_count = 0;
+ std::vector<long> age_timer;
+ long current;
+ const int size = timer.size();
+ for (int i = 0; i < size; i++)
+ {
+ current = timer[timer.size()-1].get_long();
+ if (current > coag_limit
+ || blood.sub_type == POT_BLOOD_COAGULATED && current > rot_limit)
+ {
+ // still some time until rotting/coagulating
+ break;
+ }
+
+ timer.pop_back();
+ if (current <= rot_limit)
+ rot_count++;
+ else if (blood.sub_type == POT_BLOOD && current <= coag_limit)
+ {
+ coag_count++;
+ age_timer.push_back(current);
+ }
+ }
+
+ if (!rot_count && !coag_count)
+ return false; // nothing to be done
+
+#ifdef DEBUG_BLOOD_POTIONS
+ mprf(MSGCH_DIAGNOSTICS, "in maybe_coagulate_blood_potions_INV "
+ "(turns: %d)", you.num_turns);
+
+ mprf(MSGCH_DIAGNOSTICS, "coagulated: %d, rotted: %d, total: %d",
+ coag_count, rot_count, blood.quantity);
+ more();
+#endif
+
+ if (!coag_count) // some potions rotted away
+ {
+ blood.quantity -= rot_count;
+ if (blood.quantity < 1)
+ destroy_item(blood);
+ else
+ ASSERT(blood.quantity == timer.size());
+
+ return true;
+ }
+
+ // coagulated blood cannot coagulate any further...
+ ASSERT(blood.sub_type == POT_BLOOD);
+
+ bool knew_blood = get_ident_type(OBJ_POTIONS, POT_BLOOD) == ID_KNOWN_TYPE;
+ bool knew_coag = (get_ident_type(OBJ_POTIONS, POT_BLOOD_COAGULATED)
+ == ID_KNOWN_TYPE);
+
+ _coagulating_blood_message(blood, coag_count);
+
+ // identify both blood and coagulated blood, if necessary
+ if (!knew_blood)
+ set_ident_type( OBJ_POTIONS, POT_BLOOD, ID_KNOWN_TYPE );
+
+ if (!knew_coag)
+ set_ident_type( OBJ_POTIONS, POT_BLOOD_COAGULATED, ID_KNOWN_TYPE );
+
+ // now that coagulating is necessary, check inventory for !coagulated blood
+ for (int m = 0; m < ENDOFPACK; m++)
+ {
+ if (!is_valid_item(you.inv[m]))
+ continue;
+
+ if (you.inv[m].base_type == OBJ_POTIONS
+ && you.inv[m].sub_type == POT_BLOOD_COAGULATED)
+ {
+ CrawlHashTable &props2 = you.inv[m].props;
+ if (!props2.exists("timer"))
+ init_stack_blood_potions(you.inv[m], you.inv[m].special);
+
+ ASSERT(props2.exists("timer"));
+ CrawlVector &timer2 = props2["timer"].get_vector();
+
+ blood.quantity -= coag_count + rot_count;
+ if (blood.quantity < 1)
+ destroy_item(blood);
+ else
+ {
+ ASSERT(timer.size() == blood.quantity);
+ if (!knew_blood)
+ mpr(blood.name(DESC_INVENTORY).c_str());
+ }
+
+ // update timer -> push(pop)
+ long val;
+ while (!age_timer.empty())
+ {
+ val = age_timer[age_timer.size() - 1];
+ age_timer.pop_back();
+ timer2.push_back(val);
+ }
+
+ you.inv[m].quantity += coag_count;
+ ASSERT(timer2.size() == you.inv[m].quantity);
+ if (!knew_coag)
+ mpr(you.inv[m].name(DESC_INVENTORY).c_str());
+
+ // re-sort timer
+ _long_sort(timer2);
+
+ return (rot_count > 0);
+ }
+ }
+
+ // if entire stack has coagulated, simply change subtype
+ if (rot_count + coag_count == blood.quantity)
+ {
+ ASSERT(timer.empty());
+ // update subtype
+ blood.sub_type = POT_BLOOD_COAGULATED;
+ item_colour(blood);
+
+ // re-fill vector
+ long val;
+ while (!age_timer.empty())
+ {
+ val = age_timer[age_timer.size() - 1];
+ age_timer.pop_back();
+ timer.push_back(val);
+ }
+ blood.quantity -= rot_count;
+ // stack still exists because of coag_count
+ ASSERT(timer.size() == blood.quantity);
+
+ if (!knew_coag)
+ mpr(blood.name(DESC_INVENTORY).c_str());
+
+ return (rot_count > 0);
+ }
+
+ // else, create new stack in inventory
+ int freeslot = find_free_slot(blood);
+ if (freeslot >= 0 && freeslot < ENDOFPACK
+ && !is_valid_item(you.inv[freeslot]))
+ {
+ item_def &item = you.inv[freeslot];
+ item.link = freeslot;
+ item.slot = index_to_letter(item.link);
+ item.base_type = OBJ_POTIONS;
+ item.sub_type = POT_BLOOD_COAGULATED;
+ item.quantity = coag_count;
+ item.x = -1;
+ item.y = -1;
+ item.plus = 0;
+ item.plus2 = 0;
+ item.special = 0;
+ item.flags = 0;
+ item_colour(item);
+
+ CrawlHashTable &props_new = item.props;
+ props_new.set_default_flags(SFLAG_CONST_TYPE);
+ props_new["timer"].new_vector(SV_LONG);
+ CrawlVector &timer_new = props_new["timer"].get_vector();
+
+ long val;
+ while (!age_timer.empty())
+ {
+ val = age_timer[age_timer.size() - 1];
+ age_timer.pop_back();
+ timer_new.push_back(val);
+ }
+
+ ASSERT(timer_new.size() == coag_count);
+ props_new.assert_validity();
+
+ blood.quantity -= coag_count + rot_count;
+ ASSERT(timer.size() == blood.quantity);
+
+ if (!knew_blood)
+ mpr(blood.name(DESC_INVENTORY).c_str());
+ if (!knew_coag)
+ mpr(item.name(DESC_INVENTORY).c_str());
+
+ return (rot_count > 0);
+ }
+
+ // no space in inventory, check floor
+ int o = igrd[you.x_pos][you.y_pos];
+ while (o != NON_ITEM)
+ {
+ if (mitm[o].base_type == OBJ_POTIONS
+ && mitm[o].sub_type == POT_BLOOD_COAGULATED)
+ {
+ // merge with existing stack
+ CrawlHashTable &props2 = mitm[o].props;
+ if (!props2.exists("timer"))
+ init_stack_blood_potions(mitm[o], mitm[o].special);
+
+ ASSERT(props2.exists("timer"));
+ CrawlVector &timer2 = props2["timer"].get_vector();
+ ASSERT(timer2.size() == mitm[o].quantity);
+
+ // update timer -> push(pop)
+ long val;
+ while (!age_timer.empty())
+ {
+ val = age_timer[age_timer.size() - 1];
+ age_timer.pop_back();
+ timer2.push_back(val);
+ }
+ _long_sort(timer2);
+
+ inc_mitm_item_quantity(o, coag_count);
+ ASSERT(timer2.size() == mitm[o].quantity);
+ dec_inv_item_quantity(blood.link, rot_count + coag_count);
+ ASSERT(timer.size() == blood.quantity);
+ if (!knew_blood)
+ mpr(blood.name(DESC_INVENTORY).c_str());
+ return true;
+ }
+ o = mitm[o].link;
+ }
+ // If we got here nothing was found!
+
// create a new stack of potions
o = get_item_slot( 100 + random2(200) );
if (o == NON_ITEM)
- return;
+ return false;
// these values are common to all: {dlb}
mitm[o].base_type = OBJ_POTIONS;
@@ -316,13 +659,13 @@ void maybe_coagulate_blood_floor(item_def &blood)
mitm[o].plus = 0;
mitm[o].plus2 = 0;
mitm[o].special = 0;
- mitm[o].flags = 0;
+ mitm[o].flags = ~(ISFLAG_THROWN | ISFLAG_DROPPED);
item_colour(mitm[o]);
CrawlHashTable &props_new = mitm[o].props;
props_new.set_default_flags(SFLAG_CONST_TYPE);
props_new["timer"].new_vector(SV_LONG);
- CrawlVector &timer_new = props_new["timer"];
+ CrawlVector &timer_new = props_new["timer"].get_vector();
long val;
while (!age_timer.empty())
@@ -334,14 +677,22 @@ void maybe_coagulate_blood_floor(item_def &blood)
ASSERT(timer_new.size() == coag_count);
props_new.assert_validity();
- move_item_to_grid( &o, blood.x, blood.y );
+ move_item_to_grid( &o, you.x_pos, you.y_pos );
- dec_mitm_item_quantity(blood.link, rot_count + coag_count);
- ASSERT(timer.size() == blood.quantity);
+ blood.quantity -= rot_count + coag_count;
+ if (blood.quantity < 1)
+ destroy_item(blood);
+ else
+ {
+ ASSERT(timer.size() == blood.quantity);
+ if (!knew_blood)
+ mpr(blood.name(DESC_INVENTORY).c_str());
+ }
+ return true;
}
-// used for (q)uaff, (f)ire, and Evaporate
-void remove_oldest_potion_inv(item_def &stack)
+// mostly used for (q)uaff, (f)ire, and Evaporate
+long remove_oldest_blood_potion(item_def &stack)
{
ASSERT(is_valid_item(stack));
ASSERT(stack.base_type == OBJ_POTIONS);
@@ -350,56 +701,99 @@ void remove_oldest_potion_inv(item_def &stack)
|| stack.sub_type == POT_BLOOD_COAGULATED);
CrawlHashTable &props = stack.props;
+ if (!props.exists("timer"))
+ init_stack_blood_potions(stack, stack.special);
ASSERT(props.exists("timer"));
- CrawlVector &timer = props["timer"];
- ASSERT(timer.size() == stack.quantity);
+ CrawlVector &timer = props["timer"].get_vector();
ASSERT(!timer.empty());
// assuming already sorted, and first (oldest) potion valid
+ const long val = timer[timer.size() - 1].get_long();
timer.pop_back();
// the quantity will be decreased elsewhere
+ return val;
+}
+
+// used whenever copies of blood potions have to be cleaned up
+void remove_newest_blood_potion(item_def &stack, int quant)
+{
+ ASSERT(is_valid_item(stack));
+ ASSERT(stack.base_type == OBJ_POTIONS);
+
+ ASSERT (stack.sub_type == POT_BLOOD
+ || stack.sub_type == POT_BLOOD_COAGULATED);
+
+ CrawlHashTable &props = stack.props;
+ if (!props.exists("timer"))
+ init_stack_blood_potions(stack, stack.special);
+ ASSERT(props.exists("timer"));
+ CrawlVector &timer = props["timer"].get_vector();
+ ASSERT(!timer.empty());
+
+ if (quant == -1)
+ quant = timer.size() - stack.quantity;
+
+ // overwrite newest potions with oldest ones
+ int repeats = stack.quantity;
+ if (repeats > quant)
+ repeats = quant;
+
+ for (int i = 0; i < repeats; i++)
+ {
+ timer[i] = timer[timer.size() - 1];
+ timer.pop_back();
+ }
+
+ // now remove remaining oldest potions
+ repeats = quant - repeats;
+ for (int i = 0; i < repeats; i++)
+ timer.pop_back();
+
+ // and re-sort
+ _long_sort(timer);
}
-// Should be called *after* drop_thing (and only if this returns true)
-// unless the stack has been dropped in its entirety.
-void drop_blood_potions_stack(int item, int quant)
+// Called from copy_item_to_grid.
+// Quantities are set afterwards, so don't ASSERT for those.
+void drop_blood_potions_stack(item_def &stack, int quant, int x, int y)
{
- ASSERT(quant > 0);
- // entire stack was dropped?
- if (!is_valid_item(you.inv[item]))
+ if (!is_valid_item(stack))
return;
- item_def &stack = you.inv[item];
+ ASSERT(quant > 0 && quant <= stack.quantity);
ASSERT(stack.base_type == OBJ_POTIONS);
ASSERT(stack.sub_type == POT_BLOOD
|| stack.sub_type == POT_BLOOD_COAGULATED);
CrawlHashTable &props = stack.props;
+ if (!props.exists("timer"))
+ init_stack_blood_potions(stack, stack.special);
ASSERT(props.exists("timer"));
- CrawlVector &timer = props["timer"];
+ CrawlVector &timer = props["timer"].get_vector();
ASSERT(!timer.empty());
// first check whether we can merge with an existing stack on the floor
- int o = igrd[you.x_pos][you.y_pos];
+ int o = igrd[x][y];
while (o != NON_ITEM)
{
if (mitm[o].base_type == OBJ_POTIONS
&& mitm[o].sub_type == stack.sub_type)
{
CrawlHashTable &props2 = mitm[o].props;
+ if (!props2.exists("timer"))
+ init_stack_blood_potions(mitm[o], mitm[o].special);
ASSERT(props2.exists("timer"));
- CrawlVector &timer2 = props2["timer"];
+ CrawlVector &timer2 = props2["timer"].get_vector();
// update timer -> push(pop)
for (int i = 0; i < quant; i++)
- timer2.push_back(timer.pop_back());
+ {
+ timer2.push_back(timer[timer.size() - 1].get_long());
+ timer.pop_back();
+ }
- ASSERT(timer2.size() == mitm[o].quantity);
// re-sort timer
_long_sort(timer2);
-
- // now the stack timer should be correct again
- ASSERT(timer.size() == stack.quantity);
return;
}
o = mitm[o].link;
@@ -410,27 +804,25 @@ void drop_blood_potions_stack(int item, int quant)
// have to reduce the timer vector anyway.
while (!timer.empty() && quant-- > 0)
timer.pop_back();
-
- ASSERT(stack.quantity == timer.size());
}
-// Should be called *after* move_item_to_player
-// unless the stack has been picked up in its entirety.
-void pick_up_blood_potions_stack(int item, int quant)
+// Called from move_item_to_player.
+// Quantities are set afterwards, so don't ASSERT for those.
+void pick_up_blood_potions_stack(item_def &stack, int quant)
{
- ASSERT(quant > 0);
- // entire stack was taken?
- if (!is_valid_item(mitm[item]))
+ ASSERT(quant > 0 && quant <= stack.quantity);
+ if (!is_valid_item(stack))
return;
- item_def &stack = mitm[item];
ASSERT(stack.base_type == OBJ_POTIONS);
ASSERT(stack.sub_type == POT_BLOOD
|| stack.sub_type == POT_BLOOD_COAGULATED);
CrawlHashTable &props = stack.props;
+ if (!props.exists("timer"))
+ init_stack_blood_potions(stack, stack.special);
ASSERT(props.exists("timer"));
- CrawlVector &timer = props["timer"];
+ CrawlVector &timer = props["timer"].get_vector();
ASSERT(!timer.empty());
// first check whether we can merge with an existing stack in inventory
@@ -443,25 +835,24 @@ void pick_up_blood_potions_stack(int item, int quant)
&& you.inv[m].sub_type == stack.sub_type)
{
CrawlHashTable &props2 = you.inv[m].props;
+ if (!props2.exists("timer"))
+ init_stack_blood_potions(you.inv[m], you.inv[m].special);
ASSERT(props2.exists("timer"));
- CrawlVector &timer2 = props2["timer"];
+ CrawlVector &timer2 = props2["timer"].get_vector();
// update timer -> push(pop)
for (int i = 0; i < quant; i++)
- timer2.push_back(timer.pop_back());
+ {
+ timer2.push_back(timer[timer.size() - 1].get_long());
+ timer.pop_back();
+ }
- ASSERT(timer2.size() == you.inv[m].quantity);
// re-sort timer
_long_sort(timer2);
-
- // now the stack timer should be correct again
- ASSERT(timer.size() == stack.quantity);
return;
}
}
-
// If we got here nothing was found. Huh?
- ASSERT(stack.quantity == timer.size());
}
// Deliberately don't check for rottenness here, so this check
@@ -494,8 +885,8 @@ void turn_corpse_into_blood_potions( item_def &item )
item.base_type = OBJ_POTIONS;
item.sub_type = POT_BLOOD;
- item.colour = RED;
- item.special = (item.special - 80) * 10; // potion's age
+ item_colour(item);
+ item.flags &= ~(ISFLAG_THROWN | ISFLAG_DROPPED);
// max. amount is about one third of the max. amount for chunks
const int max_chunks = mons_weight( mons_class ) / 150;
@@ -511,7 +902,10 @@ void turn_corpse_into_blood_potions( item_def &item )
item.quantity = 1;
}
- item.flags &= ~(ISFLAG_THROWN | ISFLAG_DROPPED);
+ // initialize timer depending on corpse age
+ // almost rotting: age = 100 --> potion timer = 500 --> will coagulate soon
+ // freshly killed: age = 200 --> potion timer = 2000 --> fresh !blood
+ init_stack_blood_potions(item, (item.special - 100) * 15 + 500);
// happens after the blood has been bottled
if (monster_descriptor(mons_class, MDSC_LEAVES_HIDE) && !one_chance_in(3))
@@ -534,6 +928,23 @@ void split_blood_potions_into_decay( int obj, int amount )
if (amount <= 0)
amount = random2(potion.quantity) + 1;
+ // We're being nice here, and only decay the *oldest* potions.
+ for (int i = 0; i < amount; i++)
+ remove_oldest_blood_potion(potion);
+
+ // try to merge into existing stacks of decayed potions
+ for (int m = 0; m < ENDOFPACK; m++)
+ {
+ if (you.inv[m].base_type == OBJ_POTIONS
+ && you.inv[m].sub_type == POT_DECAY
+ && you.inv[m].colour == potion.colour)
+ {
+ you.inv[obj].quantity -= amount;
+ you.inv[m].quantity += amount;
+ return;
+ }
+ }
+
// if entire stack affected just change subtype
if (amount == potion.quantity)
{
@@ -541,17 +952,42 @@ void split_blood_potions_into_decay( int obj, int amount )
return;
}
- // try to merge into existing stacks of decayed potions
- for (int m = 0; m < ENDOFPACK; m++)
- {
- if (you.inv[m].base_type == OBJ_POTIONS
- && you.inv[m].sub_type == POT_DECAY)
- {
- inc_inv_item_quantity( m, amount );
- dec_inv_item_quantity( obj, amount);
+ // else, create new stack in inventory
+ int freeslot = find_free_slot(you.inv[obj]);
+ if (freeslot >= 0 && freeslot < ENDOFPACK
+ && !is_valid_item(you.inv[freeslot]))
+ {
+ item_def &item = you.inv[freeslot];
+ item.link = freeslot;
+ item.slot = index_to_letter(item.link);
+ item.base_type = OBJ_POTIONS;
+ item.sub_type = POT_DECAY;
+ item.quantity = amount;
+ item.x = -1;
+ item.y = -1;
+ item.plus = 0;
+ item.plus2 = 0;
+ item.special = 0;
+ item.flags = 0;
+
+ you.inv[obj].quantity -= amount;
+ return;
+ }
+ // Okay, inventory is full.
- return;
- }
+ // check whether we can merge with an existing stack on the floor
+ int o = igrd[you.x_pos][you.y_pos];
+ while (o != NON_ITEM)
+ {
+ if (mitm[o].base_type == OBJ_POTIONS
+ && mitm[o].sub_type == POT_DECAY
+ && mitm[o].colour == you.inv[obj].colour)
+ {
+ dec_inv_item_quantity(obj, amount);
+ inc_mitm_item_quantity(o, amount);
+ return;
+ }
+ o = mitm[o].link;
}
// only bother creating a distinct stack of potions
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index f4cffde844..4c588fc42c 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -69,10 +69,13 @@ void trackers_init_new_level(bool transit);
void turn_corpse_into_chunks( item_def &item );
void init_stack_blood_potions( item_def &stack, int age = -1 );
-void maybe_coagulate_blood_potions_floor( item_def &blood );
-void remove_oldest_potion_inv( item_def &stack );
-void drop_blood_potions_stack( int item, int quant );
-void pick_up_blood_potions_stack( int item, int quant );
+void maybe_coagulate_blood_potions_floor( int obj );
+bool maybe_coagulate_blood_potions_inv( item_def &blood );
+long remove_oldest_blood_potion( item_def &stack );
+void remove_newest_blood_potion( item_def &stack, int quant = -1 );
+void drop_blood_potions_stack( item_def &stack, int quant, int x = you.x_pos,
+ int y = you.y_pos );
+void pick_up_blood_potions_stack( item_def &stack, int quant );
bool can_bottle_blood_from_corpse( int mons_type );
void turn_corpse_into_blood_potions ( item_def &item );
diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc
index 8f8f841d28..51138dd2a1 100644
--- a/crawl-ref/source/newgame.cc
+++ b/crawl-ref/source/newgame.cc
@@ -86,6 +86,7 @@
#include "macro.h"
#include "makeitem.h"
#include "menu.h"
+#include "misc.h"
#include "place.h"
#include "player.h"
#include "randart.h"
@@ -852,6 +853,7 @@ static void _give_starting_food()
return;
item_def item;
+ item.quantity = 1;
if ( you.species == SP_SPRIGGAN )
{
item.base_type = OBJ_POTIONS;
@@ -861,7 +863,7 @@ static void _give_starting_food()
{
item.base_type = OBJ_POTIONS;
item.sub_type = POT_BLOOD;
- item.special = 1200;
+ init_stack_blood_potions(item);
}
else
{
@@ -874,7 +876,6 @@ static void _give_starting_food()
else
item.sub_type = FOOD_BREAD_RATION;
}
- item.quantity = 1;
const int slot = find_free_slot(item);
you.inv[slot] = item; // will ASSERT if couldn't find free slot
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index e192b705a4..044e59ee2d 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -1243,10 +1243,7 @@ int player_res_fire(bool calc_unid, bool temp)
// species:
if (you.species == SP_MUMMY
- || you.species == SP_VAMPIRE && you.hunger_state <= HS_NEAR_STARVING)
- {
rf--;
- }
// mutations:
rf += you.mutation[MUT_HEAT_RESISTANCE];
@@ -3664,7 +3661,6 @@ void display_char_status()
{
case HS_STARVING:
attrib.push_back("resist poison");
- attrib.push_back("are susceptible to fire");
attrib.push_back("significantly resist cold");
attrib.push_back("strongly resist negative energy");
attrib.push_back("resist torment");
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index cbb771dfaa..d1e5192f24 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -1702,16 +1702,21 @@ bool cast_evaporate(int pow, bolt& beem, int potion)
fire_beam(beem);
// both old and new code use up a potion:
+ if (you.inv[potion].sub_type == POT_BLOOD
+ || you.inv[potion].sub_type == POT_BLOOD_COAGULATED)
+ {
+ remove_oldest_blood_potion(you.inv[potion]);
+ }
dec_inv_item_quantity( potion, 1 );
return (true);
} // end cast_evaporate()
-// The intent of this spell isn't to produce helpful potions
+// The intent of this spell isn't to produce helpful potions
// for drinking, but rather to provide ammo for the Evaporate
-// spell out of corpses, thus potentially making it useful.
+// spell out of corpses, thus potentially making it useful.
// Producing helpful potions would break game balance here...
-// and producing more than one potion from a corpse, or not
+// and producing more than one potion from a corpse, or not
// using up the corpse might also lead to game balance problems. -- bwr
void cast_fulsome_distillation( int powc )
{