Instead of storing age in item.special they now use a dynamic vector (item.props, like decks do), so that a stack of potions doesn't have to coagulate all at once.
Rather than counting down the timers every 20 turns or so, the time-out turn is calculated at creation, and comparison is done against the current turncount. Any action changing a stack (quaffing, firing, Evaporate, picking up, dropping) will always extract the oldest values from the vector, which is likely to be what the player wants.
Blood potions now last about 2000 turns (a bit more if drawn from fresh corpses), and coagulate 500 turns before rotting away.
I ran a lot of tests in wiz mode and out, but of course there may still be problems. I've added methods to calculate the new timers from old style age counters (item.special), but I'm not sure that they actually work… Oh well… if worst comes to worst, this commit breaks saves.
Also:
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@4228 c06c8d41-db1a-0410-9941-cceddc491573
QCUMH3C7GXV7ZW444WT5SFAXQOJKJSE2YCQCEHMRYXCWF4QI7UMAC
2O3C3MTT2ZBYIFGPJ4MF5R4AXBYUHOEN62KAUWFWF6JWHIIVLRNQC
75M6AVUSS3G5EJECJJRB67V5UYDOIV26FZNB2FFCMBZ33EK7FVIQC
67AF33NTJG4WEAIFQX4R5XZTC5XZ5IBVHSFLYTGOXQJIXCZVXKDQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
TFNFP2YQA4EOVE4VIXBEQSGACZSXHWIQ2T4TIPQ46R2MJW2C4B5AC
VXSORUQOM2VZA4CAZDC6KPAY373NQIN3UT7CXQXTRCYXO2WM62DAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
6LT6USGJOTDMRJGXLAN2NSZXK2GKWEXDKKUV6SVV7ZC6WI6EKMDQC
Q3XHNSHW6FI4JCXSEABATRFBJPMCF7PXNG2K6ZQTRRPVMIZFHUBQC
P2ZCF3BBG523ZEOD6XQA4X5YEHBTWH3IM33YVHXP2SQ5POXZIH4QC
2WVP47RBNL5OVYMAZH7TKRYD7F2TGSZ5X74PWVGAYCQP26G3JUHQC
DTO3EUKWHZ5RJNGNCFYXSOVTIPVXPP637F2W7WFGYKJ7JK7VNKNQC
Q3DNEB5OOJ34P5ML4CMK3L6SCP7RLW7DDOZEG24KZBX3C7BJRQDAC
M2HMYLYYXSP5XGX6MCI77IT6UW5K4YSEUJWHPQPYXVSW5L36BJ2AC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
ND3T5LCZATC63EVQ6SLI7XXMSUL7XICJDNLH3UCYUDEFWTA3N5MQC
XI7U6RL6MFTH6SZQMLO4XFWGXGIFJBCRT6ZFCJFR2B2MGRSKDDCAC
OXHOOJE4XEQKGI3JKURNSITG6CRQFAOFQ2EKKG6M5DCLN7LS4GUAC
YOZHWGKGPWZGHQYNMMBHNGDO2UEVIHPOR6UF3SEZPIYWVMBGWBOAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
CIPVRZGLOZHCERK6YPOBV3P2E4IAB4H6D5EHLRQE2O5E4P4VCBUAC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
BDFIS53HAIHOCXQ5BE7WCO2MEOFCUQPFY4JGUWVLWY6JO3IFMEKQC
DMLFJIPOE4ZXUFQ25VVEZCMURP2UPJBBWDGQS3DPQVUNVBBQ4GDQC
SWT4O2TCOAQOVFA6WRA7MCU3KMTMJWFEMIHO64N4PWL5FNHDPADAC
HIRKGUMNJPWKSVTR6TVBPD3MWNA63CEHCLCIPWEMGDFHVB3NPLDQC
LT4XSC3B5CREP5LGIG3ER3SZFZFQAHX3UAHTGCMNR2EXVOYFTTMAC
APCC5AQ77EHT57NWJA4SRRQOFNTIZDDUJRAFAXJS75Q235TTPDDQC
TPZWAV3USKO7RX4IGHLZKVPRN36K33PJPSZYL6FZMX4XBHTYOQYAC
OEISFRW2B7E4YRJSWXNXBH2IAJO4O3LHNYFPFD3MBY57LYVRHMZQC
TRZAZJJA5VQBJ65SO5H5DNSILIZEJHIZCBYEBHEATCT6ZSMWIFKQC
VCG3BRIYRTNNWYC3LOXD6KFGXOX37HAFW2HNV7WXVG2V7EUHLDZQC
G5WLU3B4MR3ZDJLGR6OHNIMLZXGQS2EWBJ5YYY5J2GWM6DTD44BAC
BMHUBADDGIOZRVN4P3O5QKIDUYD4RFWBS7MP5X6LZWAYHUBRVD2QC
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 );
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)
#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
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;
// 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!
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;
// 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)
// used whenever copies of blood potions have to be cleaned up
void remove_newest_blood_potion(item_def &stack, int quant)
ASSERT(quant > 0);
// entire stack was dropped?
if (!is_valid_item(you.inv[item]))
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);
}
// 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)
{
if (!is_valid_item(stack))
// 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)
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);
// 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;
}
}
// try to merge into existing stacks of decayed potions
for (int m = 0; m < ENDOFPACK; m++)
// 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]))
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);
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;
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);
}
}
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]);
}
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]);
}
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.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 ))
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 (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];
}
#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:
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;