summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/effects.cc
diff options
context:
space:
mode:
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));
+ }
}
}