summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/effects.cc
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-02-15 19:34:39 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-02-15 19:34:39 +0000
commite4209979f264bb890bd22269e752cbde2ed0d58c (patch)
tree25ba88a058aa13bbbd3fc050abee9cdb875264cc /crawl-ref/source/effects.cc
parent1be0369055dab6a8c64b35b083dd4ef58b411b2c (diff)
downloadcrawl-ref-e4209979f264bb890bd22269e752cbde2ed0d58c.tar.gz
crawl-ref-e4209979f264bb890bd22269e752cbde2ed0d58c.zip
Overhaul book acquirement.
1. Do a skill check to decide on manual vs. spellbook (except for Xom and Sif Muna who never gift manuals). 2. If a spellbook, pick randart or normal books with fixed chances. 3. Make randart themes dependant on actual skills, not aptitudes. 4. For normal spellbooks, pick the book randomly with weights favouring books with many unknown spells of schools you're highly skilled in. (Bye-bye, fixed book acquirement order!) Formulas (as suggested by David) may need tweaking, feedback welcome! git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@9093 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/effects.cc')
-rw-r--r--crawl-ref/source/effects.cc168
1 files changed, 141 insertions, 27 deletions
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index b5766f12e1..3c5cbf9b57 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -1187,8 +1187,7 @@ static int _choose_first_unseen_book(int first, ...)
return (NUM_BOOKS);
}
-
-
+/*
static int _acquirement_book_subtype()
{
int result = NUM_BOOKS;
@@ -1337,6 +1336,7 @@ static int _acquirement_book_subtype()
return result;
}
+*/
static int _acquirement_staff_subtype(const has_vector& already_has)
{
@@ -1463,12 +1463,14 @@ static int _find_acquirement_subtype(object_class_type class_wanted,
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;
+ case OBJ_BOOKS:
+ // type_wanted = _acquirement_book_subtype(); break;
+ return OBJ_RANDOM;
default: break; // gold
}
@@ -1486,16 +1488,65 @@ static int _find_acquirement_subtype(object_class_type class_wanted,
return (type_wanted);
}
+// The weight of a spell is defined as the average of all disciplines'
+// skill levels minus the doubled spell level.
+static int _spell_weight(spell_type spell)
+{
+ ASSERT(spell != SPELL_NO_SPELL);
+
+ int weight = 0;
+ unsigned int disciplines = get_spell_disciplines(spell);
+ int count = 0;
+ for (int i = 0; i <= SPTYP_LAST_EXPONENT; i++)
+ {
+ int disc = 1 << i;
+ if (disciplines & disc)
+ {
+ int skill = you.skills[spell_type2skill(disc)]
+ * 100 / species_skills(i, you.species);
+
+ weight += skill;
+ count++;
+ }
+ }
+ ASSERT(count > 0);
+
+ int level = spell_difficulty(spell);
+
+ return std::max(0, weight/count - 2*level);
+}
+
+// When randomly picking a book for acquirement, use the sum of the
+// weights of all unknown spells in the book.
+static int _book_weight(int book)
+{
+ ASSERT(book >= 0 && book <= MAX_NORMAL_BOOK);
+
+ if (book == BOOK_HEALING)
+ return 0;
+
+ int total_weight = 0;
+ for (int i = 0; i < SPELLBOOK_SIZE; i++)
+ {
+ spell_type stype = which_spell_in_book(book, i);
+ if (stype == SPELL_NO_SPELL)
+ continue;
+
+ // Skip over spells already seen.
+ if (you.seen_spell[stype])
+ continue;
+
+ total_weight += _spell_weight(stype);
+ }
+
+ return (total_weight);
+}
+
static void _do_book_acquirement(item_def &book, int agent)
{
// items() shouldn't make book a randart for acquirement items.
ASSERT(!is_random_artefact(book));
- // Non-normal books (i.e. manuals/book of destruction) are rare enough
- // without turning them into randart books.
- if (book.sub_type > MAX_NORMAL_BOOK)
- return;
-
int level = (you.skills[SK_SPELLCASTING] + 2) / 3;
unsigned int seen_levels = you.attribute[ATTR_RND_LVL_BOOKS];
@@ -1522,19 +1573,50 @@ static void _do_book_acquirement(item_def &book, int agent)
level = -1;
}
- int choice = random_choose_weighted(
- 58, BOOK_RANDART_THEME,
- 24, book.sub_type,
- level == -1 ? 0 :
- agent == GOD_SIF_MUNA ? 6 : 2, BOOK_RANDART_LEVEL,
- agent == GOD_XOM ? 0 : 6, BOOK_MANUAL, // too useful for Xom
- 0);
+ int choice = NUM_BOOKS;
- // No changes.
- if (choice == book.sub_type)
- return;
+ bool knows_magic = false;
+ // Manuals are too useful for Xom, and useless when gifted from Sif Muna.
+ if (agent != GOD_XOM && agent != GOD_SIF_MUNA)
+ {
+ int weights[NUM_SKILLS];
+ int magic_weights = 0;
+ int other_weights = 0;
- book.sub_type = choice;
+ for (int i = 0; i < NUM_SKILLS; i++)
+ {
+ if (i > SK_UNARMED_COMBAT && i < SK_SPELLCASTING)
+ {
+ weights[i] = 0;
+ continue;
+ }
+
+ weights[i] = you.skills[i]
+ * 100 / species_skills(i, you.species);
+
+ if (i >= SK_SPELLCASTING && i <= SK_POISON_MAGIC)
+ magic_weights += weights[i];
+ else
+ other_weights += weights[i];
+ }
+
+ if (x_chance_in_y(other_weights, magic_weights + other_weights))
+ {
+ choice = BOOK_MANUAL;
+ if (magic_weights > 0)
+ knows_magic = true;
+ }
+ }
+
+ if (choice == NUM_BOOKS)
+ {
+ choice = random_choose_weighted(
+ 60, BOOK_RANDART_THEME,
+ 24, book.sub_type,
+ level == -1 ? 0 :
+ agent == GOD_SIF_MUNA ? 6 : 1, BOOK_RANDART_LEVEL,
+ 0);
+ }
// Acquired randart books have a chance of being named after the player.
std::string owner = "";
@@ -1547,11 +1629,15 @@ static void _do_book_acquirement(item_def &book, int agent)
switch (choice)
{
case BOOK_RANDART_THEME:
+ mpr("Make book themed randart.");
+ book.sub_type = choice;
make_book_theme_randart(book, 0, 0, 7, 22, SPELL_NO_SPELL, owner);
break;
case BOOK_RANDART_LEVEL:
{
+ mpr("Make book fixed level randart.");
+ book.sub_type = choice;
int num_spells = 7 - (level + 1) / 2 + random_range(1, 2);
make_book_level_randart(book, level, num_spells, owner);
break;
@@ -1560,15 +1646,35 @@ static void _do_book_acquirement(item_def &book, int agent)
// Spell discipline manual
case BOOK_MANUAL:
{
- int weights[SK_POISON_MAGIC - SK_CONJURATIONS + 1];
+ mpr("Make book manual.");
+
+ // The Tome of Destruction is rare enough we won't change this.
+ if (book.sub_type == BOOK_DESTRUCTION)
+ return;
+
+ int weights[NUM_SKILLS];
int total_weights = 0;
- for (int i = SK_CONJURATIONS; i <= SK_POISON_MAGIC; i++)
+ for (int i = 0; i < NUM_SKILLS; i++)
{
- int w = std::max(0, 24 - you.skills[i])
- * 100 / species_skills(i, you.species);
+ if (i > SK_UNARMED_COMBAT && i < SK_SPELLCASTING)
+ {
+ weights[i] = 0;
+ continue;
+ }
+
+ int skill = you.skills[i]
+ * 100 / species_skills(i, you.species);
+
+ int w = (skill < 12) ? skill + 3
+ : 25 - skill;
- weights[i - SK_CONJURATIONS] = w;
+ // If we don't know any magic skills, make non-magic skills
+ // more likely.
+ if (!knows_magic && i < SK_SPELLCASTING)
+ w *= 2;
+
+ weights[i] = w;
total_weights += w;
}
@@ -1581,8 +1687,6 @@ static void _do_book_acquirement(item_def &book, int agent)
int skill = choose_random_weighted(weights,
weights + ARRAYSZ(weights));
- skill += SK_CONJURATIONS;
-
book.sub_type = BOOK_MANUAL;
book.plus = skill;
// Set number of reads possible before it "crumbles to dust".
@@ -1591,7 +1695,17 @@ static void _do_book_acquirement(item_def &book, int agent)
}
default:
- ASSERT(false);
+ {
+ mpr("Make book normal spellbook.");
+
+ // Pick a random spellbook according to unknown spells contained.
+ int weights[MAX_NORMAL_BOOK+1];
+ for (int bk = 0; bk <= MAX_NORMAL_BOOK; bk++)
+ weights[bk] = _book_weight(bk);
+
+ book.sub_type = choose_random_weighted(weights,
+ weights + ARRAYSZ(weights));
+ }
}
}