This section discusses a collection of tools from the lib_fun, lib_tools, lib_ietools, and lib_sfo libraries.
Here and elsewhere, I list only the most useful or general functions in these libraries: see the documentation for full contents.
This function takes a string, interprets it as a collection of strings separated by (by default) spaces, and returns the first of those strings and the rest. For instance, the function call
LAF return_first_entry STR_VAR list="Minsc Anomen Jaheira" RET entry list END
LAF return_first_entry
STR_VAR list="~Minsc the Awesome~ ~Anomen the Annoying~ ~Jaheira the Judgemental~"
RET entry list
END
You can separate elements by characters other than a space if you like, as in
LAF return_first_entry STR_VAR list="Minsc,Anomen,Jaheira" separator="," RET entry list END
LAF return_first_pair
STR_VAR list="Minsc=>Awesome Anomen=>Annoying Jaheira=>Judgemental"
RET key value list
EN3
Keys and values can again be wrapped in quotes or tildes; however, return_first_pair does not support using characters other than a space to separate entries.
Given a single string, and a character (space by default, but specified by the STR_VAR 'character') this function removes any occurrences of the character from the beginning and end of the string. For instance
LAF trim_string STR_VAR string=" Minsc " RET string END
You get a variant behavior if you set INT_VAR require_both=1. Then the character is only stripped if it is present both at the beginning and the end of the string, and in any case only one character is stripped.
Given an offset in the current file, and given a length that is 1, 2, or 4, this function reads the appropriate-length integer from that offset, e.g.
LPF read_whatever INT_VAR length=2 offset=0x20 RET value END
(The reason to use this is if you have some kind of table of variable-length data to read – the actual function call above would never be sensible!)
The inverse of read_whatever; e.g.
LPF write_whatever INT_VAR length=4 write=0x2e0 offset=0x20 END
Given an index in the current file (0 by default), a left-character ('{' by default), and a right-character ('}' by default), extract the index number of the first occurrence of the left string at or after the index, and the matching occurrence of the right string.
For instance,
OUTER_PATCH "(cat) (dog with a (bone) )" BEGIN
LPF find_parenthesis_range INT_VAR index=1 STR_VAR left="(" right=")" RET start end END
END
Given either 'data' (a string), or a file name/location, return either the string or the file separated into an array of lines.
For instance:
<<<<<<<< …/stratagems-inline/poem.txt
Twas brillig, and the slithy toves
Did gyre and gimble in the wabe.
All mimsy were the borogroves
And the mome raths outgrabe.
>>>>>>>>
LAF data_lines STR_VAR path="…/stratagems-inline" file="poem.txt" RET_ARRAY poem_array=lines END
$poem_array(0)="Twas brillig, and the slithy toves"
Create a new file 'file' at the location specified by location/locbase/path, containing only the string 'arguments' (with no added spaces or line breaks).
e.g.
LAF new_file STR_VAR file=spell_log.txt path="%data_loc%" arguments="SPWI304" END
This dumps the string 'input' (synonym: 'arguments') into the text file 'file' (by default placed in the 'data_loc' directory, but you can override this by explicitly specifying 'path'). For instance,
LAF log_this STR_VAR file="new_kit_list.txt" input="DW_ELEMENTALIST_FIRE" END
There are two optional INT_VARs. If repeat=0 (the default is 1) the string will be added only if it not already present (as an entire line, not just a substring of a line). If new=1 (default is 0) any existing contents of the file will be wiped.
This dumps the string 'warning' (synonym: 'arguments') into the text file '%data_loc%/sfo_warnings.txt, prepended with the component number and mod name. If repeat=0, we do this only if it is not already there.
This is a lightweight way to apply EXTEND_TOP or EXTEND_BOTTOM. You specify:
For instance (assuming you haven't set 'component_loc') this code
LAF extend STR_VAR script=mage1 top=mage_add location=resource END
is equivalent to this:
EXTEND_TOP "mage1.bcs" "%MOD_FOLDER%/resource/mage_add.baf" EVALUATE_BUFFER
'script' can actually be a space-separated list of scripts, all of which have the same top/bottom addition made; e.g.
LAF extend STR_VAR script="mage1 mage2 mage3" top=mage_add location=resource END
If you set INT_VAR inline=1, we use '…/stratagems-inline" as the location of the top / bottom scripts.
This works like extend, except that instead of specifying a bcs file you specify an are file. The scripts are added to the are file's area script (if it doesn't have one, one is created and set using the usual conventions). For instance,
LAF extend_area_script STR_VAR area=ar2100 top=ar2100_add location=resource END
Again, 'area' can be a list of areas.
This works like extend, except that the extension is made to all worldscripts (i.e. baldur.bcs (on any game), baldur25.bcs (on any BG2-based game), and any worldscript listed in campaign.2da. For instance:
LAF extend_worldscripts STR_VAR top=baldur_add location=resource END
Takes the existing BCS files '%top%.bcs' and '%bottom%.bcs' and merges them into a new script. You can specify the name of that script via the 'script' STR_VAR or let SFO generate a unique name automatically; either way, the name of the script is returned as 'script'. E.g.
LAF merge_scripts STR_VAR top=wtasight bottom=bdsumm00 RET script END
If one of the scripts does not exist, merge_scripts does nothing and just returns the name of the other one. (If neither exists, it returns the value of 'bottom'.)
Given 'stat', 'val', and either 'relation number' or 'relation', this returns an appropriate line number in splprot.2da, adding that line if it is not already present. (See the IESDP documentation for opcode #324.) For instance:
LAF resolve_splprot_entry INT_VAR stat=0x112 val="-1" STR_VAR relation=equal RET value END
would return value=110, since that row is already present in splprot.2da on the unmodded game, whereas
LAF resolve_splprot_entry INT_VAR stat=0x110 val="-1" STR_VAR relation=equal RET value END
would (on the unmodded game) return a new value, 146 and add a new line to splprot.2da:
146 0x110 -1 1
'relation' can have the following values:
STR_VAR relation | Equivalent to INT_VAR relation_number |
---|---|
'equal', 'equals' | 1 |
'greater', 'greater_than' | 3 |
'less', 'less_than' | 2 |
'greater_equal', 'greater_equals' | 4 |
'less_than_equal', 'less_than_equals', 'less_equal' | 0 |
not_equal | 5 |
You can specify an optional STR_VAR, 'description', which will be added 2.6-style to splprot.2da. For instance, on the unmodded game this code
LAF resolve_splprot_entry
INT_VAR stat=0x110 val="-1"
STR_VAR relation=equal description="ALIGNMENT=n"
RET value
END
would add the line
146_ALIGNMENT=n 0x110 -1 1
(NB this function is actually in the Detectable Spells library, ds.tph.)
Given a string intended to name an entry in stats.ids or splstate.ids, return the number of that entry, adding it if necessary, as in
LAF ds_resolve_stat STR_VAR id="HOLD_IMMUNITY" RET stat_ind END
On EE, this would add 'HOLD_IMMUNITY' to splstate.ids if it is not already present, and in any case return its number.
ds_resolve_stat determines heuristically where to put the stat. To understand the algorithm, let's briefly review the IE rules for which stat values are available for assignment:
LAF ds_resolve_stat STR_VAR id="DEATH_WARD" RET stat_ind END
returns 157, since DEATH_WARD is in stats.ids, but
LAF ds_resolve_stat STR_VAR id="DEATH_WARD:splstate" RET stat_ind END
returns 8, the DEATH_WARD number in splstate.ids.
ds_resolve stat actually has several return values:
The following code, for instance, should let you set a stat on a creature:
LPF ds_resolve_stat STR_VAR id=IMMUNE_TO_FIRE RET stat_ind stat_param opcode END
LPF ADD_CRE_EFFECT INT_VAR opcode parameter1=1 parameter2=stat_param timing=9 target=1 END
Given a cre file (specified by 'creature'), if that creature has a death variable (i.e., scripting name), the function just returns it. If not, the function allocates one and returns it. You can specify a default value (using the 'default' STR_VAR); if not, the default is just the resref of the file. (This is useful for compatibility if you need to assign a death variable to a creature that doesn't have one assigned.)
For instance, in BG2 there is a mad cleric of Cyric, DCLERIC.CRE, with no allocated script name. This code returns a valid script name for him:
LAF resolve_dv STR_VAR creature=DCLERIC RET mad_cleric_dv=dv END
If no other mod has already given him a death variable, the returned value will be DCLERIC; if another mod has given one to him, the returned value will be whatever he was given.
A somewhat complicated function to add lines to statdesc.2da; see the main documentation if you want to use it!
This is a fast installer for files. You feed it a list of files (including extensions), all located at the same path (which you specify SFO-style via location/locbase/path). For each file:
LAF install STR_VAR files="dwhobgob.baf dwhobgob.d hobgob.cre" location=resource END
is equivalent (if you haven't set component_loc) to
COMPILE "%MOD_FOLDER%/resource/dwhobgob.baf" EVALUATE_BUFFER
COMPILE "%MOD_FOLDER%/resource/dwhobgob.d" EVALUATE_BUFFER
ACTION_IF !FILE_EXISTS_IN_GAME "hobgob.cre" BEGIN
COPY "%MOD_FOLDER%/resource/hobgob.cre" override
END
A few more details:
This patch function is intended to be used with WEIDU's CREATE command: operating on a newly-created spell, it adds a single ability (treated as innate). This is useful to create lightweight mini-spells to produce specific effects.
For instance, here's code to produce a spell that does 4d6 fire damage:
CREATE spl dw-fire
LPF add_basic_spell_ability END
LPF ADD_SPELL_EFFECT
INT_VAR opcode=12 parameter2=8*0x10000 timing=1 dicenumber=4 dicesize=6 target=2
END