MSFD Targeted scripts: running "global" scripts tied to an object
"Object_ID"->StartScript "Script_ ID"
(Credit for discovery of this technique and much of the following information goes to FreshFish. Further information supplied by Riiak, MentalElf, DinkumThinkum, Argent, Cortex, and others.)
It is possible to use the StartScript function to run global scripts that are tied to an object or Actor. These scripts resemble both local scripts (in that the functions called always default to the object or Actor the script targets) and global scripts (in that they are always running). Objects may have several different targeted scripts running on them at one time, and may also have a local script.
To start a script as a targeted script:
• Object_ID->StartScript Script_ID (may be used from script, but does not work from dialogue results).
• Start the script from the intended target's local script or another targeted script on the object (it will inherit the target).
• Start the script from dialogue results (this will only work to target the actor the player is in dialogue with: it is not possible to specify a different target in dialogue results). This method is particularly useful as you don't need access to scripts running on the actor, nor do you need an ID.
Uses of targeted scripts:
As a general rule: If a function requires a fix in a global script but the fix can be omitted in a local script, that function may be used without a fix in a targeted script as well. Examples of popular functions for targeted scripts include:
AddItem, RemoveItem, GetItemCount
AIFollow, AIWander, AIEscort
GetPos, SetPos, PositionCell
Get/Set/ModStat
StartCombat, StopCombat
Targeted scripts can be powerful tools, especially in combination with dialogue: you can create generic dialogue (e.g. filtered for class only) and start your script from the resultbox. CDCooley's "Companion Teleportation" is a good example of use with dialogue. Voice dialogue can also be used this way: for example, many companions have a targeted "pacifist" script that is started from Attack voice results if the player tells the companion to avoid combat.
Cautions and limitations:
• Variables defined in a targeted script are not considered local to the object from the point of view of dialogue and other scripts. For example, they cannot be used as dialogue conditions. The special variable "companion" also cannot be used, i.e. declaring a short variable "companion" in a targeted script and setting it to 1 will not enable companion share on the target actor. I assume this applies to other special locals as well, but I haven't tested any others.
• You cannot have more than one instance of a targeted script running at one time (same as global scripts). The obvious workaround is to have several different scripts that all do the same thing.
• If OnActivate is used in a targeted script, the object will not be able to be activated by normal means after the script is stopped, unless a targeted script with an OnActivate is again added to the object.
• If an object is deleted while a targeted script is running on it, the game will CTD. If the target is not necessary but is merely a consequence of the way the script was started, you can usually target the script on the player instead to avoid this: "player->StartScript ScriptName". Otherwise, the script must be stopped before deleting the object.
• Scripts will detach from non-persistent targets when the game is saved and reloaded. This may give errors on load ("Unable to locate reference for global script…"), or may not; either way it may also give odd effects in some circumstances.
• When a targeted script is started on an object that was not placed into the gameworld in the editor (i.e. an object that was placed or generated during the game), the script will lose its targeting when a savegame is reloaded. Note that this applies to the player character as well.
• Load list changes may also cause targeted scripts to lose their targeting when the game is reloaded, whether or not the target is persistent and whether or not it was placed in the editor. This doesn't always happen, but it can (adding several mods higher in the load list will usually do it).
If a script becomes detached from its target, some functions that manipulate data about the previously targeted object (e.g. getHealthGetRatio) may cause CTD if used without a fix.
As a workaround to avoid untargeted scripts running, you may be able to use a startscript to stop the targeted script if it is running, then restart it if necessary. As a safety check for targeted scripts on actors, GetHealth may be used before any functions that may cause problems (returns 0 in an untargeted script):
if ( GetHealth <= 0 )
StopScript ScriptName
return
endif
; main body of script goes here