tweaks.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@10660 c06c8d41-db1a-0410-9941-cceddc491573
664OROPKKA6CEBNMMRM67KB4KVKTKFPCHEUWCHZVQVYNKYPHWL4QC
ZRH5DNUOMGDPUHM2CJM566ELXH562CIH57YTGDYKSKTPDCQC32YQC
FXCVO7LPJ7JK77YSNTHQF452UQJFA6LBVUJ2OFJA5EZ6OF5QADHAC
I3GNXBIGS7FK6WL3ZSVPRM6FRICFU4FCIJQFK6VB4YLF2SBLGIXAC
NTS6Z2PI5MKI73DL5ZQN72OBMFGHRCT23CTTHBVD2BLPPQFCG6GQC
H65CCZM2SL5E2XLBYO6ZOHRKLB7UALHI3OLGJ67PFIZ2QNAPFQDQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
FEMG2L5AKPPUVYNAHL4KSFP577SRC67O7PFZKKPIXWRSFN7XNJNQC
WMFU65IAJ3LX2YSFXXRS7ZFNDCZYQC3ZQ3QDHHK3DU3UMLJMAP4QC
C2PRXJYHDRF2642VDAUY76HJKCPQFGWDI6AM3SMCMYCHGWYDQXQQC
JJULXW764V5C2HJKZNWQAEWB6QM5YZADD7ZCE35LYTBFEM6PMYCAC
UFNXOEBCAUO3QMYOF6EXYILHZ44AXVMCOV76SFV3VV7DMVUPZWBAC
XCEZ7OA2INNPSYNAB5U6JB7XNDAD5BKU26YLFPPZ3SEESFZKADQAC
KH5DN75GPQGMSUV5VTNFSXV4G3Q43O4R4M2BADFSYEEQYUQFCWMAC
T7CUIVICB74342RA32BR37T36FOX4RBSQIB5PNOHTGTGUYGDKSTQC
WN3ZHNL4T7QMQC6JF5DJR6NHLZVOGQVO4OJNEKEM5FZKQ7AVOP4AC
5FECCMAC5QKG3SJ4ATZFE2QF7I3A4YKWKCU4XQEW2P2SWZ2J33YQC
P2YNOE2TUTZFAOBTHJOIVD6TCV7J7D2UKUX67LHZUL6QY44ZMENQC
ACO4RHJ6A5I3ECRL4MVU7PGTNWIDY7JNR7IK3NJFWZO2OEG2OFAAC
3GRGONHWIZ7PTTNMJ6CIZEMIKC7N2DTU62BLJ5QG4E7RGA5O2XMAC
Z6343ZVG2VOE7WOLBS7YLIWJ6XGCRCGJRJLP5WUVRTG7VOIXRRLAC
3A3OAIFRFU3IHF6SDNDPCN3XYOFYIBYCEYJAXAFASCFDY76SMFXQC
B5OK4FEITJ6MUT7J76OJJH2TOPTZGG7J7UPIJ6Z6WA5FC526FLTAC
SJP5BHX6MFWF3OSQPEF4WUWZWPUGMOVURTT2CUVT6H3A66LETXUAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
CIZ6TVSDTU7YJI3DGHNSC2SHGMEGT5AXSEO5X65EUD7UW5FPGQDAC
VXSORUQOM2VZA4CAZDC6KPAY373NQIN3UT7CXQXTRCYXO2WM62DAC
BTDIRPAGSX5DWEEV62VGTYALWM6G5LKFKHT7HYJXVH7XBA4BPHLQC
S4BRP4VHB23F2FCC6BXNAN2MZRVUGW7QMXUEOAVZVGFXKXJPVLLQC
XSGOCZRVJO3C2Z7ADWP5N6HTDKJLJ4LN5OY6RNXX3L42FZGGVRLAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
case JOB_WANDERER: s = 2; i = 2; d = 2; hp = 11; mp = 1; break;
case JOB_WANDERER:
{
// Wanderers get 2 points per stat as a baseline, and 4 more are
// randomly distributed.
s = 2; i = 2; d = 2;
_assign_remaining_stats(4);
hp = 11; mp = 1; break;
}
static void _give_random_potion(int slot)
{
// If you can't quaff, you don't care.
if (you.is_undead == US_UNDEAD)
return;
you.inv[ slot ].quantity = 1;
you.inv[ slot ].base_type = OBJ_POTIONS;
you.inv[ slot ].plus = 0;
you.inv[ slot ].plus2 = 0;
// No Berserk for undead other than vampires.
int temp_rand = 8;
if (you.is_undead && you.species != SP_VAMPIRE)
temp_rand--;
switch (random2(temp_rand))
{
case 0:
case 1:
case 2:
you.inv[slot].sub_type = POT_HEALING;
break;
case 3:
case 4:
you.inv[slot].sub_type = POT_HEAL_WOUNDS;
break;
case 5:
you.inv[slot].sub_type = POT_SPEED;
break;
case 6:
you.inv[slot].sub_type = POT_MIGHT;
break;
case 7:
you.inv[slot].sub_type = POT_BERSERK_RAGE;
break;
}
}
static void _give_random_secondary_armour(int slot)
{
you.inv[slot].quantity = 1;
you.inv[slot].base_type = OBJ_ARMOUR;
you.inv[slot].special = 0;
you.inv[slot].plus = 0;
you.inv[slot].plus2 = 0;
switch (random2(4))
{
case 0:
if (you_can_wear(EQ_BOOTS))
{
you.inv[slot].sub_type = ARM_BOOTS;
you.equip[EQ_BOOTS] = slot;
break;
}
// else fall through
case 1:
if (you_can_wear(EQ_HELMET))
{
you.inv[slot].sub_type = ARM_HELMET;
you.equip[EQ_HELMET] = slot;
break;
}
// else fall through
case 2:
if (you_can_wear(EQ_GLOVES))
{
you.inv[slot].sub_type = ARM_GLOVES;
you.equip[EQ_GLOVES] = slot;
break;
}
// else fall through
case 3: // Anyone can wear this.
you.inv[slot].sub_type = ARM_CLOAK;
you.equip[EQ_CLOAK] = slot;
break;
}
}
// Returns true if a "good" weapon is given.
static bool _give_wanderer_weapon(int slot, int wpn_skill)
{
bool ret = false;
// Slot's always zero, but we pass it anyway.
// We'll also re-fill the template, all this for later possible
// safe reuse of code in the future.
you.inv[slot].quantity = 1;
you.inv[slot].base_type = OBJ_WEAPONS;
you.inv[slot].plus = 0;
you.inv[slot].plus2 = 0;
you.inv[slot].special = 0;
// Now fill in the type according to the random wpn_skill.
switch (wpn_skill)
{
case SK_MACES_FLAILS:
you.inv[slot].sub_type = WPN_CLUB;
break;
case SK_POLEARMS:
you.inv[slot].sub_type = WPN_SPEAR;
break;
case SK_SHORT_BLADES:
you.inv[slot].sub_type = WPN_DAGGER;
break;
case SK_AXES:
you.inv[slot].sub_type = WPN_HAND_AXE;
ret = true;
break;
case SK_STAVES:
you.inv[slot].sub_type = WPN_QUARTERSTAFF;
ret = true;
break;
case SK_LONG_BLADES:
default:
// All long swords are too good for a starting character...
// Especially this class where we have to be careful about
// giving away anything good at all.
// We default here if the character only has fighting skill. - bwr
you.inv[slot].sub_type = WPN_SHORT_SWORD;
ret = true;
break;
}
return (ret);
}
// Returns true if a "good" weapon is given.
static bool _give_wanderer_weapon(int & slot, int wpn_skill, int plus)
{
// Darts skill also gets you some needles.
if (wpn_skill == SK_DARTS)
{
// Plus is set if we are getting a good item. In that case, we
// get curare here.
if (plus)
{
_newgame_make_item(slot, EQ_NONE, OBJ_MISSILES, MI_NEEDLE, -1,
1 + random2(4));
set_item_ego_type(you.inv[slot], OBJ_MISSILES, SPMSL_CURARE);
slot++;
}
// Otherwise, we just get some poisoned needles.
else
{
_newgame_make_item(slot, EQ_NONE, OBJ_MISSILES, MI_NEEDLE, -1,
5 + roll_dice(2, 5));
set_item_ego_type(you.inv[slot], OBJ_MISSILES, SPMSL_POISONED);
slot++;
}
}
_newgame_make_item(slot, EQ_WEAPON, OBJ_WEAPONS, WPN_KNIFE);
// We'll also re-fill the template, all for later possible safe
// reuse of code in the future.
you.inv[slot].quantity = 1;
you.inv[slot].plus = 0;
you.inv[slot].plus2 = 0;
you.inv[slot].special = 0;
// Now fill in the type according to the random wpn_skill.
switch (wpn_skill)
{
case SK_MACES_FLAILS:
you.inv[slot].sub_type = WPN_MACE;
break;
case SK_POLEARMS:
you.inv[slot].sub_type = WPN_SPEAR;
break;
case SK_SHORT_BLADES:
you.inv[slot].sub_type = WPN_SHORT_SWORD;
break;
case SK_AXES:
you.inv[slot].sub_type = WPN_HAND_AXE;
break;
case SK_STAVES:
you.inv[slot].sub_type = WPN_QUARTERSTAFF;
break;
case SK_BOWS:
you.inv[slot].sub_type = WPN_BOW;
break;
case SK_CROSSBOWS:
you.inv[slot].sub_type = WPN_HAND_CROSSBOW;
break;
case SK_DARTS:
you.inv[slot].sub_type = WPN_BLOWGUN;
break;
}
int offset = plus ? 1 : 0;
you.inv[slot].plus = random2(plus) + offset;
you.inv[slot].plus2 = random2(plus) + offset;
return (true);
}
}
// The overall role choice for wanderers is a weighted chance based on
// stats.
static stat_type _wanderer_choose_role()
{
int total_stats = 0;
total_stats += you.strength;
total_stats += you.dex;
total_stats += you.intel;
int target = random2(total_stats);
stat_type role;
if (target < you.strength)
role = STAT_STRENGTH;
else if (target < (you.dex + you.strength))
role = STAT_DEXTERITY;
else
role = STAT_INTELLIGENCE;
return (role);
}
static skill_type _apt_weighted_choice(const skill_type * skill_array,
unsigned arr_size)
{
int total_apt = 0;
for (unsigned i = 0; i < arr_size; ++i)
{
int reciprocal_apt = (100 * 100) /
species_skills(skill_array[i], you.species);
total_apt += reciprocal_apt;
}
unsigned probe = random2(total_apt);
unsigned region_covered = 0;
for (unsigned i = 0; i < arr_size; ++i)
{
int reciprocal_apt = (100 * 100) /
species_skills(skill_array[i], you.species);
region_covered += reciprocal_apt;
if (probe < region_covered)
return (skill_array[i]);
}
return (NUM_SKILLS);
// The idea behind wanderers is a class that has various different
// random skills that's a challenge to play... not a class that can
// be continually rerolled to gain the ideal character. To maintain
// this, we have to try and make sure that they typically get worse
// equipment than any other class... this for certain means no
// spellbooks ever, and the bows and xbows down below might be too
// much... so pretty much things should be removed rather than
// added here. -- bwr
static void _create_wanderer(void)
switch((int)selected_role)
{
case STAT_DEXTERITY:
switch (random2(6))
{
case 0:
case 1:
selected_skill = SK_FIGHTING;
break;
case 2:
selected_skill = SK_DODGING;
break;
case 3:
selected_skill = SK_STEALTH;
break;
case 4:
case 5:
selected_skill = sk_1;
break;
}
break;
case STAT_STRENGTH:
{
int options = 3;
if (!you_can_wear(EQ_BODY_ARMOUR))
options--;
switch (random2(options))
{
case 0:
selected_skill = SK_FIGHTING;
break;
case 1:
selected_skill = sk_1;
break;
case 2:
selected_skill = SK_ARMOUR;
break;
}
break;
}
case STAT_INTELLIGENCE:
switch (random2(3))
{
case 0:
selected_skill = SK_SPELLCASTING;
break;
case 1:
selected_skill = sk_1;
break;
case 2:
selected_skill = sk_2;
break;
}
break;
}
return (selected_skill);
}
static skill_type _wanderer_role_weapon_select(stat_type role)
const skill_type util_skills[] =
{ SK_DARTS, SK_THROWING, SK_ARMOUR, SK_DODGING, SK_STEALTH,
SK_STABBING, SK_SHIELDS, SK_TRAPS_DOORS, SK_UNARMED_COMBAT,
SK_INVOCATIONS, SK_EVOCATIONS };
skill_type skill = NUM_SKILLS;
const skill_type str_weapons[] =
{ SK_AXES, SK_MACES_FLAILS, SK_BOWS, SK_CROSSBOWS };
// Long swords is missing to increase its rarity because we
// can't give out a long sword to a starting character (they're
// all too good)... Staves is also removed because it's not
// one of the fighter options.-- bwr
const skill_type fight_util_skills[] =
{ SK_FIGHTING, SK_SHORT_BLADES, SK_AXES,
SK_MACES_FLAILS, SK_POLEARMS,
SK_DARTS, SK_THROWING, SK_ARMOUR, SK_DODGING, SK_STEALTH,
SK_STABBING, SK_SHIELDS, SK_TRAPS_DOORS, SK_UNARMED_COMBAT,
SK_INVOCATIONS, SK_EVOCATIONS };
int str_size = sizeof(str_weapons) / sizeof(skill_type);
const skill_type not_rare_skills[] =
{ SK_SLINGS, SK_BOWS, SK_CROSSBOWS,
SK_SPELLCASTING, SK_CONJURATIONS, SK_ENCHANTMENTS,
SK_FIRE_MAGIC, SK_ICE_MAGIC, SK_AIR_MAGIC, SK_EARTH_MAGIC,
SK_FIGHTING, SK_SHORT_BLADES, SK_LONG_BLADES, SK_AXES,
SK_MACES_FLAILS, SK_POLEARMS, SK_STAVES,
SK_DARTS, SK_THROWING, SK_ARMOUR, SK_DODGING, SK_STEALTH,
SK_STABBING, SK_SHIELDS, SK_TRAPS_DOORS, SK_UNARMED_COMBAT,
SK_INVOCATIONS, SK_EVOCATIONS };
const skill_type dex_weapons[] =
{ SK_SHORT_BLADES, SK_STAVES, SK_UNARMED_COMBAT, SK_POLEARMS };
const skill_type all_skills[] =
{ SK_SUMMONINGS, SK_NECROMANCY, SK_TRANSLOCATIONS, SK_TRANSMUTATIONS,
SK_DIVINATIONS, SK_POISON_MAGIC,
SK_SLINGS, SK_BOWS, SK_CROSSBOWS,
SK_SPELLCASTING, SK_CONJURATIONS, SK_ENCHANTMENTS,
SK_FIRE_MAGIC, SK_ICE_MAGIC, SK_AIR_MAGIC, SK_EARTH_MAGIC,
SK_FIGHTING, SK_SHORT_BLADES, SK_LONG_BLADES, SK_AXES,
SK_MACES_FLAILS, SK_POLEARMS, SK_STAVES,
SK_DARTS, SK_THROWING, SK_ARMOUR, SK_DODGING, SK_STEALTH,
SK_STABBING, SK_SHIELDS, SK_TRAPS_DOORS, SK_UNARMED_COMBAT,
SK_INVOCATIONS, SK_EVOCATIONS };
int dex_size = sizeof(dex_weapons) / sizeof(skill_type);
const skill_type casting_schools[] =
{ SK_SUMMONINGS, SK_NECROMANCY, SK_TRANSLOCATIONS,
SK_TRANSMUTATIONS, SK_POISON_MAGIC, SK_CONJURATIONS,
SK_ENCHANTMENTS, SK_FIRE_MAGIC, SK_ICE_MAGIC,
SK_AIR_MAGIC, SK_EARTH_MAGIC };
do
skill = RANDOM_ELEMENT(util_skills);
while (you.skills[skill] >= 2);
case STAT_STRENGTH:
skill = _apt_weighted_choice(str_weapons, str_size);
break;
case STAT_DEXTERITY:
skill = _apt_weighted_choice(dex_weapons, dex_size);
break;
for (int i = 0; i < 3; i++)
return (skill);
}
static void _wanderer_role_skill(stat_type role, int levels)
{
skill_type weapon_type = NUM_SKILLS;
skill_type spell2 = NUM_SKILLS;
weapon_type = _wanderer_role_weapon_select(role);
if (role == STAT_INTELLIGENCE)
spell2 = _wanderer_role_weapon_select(role);
skill_type selected_skill = NUM_SKILLS;
for (int i = 0; i < levels; ++i)
do
skill = RANDOM_ELEMENT(fight_util_skills);
while (you.skills[skill] >= 2);
selected_skill = _wanderer_role_skill_select(role, weapon_type,
spell2);
you.skills[selected_skill]++;
}
}
// Select a random skill from all skills we have at least 1 level in.
static skill_type _weighted_skill_roll()
{
int total_skill = 0;
for (unsigned i = 0; i < NUM_SKILLS; ++i)
total_skill += you.skills[i];
int probe = random2(total_skill);
int covered_region = 0;
// Spell skills are possible past this point, but we won't allow two
// levels of any of them. - bwr
for (int i = 0; i < 3; i++)
return (NUM_SKILLS);
}
static void _give_wanderer_book(skill_type skill, int & slot)
{
int book_type = BOOK_MINOR_MAGIC_I;
switch((int)skill)
do
skill = RANDOM_ELEMENT(not_rare_skills);
while (you.skills[skill] >= 2
|| (skill >= SK_SPELLCASTING && you.skills[skill] > 0));
case SK_SPELLCASTING:
switch (random2(3))
{
case 0:
book_type = BOOK_MINOR_MAGIC_I;
break;
case 1:
book_type = BOOK_MINOR_MAGIC_II;
break;
case 2:
book_type = BOOK_MINOR_MAGIC_III;
break;
}
break;
case SK_CONJURATIONS:
switch (random2(6))
{
case 0:
book_type = BOOK_MINOR_MAGIC_I;
break;
you.skills[skill]++;
case 1:
book_type = BOOK_MINOR_MAGIC_II;
break;
case 2:
book_type = BOOK_CONJURATIONS_I;
break;
case 3:
book_type = BOOK_CONJURATIONS_II;
break;
case 4:
book_type = BOOK_YOUNG_POISONERS;
break;
case 5:
book_type = BOOK_STALKING;
break;
}
break;
case SK_SUMMONINGS:
switch (random2(2))
{
case 0:
book_type = BOOK_MINOR_MAGIC_III;
break;
case 1:
book_type = BOOK_CALLINGS;
break;
}
break;
case SK_NECROMANCY:
book_type = BOOK_NECROMANCY;
break;
case SK_TRANSLOCATIONS:
book_type = BOOK_SPATIAL_TRANSLOCATIONS;
break;
case SK_TRANSMUTATIONS:
switch (random2(2))
{
case 0:
book_type = BOOK_GEOMANCY;
break;
case 1:
book_type = BOOK_CHANGES;
break;
}
break;
case SK_FIRE_MAGIC:
switch (random2(3))
{
case 0:
book_type = BOOK_MINOR_MAGIC_I;
break;
case 1:
book_type = BOOK_FLAMES;
break;
case 2:
book_type = BOOK_CONJURATIONS_I;
break;
}
break;
case SK_ICE_MAGIC:
switch (random2(3))
{
case 0:
book_type = BOOK_MINOR_MAGIC_II;
break;
case 1:
book_type = BOOK_FROST;
break;
case 2:
book_type = BOOK_CONJURATIONS_II;
break;
}
break;
case SK_AIR_MAGIC:
book_type = BOOK_AIR;
break;
case SK_EARTH_MAGIC:
book_type = BOOK_GEOMANCY;
break;
case SK_POISON_MAGIC:
switch (random2(2))
{
case 0:
book_type = BOOK_STALKING;
break;
case 1:
book_type = BOOK_YOUNG_POISONERS;
break;
}
break;
case SK_ENCHANTMENTS:
switch (random2(2))
{
case 0:
book_type = BOOK_WAR_CHANTS;
break;
case 1:
book_type = BOOK_CHARMS;
break;
}
break;
for (int i = 0; i < 2; i++)
_newgame_make_item(slot, EQ_NONE, OBJ_BOOKS, book_type);
}
// Players can get some consumables as a "good item".
static void _good_potion_or_scroll(int & slot)
{
int base_rand = 5;
// No potions for mummies.
if (you.is_undead == US_UNDEAD)
base_rand -= 3;
// No berserk rage for ghouls.
else if (you.is_undead != US_SEMI_UNDEAD)
base_rand--;
you.inv[slot].quantity = 1;
you.inv[slot].plus = 0;
you.inv[slot].plus2 = 0;
switch (random2(base_rand))
do
skill = RANDOM_ELEMENT(all_skills);
while (you.skills[skill] >= 2
|| (skill >= SK_SPELLCASTING && you.skills[skill] > 0));
case 0:
you.inv[slot].base_type = OBJ_SCROLLS;
you.inv[slot].sub_type = SCR_FEAR;
break;
case 1:
you.inv[slot].base_type = OBJ_SCROLLS;
you.inv[slot].sub_type = SCR_BLINKING;
break;
case 2:
you.inv[slot].base_type = OBJ_POTIONS;
you.inv[slot].sub_type = POT_HEAL_WOUNDS;
break;
case 3:
you.inv[slot].base_type = OBJ_POTIONS;
you.inv[slot].sub_type = POT_SPEED;
break;
// Demigods can't use invocations, so we'll swap it for something else.
if (you.species == SP_DEMIGOD && you.skills[SK_INVOCATIONS])
slot++;
}
// Add a specified number of healing/teleportation items to the
// inventory.
static void _healing_or_teleport(int quantity, int & slot)
{
int healing_slot = -1;
int teleport_slot = -1;
for (int i = 0; i < slot; ++i)
do
skill = RANDOM_ELEMENT(all_skills);
while (you.skills[skill] > 0);
if (you.inv[i].sub_type == SCR_TELEPORTATION
&& you.inv[i].base_type == OBJ_SCROLLS)
{
teleport_slot = i;
}
else if (you.inv[i].sub_type == POT_HEALING
&& you.inv[i].base_type == OBJ_POTIONS)
{
healing_slot = i;
}
}
int temp_rand = 2;
// No potions for mummies.
if (you.is_undead == US_UNDEAD)
temp_rand--;
you.skills[skill] = you.skills[SK_INVOCATIONS];
you.skills[SK_INVOCATIONS] = 0;
for (int i = 0; i < quantity; ++i)
{
switch (random2(temp_rand))
{
case 0:
if (teleport_slot == -1)
{
teleport_slot = slot;
you.inv[teleport_slot].quantity = 0;
you.inv[teleport_slot].base_type = OBJ_SCROLLS;
you.inv[teleport_slot].plus = 0;
you.inv[teleport_slot].plus2 = 0;
you.inv[teleport_slot].sub_type = SCR_TELEPORTATION;
slot++;
}
you.inv[teleport_slot].quantity++;
break;
case 1:
if (healing_slot == -1)
{
healing_slot = slot;
you.inv[healing_slot].quantity = 0;
you.inv[healing_slot].base_type = OBJ_POTIONS;
you.inv[healing_slot].plus = 0;
you.inv[healing_slot].plus2 = 0;
you.inv[healing_slot].sub_type = POT_HEALING;
slot++;
}
you.inv[healing_slot].quantity++;
break;
}
// Some species cannot wear real armour.
if (you.skills[SK_ARMOUR] && !you_can_wear(EQ_BODY_ARMOUR))
// Create a random wand/rod of striking in the inventory.
static void _wanderer_random_evokable(int & slot)
{
wand_type selected_wand = WAND_ENSLAVEMENT;
switch (random2(6))
do
skill = RANDOM_ELEMENT(all_skills);
while (you.skills[skill] > 0);
case 0:
selected_wand = WAND_ENSLAVEMENT;
break;
case 1:
selected_wand = WAND_CONFUSION;
break;
case 2:
selected_wand = WAND_FLAME;
break;
case 3:
selected_wand = WAND_FROST;
break;
int wpn_skill = SK_FIGHTING; // preferred weapon type
int wpn_skill_size = 0; // level of skill in preferred weapon type
int num_wpn_skills = 0; // used to choose preferred weapon
int total_wpn_skills = 0; // used to choose template
_newgame_make_item(slot, EQ_NONE, OBJ_WANDS, selected_wand, -1, 1,
15);
slot++;
}
// This algorithm is the same as the one used to pick a random
// angry god for retribution, except that whenever a higher skill
// is found than the current one, we automatically take it and
// only consider skills at that level or higher from that point on,
// This should give a random wpn skill from the set of skills with
// the highest value. -- bwr
for (int i = SK_SHORT_BLADES; i <= SK_STAVES; i++)
void _wanderer_good_equipment(skill_type & skill, int & slot)
{
const skill_type combined_weapon_skills[] =
{ SK_AXES, SK_MACES_FLAILS, SK_BOWS, SK_CROSSBOWS,
SK_SHORT_BLADES, SK_STAVES, SK_UNARMED_COMBAT, SK_POLEARMS };
int total_weapons = sizeof(combined_weapon_skills) / sizeof(skill_type);
// Normalise the input type.
if (skill == SK_FIGHTING)
if (you.skills[i] > wpn_skill_size)
switch((int)skill)
{
case SK_MACES_FLAILS:
case SK_AXES:
case SK_POLEARMS:
case SK_BOWS:
case SK_CROSSBOWS:
case SK_DARTS:
case SK_STAVES:
case SK_SHORT_BLADES:
_give_wanderer_weapon(slot, skill, 3);
slot++;
break;
case SK_ARMOUR:
// Deformed races aren't given armor skill, so there's no need
// to worry about scale mail's not fitting.
_newgame_make_item(slot, EQ_BODY_ARMOUR, OBJ_ARMOUR, ARM_SCALE_MAIL);
slot++;
break;
case SK_SHIELDS:
_newgame_make_item(slot, EQ_SHIELD, OBJ_ARMOUR, ARM_SHIELD,
ARM_BUCKLER);
slot++;
break;
case SK_SPELLCASTING:
case SK_CONJURATIONS:
case SK_SUMMONINGS:
case SK_NECROMANCY:
case SK_TRANSLOCATIONS:
case SK_TRANSMUTATIONS:
case SK_FIRE_MAGIC:
case SK_ICE_MAGIC:
case SK_AIR_MAGIC:
case SK_EARTH_MAGIC:
case SK_POISON_MAGIC:
case SK_ENCHANTMENTS:
_give_wanderer_book(skill, slot);
slot++;
break;
case SK_DODGING:
case SK_STEALTH:
case SK_TRAPS_DOORS:
case SK_STABBING:
case SK_UNARMED_COMBAT:
case SK_INVOCATIONS:
{
// Random consumables: 2x random healing/teleportation and 1
// good potion/scroll.
_healing_or_teleport(2, slot);
_good_potion_or_scroll(slot);
break;
}
case SK_EVOCATIONS:
// Random wand/rod of striking.
_wanderer_random_evokable(slot);
break;
}
}
// The "decent" spell type item puts a spell in the player's memory.
static void _give_wanderer_spell(skill_type skill)
{
spell_type spell = SPELL_NO_SPELL;
// Doing a rejection loop for this because I am lazy.
while (skill == SK_SPELLCASTING || skill == SK_DIVINATIONS)
{
int value = SK_POISON_MAGIC-SK_CONJURATIONS + 1;
skill = skill_type(SK_CONJURATIONS + random2(value));
}
switch ((int)skill)
{
case SK_CONJURATIONS:
spell = SPELL_MAGIC_DART;
break;
case SK_SUMMONINGS:
spell = SPELL_SUMMON_SMALL_MAMMALS;
break;
case SK_NECROMANCY:
spell = SPELL_PAIN;
break;
case SK_TRANSLOCATIONS:
spell = SPELL_APPORTATION;
break;
case SK_TRANSMUTATIONS:
spell = SPELL_SANDBLAST;
break;
case SK_FIRE_MAGIC:
spell = SPELL_FLAME_TONGUE;
break;
case SK_ICE_MAGIC:
spell = SPELL_FREEZE;
break;
case SK_AIR_MAGIC:
spell = SPELL_SHOCK;
break;
case SK_EARTH_MAGIC:
spell = SPELL_SANDBLAST;
break;
case SK_POISON_MAGIC:
spell = SPELL_STING;
break;
case SK_ENCHANTMENTS:
spell = SPELL_BACKLIGHT;
break;
}
add_spell_to_memory(spell);
}
void _wanderer_decent_equipment(skill_type & skill,
std::set<skill_type> & gift_skills,
int & slot)
{
const skill_type combined_weapon_skills[] =
{ SK_AXES, SK_MACES_FLAILS, SK_BOWS, SK_CROSSBOWS,
SK_SHORT_BLADES, SK_STAVES, SK_UNARMED_COMBAT, SK_POLEARMS };
int total_weapons = sizeof(combined_weapon_skills) / sizeof(skill_type);
// If we already gave an item for this type, just give the player
// a consumable.
if((skill == SK_DODGING || skill == SK_STEALTH)
&& gift_skills.find(SK_ARMOUR) != gift_skills.end())
{
skill = SK_TRAPS_DOORS;
}
// Give the player knowledge of only one spell.
if (skill >= SK_SPELLCASTING && skill <= SK_POISON_MAGIC)
{
for (unsigned i = 0; i < you.spells.size(); ++i)
{
if (you.spells[i] != SPELL_NO_SPELL)
// Switch to looking in the new set of better skills.
num_wpn_skills = 1; // Reset to one, because it's a new set.
wpn_skill = i;
wpn_skill_size = you.skills[i];
skill = SK_TRAPS_DOORS;
break;
else if (you.skills[i] == wpn_skill_size)
}
}
// If fighting comes up, give something from the highest weapon
// skill.
if (skill == SK_FIGHTING)
{
int max_sklev = 0;
skill_type max_skill = SK_NONE;
for (int i = 0;i < total_weapons; ++i)
{
if (you.skills[combined_weapon_skills[i]] >= max_sklev)
// Still looking at the old level...
num_wpn_skills++;
if (one_chance_in( num_wpn_skills ))
{
wpn_skill = i;
wpn_skill_size = you.skills[i];
}
max_skill = combined_weapon_skills[i];
max_sklev = you.skills[max_skill];
// Let's try to make an appropriate weapon.
// Start with a template for a weapon.
_newgame_make_item(0, EQ_WEAPON, OBJ_WEAPONS, WPN_KNIFE);
// Don't give a gift from the same skill twice; just default to
// a healing potion/teleportation scroll.
if (gift_skills.find(skill) != gift_skills.end())
skill = SK_TRAPS_DOORS;
// And a default armour template for a robe (leaving slot 1 open for
// a secondary weapon).
_newgame_make_item(2, EQ_BODY_ARMOUR, OBJ_ARMOUR, ARM_ROBE);
switch((int)skill)
{
case SK_MACES_FLAILS:
case SK_AXES:
case SK_POLEARMS:
case SK_BOWS:
case SK_CROSSBOWS:
case SK_DARTS:
case SK_STAVES:
case SK_SHORT_BLADES:
_give_wanderer_weapon(slot, skill, 0);
slot++;
break;
// Wanderers have at least seen one type of potion, and if they
// don't get anything else good, they'll get to keep this one...
// Note: Even if this is taken away, the knowledge of the potion
// type is still given to the character.
_give_random_potion(3);
case SK_ARMOUR:
_newgame_make_item(slot, EQ_BODY_ARMOUR, OBJ_ARMOUR, ARM_RING_MAIL);
slot++;
break;
case SK_SHIELDS:
_newgame_make_item(slot, EQ_SHIELD, OBJ_ARMOUR, ARM_BUCKLER,
ARM_SHIELD);
slot++;
break;
case SK_DODGING:
case SK_STEALTH:
_newgame_make_item(slot, EQ_BODY_ARMOUR, OBJ_ARMOUR, ARM_ROBE);
slot++;
break;
case SK_SPELLCASTING:
case SK_CONJURATIONS:
case SK_SUMMONINGS:
case SK_NECROMANCY:
case SK_TRANSLOCATIONS:
case SK_TRANSMUTATIONS:
case SK_FIRE_MAGIC:
case SK_ICE_MAGIC:
case SK_AIR_MAGIC:
case SK_EARTH_MAGIC:
case SK_POISON_MAGIC:
_give_wanderer_spell(skill);
break;
if (you.skills[SK_FIGHTING] || total_wpn_skills >= 3)
case SK_TRAPS_DOORS:
case SK_STABBING:
case SK_UNARMED_COMBAT:
case SK_INVOCATIONS:
case SK_EVOCATIONS:
_healing_or_teleport(1, slot);
break;
}
}
// We don't actually want to send adventurers wandering naked into the
// dungeon.
static void _wanderer_cover_equip_holes(int & slot)
{
// We are going to cover any glaring holes (no armor/no weapon) that
// occurred during equipment generation.
if (you.equip[EQ_BODY_ARMOUR] == -1)
{
_newgame_make_item(slot, EQ_BODY_ARMOUR, OBJ_ARMOUR, ARM_ROBE);
slot++;
}
if (you.equip[EQ_WEAPON] == -1)
// Fighter style wanderer
if (you.skills[SK_ARMOUR])
weapon_type weapon = WPN_CLUB;
if (you.dex > you.strength || you.skills[SK_STABBING])
weapon = WPN_DAGGER;
_newgame_make_item(slot, EQ_WEAPON, OBJ_WEAPONS, weapon);
slot++;
}
// Give a dagger if you have stabbing skill. Maybe this is
// unnecessary?
if (you.skills[SK_STABBING])
{
bool has_dagger = false;
for (int i = 0; i < slot; ++i)
_newgame_make_item(4, EQ_SHIELD, OBJ_ARMOUR, ARM_SHIELD,
ARM_BUCKLER);
you.inv[3].quantity = 0; // remove potion
_newgame_make_item(slot, EQ_WEAPON, OBJ_WEAPONS, WPN_DAGGER);
slot++;
// Remove potion if good weapon is given.
if (_give_wanderer_weapon(0, wpn_skill))
you.inv[3].quantity = 0;
// The player gets a stack of darts if they have a hand
// crossbow/darts skill but no blowgun.
bool need_darts = false;
for (int i = 0; i < slot; ++i)
{
if (you.inv[i].base_type == OBJ_WEAPONS
&& you.inv[i].sub_type == WPN_HAND_CROSSBOW)
{
need_darts = true;
break;
}
// Generic wanderer
_give_wanderer_weapon(0, wpn_skill);
_give_random_secondary_armour(5);
need_darts = true;
for (int i = 0; i < slot; ++i)
{
if (you.inv[i].base_type == OBJ_WEAPONS
&& you.inv[i].sub_type == WPN_BLOWGUN)
{
need_darts = false;
break;
}
}
}
if (need_darts)
{
_newgame_make_item(slot, EQ_NONE, OBJ_MISSILES, MI_DART, -1,
8 + roll_dice(2, 8));
slot++;
you.equip[EQ_WEAPON] = 0;
you.equip[EQ_BODY_ARMOUR] = 2;
// And the player needs arrows if they have a bow.
bool needs_arrows = false;
for (int i = 0; i < slot; ++i)
{
if (you.inv[i].base_type == OBJ_WEAPONS
&& you.inv[i].sub_type == WPN_BOW)
{
needs_arrows = true;
break;
}
}
if (needs_arrows)
{
_newgame_make_item(slot, EQ_NONE, OBJ_MISSILES, MI_ARROW, -1,
15 + random2avg(21, 5));
slot++;
}
}
// New style wanderers are supposed to be decent in terms of skill
// levels/equipment, but pretty randomised.
static void _create_wanderer(void)
{
// Decide what our character roles are.
stat_type primary_role = _wanderer_choose_role();
stat_type secondary_role = _wanderer_choose_role();
// Regardless of roles, players get a couple levels in these skills.
const skill_type util_skills[] =
{ SK_DARTS, SK_STABBING, SK_TRAPS_DOORS, SK_STEALTH,
SK_SHIELDS, SK_EVOCATIONS, SK_INVOCATIONS };
int util_size = sizeof(util_skills) / sizeof(skill_type);
// No Invocations for demigods.
if (you.species == SP_DEMIGOD)
util_size--;
// Maybe too many skill levels, given the level 1 floor on skill
// levels for wanderers?
int primary_skill_levels = 5;
int secondary_skill_levels = 3;
// Allocate main skill levels.
_wanderer_role_skill(primary_role, primary_skill_levels);
_wanderer_role_skill(secondary_role, secondary_skill_levels);
skill_type util_skill1 = _apt_weighted_choice(util_skills, util_size);
skill_type util_skill2 = _apt_weighted_choice(util_skills, util_size);
// And a couple levels of utility skills.
you.skills[util_skill1]++;
you.skills[util_skill2]++;
// Caster types maybe need more MP?
int mp_adjust = 0;
if (primary_role == STAT_INTELLIGENCE)
mp_adjust++;
if (secondary_role == STAT_INTELLIGENCE)
mp_adjust++;
set_mp(you.magic_points + mp_adjust, true);
// Keep track of what skills we got items from, mostly to prevent
// giving a good and then a normal version of the same weapon.
std::set<skill_type> gift_skills;
// Wanderers get 1 good thing, a couple average things, and then
// 1 last stage to fill any glaring equipment holes (no clothes,
// etc.).
skill_type good_equipment = _weighted_skill_roll();
// The first of these goes through the whole role/aptitude weighting
// thing again. It's quite possible that this will give something
// we have no skill in.
stat_type selected_role = one_chance_in(3) ? secondary_role : primary_role;
skill_type sk_1 = SK_NONE;
skill_type sk_2 = SK_NONE;
sk_1 = _wanderer_role_weapon_select(selected_role);
if (selected_role == STAT_INTELLIGENCE)
sk_2 = _wanderer_role_weapon_select(selected_role);
skill_type decent_1 = _wanderer_role_skill_select(selected_role,
sk_1, sk_2);
skill_type decent_2 = _weighted_skill_roll();
// Not even trying to put things in the same slot from game to game.
int equip_slot = 0;
_wanderer_good_equipment(good_equipment, equip_slot);
gift_skills.insert(good_equipment);
_wanderer_decent_equipment(decent_1, gift_skills, equip_slot);
gift_skills.insert(decent_1);
_wanderer_decent_equipment(decent_2, gift_skills, equip_slot);
gift_skills.insert(decent_2);
_wanderer_cover_equip_holes(equip_slot);