These two libraries (the second is really a single function) simplify various tasks involving script and dialog files.
The alter_script library lets you make fine-grained alterations to scripts (i.e., .bcs files) – specifically, it lets you alter, add, clone, or remove script blocks on a block-by-block basis. There are five different functions in alter_script, but they all operate in a similar way.
This is the simplest alter_script function, but it serves as a good illustration of the way the other functions work. You specify the name of the script you want to alter, and up to six regexps (labelled by STR_VARs match, match1, match2, match3, match4, match5). The script is decompiled, and the regexps are checked on each script block separately, Any block that matches all specified regexps is deleted.
For instance, the wtasight script in BG2EE contains a block that responds to Shouts from creatures giving Shout=111. You could delete this block like this:
LAF delete_script_block STR_VAR script=wtasight match1=”111” match2=”Heard” END
SFO checks all four blocks in the script. Only one matches both ‘Heard’ and ‘111’; that block is deleted. (In fact either regexp alone would be sufficient.)
A more advanced option is to use the STR_VAR match_function, which specifies an SFO standard patch function that is run sequentially on each block. Blocks that return value=1 are deleted. You can use the anonymous function construct.
Two more occasionally-useful arguments:
This function finds blocks exactly as does delete_script_block, but when a block is found, it is edited rather than deleted. Editing is via up to six pairs of STR_VARs (swap_out/swap_in, swap_out1/swap_in1, etc.). On any matched block, we do a REPLACE_TEXTUALLY for each pair.
For instance, this adds a go-hostile command to all blocks that use Attack or AttackReevaluate:
LAF alter_script_block
STR_VAR
script=wtasight
match="\(Attack(\|AttackReevaluate(\)"
swap_out="RESPONSE #\([0-9]+\)"
swap_in="RESPONSE #\1 Enemy()"
END
LAF clone_script_block
STR_VAR
script=wtasight
match="\(Attack(\|AttackReevaluate\)"
swap_out1="ActionListEmpty()"
swap_in1="ActionListEmpty() General(Myself,HUMANOID)"
swap_out2="RESPONSE #\([0-9]+\)"
swap_in2="RESPONSE #\1 Help()"
original_swap_out="ActionListEmpty()"
original_swap_in="ActionListEmpty() !General(Myself,HUMANOID)"
END
This function inserts a new BAF file immediately after (or, if you set INT_VAR insert_above=1, immediately before) any matched block. Set ‘insert’ to the name of a BAF file to be inserted (without the .baf) and specify its location in the usual SFO style via ‘location’, ‘locbase’, and ‘path’.
Like insert_script_block, except that the new script replaces any matched block.
REPLACE_TEXTUALLY "Class(\([^,]*\),OHTYR)" "OR(2)Class(\1,OHTYR)Class(\1,DW_TYR_PALADIN)"
REPLACE_TEXTUALLY "Class(\([^,]*\),OHTYR)" "Class(\1,OHTYR)Alignment(\1,LAWFUL_GOOD)"
LAF disjunctive_substitution
STR_VAR script="script1 script2"
dialog="dialog1 dialog2"
match="Class(\([^,]*\),OHTYR)"
replace="Class(\1,OHTYR)|Alignment(\1,LAWFUL_GOOD)"
END
LAF disjunctive_substitution
STR_VAR script=”script1 script2”
dialog=”dialog1 dialog2”
match=”Class(\([^,]*\),OHTYR)”
replace=”OR()Class(\1,OHTYR)|Class(\1,DW_TYR_PALADIN)”
END
Note that you need not (indeed, must not) use OR(2) here. Just use OR(), and SFO will take care of the rest.
You can set ‘script’ and/or ‘dialog’ to ‘all’, and then SFO will do all the scripts/dialogs. Use with caution, though: it’s a bit slow.
(Incidentally, WEIDU theoretically has native support for this task, via REFACTOR_TRIGGER. My experience is that it’s ridiculously slow and not that reliable, though, whereas disjunctive_substitution is pretty fast unless you’re patching thousands of scripts.)