# ui_spell_system function library

Dependencies: alter_effect, ds, lib_2da, lib_2daq, lib_anon, lib_array, lib_class, lib_cre, lib_data, lib_eff, lib_fn, lib_ids, lib_ietool, lib_ini, lib_kit, lib_script, lib_sfo, lib_spl, lib_splconv, lib_ssl, lib_struct, lib_sugar, lib_tools, lib_ui, lib_vtable, resolve_spell, ui_add_subraces, ui_bonus_spells, ui_deolvynize, ui_detect_class_kit, ui_dual_class_kits, ui_externalize_hlas, ui_externalize_proficiencies, ui_extra_spells, ui_on_open, ui_shared_code, ui_system_call, ui_virtual_class

## Description

Set up and add to SFO's externalized spell system. You can define any number of spell lists, labelled by a string (the 'key'). Each class and kit then has four lists of spell-list keys: allow_learn, block_learn, allow_priest and block_priest. A combination of UI editing and item alterations then enforces those lists on all classes and kits.

## Public functions

define_spell_list(determine_empty_levels:b, empty_level_max:i=9, silent:b, spells:s, key:s, list_name:s, spell_array:s)=() action

Given a space-separated list of spells 'spells', and/or an array spell=>_ or spell=>spell_level of spells, and a string 'key', construct a spell list 'key' comprising those spells. If you use the spell=>spell_level format, it saves looking up the levels of the spells).

Spells can be given either as resrefs or as IDS entries (if the latter, they need to have been loaded into memory using data_spell_resrefs). If a spell is missing, whine unless silent=1.

If determine_empty_levels=1, also record which levels are empty in the lua output. (empty_level_max is the highest level at which this is done - default is 9.)

Spell system is automatically set up if it isn't already.

get_spell_array(list:s, root:s)=(this_array:a) action

Given 'root' either SPPR or SPWI, and 'list' a list of spell-list keys, return an array of all spells with that root, in the format resref=>[01], with the value being 1 iff the spell is in one of the lists.

If list is 'cleric' or 'druid', instead parse the spell directly and check its usability fla

no_int_max_spells()=() action

parse_spell_lists(allow_learn:s, block_learn:s, allow_priest:s, block_priest:s, type:s="priest")=(spell_array:a) action

Given the 'allow_learn', 'block_learn', 'allow_priest', 'block_priest' values for some (actual or fictional) kit, and its type (either 'priest' or 'mage') return an array of all usable spells, in the format resref=>1

process_scroll_usability_now()=() action

remove_erase_bg()=() patch

remove_erase_iwd()=() patch

scroll_spec_bonus_setup()=() action

Build the various resources needed for the externalized bonus-spell setup.

set_specialist_spells(number_required:i=1, list_spells:b=1, update_description:b, learn_more_line:s, memorize_more_line:s, old_line:s, new_line_1:s, new_line_2:s, string_school:s, string_school2:s, kit:s, spell_list:s, tra:s="sfo_lua", tra_path:s)=() action

Given a kit 'kit' (a rowname entry in kitlist.2da), an optional integer 'number_required' (default=1) and a space-separated list of spell-list keys 'spell_list', require that kit to learn at least number_required spells from that list.

The optional 'learn_more_line' and 'memorize_more_line' are displayed to players in character generation if they don't learn/memorize an appropriate number of speciality spells. (If not set, the component autogenerates a default warning.)

The variables 'tra' and 'tra_path' specify where some standard strings are drawn from (the default assumption is that they're from sfo/lua/lang//sfo_lua.tra").

If update_description is set to 1, the function will attempt to update the kit description. (This only works with kits in a relatively standard format.) The various other variables control how this works:

- 'old_line' is by default 'May cast one additional spell per level.', but it can be any 'advantage' or 'disadvantage' line from the kit description. It is deleted from the kit description if present.
- 'school_string' is by default 'from the LISTNAME school', where LISTNAME is the name-string of the specialist list, or the last such list if there is more than one.
- 'new_line_1' is by default 'May cast one additional spell per level. This additional spell must be SCHOOL_PLACEHOLDER'; SCHOOL_PLACEHOLDER is swapped for 'string_school'. It is added to the top of the 'Advantages' list if number_required=1.
- 'new_line_2' is by default 'May cast one additional spell per level. At least NUMBER_PLACEHOLDER memorized spells of each level must be SCHOOL_PLACEHOLDER'; SCHOOL_PLACEHOLDER is swapped for 'string_school' and NUMBER_PLACEHOLDER is swapped for the value of 'number_required'. It is added to the top of the 'Advantages' list if number_required>1.
- list_spells, if set, includes a list of all spells from the preferred list. In this case, 'string_school2' (default value: the name-string of the specialist list, or the last such list if there is more than one) is substituted into the string 'The full list of SCHOOL_PLACEHOLDER_2 spells is:'.

set_spell_learn_modifiers(kit:s, modifiers:s)=() action

Set the externalized modifications to the chance of learning a spell. Specify 'kit' (a rowname from kitlist) and 'modifiers' (the actual LUA list of modifiers). 'modifiers' should be a comma-separated list with elements of form 'list=integer', where 'list' is either a spell list or 'default' (applies to all spell lists not called out.)

set_spell_list(chargen_choose_spells:b, update_scroll_usability:b=1, update_scrolls_later:b, silent:b, import_parent_blocks:b=1, class:s, kit:s, kit_clastext:s, block_learn:s="no_change", allow_learn:s="no_change", block_priest:s="no_change", allow_priest:s="no_change")=() action

Set the spell lists available to, or blocked for, a given class or kit (either set class to a class.ids entry, or kit to a kitlist.2da rowname). Each of block_learn, allow_learn, block_priest, or allow_priest can be a space-separated or comma-separated list of spell-list keys, or 'no_change' (the default) in which case whatever it's currently set to will be unchanged.

If chargen_choose_spells=1, the lua also sets dwChargenChooseSpells to 1 for that class or kit. That causes the UI to try to learn spells from the character's specialist list, if any. [This is an odd place to put this, on reflection.]

If update_scroll_usability=1, we also go through all scrolls and mark them up as usable/unusable for that class/kit.

If the spell system is not already set up, we set it up.

ui_copy_spell_lists(from:s, to:s)=() action

Read in the spell lists associated with a given kit, and copy it to a different kit

ui_read_all_spell_lists()=(block_learn:a, block_priest:a, allow_learn:a, allow_priest:a, list_names:a, kit_names:a) dimorphic

Read in all the spell lists, and store them in arrays block_learn, block_priest, allow_learn, allow_priest, in this format: $allow_priest(OHTEMPUS combat)=1. Also return a k=>_ array of all list names, and a k=> array of all kit names.

ui_read_spell_lists(literal:b, kit:s)=(learn:s, priest:s, block_learn:s, block_priest:s) action

Read in the spell lists associated with a given kit. If literal=1, leave in the commas and quote marks; otherwise remove them.

ui_spell_system_setup()=() action

Set up the externalized spell system. (Idempotent.)

## Internal functions

These should not be called from outside the library itself.

chargen_memorize_mage_spells()=() patch

choose_spells_edit()=() patch

edit_rightbuttonenabled()=() patch

edit_specialist_message_function()=() patch

get_no_spell_level_string(list:s)=(no_spell_level_string:s) action

get_scroll_contents_map()=(scroll_contents_map:a) dimorphic

get_strrefs_for_lua()=(cleric_strref:s, druid_strref:s, shaman_strref:s) action

learn_spell_bonus_patch()=() patch

list_spec_spells(list:s)=(spell_list_string:s) action

load_spell_lists()=(spell_lists:a) action

mage_spellbook_hack()=() patch

memorize_priest_spells_edit()=() patch

patch_spec_bg()=() patch

patch_spec_bg_priest()=() patch

patch_spec_iwd()=() patch

patch_spec_iwd_priest()=() patch

priest_spellbook_hack()=() patch

refresh_priest_book_edit()=() patch

refresh_priest_spells_edit()=() patch

scroll_usability(class_id:i, kit_ids_entry:i, update_scrolls_later:i, block_learn:s, allow_learn:s="every_spell", block_priest:s, allow_priest:s="every_spell", type:s=priest)=() action

Given the block_learn, allow_learn, block_priest, allow_priest entries for a kit, the (unused) class_id and kit_id for the kit, and the type (mage or priest), go through every scroll in the game and issue 319s to any unusable scrolls.

specialist_spell_edit()=() patch

spell_system_scroll_data()=() action