From 319dfbdaa3e608e88e39e0a296a9c41febfc1a59 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Sat, 2 Dec 2023 03:46:55 +0000 Subject: [PATCH] Wizards learn about spellbooks as they enhance their spell skills Previously, Wizards got a boost to the chance of writing unknown spellbooks based purely on being a Wizard (with the chance still luck-based), leading to a very large power spike when the Wizard gained access to a luckstone and the ability to max out luck. This had two main issues: this power spike came *after* the major early-game difficulty spike, often leaving Wizards forced to deal with it without having appropriate spells; and it promotes grinding (for Luck and for Magicbane) at an early point in the game, meaning that the Wizard early game effectively followed a sequence of extreme difficulty -> grinding -> minimal difficulty, which isn't very good balance-wise. With this commit, Wizards lose their advantage to writing unknown spellbooks by guessing, and instead learn spellbook IDs based on their spell skills (advancing a skill gives knowledge of higher- level spellbooks). This means that writing unknown spellbooks becomes guaranteed with sufficient skill, but has no advantage over non-Wizards in schools where the Wixard does not have sufficient skill. Due to Wizards' skill caps, there are two spells which they can't ever write guaranteed: create familiar and charm monster. Create familiar is a fairly niche spell (that doesn't match the Wizard playstyle that well) and being unable to write it is not a major problem. The inability to easily write charm monster is intentional. --- doc/fixes3-7-0.txt | 5 ++++- include/extern.h | 1 + src/spell.c | 34 ++++++++++++++++++++++++++++++++++ src/weapon.c | 4 ++++ src/write.c | 7 ++++--- 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index e6830d474..01195bd5f 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1292,7 +1292,10 @@ if hero destroys a shop wall by breaking a wand of digging or applying a drum of earthquake, have shopkeeper demand payment mimics sometimes woke up and came out of hiding when they shouldn't have if hero without protection from shape changers returned to a previously - visitied level (though they would usually rehide so it wasn't obvious) + visited level (though they would usually rehide so it wasn't obvious) +Wizards no longer have a bonus to writing unknown spellbooks, but now + learn what spellbooks look like as they gain skill in their + spell schools (allowing a guaranteed write with enough skill) Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index e4974fe9c..63e98a677 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2760,6 +2760,7 @@ extern int known_spell(short); extern int spell_idx(short); extern char force_learn_spell(short); extern int num_spells(void); +extern void skill_based_spellbook_id(void); /* ### steal.c ### */ diff --git a/src/spell.c b/src/spell.c index c8458dc2a..567e077bf 100644 --- a/src/spell.c +++ b/src/spell.c @@ -831,6 +831,40 @@ spell_skilltype(int booktype) return objects[booktype].oc_skill; } +/* Wizards learn what spellbooks look like based on their skill in the + spell's school */ +void +skill_based_spellbook_id(void) +{ + if (!Role_if(PM_WIZARD)) + return; + + int booktype; + const uchar spbook_class = (uchar) SPBOOK_CLASS; + + for (booktype = gb.bases[spbook_class]; + booktype < gb.bases[spbook_class + 1]; + booktype++) { + int skill = spell_skilltype(booktype); + if (skill == P_NONE) continue; + + int known_up_to_level; + switch (P_SKILL(skill)) { + case P_BASIC: + known_up_to_level = 2; break; + case P_SKILLED: + known_up_to_level = 4; break; + case P_EXPERT: case P_MASTER: case P_GRAND_MASTER: + known_up_to_level = 7; break; + case P_UNSKILLED: default: + known_up_to_level = 0; break; + } + + if (objects[booktype].oc_level <= known_up_to_level) + makeknown(booktype); + } +} + static void cast_protection(void) { diff --git a/src/weapon.c b/src/weapon.c index 3f294aca6..a4db60e92 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1136,6 +1136,8 @@ skill_advance(int skill) You("are now %s skilled in %s.", P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more", P_NAME(skill)); + + skill_based_spellbook_id(); } static const struct skill_range { @@ -1689,6 +1691,8 @@ skill_init(const struct def_skill *class_skill) /* each role has a special spell; allow at least basic for its type (despite the function name, this works for spell skills too) */ unrestrict_weapon_skill(spell_skilltype(gu.urole.spelspec)); + + skill_based_spellbook_id(); } void diff --git a/src/write.c b/src/write.c index 924ce4519..8ca32a667 100644 --- a/src/write.c +++ b/src/write.c @@ -313,8 +313,8 @@ dowrite(struct obj *pen) /* * Writing by name requires that the hero knows the scroll or * book type. One has previously been read (and its effect - * was evident) or been ID'd via scroll/spell/throne and it - * will be on the discoveries list. + * was evident) or been ID'd via scroll/spell/throne (or skill + * for Wizards) and it will be on the discoveries list. * Unknown spellbooks can also be written by name if the hero * has fresh knowledge of the spell, or if the spell is almost * forgotten and the hero is Lucky (with a greater chance than @@ -349,7 +349,8 @@ dowrite(struct obj *pen) /* else fresh knowledge of the spell works */ && spell_knowledge != spe_Fresh /* and Luck might override after previous checks have failed */ - && rnl((Role_if(PM_WIZARD) || spell_knowledge == spe_GoingStale) + && rnl(((Role_if(PM_WIZARD) && paper->oclass != SPBOOK_CLASS) || + spell_knowledge == spe_GoingStale) ? 5 : 15)) { You("%s to write that.", by_descr ? "fail" : "don't know how"); /* scrolls disappear, spellbooks don't */