From 3c4a60908487170145e20d7a7e298496bef1666f Mon Sep 17 00:00:00 2001 From: zelgadis Date: Fri, 16 Jan 2009 07:05:32 +0000 Subject: 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 --- crawl-ref/source/debug.cc | 22 +++++- crawl-ref/source/items.cc | 23 +++--- crawl-ref/source/items.h | 2 + crawl-ref/source/misc.cc | 167 ++++++++++++++----------------------------- crawl-ref/source/misc.h | 4 +- crawl-ref/source/mon-util.cc | 4 +- 6 files changed, 96 insertions(+), 126 deletions(-) (limited to 'crawl-ref') 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(); -- cgit v1.2.3-54-g00ecf