summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2009-01-16 07:05:32 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2009-01-16 07:05:32 +0000
commit3c4a60908487170145e20d7a7e298496bef1666f (patch)
tree3282b642e80dfa2b1bc208e54692ac4bc084b00f /crawl-ref
parentc4968d0089d5c0d165b38b8f3c3e3f7983d0e191 (diff)
downloadcrawl-ref-3c4a60908487170145e20d7a7e298496bef1666f.tar.gz
crawl-ref-3c4a60908487170145e20d7a7e298496bef1666f.zip
Fix bug #2510110: blood potions coagulating while in a monster's inventory
was causing crashes. Get rid of drop_blood_potions_stack() and pick_up_blood_potions_stack(), replace with the more general merge_blood_potion_stacks() and merge_item_stacks(). When creating blood potions via debug command you can now specify how many turns away from coagulating/rotting it should be. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@8471 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/debug.cc22
-rw-r--r--crawl-ref/source/items.cc23
-rw-r--r--crawl-ref/source/items.h2
-rw-r--r--crawl-ref/source/misc.cc167
-rw-r--r--crawl-ref/source/misc.h4
-rw-r--r--crawl-ref/source/mon-util.cc4
6 files changed, 96 insertions, 126 deletions
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index e3c37053cb..dd8b259b0c 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -1580,7 +1580,24 @@ bool get_item_by_name(item_def *item, char* specs,
case OBJ_POTIONS:
item->quantity = 12;
if (is_blood_potion(*item))
- init_stack_blood_potions(*item);
+ {
+ const char* prompt;
+ if (item->sub_type == POT_BLOOD)
+ prompt = "# turns away from coagulation? "
+ "[ENTER for fully fresh] ";
+ else
+ prompt = "# turns away from rotting? "
+ "[ENTER for fully fresh] ";
+ int age =
+ _debug_prompt_for_int(prompt, false);
+
+ if (age <= 0)
+ age = -1;
+ else if (item->sub_type == POT_BLOOD)
+ age += 500;
+
+ init_stack_blood_potions(*item, age);
+ }
break;
case OBJ_FOOD:
@@ -4985,7 +5002,8 @@ void wizard_give_monster_item(monsters *mon)
// Move monster's old item to player's inventory as last step.
int old_eq = NON_ITEM;
bool unequipped = false;
- if (mon->inv[mon_slot] != NON_ITEM)
+ if (mon->inv[mon_slot] != NON_ITEM
+ && !items_stack(item, mitm[mon->inv[mon_slot]]))
{
old_eq = mon->inv[mon_slot];
// Alternative weapons don't get (un)wielded unless the monster
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 5e4fe0129b..ca2dcb11f6 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -1408,6 +1408,17 @@ bool items_stack( const item_def &item1, const item_def &item2,
return items_similar(item1, item2);
}
+void merge_item_stacks(item_def &source, item_def &dest, int quant)
+{
+ if (quant == -1)
+ quant = source.quantity;
+
+ ASSERT(quant > 0 && quant <= source.quantity);
+
+ if (is_blood_potion(source) && is_blood_potion(dest))
+ merge_blood_potion_stacks(source, dest, quant);
+}
+
static int _userdef_find_free_slot(const item_def &i)
{
#ifdef CLUA_BINDINGS
@@ -1599,8 +1610,7 @@ int move_item_to_player( int obj, int quant_got, bool quiet,
"god gift", "");
}
- if (is_blood_potion(mitm[obj]))
- pick_up_blood_potions_stack(mitm[obj], quant_got);
+ merge_item_stacks(mitm[obj], you.inv[m], quant_got);
inc_inv_item_quantity( m, quant_got );
dec_mitm_item_quantity( obj, quant_got );
@@ -1745,6 +1755,7 @@ bool move_item_to_grid( int *const obj, const coord_def& p )
// Add quantity to item already here, and dispose
// of obj, while returning the found item. -- bwr
inc_mitm_item_quantity( si->index(), item.quantity );
+ merge_item_stacks(item, *si);
destroy_item( ob );
ob = si->index();
return (true);
@@ -1837,12 +1848,8 @@ bool copy_item_to_grid( const item_def &item, const coord_def& p,
if (items_stack( item, *si ))
{
inc_mitm_item_quantity( si->index(), quant_drop );
-
- if (is_blood_potion(item))
- {
- item_def help = item;
- drop_blood_potions_stack(help, quant_drop, p);
- }
+ item_def copy = item;
+ merge_item_stacks(copy, *si, quant_drop);
// If the items on the floor already have a nonzero slot,
// leave it as such, otherwise set the slot.
diff --git a/crawl-ref/source/items.h b/crawl-ref/source/items.h
index 1770c8032f..8a0c9bd397 100644
--- a/crawl-ref/source/items.h
+++ b/crawl-ref/source/items.h
@@ -47,6 +47,8 @@ bool is_stackable_item( const item_def &item );
bool items_similar( const item_def &item1, const item_def &item2 );
bool items_stack( const item_def &item1, const item_def &item2,
bool force_merge = false );
+void merge_item_stacks(item_def &source, item_def &dest,
+ int quant = -1);
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);
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 0befb1a692..4278b7d6fb 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -315,38 +315,44 @@ void maybe_coagulate_blood_potions_floor(int obj)
// Coagulated blood cannot coagulate any further...
ASSERT(blood.sub_type == POT_BLOOD);
- // Now that coagulating is necessary, check square for !coagulated blood.
- ASSERT(blood.pos.x >= 0 && blood.pos.y >= 0);
- for (int o = igrd[blood.pos.x][blood.pos.y]; o != NON_ITEM; o = mitm[o].link)
+ if (!held_by_monster(blood))
{
- if (mitm[o].base_type == OBJ_POTIONS
- && mitm[o].sub_type == POT_BLOOD_COAGULATED)
+ // Now that coagulating is necessary, check square for
+ // !coagulated blood.
+ ASSERT(blood.pos.x >= 0 && blood.pos.y >= 0);
+ for (int o = igrd[blood.pos.x][blood.pos.y]; o != NON_ITEM;
+ o = mitm[o].link)
{
- // 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())
+ if (mitm[o].base_type == OBJ_POTIONS
+ && mitm[o].sub_type == POT_BLOOD_COAGULATED)
{
- val = age_timer[age_timer.size() - 1];
- age_timer.pop_back();
- timer2.push_back(val);
+ // 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_mitm_item_quantity(obj, rot_count + coag_count);
+ return;
}
- _long_sort(timer2);
- inc_mitm_item_quantity(o, coag_count);
- ASSERT(timer2.size() == mitm[o].quantity);
- dec_mitm_item_quantity(obj, rot_count + coag_count);
- return;
}
}
- // If we got here, nothing was found!
+ // If we got here, nothing was found! (Or it's in a monster's
+ // inventory).
// Entire stack is gone, rotted or coagulated.
// -> Change potions to coagulated type.
@@ -398,10 +404,13 @@ void maybe_coagulate_blood_potions_floor(int obj)
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.pos);
+
+ if (held_by_monster(blood))
+ move_item_to_grid(&o, holding_monster(blood)->pos());
+ else
+ move_item_to_grid(&o, blood.pos);
dec_mitm_item_quantity(obj, rot_count + coag_count);
ASSERT(timer.size() == blood.quantity);
@@ -807,102 +816,36 @@ void remove_newest_blood_potion(item_def &stack, int quant)
_long_sort(timer);
}
-// Called from copy_item_to_grid.
-// NOTE: Quantities are set afterwards, so don't ASSERT for those.
-void drop_blood_potions_stack(item_def &stack, int quant, const coord_def& p)
+void merge_blood_potion_stacks(item_def &source, item_def &dest, int quant)
{
- if (!is_valid_item(stack))
+ if (!is_valid_item(source) || !is_valid_item(dest))
return;
- ASSERT(quant > 0 && quant <= stack.quantity);
- ASSERT(is_blood_potion(stack));
+ ASSERT(quant > 0 && quant <= source.quantity);
+ ASSERT(is_blood_potion(source) && is_blood_potion(dest));
- CrawlHashTable &props = stack.props;
+ CrawlHashTable &props = source.props;
if (!props.exists("timer"))
- init_stack_blood_potions(stack, stack.special);
+ init_stack_blood_potions(source, source.special);
ASSERT(props.exists("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[p.x][p.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"].get_vector();
-
- // Update timer -> push(pop).
- for (int i = 0; i < quant; i++)
- {
- timer2.push_back(timer[timer.size() - 1].get_long());
- timer.pop_back();
- }
-
- // Re-sort timer.
- _long_sort(timer2);
- return;
- }
- o = mitm[o].link;
- }
-
- // If we got here nothing was found.
- // Stuff could have been destroyed or offered, either case we'll
- // have to reduce the timer vector anyway.
- while (!timer.empty() && quant-- > 0)
- timer.pop_back();
-}
-
-// 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 && quant <= stack.quantity);
- if (!is_valid_item(stack))
- return;
-
- ASSERT(is_blood_potion(stack));
-
- 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());
+ CrawlHashTable &props2 = dest.props;
+ if (!props2.exists("timer"))
+ init_stack_blood_potions(dest, dest.special);
+ ASSERT(props2.exists("timer"));
+ CrawlVector &timer2 = props2["timer"].get_vector();
- // First check whether we can merge with an existing stack in inventory.
- for (int m = 0; m < ENDOFPACK; m++)
+ // Update timer -> push(pop).
+ for (int i = 0; i < quant; i++)
{
- if (!is_valid_item(you.inv[m]))
- continue;
-
- if (you.inv[m].base_type == OBJ_POTIONS
- && 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"].get_vector();
-
- // Update timer -> push(pop).
- for (int i = 0; i < quant; i++)
- {
- timer2.push_back(timer[timer.size() - 1].get_long());
- timer.pop_back();
- }
-
- // Re-sort timer.
- _long_sort(timer2);
- return;
- }
+ timer2.push_back(timer[timer.size() - 1].get_long());
+ timer.pop_back();
}
- // If we got here nothing was found. Huh?
+
+ // Re-sort timer.
+ _long_sort(timer2);
}
// Deliberately don't check for rottenness here, so this check
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index 77ba1e643f..ec3804ea30 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -33,9 +33,7 @@ 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,
- const coord_def& p = you.pos() );
-void pick_up_blood_potions_stack( item_def &stack, int quant );
+void merge_blood_potion_stacks(item_def &source, item_def &dest, int quant);
bool can_bottle_blood_from_corpse( int mons_type );
int num_blood_potions_from_corpse( int mons_class, int chunk_type = -1 );
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 8a05badd17..1b33419dbe 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -4321,7 +4321,8 @@ bool monsters::pickup(item_def &item, int slot, int near, bool force_merge)
if (inv[slot] != NON_ITEM)
{
- if (items_stack(item, mitm[inv[slot]], force_merge))
+ item_def &dest(mitm[inv[slot]]);
+ if (items_stack(item, dest, force_merge))
{
dungeon_events.fire_position_event(
dgn_event(DET_ITEM_PICKUP, pos(), 0, item.index(),
@@ -4330,6 +4331,7 @@ bool monsters::pickup(item_def &item, int slot, int near, bool force_merge)
pickup_message(item, near);
inc_mitm_item_quantity( inv[slot], item.quantity );
+ merge_item_stacks(item, dest);
destroy_item(item.index());
equip(item, slot, near);
lose_pickup_energy();