Be a bit more generous regarding books for Evoc and Invoc types.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@8890 c06c8d41-db1a-0410-9941-cceddc491573
OE3TD4J5FSIFAM37J2UPEV7QQNXLSZM6GDUMPI66LC5LW2OM2J4AC
RUQVAI734QP35FKCUOPWHBY7C63BDOLNMJ3P5I5BLM7N34ZSCAJQC
YDWBT7CZGY33CNDPF7S4LK7YULFMDUJAKIODKMGB2IYIWHF4SJWQC
CIZ6TVSDTU7YJI3DGHNSC2SHGMEGT5AXSEO5X65EUD7UW5FPGQDAC
6ZZO2QBB46RZM6OXVS7OIKC5M3SEAULSSJFXW5PJG556JDKKUHWAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
NW6P7VRKBFBQ2FRDZBXN7APJZPYC4SYCIA3MOOE2KZGX43IXNK2AC
Q3DNEB5OOJ34P5ML4CMK3L6SCP7RLW7DDOZEG24KZBX3C7BJRQDAC
DTO3EUKWHZ5RJNGNCFYXSOVTIPVXPP637F2W7WFGYKJ7JK7VNKNQC
7YUGK5Q64KG5O7GJGTUBRRLHAHBCJ5YOE23YUPT6UBKUSB67CYAQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
2YLX45THVAG2ICWFAOANL3BQQBYMPQV36EY73TYCWA336RVW7KGQC
52XHD5LKS6UVLXBYUXMPTMVMTXQ6FBUFXJ2TAW6R7CSJY7OXWVJAC
75M6AVUSS3G5EJECJJRB67V5UYDOIV26FZNB2FFCMBZ33EK7FVIQC
557IY36VX2M4ERVCP5HNI3YTHHVTHPETZ5RWDX5BKDKXXIYCFUJAC
4FQAKUKUO6PCAZ3N4HUR5XL6E4VA5UQUZ3AEDGRBLVY7W2LMWI7QC
P2ZCF3BBG523ZEOD6XQA4X5YEHBTWH3IM33YVHXP2SQ5POXZIH4QC
7V4DCKFJCNBXFODMKJ6H3MCDUTSD4XVQ7D4D6XFCD4JNF4HCE4KAC
2W34FMSGJ2BZY7QQM6X6RTVRXXI2H72Z2MH75SU3SDL4FN4G74KAC
LUNOTEIMYZJ7JL5P55GEHUVSDEZMYX3TWYUB2ABRHAYJEWQSSXIAC
3ZWALZFSTSIVYXY4BAY6ANGINTDACZC6RSSJTEMQSTSUIE66YOBQC
VCQYSNAWZZHOZMARWQ4AJBDNFSS7T7CZBQISSPZ2YIIK5PVAWPRQC
VD4KDTGHVKCN35AWREYB4TEOUMCTW7SAUPAMTMF5ABC7VBHVKP4AC
FIYBXLWALQINNQTHG2KNDUUTAQAZRDDLXW2XOVSKDKBADJ3XCJ4AC
RZLMIEOHITWGYNVBHDVVWS24YQ5SD5HG3T3JCMIBCD2VA5TEPHCQC
SJP5BHX6MFWF3OSQPEF4WUWZWPUGMOVURTT2CUVT6H3A66LETXUAC
JZ4YC57SR2WQJIEIZSO3ZECA2FNMQUB7JYFKID4SIQ3RQ5NYXIVAC
64VBM7SGUX7CVO5TMVOFU4A26BDOFQXKS6G5K7BXCSWKCCXEETOAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
VJZ4D26E4L4E22SO6UYB44DNUTLG72LA4GTAEZ2DKKEMAICHOXBQC
45CXZWWXI7SGKLHVSRP2U6KNXJBT2XADNLIIHQQJYL2E6QWNURKQC
KQNIGKATHT4YSPJFPJGIGPD6VNR5B753SE2JN2LCXZZJNHCGY3DQC
QG7MKYZECIRDJJZKVRFI6XTCH42GTKA55BFIWPJBQZ27CZVLUJDQC
OQ4KB7QCJSK7GSW3DYBARH4DCB75HFKLUSOSOZZZ4IUFKNGFRUDQC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
CCRQESB4ADT4WA7FGLNZZXAJ6G5QMCTYCZIWORBN45P6ZPILC34AC
OFH2B2UZBK43QLFQBZ54FOCFLFNE54BZVDNCEUGDTBCUGNVZULIQC
P6JHIG4GFZEBV3XFKWZMZRUD6PJWQKNPG6CUNIWBYV3WHBY73ONQC
SWT4O2TCOAQOVFA6WRA7MCU3KMTMJWFEMIHO64N4PWL5FNHDPADAC
V53DXVC5T3N6J47H2CNG4MMPRR4PHW4AIS66QNVTKJNNYTTTQL4AC
KNO4TZR76DMOYJCF24PSVQW7FUZOTMOJTL7I7J74SM4IHOGDX6TAC
// last_updated 24may2000 {dlb}
/* ***********************************************************************
* called from: acr - chardump - effects - files - player - skills -
* skills2 - stuff
* *********************************************************************** */
case TRAP_BLADE:
return (10 + random2(30));
case TRAP_DART:
return (random2(4));
case TRAP_ARROW:
return (random2(7));
case TRAP_SPEAR:
return (random2(10));
case TRAP_BOLT:
return (random2(13));
case TRAP_AXE:
return (random2(15));
default:
return (0);
case TRAP_BLADE: return (10 + random2(30));
case TRAP_DART: return (random2(4));
case TRAP_ARROW: return (random2(7));
case TRAP_SPEAR: return (random2(10));
case TRAP_BOLT: return (random2(13));
case TRAP_AXE: return (random2(15));
default: return (0);
ASSERT(class_wanted != OBJ_RANDOM);
// Increasing the representation of the non-body armour
// slots here to make up for the fact that there's one
// one type of item for most of them. -- bwr
//
// NUM_ARMOURS is body armour and handled below
armour_type result = (coinflip()) ? NUM_ARMOURS
: _random_nonbody_armour_type();
int type_wanted = OBJ_RANDOM;
int iteration = 0;
// Some species specific fitting problems.
// FIXME: switch to the cleaner logic in can_wear_armour()
switch (you.species)
{
case SP_OGRE:
case SP_TROLL:
case SP_RED_DRACONIAN:
case SP_WHITE_DRACONIAN:
case SP_GREEN_DRACONIAN:
case SP_YELLOW_DRACONIAN:
case SP_GREY_DRACONIAN:
case SP_BLACK_DRACONIAN:
case SP_PURPLE_DRACONIAN:
case SP_MOTTLED_DRACONIAN:
case SP_PALE_DRACONIAN:
case SP_BASE_DRACONIAN:
case SP_SPRIGGAN:
if (result == ARM_GLOVES
|| result == ARM_BOOTS
|| result == ARM_CENTAUR_BARDING
|| result == ARM_NAGA_BARDING)
{
result = ARM_ROBE; // no heavy armour
}
else if (result == ARM_SHIELD)
{
if (you.species == SP_SPRIGGAN)
result = ARM_BUCKLER;
else if (coinflip()) // giant races: 50/50 shield/large shield
result = ARM_LARGE_SHIELD;
}
else if (result == NUM_ARMOURS)
{
result = ARM_ROBE; // no heavy armour, see below
}
break;
int spell_skills = 0;
for (int i = SK_SPELLCASTING; i <= SK_POISON_MAGIC; i++)
spell_skills += you.skills[i];
for (int acqc = 0; acqc < ENDOFPACK; acqc++)
// Mutation specific problems (horns allow caps).
if (result == ARM_BOOTS && !player_has_feet()
|| result == ARM_GLOVES && you.has_claws(false) >= 3)
if (is_valid_item( you.inv[acqc] )
&& you.inv[acqc].base_type == class_wanted)
{
ASSERT( you.inv[acqc].sub_type < max_has_value );
already_has[you.inv[acqc].sub_type] += you.inv[acqc].quantity;
}
result = NUM_ARMOURS;
if (class_wanted == OBJ_FOOD)
// Do this here, before acquirement()'s call to can_wear_armour(),
// so that caps will be just as common as helmets for those
// that can't wear helmets.
// We check for the mutation directly to avoid acquirement fiddles
// with vampires.
if (result == ARM_HELMET
&& (!you_can_wear(EQ_HELMET) || you.mutation[MUT_HORNS]))
if (you.species == SP_GHOUL)
{
type_wanted = one_chance_in(10) ? FOOD_ROYAL_JELLY
: FOOD_CHUNK;
}
else if (you.species == SP_VAMPIRE)
{
// Vampires really don't want any OBJ_FOOD but OBJ_CORPSES
// but it's easier to just give them a potion of blood
// class type is set elsewhere
type_wanted = POT_BLOOD;
quantity = 2 + random2(4);
}
// Now we'll randomly pick a body armour (light only in the
// case of ARM_ROBE). Unlike before, now we're only giving
// out the finished products here, never the hides. -- bwr
if (result == NUM_ARMOURS || result == ARM_ROBE)
{
// start with normal base armour
if (result == ARM_ROBE)
result = coinflip() ? ARM_ROBE : ARM_ANIMAL_SKIN;
// Meat is better than bread (except for herbivores), and
// by choosing it as the default we don't have to worry
// about special cases for carnivorous races (e.g. kobolds)
type_wanted = FOOD_MEAT_RATION;
result = static_cast<armour_type>(ARM_ROBE + random2(8));
// If we have some regular rations, then we're probably more
// interested in faster foods (especially royal jelly)...
// otherwise the regular rations should be a good enough offer.
if (already_has[FOOD_MEAT_RATION]
+ already_has[FOOD_BREAD_RATION] >= 2 || coinflip())
{
type_wanted = one_chance_in(5) ? FOOD_HONEYCOMB
: FOOD_ROYAL_JELLY;
}
if (one_chance_in(10))
result = ARM_ANIMAL_SKIN;
quantity = 3 + random2(5);
// giving more of the lower food value items
if (type_wanted == FOOD_HONEYCOMB || type_wanted == FOOD_CHUNK)
// everyone can wear things made from hides
if (one_chance_in(20))
quantity += random2avg(10, 2);
result = static_cast<armour_type>(
random_choose_weighted(20, ARM_TROLL_LEATHER_ARMOUR,
20, ARM_STEAM_DRAGON_ARMOUR,
15, ARM_MOTTLED_DRAGON_ARMOUR,
15, ARM_SWAMP_DRAGON_ARMOUR,
10, ARM_DRAGON_ARMOUR,
10, ARM_ICE_DRAGON_ARMOUR,
5, ARM_STORM_DRAGON_ARMOUR,
5, ARM_GOLD_DRAGON_ARMOUR,
0));
// Adding a small constant allows for the occasional
// weapon in an untrained skill.
// Write results into arguments.
void _acquirement_determine_food(int& type_wanted, int& quantity,
const has_vector& already_has)
{
// food is a little less predictable now -- bwr
if (you.species == SP_GHOUL)
type_wanted = one_chance_in(10) ? FOOD_ROYAL_JELLY : FOOD_CHUNK;
else if (you.species == SP_VAMPIRE)
{
// Vampires really don't want any OBJ_FOOD but OBJ_CORPSES
// but it's easier to just give them a potion of blood
// class type is set elsewhere
type_wanted = POT_BLOOD;
quantity = 2 + random2(4);
}
else
{
// Meat is better than bread (except for herbivores), and
// by choosing it as the default we don't have to worry
// about special cases for carnivorous races (e.g. kobolds)
type_wanted = FOOD_MEAT_RATION;
if (x_chance_in_y(weight, count))
skill = i;
// If we have some regular rations, then we're probably more
// interested in faster foods (especially royal jelly)...
// otherwise the regular rations should be a good enough offer.
if (already_has[FOOD_MEAT_RATION]
+ already_has[FOOD_BREAD_RATION] >= 2 || coinflip())
{
type_wanted = one_chance_in(5) ? FOOD_HONEYCOMB
: FOOD_ROYAL_JELLY;
item_def item_considered;
item_considered.base_type = OBJ_WEAPONS;
for (int i = 0; i < NUM_WEAPONS; ++i)
{
item_considered.sub_type = i;
// giving more of the lower food value items
if (type_wanted == FOOD_HONEYCOMB || type_wanted == FOOD_CHUNK)
{
quantity += random2avg(10, 2);
}
}
const int acqweight = property(item_considered, PWPN_ACQ_WEIGHT);
static int _acquirement_weapon_subtype()
{
// Asking for a weapon is biased towards your skills.
// First pick a skill, weighting towards those you have.
int count = 0;
int skill = SK_FIGHTING;
int wskill = range_skill(OBJ_WEAPONS, i);
if (wskill == SK_THROWING)
wskill = weapon_skill(OBJ_WEAPONS, i);
// Adding a small constant allows for the occasional
// weapon in an untrained skill.
if (wskill == skill && x_chance_in_y(acqweight, count += acqweight))
type_wanted = i;
}
const int weight = you.skills[i] + 1;
count += weight;
if (x_chance_in_y(weight, count))
skill = i;
for (int i = SK_SLINGS; i <= SK_DARTS; i++)
{
if (you.skills[i])
{
count += you.skills[i];
if (x_chance_in_y(you.skills[i], count))
skill = i;
}
}
switch (skill)
{
case SK_SLINGS:
type_wanted = MI_STONE;
break;
// Now choose a subtype which uses that skill.
int result = OBJ_RANDOM;
count = 0;
item_def item_considered;
item_considered.base_type = OBJ_WEAPONS;
for (int i = 0; i < NUM_WEAPONS; ++i)
{
item_considered.sub_type = i;
case SK_CROSSBOWS:
type_wanted = MI_DART;
for (int i = 0; i < ENDOFPACK; i++)
{
// Assuming that crossbow in inventory means that they
// want bolts for it (not darts for a hand crossbow)...
// perhaps we should check for both and compare ammo
// amounts on hand?
if (is_valid_item( you.inv[i] )
&& you.inv[i].base_type == OBJ_WEAPONS
&& you.inv[i].sub_type == WPN_CROSSBOW)
{
type_wanted = MI_BOLT;
break;
}
}
break;
if (!acqweight)
continue;
case SK_DARTS:
type_wanted = MI_DART;
for (int i = 0; i < ENDOFPACK; i++)
{
if (is_valid_item( you.inv[i] )
&& you.inv[i].base_type == OBJ_WEAPONS
&& you.inv[i].sub_type == WPN_BLOWGUN)
{
// Assuming that blowgun in inventory means that they
// may want needles for it (but darts might also be
// wanted). Maybe expand this... see above comment.
if (coinflip())
type_wanted = MI_NEEDLE;
break;
}
}
break;
int wskill = range_skill(OBJ_WEAPONS, i);
if (wskill == SK_THROWING)
wskill = weapon_skill(OBJ_WEAPONS, i);
else if (class_wanted == OBJ_ARMOUR)
{
// Increasing the representation of the non-body armour
// slots here to make up for the fact that there's one
// one type of item for most of them. -- bwr
//
// OBJ_RANDOM is body armour and handled below
type_wanted = (coinflip())? OBJ_RANDOM :
static_cast<int>(_random_nonbody_armour_type());
return (result);
}
// Some species specific fitting problems.
switch (you.species)
static bool _have_item_with_types(object_class_type basetype, int subtype)
{
for (int i = 0; i < ENDOFPACK; i++)
{
const item_def& item = you.inv[i];
if (is_valid_item(item)
&& item.base_type == basetype && item.sub_type == subtype)
case SP_OGRE:
case SP_TROLL:
case SP_RED_DRACONIAN:
case SP_WHITE_DRACONIAN:
case SP_GREEN_DRACONIAN:
case SP_YELLOW_DRACONIAN:
case SP_GREY_DRACONIAN:
case SP_BLACK_DRACONIAN:
case SP_PURPLE_DRACONIAN:
case SP_MOTTLED_DRACONIAN:
case SP_PALE_DRACONIAN:
case SP_BASE_DRACONIAN:
case SP_SPRIGGAN:
if (type_wanted == ARM_GLOVES || type_wanted == ARM_BOOTS
|| type_wanted == ARM_CENTAUR_BARDING
|| type_wanted == ARM_NAGA_BARDING)
{
type_wanted = ARM_ROBE; // no heavy armour
}
else if (type_wanted == ARM_SHIELD)
{
if (you.species == SP_SPRIGGAN)
type_wanted = ARM_BUCKLER;
else if (coinflip()) // giant races: 50/50 shield/large shield
type_wanted = ARM_LARGE_SHIELD;
}
else if (type_wanted == OBJ_RANDOM)
{
type_wanted = ARM_ROBE; // no heavy armour, see below
}
break;
case SP_NAGA:
if (type_wanted == ARM_BOOTS || type_wanted == ARM_CENTAUR_BARDING)
type_wanted = ARM_NAGA_BARDING;
break;
case SP_CENTAUR:
if (type_wanted == ARM_BOOTS || type_wanted == ARM_NAGA_BARDING)
type_wanted = ARM_CENTAUR_BARDING;
break;
default:
if (type_wanted == ARM_CENTAUR_BARDING
|| type_wanted == ARM_NAGA_BARDING)
{
type_wanted = ARM_BOOTS;
}
break;
return (true);
// Mutation specific problems (horns allow caps).
if (type_wanted == ARM_BOOTS && !player_has_feet()
|| type_wanted == ARM_GLOVES && you.has_claws(false) >= 3)
{
type_wanted = OBJ_RANDOM;
}
static missile_type _acquirement_missile_subtype()
{
int count = 0;
int skill = SK_THROWING;
// Do this here, before acquirement()'s call to can_wear_armour(),
// so that caps will be just as common as helmets for those
// that can't wear helmets.
// We check for the mutation directly to avoid acquirement fiddles
// with vampires.
if (type_wanted == ARM_HELMET
&& (!you_can_wear(EQ_HELMET) || you.mutation[MUT_HORNS]))
for (int i = SK_SLINGS; i <= SK_DARTS; i++)
{
if (you.skills[i])
// Now we'll randomly pick a body armour (light only in the
// case of ARM_ROBE). Unlike before, now we're only giving
// out the finished products here, never the hides. -- bwr
if (type_wanted == OBJ_RANDOM || type_wanted == ARM_ROBE)
{
// start with normal base armour
if (type_wanted == ARM_ROBE)
type_wanted = coinflip() ? ARM_ROBE : ARM_ANIMAL_SKIN;
else
{
type_wanted = ARM_ROBE + random2(8);
missile_type result = MI_DART;
if (one_chance_in(10))
type_wanted = ARM_ANIMAL_SKIN;
}
case SK_CROSSBOWS:
// Assuming that crossbow in inventory means that they
// want bolts for it (not darts for a hand crossbow)...
// perhaps we should check for both and compare ammo
// amounts on hand?
result = (_have_item_with_types(OBJ_WEAPONS, WPN_CROSSBOW) ? MI_BOLT
: MI_DART);
break;
// everyone can wear things made from hides
if (one_chance_in(20))
{
int rnd = random2(20);
case SK_DARTS:
// Assuming that blowgun in inventory means that they
// may want needles for it (but darts might also be
// wanted). Maybe expand this... see above comment.
result =
(_have_item_with_types(OBJ_WEAPONS, WPN_BLOWGUN) && coinflip())
? MI_NEEDLE : MI_DART;
break;
type_wanted = (rnd < 4) ? ARM_TROLL_LEATHER_ARMOUR : // 20%
(rnd < 8) ? ARM_STEAM_DRAGON_ARMOUR : // 20%
(rnd < 11) ? ARM_MOTTLED_DRAGON_ARMOUR : // 15%
(rnd < 14) ? ARM_SWAMP_DRAGON_ARMOUR : // 15%
(rnd < 16) ? ARM_DRAGON_ARMOUR : // 10%
(rnd < 18) ? ARM_ICE_DRAGON_ARMOUR : // 10%
(rnd < 19) ? ARM_STORM_DRAGON_ARMOUR // 5%
: ARM_GOLD_DRAGON_ARMOUR; // 5%
}
}
default:
break;
unsigned char i;
switch (class_wanted)
{
case OBJ_JEWELLERY:
// Try for a base type the player hasn't identified
for (i = 0; i < 10; i++)
{
type_wanted = random2(24);
result = AMU_FIRST_AMULET
+ random2(NUM_JEWELLERY - AMU_FIRST_AMULET);
}
else
{
result = random2(NUM_RINGS);
}
case OBJ_BOOKS:
// Remember, put rarer books higher in the list.
iteration = 1;
type_wanted = NUM_BOOKS;
static int _choose_first_unseen_book(int first, ...)
{
va_list args;
va_start(args, first);
switch (best_spell)
{
default:
case SK_SPELLCASTING:
if (you.skills[SK_SPELLCASTING] <= 3
&& !you.had_book[BOOK_CANTRIPS])
{
// Handful of level one spells, very useful for the
// new spellcaster who's asking for a book -- bwr
type_wanted = BOOK_CANTRIPS;
}
else if (!you.had_book[BOOK_MINOR_MAGIC_I])
type_wanted = BOOK_MINOR_MAGIC_I + random2(3);
else if (!you.had_book[BOOK_WIZARDRY])
type_wanted = BOOK_WIZARDRY;
else if (!you.had_book[BOOK_CONTROL])
type_wanted = BOOK_CONTROL;
else if (!you.had_book[BOOK_POWER])
type_wanted = BOOK_POWER;
break;
while (nargs-- > 0)
{
const int another = va_arg(args, int);
if (another == NUM_BOOKS || !you.had_book[another])
{
va_end(args);
return (another);
}
}
case SK_SUMMONINGS:
if (!you.had_book[BOOK_CALLINGS])
type_wanted = BOOK_CALLINGS;
else if (!you.had_book[BOOK_SUMMONINGS])
type_wanted = BOOK_SUMMONINGS;
skill_type best_spell_skill = SK_NONE;
// Do two iterations: one with the best spell skill, one with
// the second-best.
for (int i = 0; i < 2; ++i)
{
// FIXME: Assumes that SK_POISON_MAGIC is the last spell skill.
best_spell_skill = best_skill(SK_SPELLCASTING, SK_POISON_MAGIC,
best_spell_skill);
switch (best_spell_skill)
{
default:
case SK_SPELLCASTING:
if (you.skills[SK_SPELLCASTING] <= 3
&& !you.had_book[BOOK_CANTRIPS])
{
// Handful of level one spells, very useful for the
// new spellcaster who's asking for a book -- bwr
result = BOOK_CANTRIPS;
}
else
{
result = _choose_first_unseen_book(BOOK_MINOR_MAGIC_I,
BOOK_WIZARDRY,
BOOK_CONTROL,
BOOK_POWER,
NUM_BOOKS);
if (result == BOOK_MINOR_MAGIC_I)
result += random2(3);
}
break;
// So many enchantment books! I really can't feel
// guilty at all for dividing out the fighting
// books and forcing the player to raise a fighting
// skill (or enchantments in the case of Crusaders)
// to get the remaining books... enchantments are
// much too good (most spells, lots of books here,
// id wand charges, gives magic resistance),
// something will eventually have to be done. -- bwr
if (best_any >= SK_FIGHTING && best_any <= SK_STAVES)
{
// Fighter mages get the fighting enchantment books
if (!you.had_book[BOOK_WAR_CHANTS])
type_wanted = BOOK_WAR_CHANTS;
else if (!you.had_book[BOOK_TUKIMA])
type_wanted = BOOK_TUKIMA;
}
else if (!you.had_book[BOOK_CHARMS])
type_wanted = BOOK_CHARMS;
else if (!you.had_book[BOOK_HINDERANCE])
type_wanted = BOOK_HINDERANCE;
else if (!you.had_book[BOOK_ENCHANTMENTS])
type_wanted = BOOK_ENCHANTMENTS;
break;
case SK_AIR_MAGIC:
result = _choose_first_unseen_book(BOOK_AIR, BOOK_SKY, NUM_BOOKS);
break;
case SK_CONJURATIONS:
if (!you.had_book[BOOK_CONJURATIONS_I])
type_wanted = give_first_conjuration_book();
else if (!you.had_book[BOOK_TEMPESTS])
type_wanted = BOOK_TEMPESTS;
case SK_ICE_MAGIC:
result = _choose_first_unseen_book(BOOK_FROST, BOOK_ICE, NUM_BOOKS);
break;
// now a Vehumet special -- bwr
// else if (!you.had_book[BOOK_ANNIHILATIONS])
// type_wanted = BOOK_ANNIHILATIONS;
break;
case SK_FIRE_MAGIC:
result = _choose_first_unseen_book(BOOK_FLAMES, BOOK_FIRE,
NUM_BOOKS);
break;
case SK_NECROMANCY:
if (!you.had_book[BOOK_NECROMANCY])
type_wanted = BOOK_NECROMANCY;
else if (!you.had_book[BOOK_DEATH])
type_wanted = BOOK_DEATH;
else if (!you.had_book[BOOK_UNLIFE])
type_wanted = BOOK_UNLIFE;
case SK_SUMMONINGS:
// Don't give Demonology, that's a Vehumet special.
result = _choose_first_unseen_book(BOOK_CALLINGS, BOOK_SUMMONINGS,
NUM_BOOKS);
break;
case SK_TRANSLOCATIONS:
if (!you.had_book[BOOK_SPATIAL_TRANSLOCATIONS])
type_wanted = BOOK_SPATIAL_TRANSLOCATIONS;
else if (!you.had_book[BOOK_WARP])
type_wanted = BOOK_WARP;
break;
// So many enchantment books! I really can't feel
// guilty at all for dividing out the fighting
// books and forcing the player to raise a fighting
// skill (or enchantments in the case of Crusaders)
// to get the remaining books... enchantments are
// much too good (most spells, lots of books here,
// id wand charges, gives magic resistance),
// something will eventually have to be done. -- bwr
if (best_any >= SK_FIGHTING && best_any <= SK_STAVES)
{
// Fighter mages get the fighting enchantment books
result = _choose_first_unseen_book(BOOK_WAR_CHANTS, BOOK_TUKIMA,
NUM_BOOKS);
}
else
{
result = _choose_first_unseen_book(BOOK_CHARMS, BOOK_HINDERANCE,
BOOK_ENCHANTMENTS,
NUM_BOOKS);
}
break;
}
case SK_TRANSMUTATION:
if (!you.had_book[BOOK_CHANGES])
type_wanted = BOOK_CHANGES;
else if (!you.had_book[BOOK_TRANSFIGURATIONS])
type_wanted = BOOK_TRANSFIGURATIONS;
else if (!you.had_book[BOOK_MUTATIONS])
type_wanted = BOOK_MUTATIONS;
break;
case SK_CONJURATIONS:
// Don't give Annihilations, that's a Vehumet special.
result = _choose_first_unseen_book(BOOK_CONJURATIONS_I,
BOOK_TEMPESTS, NUM_BOOKS);
if (result == BOOK_CONJURATIONS_I)
result = give_first_conjuration_book();
break;
case SK_DIVINATIONS: //jmf: added 24mar2000
if (!you.had_book[BOOK_SURVEYANCES])
type_wanted = BOOK_SURVEYANCES;
else if (!you.had_book[BOOK_DIVINATIONS])
type_wanted = BOOK_DIVINATIONS;
break;
}
/*
if (type_wanted == 99 && glof == best_skill(SK_SPELLCASTING, (NUM_SKILLS - 1), 99))
*/
if (type_wanted == NUM_BOOKS && iteration == 1)
{
best_spell = best_skill( SK_SPELLCASTING, NUM_SKILLS - 1,
best_skill(SK_SPELLCASTING,
NUM_SKILLS - 1, 99) );
iteration++;
goto which_book;
}
case SK_NECROMANCY:
// Don't give the Necromicon, that's a Kikubaaqudgha special.
result = _choose_first_unseen_book(BOOK_NECROMANCY, BOOK_DEATH,
BOOK_UNLIFE, NUM_BOOKS);
break;
// If we don't have a book, try and get a new one.
if (type_wanted > MAX_FIXED_BOOK)
{
do
{
type_wanted = random2(NUM_NORMAL_BOOKS);
if (one_chance_in(500))
break;
}
while (you.had_book[type_wanted]);
}
case SK_TRANSLOCATIONS:
result = _choose_first_unseen_book(BOOK_SPATIAL_TRANSLOCATIONS,
BOOK_WARP, NUM_BOOKS);
break;
// If the book is invalid find any valid one.
while (type_wanted == BOOK_HEALING)
type_wanted = random2(NUM_NORMAL_BOOKS);
break;
case SK_TRANSMUTATION:
result = _choose_first_unseen_book(BOOK_CHARMS,
BOOK_TRANSFIGURATIONS,
BOOK_MUTATIONS,
NUM_BOOKS);
break;
// Elemental preferences -- bwr
if (type_wanted == STAFF_FIRE || type_wanted == STAFF_COLD)
{
if (you.skills[SK_FIRE_MAGIC] > you.skills[SK_ICE_MAGIC])
type_wanted = STAFF_FIRE;
else if (you.skills[SK_FIRE_MAGIC] != you.skills[SK_ICE_MAGIC])
type_wanted = STAFF_COLD;
}
else if (type_wanted == STAFF_AIR || type_wanted == STAFF_EARTH)
{
if (you.skills[SK_AIR_MAGIC] > you.skills[SK_EARTH_MAGIC])
type_wanted = STAFF_AIR;
else if (you.skills[SK_AIR_MAGIC] != you.skills[SK_EARTH_MAGIC])
type_wanted = STAFF_EARTH;
}
// If we don't have a book, try and get a new one.
if (result == NUM_BOOKS)
{
do
{
result = random2(NUM_NORMAL_BOOKS);
if (one_chance_in(500))
break;
}
while (you.had_book[result]);
}
// If we're going to give out an enhancer staff,
// we should at least bias things towards the
// best spell skill. -- bwr
switch (best_spell)
{
case SK_FIRE_MAGIC:
if (!already_has[STAFF_FIRE])
type_wanted = STAFF_FIRE;
break;
return result;
}
case SK_AIR_MAGIC:
if (!already_has[STAFF_AIR])
type_wanted = STAFF_AIR;
break;
// Elemental preferences -- bwr
if (result == STAFF_FIRE || result == STAFF_COLD)
{
if (you.skills[SK_FIRE_MAGIC] > you.skills[SK_ICE_MAGIC])
result = STAFF_FIRE;
if (you.skills[SK_FIRE_MAGIC] < you.skills[SK_ICE_MAGIC])
result = STAFF_COLD;
}
else if (result == STAFF_AIR || result == STAFF_EARTH)
{
if (you.skills[SK_AIR_MAGIC] > you.skills[SK_EARTH_MAGIC])
result = STAFF_AIR;
if (you.skills[SK_AIR_MAGIC] < you.skills[SK_EARTH_MAGIC])
result = STAFF_EARTH;
}
case SK_POISON_MAGIC:
if (!already_has[STAFF_POISON])
type_wanted = STAFF_POISON;
break;
#define TRY_GIVE(x) { if (!already_has[x]) result = x; }
// If we're going to give out an enhancer staff,
// we should at least bias things towards the
// best spell skill. -- bwr
switch (best_spell_skill)
{
case SK_FIRE_MAGIC: TRY_GIVE(STAFF_FIRE); break;
case SK_ICE_MAGIC: TRY_GIVE(STAFF_COLD); break;
case SK_AIR_MAGIC: TRY_GIVE(STAFF_AIR); break;
case SK_EARTH_MAGIC: TRY_GIVE(STAFF_EARTH); break;
case SK_POISON_MAGIC: TRY_GIVE(STAFF_POISON); break;
case SK_NECROMANCY: TRY_GIVE(STAFF_DEATH); break;
case SK_CONJURATIONS: TRY_GIVE(STAFF_CONJURATION); break;
case SK_ENCHANTMENTS: TRY_GIVE(STAFF_ENCHANTMENT); break;
case SK_SUMMONINGS: TRY_GIVE(STAFF_SUMMONING); break;
#undef TRY_GIVE
case SK_CONJURATIONS:
if (!already_has[STAFF_CONJURATION])
type_wanted = STAFF_CONJURATION;
break;
default: // Invocations and leftover spell schools.
switch (random2(5))
{
case 0: result = STAFF_WIZARDRY; break;
case 1: result = STAFF_POWER; break;
case 2: result = STAFF_ENERGY; break;
case 3: result = STAFF_CHANNELING; break;
case 4: break; // keep the original random staff
}
break;
}
case SK_SUMMONINGS:
if (!already_has[STAFF_SUMMONING])
type_wanted = STAFF_SUMMONING;
break;
// Increased chance of getting a rod for new or
// non-spellcasters. -- bwr
if (one_chance_in(20)
|| (spell_skills <= 1 // short on spells
&& result < STAFF_FIRST_ROD
&& !one_chance_in(4)))
{
result = coinflip() ? STAFF_STRIKING : random_rod_subtype();
}
default: // Invocations and leftover spell schools.
switch (random2(5))
{
case 0:
type_wanted = STAFF_WIZARDRY;
break;
static int _acquirement_misc_subtype()
{
int result = NUM_MISCELLANY;
do
{
result = random2(NUM_MISCELLANY);
}
while (result == MISC_HORN_OF_GERYON
|| result == MISC_RUNE_OF_ZOT
|| result == MISC_CRYSTAL_BALL_OF_FIXATION
|| result == MISC_EMPTY_EBONY_CASKET
|| result == MISC_DECK_OF_PUNISHMENT);
case 4:
break;
}
break;
}
// Write down what the player is carrying.
has_vector already_has;
already_has.init(0);
for (int i = 0; i < ENDOFPACK; ++i)
{
const item_def& item = you.inv[i];
if (is_valid_item(item) && item.base_type == class_wanted)
{
ASSERT(item.sub_type < max_has_value);
already_has[item.sub_type] += item.quantity;
}
}
// Increased chance of getting a rod for new or
// non-spellcasters. -- bwr
if (one_chance_in(20)
|| (spell_skills <= 1 // short on spells
&& type_wanted < STAFF_SMITING
&& !one_chance_in(4)))
{
type_wanted = coinflip() ? STAFF_STRIKING :
random_rod_subtype();
}
break;
bool try_again = (class_wanted == OBJ_JEWELLERY
|| class_wanted == OBJ_BOOKS
|| class_wanted == OBJ_STAVES
|| class_wanted == OBJ_MISCELLANY);
do
{
switch (class_wanted)
{
case OBJ_FOOD:
// set type_wanted and quantity
_acquirement_determine_food(type_wanted, quantity, already_has);
break;
case OBJ_MISCELLANY:
do
{
type_wanted = random2(NUM_MISCELLANY);
}
while (type_wanted == MISC_HORN_OF_GERYON
|| type_wanted == MISC_RUNE_OF_ZOT
|| type_wanted == MISC_CRYSTAL_BALL_OF_FIXATION
|| type_wanted == MISC_EMPTY_EBONY_CASKET
|| type_wanted == MISC_DECK_OF_PUNISHMENT);
break;
default:
break;
}
case OBJ_WEAPONS: type_wanted = _acquirement_weapon_subtype(); break;
case OBJ_MISSILES: type_wanted = _acquirement_missile_subtype(); break;
case OBJ_ARMOUR: type_wanted = _acquirement_armour_subtype(); break;
case OBJ_BOOKS: type_wanted = _acquirement_book_subtype(); break;
case OBJ_MISCELLANY: type_wanted = _acquirement_misc_subtype(); break;
case OBJ_STAVES: type_wanted = _acquirement_staff_subtype(already_has);
break;
case OBJ_JEWELLERY: type_wanted = _acquirement_jewellery_subtype();
break;