This SFO-LUA library adds space for additional spells, outside the space limits of the normal namespace.
In the unmodded Infinity Engine, only the first 49 spell slots of each level (e.g., SPPR101-SPPR149 for first level cleric spells) are available for player-usable spells. Spells placed in the 50th-99th slots, or outside the SPPR/SPWI namespace, aren’t available for mages to learn at character generation, for sorcerers and shamans to learn when levelling up, or for clerics, druids, rangers, and paladins to memorize.
The ’ui_extra_spells’ library extends the namespace, in two ways.
An alternate tool, OlvynChuru's ClassSpellTool function, also adds space for extra spells, using similar but distinct UI edits and very different conventions. The two are not compatible. If you install ui_extra_spells after a mod that uses ClassSpellTool, SFO will try to uninstall ClassSpellTool and map any spells it added over to SFO's method. If you install a mod that uses ClassSpellTool after one that uses ui_extra_spells, you will definitely break your game.
Assuming that you are not using SFO's 'struct paradigm', the simplest, and recommended, way to use ui_extended_spells is via the 'add_extended_spell' function, which you can think of as an extension of WEIDU's native ADD_SPELL command. You use it like this:
LAF add_extended_spell
STR_VAR
id=WIZARD_AWESOME_SPELL
file=”awesomespell.spl”
path=”%MOD_FOLDER%/spl”
RET resref
END
This takes the spell at 'path/file' (normally, as here, a spell in your mod directory), finds a slot for it in either spell.ids or the extended namespace, sets ‘resref’ to the resref of that slot, copies the spell over, and if necessary installs it in the extended system. 'id' is the identifier, which is stored in either spell.ids or, for extended spells, in weidu_external/data/dw_shared/dw_ext_spell.ids. The various resources needed for extended spells are installed the first time you use the function.
Note that add_extended_spell infers the level, exclusion flags etc from the spell file. So if you’re going to edit it during installation (e.g. if you’re making a spell in place) you need to do those edits first. (Copy the spell to a temporary workspace and install it from there.)
add_extended_spell takes two optional INT_VAR arguments:
If replace=1 (default=0), then if that id entry is already present, it will be replaced by a placeholder entry before the spell is added. (If replace=0, the spell just won’t be added if this ids entry is there already.)
e.g. if you try to add WIZARD_ENORMOUS_KABOOM (a level 8 spell), and some other mod has already added WIZARD_ENORMOUS_KABOOM to the 7th level spells as SPWI768, then:
(In addition, add_extended_spell takes additional arguments that allow you to restrict which classes, kits, and alignments can use a given spell; these are described in section 5 below.)
If you are using SFO's 'struct paradigm', ui_extra_spells is automatically integrated into lib_spl and specifically into the spl_copy and spl_make functions. When you use these functions, if there is no space in the standard namespace then spells will automatically be placed in the extended namespace. You can force resolution in the extended namespace by setting the INT_VAR force_extended=1.
The alternative way to use add_extended spells is to install the spells manually in the permitted namespace, and then do
LAF spell_system_extension_setup END
SFO stores the details for the extended spells in weidu_external/data/dw_shared/dw_ext_spell.ids. This is a 2-column file where the first entry in each row is the resref of a spell in the extended namespace (e.g., SPWI7A4) and the second row is its id (e.g., WIZARD_ENORMOUS_KABOOM). Think of this file as the extended-namespace version of spell.ids.
SFO also extends WEIDU's included functions RES_NUM_OF_SPELL_NAME and NAME_NUM_OF_SPELL_RES so that they resolve in the extended namespace as well as the normal namespace. (It doesn't bother with RES_NAME_OF_SPELL_NUM since IDS numbers aren't defined for the extended namespace.) The usage is the same as for the usual functions.
In addition, SFO automatically sets a spell-name variable for each spell in dw_ext_spell.ids, just as it does for spells in spell.ids. For instance, if you've added WIZARD_AWESOME_SPELL in a previous component, you can do
SpellRES("%WIZARD_AWESOME_SPELL%",Myself)
LAM data_spell_resrefs
The 'add_extended_spell' function has some limited functionality that lets you fine-tune which kits, classes and alignments can use a spell. In general this is not recommended: the interface is clunky and the ui_spell_system functions offer much more power and flexibility. Still, here's how it works:
There are two places the new spells need to show up: on the character-generation/levelling up screen where sorcerers/mages/shamans select their known spells, and in the spell books of clerics, druids, paladins, and rangers, who get all spells at a given level automatically.
As for the first: the UI interfaces with the engine during spell-learning through an array called chargen.choose_spells. We simply inject the new spells into that array when the spell-choose menu is opened, through a one-line UI edit (tied to a new function). (At install time, we read the alignment/kit/class unusability flags into a lua array; when we populate chargen.choose_spells, we check that array against the character’s alignment/kit/class, which we have to make some more insertions into ui.menu to detect.) We also have to populate another array that the UI uses to record the names, descriptions and icons of the new spells.
As for the second: we build a bunch of spells that grant the new cleric/druid spells (for each of cleric and druid, one for each alignment and one master spell) and apply the master spell in the CLAB files at level 1. (The master spell grants all spells without alignment restrictions, and then applies the spell of the appropriate alignment.) Then, just for cosmetic purposes, we do a second little UI edit to hide cleric-spellbook spells that are too high level to be cast. (Normally there shouldn’t be any.)
(We could alternatively have granted the spells on a per-level basis, which would save us the UI tweak. I haven’t done this because (a) it’s a lot more hassle; (b) it runs some risk of a slight delay on level-up before you see the new spells in your spellbook; (c) we’re tweaking the UI anyway so there’s not much to be gained by abjuring UI tweaks here.