This section explains how SFO's function library is organized and how its documentation works, along with some conventions that it is useful to know and a brief discussion of a few redefined WEIDU functions.
The main SFO function library lives in files with the .tph suffix in the main sfo folder. To first approximation, SFO uses these conventions:
The SFO-LUA function library lives in files with the .tph suffix in the lua subfolder of the sfo folder. It has no special naming conventions beyond the convention that functions are lowercased (yes, this is a poor design choice; it's too late to change without doing more harm than good.)
SFO and SFO-LUA functions are documented in files in sfo/doc/functions, all linked to index.html. If you go to that link, you'll find a few links to master lists of functions, and then an alphabetical list of all SFO libraries with a link to each library's documentation page, followed by a similar list for each SFO-LUA function.
The documentation page for a library starts by listing which libraries that library depends on (this might matter if you want to port fragments of an SFO library elsewhere.) It then lists the functions, in two groups: the public functions and the internal functions. The distinction is that internal functions are only used inside this library itself, and should not be used by other libraries or in your mod; only the public functions should be used. (In a more sophisticated language, this would be enforced and calls to internal functions would fail; WEIDU isn't that clever, so nothing actually stops you using an internal function. But I strongly recommend against it, and I make no promises about the stability of internal functions in future SFO updates.)
SFO describes functions in a standard, quite abbreviated, format. Here's an example:
resolve_sectype(strref:i="-1", sectype:s, arguments:s, string:s)=(sectype_value:s, value:s) dimorphic
The general shape of this is function_name(arguments)=(return values) function_type. Arguments and return values are labeled with their type: sectype:s means that the 'sectype' variable is a string, i.e. a STR_VAR, while strref:i means that the 'strref' variable is an integer, i.e. an INT_VAR. The default value for an integer variable is usually 0 and the default value for a string variable is usually ""; when other default values are used, they are listed explicitly. The function type is either action, patch, dimorphic, action-macro, or patch-macro. So, the resolve_sectype function looks like this in WEIDU:
DEFINE_DIMORPHIC_FUNCTION resolve_sectype
INT_VAR strref="-1"
STR_VAR
sectype=""
arguments=""
string=""
RET
sectype_value
value
BEGIN
...
END
SFO recognizes several other function argument types other than i and s: these include:
Of course, this is just an internal labeling convention: SFO can't change the fact that the only variables that WEIDU deals with are INT_VAR and STR_VAR.
SFO documentation is generated automatically (via the lib_funlib SFO library) using markup codes inside the .tph file. If you want to regenerate it for any reason, just do
LAF funlib_document_libraries END
Many SFO action functions use a standard system to specify the location of a file to be edited. For instance, the ini_read function reads a file in the ini format into an array, and is formatted like this:
ini_read(backwards:b, flat:b, file:s, section:s, path:s, location:s, locbase:s, case:[upper|lower])=(array:a, section_array:a) action
Here 'file' is the name of the file to be read in, and 'location', 'locbase' and 'path' specify where to find that file.
The formal rules for identification work like this:
To understand this system, it helps to understand that SFO is designed around the way I organize my mods. I organize my mod into one folder per component or group of components; within each folder, I put a bunch of sub-folders that contain particular sort of files. So in Sword Coast Stratagems, for instance, there is a folder 'spell' inside the main mod folder that contains all the spell tweak components. Within 'spell' there is a folder 'resource' that contains human-readable data files, a folder 'resource' that contains ITM, SPL files and the like, and so on. The first thing the 'spell' component does when run is set component_loc=spell. With that done:
Another way of organizing mods is more popular: in that approach, you organize your mod by file type, so that the 'baf' folder contains all BAF files, the 'spl' folder contains all SPL files, and so on. If your mod is organized like that, you'll want to ignore the 'locbase' variable entirely: 'location' is used to point to any file in your main mod folder.
In very many (not all) functions, SFO uses one more convention: if 'path', 'location' and 'locbase' are all empty, it assumes that the file being edited is a game file, and uses COPY_EXISTING rather than COPY to edit it. For instance, this
LAF ini_read STR_VAR file="1205.ini" RET_ARRAY array END
tries to read the in-game file '1205.ini' (and complains if there is no such file). The convention shouldn't get in the way in most circumstances; the main exception is if you are using my organizational convention and for some reason you want to edit a file that's directly in your component's component_loc folder. If this happens, just work around it with locbase="%component_loc%".
Should you ever wish to get the file location encoded by 'location', 'locbase' and 'path' yourself (for instance, in your own function) then you can use the function 'sfo_path' to do so. For instance, this
LAF sfo_path STR_VAR location="resource" file="myscript.baf" RET_ARRAY file_path path END
A number of SFO functions refer to an 'SFO standard function'. This is a function (nearly always a patch function) with the following format:
DEFINE_PATCH_FUNCTION myfunction
STR_VAR arguments=""
RET value
BEGIN
...
END
myfunction (arguments:s) = (value:s) patch
That is, the function has exactly one argument, the STR_VAR 'arguments', and exactly one return value, just called 'value'. A standard function uses exactly these names for the argument and return value: a standard function isn't just one where there is one STR_VAR argument and one return value, it's one where the STR_VAR is specifically called 'arguments' and the return value is specifically called 'value'.
The SFO functions that use standard functions usually use them to apply the function to some file being edited. In many cases, you can define a standard function in-place via the 'anonymous function construct' (I discuss this in chapter 2.2).
As well as defining its own functions, SFO redefines a (very) few standard WEIDU functions. These are RES_NUM_OF_SPELL_NAME and NAME_NUM_OF_SPELL_RES (in the resolve_spell library), and ALTER_EFFECT, CLONE_EFFECT, and DELETE_EFFECT (in the alter_effect library).
The changes to RES_NUM_OF_SPELL_NAME and NAME_NUM_OF_SPELL_RES allow them to fail gracefully (rather than throw a runtime failure) if the spell cannot be resolved, and also to read spells from the so-called 'extended namespace' introduced by SFO-LUA. In any circumstance where the original version of the function would have executed without FAILing, the new function gives the same return values as the old function.
The changes to ALTER_EFFECT and friends mostly extend their functionality; I discuss the changes in chapter 2.2. In any circumstance where a call of the original version of the function would have executed correctly, the new function makes the same edits as the old function.