diff options
Diffstat (limited to 'crawl-ref/source')
-rw-r--r-- | crawl-ref/source/effects.cc | 168 | ||||
-rw-r--r-- | crawl-ref/source/spl-book.cc | 57 | ||||
-rw-r--r-- | crawl-ref/source/spl-util.cc | 8 |
3 files changed, 175 insertions, 58 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)); + } } } diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc index 89905a420a..e771b0ce31 100644 --- a/crawl-ref/source/spl-book.cc +++ b/crawl-ref/source/spl-book.cc @@ -1729,7 +1729,8 @@ bool is_memorised(spell_type spell) static void _get_spell_list(std::vector<spell_type> &spell_list, int level, unsigned int disc1, unsigned int disc2, god_type god, bool avoid_uncastable, - int &god_discard, int &uncastable_discard) + int &god_discard, int &uncastable_discard, + bool avoid_known = false) { for (int i = 0; i < NUM_SPELLS; i++) { @@ -1743,6 +1744,9 @@ static void _get_spell_list(std::vector<spell_type> &spell_list, int level, if (spell_rarity(spell) == -1) continue; + if (avoid_known && you.seen_spell[spell]) + continue; + const unsigned int disciplines = get_spell_disciplines(spell); if (level != -1) { @@ -1788,18 +1792,22 @@ static void _get_spell_list(std::vector<spell_type> &spell_list, int level, static void _get_spell_list(std::vector<spell_type> &spell_list, unsigned int disc1, unsigned int disc2, god_type god, bool avoid_uncastable, - int &god_discard, int &uncastable_discard) + int &god_discard, int &uncastable_discard, + bool avoid_known = false) { _get_spell_list(spell_list, -1, disc1, disc2, - god, avoid_uncastable, god_discard, uncastable_discard); + god, avoid_uncastable, god_discard, uncastable_discard, + avoid_known); } static void _get_spell_list(std::vector<spell_type> &spell_list, int level, god_type god, bool avoid_uncastable, - int &god_discard, int &uncastable_discard) + int &god_discard, int &uncastable_discard, + bool avoid_known = false) { _get_spell_list(spell_list, level, SPTYP_NONE, SPTYP_NONE, - god, avoid_uncastable, god_discard, uncastable_discard); + god, avoid_uncastable, god_discard, uncastable_discard, + avoid_known); } @@ -2050,9 +2058,9 @@ static bool _get_weighted_discs(bool completely_random, god_type god, std::vector<spell_type> spell_list; _get_spell_list(spell_list, disc, disc, god, !completely_random, - junk1, junk2); + junk1, junk2, true); - if(spell_list.empty()) + if (spell_list.empty()) continue; ok_discs.push_back(disc); @@ -2070,48 +2078,39 @@ static bool _get_weighted_discs(bool completely_random, god_type god, } int skill_weights[SPTYP_LAST_EXPONENT]; - int apt_weights[SPTYP_LAST_EXPONENT]; memset(skill_weights, 0, SPTYP_LAST_EXPONENT * sizeof(int)); - memset(apt_weights, 0, SPTYP_LAST_EXPONENT * sizeof(int)); - if (completely_random) - { - for (int i = 0; i < num_discs; i++) - { - skill_weights[i] = 1; - apt_weights[i] = 1; - } - } - else + if (!completely_random) { int total_skills = 0; for (int i = 0; i < num_discs; i++) { int skill = skills[i]; - skill_weights[i] = you.skills[skill]; - - int apt = species_skills(skill, you.species); - apt_weights[i] = (int) ( (1.0 / (double) apt) * 1000000.0); + skill_weights[i] = you.skills[skill] + * 100 / species_skills(skill, you.species); total_skills += skill_weights[i]; } if (total_skills == 0) - { - for (int i = 0; i < num_discs; i++) - skill_weights[i] = apt_weights[i]; - } + completely_random = true; + } + + if (completely_random) + { + for (int i = 0; i < num_discs; i++) + skill_weights[i] = 1; } do { disc1 = ok_discs[choose_random_weighted(skill_weights, skill_weights + num_discs)]; - disc2 = ok_discs[choose_random_weighted(apt_weights, - apt_weights + num_discs)]; + disc2 = ok_discs[choose_random_weighted(skill_weights, + skill_weights + num_discs)]; } - while(disciplines_conflict(disc1, disc2)); + while (disciplines_conflict(disc1, disc2)); return (true); } diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc index 4f892d6f4e..5b4ab85812 100644 --- a/crawl-ref/source/spl-util.cc +++ b/crawl-ref/source/spl-util.cc @@ -104,12 +104,16 @@ void init_spell_descs(void) end(1, false, "spell #%d, id %d has no name", i, data.id); if (data.level < 1 || data.level > 9) + { end(1, false, "spell '%s' has invalid level %d", data.title, data.level); + } if (data.min_range > data.max_range) + { end(1, false, "spell '%s' has min_range larger than max_range", data.title); + } if (data.flags & SPFLAG_TARGETING_MASK) { @@ -312,14 +316,14 @@ int spell_hunger(spell_type which_spell) int hunger; - if ( level < 10 && level > 0 ) + if (level < 10 && level > 0) hunger = basehunger[level-1]; else hunger = (basehunger[0] * level * level) / 4; hunger -= you.intel * you.skills[SK_SPELLCASTING]; - if ( hunger < 0 ) + if (hunger < 0) hunger = 0; return hunger; |