Add several functions for later improved handling of stacks of !blood.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@4109 c06c8d41-db1a-0410-9941-cceddc491573
VXSORUQOM2VZA4CAZDC6KPAY373NQIN3UT7CXQXTRCYXO2WM62DAC
Z5K63RTQ7GBQFNOWQ27RR2K7B6J6KLT42IM3CMNT52JNVYDPY7IQC
H53LXVICYVVJNETLDPVZGZV7U3SLB2XUOYSMFM2VM6ST226MTBHQC
RG7ASPEZNL3OIYMMNABKIBEYGI7USZITHRVJ65HMWKTU4X3FVPYAC
XL7E3EW5RPRYR7XHURIVKUJ3ATQAXMEGDLI3RSG3V4PGMLQ7CY3AC
Y3N66XTY5HEWDFX2UV2KK4JFLZ3GTFAFBYPD7IHWCBBGMR6EJ6XAC
4RYFMDXFDD6CDZ73T2A4LBPBJEZ7N5DANPY6EVGFH43IQX2ZEFEQC
7G3PQFF6KRL7XLFTHVDNPFNFHNJRACG2SQK32WXK2D22AMUPFP3QC
L2G3D7YWKDUA6FMEIWBCAJQVHEWE5RELWMWWLGBXFUDSVP7ZKUSQC
JE5K2LGM25NQQ3VIBZ25WJEQ4AJJVFLZWOH5RLNX66NVGQWI3YMQC
45EMD3KLQPMERNMIKU5G76H6556XOMIW352TSBP7VLWJX2YYGS7AC
C5U3HSOOQ7BKXKXIDS7MLVXUKDTHAWJ5NXNX6YDXTM3GWY5UWX4QC
OYYZVCE3QHBVJM6IEKK5HTJRG5YOVQNCBRMSJENTHOI2WPJLNCFAC
HC35ORPWMUNGV4G2TVNPID4ZDRNTWXE4U37LYT4QGSEQR2EXQJNAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
6GSGCC5JQJ5NOKX36UHRNOCXNHDBS2A2TDMAR34UBOGWE2DORXIQC
2H32CFFM2FNS63JJPNM2S6HMO543EX72GMPOU5GI6HTMQYPL6I3AC
7CMQLE4XIFMWDEUZAOKIKDW7BHAJCK5S26APMEZ6TEFEH63TEZ6AC
3BYA46OYLVN6ZPGAZD5OGIMMH5PRWGNSU3ITJRCVBE6P5HYYYAYQC
BZMLXBTB63CXPZZPFXM4VLE7IBXPBEZ6YLM4MSNQGJR4L5IBM3OAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
QVVC7AYGVA6U64PTNA7L27422NLMO327P22BQKXEVIMPZHIHO7MQC
P2ZCF3BBG523ZEOD6XQA4X5YEHBTWH3IM33YVHXP2SQ5POXZIH4QC
J7KCPTGASQNRAKVKQ5FCXZ75E75PK7I2BB6MFSI3COWU6HRKTWSAC
TFNFP2YQA4EOVE4VIXBEQSGACZSXHWIQ2T4TIPQ46R2MJW2C4B5AC
FBK5ECMQ6HJSQSN7C3DICKJIRJ3CSO3CHCQ3ONPBKLLSHDGPBQ7QC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
V3GWLMX6JL3YOYB427VLHPOTGHGWZK64HI6LLUU4X6CFMD2MEQMQC
ILO5P5FRDUY4SEQEXMTUDKOPXAUBJRSORHHUVTLLCYOYSXBXOVRAC
F42F3QNVICCXWPMNYL2QQJZNOVBVF4MXZUXNUC7KKYIRZ7R5HGPAC
LJK4ZQATLSB4MKZG3ARZX5V6RFGTN3NLCN6GTCUGJQKU26SOXMUAC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
74LQ7JXVLAFSHLI7LCBKFX47CNTYSKGUQSXNX5FCIUIGCC2JTR3QC
ENOQQ6DEA6ECRNTBGYYNK7G3DFEILMKQBNKP4SUQIZW2L6HWVR7QC
QHAYBZTRPVJMK55WXT3F63CNRSAEVN3CQAAG42GCJTONLXQLNNNQC
APCC5AQ77EHT57NWJA4SRRQOFNTIZDDUJRAFAXJS75Q235TTPDDQC
TRCCLE5RJ4VJULBOWOI2WC3RJU7WTEGS7RRQTDQL6W5UU246LKTQC
F7Q7QRZACTDPP6KH3AB5J6B6B5PRVV4FURTOIGXHRHWNVSQT3TVAC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC
T2SN3NCG67IWNPYKDUUO45JADBS5QHFHAOD5V4ZYRRZ5CDTSEB6AC
M5ZDZJBTOJ7SWQPZZQPC24JYZKP26MWSRDHXBWQE2MPPL6WCXOIQC
HFCPPPYI366EDKNBDGVNSAW76OGQA2NYTKLSP4LC3VYKHPLWFJ6QC
KXE7V7TPV4DW3Z4D6A2MJHEOBEX2WIIT4XGWLNIT4EL5QRBFNFIQC
XPCGZBHHSL6MB3ORMUJI64BAERU6AZTIY6RK56BBW7SNB3IK24IAC
UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC
KBBSDMAXAGEDFMIVL6BSPMMSOBZKWPJTFCLBGCHRLE5DGTVAACSAC
XEC3L6W6TGIRWHINULNLKCIP4UBMHFYE33WJL7272I2GRRCFZBWAC
ZJLJGSB2XSBQU42OFQMXL3EG4CXAQGOYAU6YTV2SAWZEJIPFH2CAC
TV3ZC6WOZKSQQJQN26JIVKCHK6UK7WMDBYZDUYRWEAZ4JB4YVNAAC
BIZDHHK5LIO57S5AKHEPJFLWV5DAFKZIKYBGOUNGICSWTX7DCXKAC
Z63Q4DA5J5TZAC5LN55UD4CLADUMU5Z73TGEVE2YUXCHIST2Y4QAC
SJOTTUZMA3UTGT5D6LKUTBDP2CZFXT24FB5IAWCUFHSHLLACM75QC
OXQNVH5GIMZERIBTC2S4EXHOEE4ZRIYZNY6IIY7HITBNBNI42DKAC
2RSY5J2ED2GM5R564UF5NEPDAEJDGLJJ6U3YO6UBQOX4KSLGNY7QC
6SSW2WIX3LUPDP2QI6Z75YUE53G5H3CZBAPCQA7OEQEPOCIXT73AC
23I5KJ245D43B6QYWS4TDQYJO2W2PKTDCLFBWPVAFDWS6L7NMGKQC
DOZORMA366M4HB5JKSS27BMCR6ET7QNZNND2B7KV3NVEEPR5H7EAC
JDM5R3HYGXKQKZWY35QZ2KOB24TFZ3FW2PCNXCRCMWG72AZC5ZXQC
6O5667Y65C5GTP4V3NBKWUN22IRGCAXEELJ6MCANMYPBOKDUO75QC
JJULXW764V5C2HJKZNWQAEWB6QM5YZADD7ZCE35LYTBFEM6PMYCAC
UKYGZDI6PYZPXDACCQGVPHANUP5ADCSNROOZIE7LYIZQWSNFHJZAC
PNRMCHHEBCAUD2XBSSH6JOEQ6A6CFEZBCIX436DVD26DA52OCYTQC
M2HMYLYYXSP5XGX6MCI77IT6UW5K4YSEUJWHPQPYXVSW5L36BJ2AC
HODV46TCH5AGI42Z5JKVDX4VCRVQCNREJUL6W3TUJK6S77SXQNLQC
6LT6USGJOTDMRJGXLAN2NSZXK2GKWEXDKKUV6SVV7ZC6WI6EKMDQC
DE2BXPJDLWN7F3LAYKUSWI5CFEYZMV2ZN4K2Y356NWIX4AIGD73QC
VDMADGWYGYZJWAEWU3WE7UCPVDS2O6HOHCXLOML64U5UCH4FER3AC
XRZPPYWPWUOM4SFNI6BHKH2UKJQNLKOV6Y7XIEPEZXE5QYRT26PAC
ZBPZZ5A7AB2VFZKQ2UJXVDGUK22OCZJCEN2RWTGDGK3VXFCCDKVAC
LUNOTEIMYZJ7JL5P55GEHUVSDEZMYX3TWYUB2ABRHAYJEWQSSXIAC
GUXTGUEMZYBRGV5QUAQSJHG3AOIQDWWCDIMOX4LASFJAZVGL2WQAC
RBC6SN3MFBHGSIHAMKBUD7S7ULXOW7AX3WLAB2DPFMHAADOEIL2QC
RGWUYJO74FDGTH22CYSHBKFDGJ4S76WTLIULKPXA4QT5ZCNOB4LQC
B5OK4FEITJ6MUT7J76OJJH2TOPTZGG7J7UPIJ6Z6WA5FC526FLTAC
FW3BFOY6UIWUMYNALIJMPEBTRQIMKUVRHOVFOHDKB3KRGA2QOGPQC
WTBQLBYFLQCF3NRAMB4Z2YA4MHYVFYI5YS7FXXBPICY2KCBA63AQC
4O3VTUJT5T7NBNF3Q45XO2WHS6TCJXVLH6CKX4K36WUBDRT5F6KAC
TW7QOMTSLYPGUUWHGHLY5G5LV6QQRQIKK4BSE64RY7RDGKVDHCEAC
JR2RAQ523LOWNDYJNK6AZVKI6WVMI622PIV72XWOVZYPXPUKSQWAC
3A3OAIFRFU3IHF6SDNDPCN3XYOFYIBYCEYJAXAFASCFDY76SMFXQC
LJSES3YZH4RECLXVBRJXS54NJOLWXVBKV5GXBPVQBLRCYXX23X4AC
Z6343ZVG2VOE7WOLBS7YLIWJ6XGCRCGJRJLP5WUVRTG7VOIXRRLAC
S4BRP4VHB23F2FCC6BXNAN2MZRVUGW7QMXUEOAVZVGFXKXJPVLLQC
LAMIVDKY7LO5ONX5Z273ZCCEA5UBENOJD5VWNE4AK2EXGFED6BFQC
CJKEUBURR2NB7I43WBO3LGPSNMCM6SGR5HOPQKK5IKC3PN47JUDQC
QHABWX5UYQAREZC4B6JGSRXSUH6DQLRD7WB4YGV4HHUHMTXY3ERAC
YYMVEFSCN7DGZC74WGG53XOLQF42KY2KGBXF2GOAXCR6WEE5VHCQC
XVRZIUEK3PHCL6JIBTIBYEUWOVLZ6MQZYUIFYCH454WDGDSBADLAC
JXOE7KJIEAJHPLMZAJ6O4YHDTRB6BGNP6XT3ZSEFYGSIUMHR77KQC
DMRXDEKHHBQNY37NPGZFAGUQPALWFANGGK4CUWIOQUPSLM2JBNFQC
3BJ2OOF4F524G6UKVGOZVT6W3FSTSHHTKRJADUBZCHDXZWV3KANQC
G3HJCS277WA2VONPOJW6FAOQO7VHMSMLXZWYIXKFE4N4Y3OV7UZAC
HSN6H5HDKBALFSBCGJMCNEG6M5KSCXGWPPHJGHUWOZI5EIERCBFQC
Q3XHNSHW6FI4JCXSEABATRFBJPMCF7PXNG2K6ZQTRRPVMIZFHUBQC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
MJWFTUS66PTCNEYXEJA3CUJFXNWXIKDD6H3V24PW7HK64NSVOFSAC
2WVP47RBNL5OVYMAZH7TKRYD7F2TGSZ5X74PWVGAYCQP26G3JUHQC
L4RYVF46EQKMVOEADGRG4WMPVTQ6NNFGYMU4SHAH6XJIKWVHT77QC
TLO257LZSB6ZO36STDUEWJBO2LETXFKTFGXELA6Y4BZBVAEIIINAC
7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC
RM2JXW3ATVYRYHF3NMG5ALGI64OJ7IP2F3MDUDPUT5TBKSSN4KVQC
OR7VGWIBRR55M7HATPIORQMMB4YQ7EQXO2IWAFFFPEJ4VV3ASRRQC
F4WAQJD7KLOXHZOTOT6WG26PVIDHYNVS3AV6ZNXGAS7PDR4HBWQAC
W5VEC2PBIM5DMU5233HOWAZUEPTGWJRZZIA3H35YYQQW6BTP6XUAC
IWMCGZ57ZVHE6WSPYD2CZNSG7ZDKGRBNZVY3KLR53TGEM3OQJLBAC
BPSH3LUDUTXMK2QZKSMFDTBNDD6HPILMCBLZNMCRLZZQKPS5QOQQC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
EWC3J3FZP62OZWT3JBBPNPZUB7NR5ZF6MAJNMPCVV75E3TFBFYYAC
OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC
R325RPUV26YH65VIJKYEFZ2XCVXQHO5N3ELPX6RNQ5TSI3JJNQGQC
ZP2KE7A2LE7Z2S7AC45WE4CXDSEVDTWIMV2EM4IBUKXYJIDU6R7QC
B62ICMDTN5V7R7RBL4JALFVKEMVOOVLRSJASRNYS6CGFWBEEF5JQC
5XSXMOBGXFLTIQE6WDXWWFVDOTUPZSIQ2FWT3YI5QMVU6D76IUYQC
hunger += you.mutation[MUT_FAST_METABOLISM];
if (you.species == SP_VAMPIRE)
{
switch (you.hunger_state)
{
case HS_STARVING:
case HS_NEAR_STARVING:
hunger -= 3;
break;
case HS_VERY_HUNGRY:
hunger -= 2;
break;
case HS_HUNGRY:
hunger--;
break;
case HS_SATIATED:
break;
case HS_FULL:
hunger++;
break;
case HS_VERY_FULL:
hunger += 2;
break;
case HS_ENGORGED:
hunger += 3;
}
}
else
{
hunger += you.mutation[MUT_FAST_METABOLISM];
hunger += 6 * player_equip_ego_type( EQ_WEAPON, SPWPN_VAMPIRICISM );
hunger += 9 * player_equip_ego_type( EQ_WEAPON, SPWPN_VAMPIRES_TOOTH );
hunger += 6 * player_equip_ego_type( EQ_WEAPON, SPWPN_VAMPIRICISM );
hunger += 9 * player_equip_ego_type( EQ_WEAPON, SPWPN_VAMPIRES_TOOTH );
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");
if (you.experience_level >= 13)
attrib.push_back("are in touch with the powers of death");
if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BAT)
attrib.push_back("heal slowly (as a bat)!");
else
attrib.push_back("do not heal!");
break;
case HS_NEAR_STARVING:
attrib.push_back("resist poison");
attrib.push_back("significantly resist cold");
attrib.push_back("strongly resist negative energy");
if (you.experience_level >= 13)
attrib.push_back("are in touch with the powers of death");
attrib.push_back("heal slowly!");
break;
case HS_HUNGRY:
case HS_VERY_HUNGRY:
attrib.push_back("resist poison");
attrib.push_back("resist cold");
attrib.push_back("significantly resist negative energy");
if (you.experience_level >= 13)
attrib.push_back("are in touch with the powers of death");
attrib.push_back("heal slowly!");
break;
case HS_SATIATED:
attrib.push_back("resist negative energy.");
break;
case HS_FULL:
case HS_VERY_FULL:
attrib.push_back("heal quickly.");
break;
case HS_ENGORGED:
attrib.push_back("heal extremely quickly.");
break;
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");
if (you.experience_level >= 13)
attrib.push_back("are in touch with the powers of death");
if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BAT)
attrib.push_back("heal slowly (as a bat)!");
else
attrib.push_back("do not heal!");
break;
case HS_NEAR_STARVING:
attrib.push_back("resist poison");
attrib.push_back("significantly resist cold");
attrib.push_back("strongly resist negative energy");
if (you.experience_level >= 13)
attrib.push_back("are in touch with the powers of death")
attrib.push_back("have an extremely slow metabolism");
attrib.push_back("heal slowly!");
break;
case HS_HUNGRY:
case HS_VERY_HUNGRY:
attrib.push_back("resist poison");
attrib.push_back("resist cold");
attrib.push_back("significantly resist negative energy");
if (you.experience_level >= 13)
attrib.push_back("are in touch with the powers of death");
if (you.hunger_state == HS_HUNGRY)
attrib.push_back("have a slow metabolism");
else
attrib.push_back("have a very slow metabolism");
attrib.push_back("heal slowly!");
break;
case HS_SATIATED:
attrib.push_back("resist negative energy.");
break;
case HS_FULL:
attrib.push_back("have a fast metabolism");
attrib.push_back("heal quickly.");
break;
case HS_VERY_FULL:
attrib.push_back("have a very fast metabolism");
attrib.push_back("heal quickly.");
break;
case HS_ENGORGED:
attrib.push_back("have an extremely fast metabolism");
attrib.push_back("heal extremely quickly.");
break;
// The values that are considerably different (ie level 13 is now 29000,
// down from 41040 are because the second derivative goes from 9040 to
// The values that are considerably different (ie level 13 is now 29000,
// down from 41040 are because the second derivative goes from 9040 to
// Note: The stats in in this list aren't intended to sum the same
// for all races. The fact that Mummies and Ghouls are really low
// Note: The stats in in this list aren't intended to sum the same
// for all races. The fact that Mummies and Ghouls are really low
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 );
}
// initialize blood potions with a vector of timers
void init_stack_blood_potions(item_def &stack, int age)
{
ASSERT(stack.base_type == OBJ_POTIONS);
ASSERT(stack.sub_type == POT_BLOOD);
CrawlHashTable &props = stack.props;
props.set_default_flags(SFLAG_CONST_TYPE);
props["timer"].new_vector(SV_LONG);
CrawlVector &timer = props["timer"];
// for a newly created stack, all potions use the same timer
const long max_age = you.num_turns + (age == -1 ? 1200 : age);
for (int i = 0; i < stack.quantity; i++)
timer.push_back(max_age);
ASSERT(timer.size() == stack.quantity);
props.assert_validity();
}
// sort a CrawlVector<long>, should probably be done properly with templates
static void _long_sort(CrawlVector &vec)
{
std::vector<long> help;
while (!vec.empty())
help.push_back(vec.pop_back());
std::sort(help.begin(), help.end());
long val;
while (!help.empty())
{
val = help[help.size() - 1];
help.pop_back();
vec.push_back(val);
}
}
void maybe_coagulate_blood_floor(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;
ASSERT(props.exists("timer"));
CrawlVector &timer = props["timer"];
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 + 200; // check 200 turns later
// first count whether coagulating is even necessary
int rot_count = 0;
int coag_count = 0;
std::vector<long> age_timer;
long current;
int size = timer.size();
for (int i = 0; i < size; i++)
{
current = timer.pop_back();
if (rot_limit >= current)
rot_count++;
else if (coag_limit >= current)
{
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
if (!coag_count)
{
dec_mitm_item_quantity(blood.link, rot_count);
// timer is already up to date
return;
}
// coagulated blood cannot coagulate any further...
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)
{
if (mitm[o].base_type == OBJ_POTIONS
&& mitm[o].sub_type == POT_BLOOD_COAGULATED)
{
CrawlHashTable &props2 = mitm[o].props;
ASSERT(props2.exists("timer"));
CrawlVector &timer2 = props2["timer"];
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);
dec_mitm_item_quantity(blood.link, rot_count + coag_count);
return;
}
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;
// these values are common to all: {dlb}
mitm[o].base_type = OBJ_POTIONS;
mitm[o].sub_type = POT_BLOOD_COAGULATED;
mitm[o].quantity = coag_count;
mitm[o].plus = 0;
mitm[o].plus2 = 0;
mitm[o].special = 0;
mitm[o].flags = 0;
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"];
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(blood.link, rot_count + coag_count);
}
// used for (q)uaff, (f)ire, and Evaporate
void remove_oldest_potion_inv(item_def &stack)
{
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;
ASSERT(props.exists("timer"));
CrawlVector &timer = props["timer"];
ASSERT(timer.size() == stack.quantity);
ASSERT(!timer.empty());
// assuming already sorted, and first (oldest) potion valid
timer.pop_back();
// the quantity will be decreased elsewhere
item_def &stack = you.inv[item];
ASSERT(stack.base_type == OBJ_POTIONS);
ASSERT(stack.sub_type == POT_BLOOD
|| stack.sub_type == POT_BLOOD_COAGULATED);
CrawlHashTable &props = stack.props;
ASSERT(props.exists("timer"));
CrawlVector &timer = props["timer"];
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];
while (o != NON_ITEM)
{
if (mitm[o].base_type == OBJ_POTIONS
&& mitm[o].sub_type == stack.sub_type)
{
CrawlHashTable &props2 = mitm[o].props;
ASSERT(props2.exists("timer"));
CrawlVector &timer2 = props2["timer"];
// update timer -> push(pop)
for (int i = 0; i < quant; i++)
timer2.push_back(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;
}
// 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();
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)
{
ASSERT(quant > 0);
// entire stack was taken?
if (!is_valid_item(mitm[item]))
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;
ASSERT(props.exists("timer"));
CrawlVector &timer = props["timer"];
ASSERT(!timer.empty());
// first check whether we can merge with an existing stack in inventory
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 == stack.sub_type)
{
CrawlHashTable &props2 = you.inv[m].props;
ASSERT(props2.exists("timer"));
CrawlVector &timer2 = props2["timer"];
// update timer -> push(pop)
for (int i = 0; i < quant; i++)
timer2.push_back(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());
}