[Tutorial] Morrowind Scripting for Dummies

Morrowind Scripting For Dummies

This file is hosted at Morrowind Modding History, and is a complete guide to how to write and edit scripts in Morrowind.

MSFD, 9th edition, still contains a few errors (some inherited from the original Construction Set manual), but is otherwise generally correct and is the most comprehensive guide available. When looking up a function in MSFD do read beyond the description and through its notes and comments, which contain valuable information.


AiActivate can not make a NPC drink a potion.
It will only pick up objects in the cell; does not check for objects in inventory. See also notes below about what [reset] does.
note: Morrowind Code Patch feature "Scriptable potion use" lets you do this with the Equip function instead
does not "check if the target is currently in the crosshair".
Its function for the player is exactly the same as for NPCs: checking if the target ID is engaged in combat.

Modifies or defines the reputation (not reaction) modifier for members of the specified faction towards the PC. This affects advancement and Reputation checks for NPCs of the same faction, but doesn't directly affect their Disposition (only Rank affects the NPC's disposition if the NPC's faction is favorably disposed towards the player's faction).

Position , PositionCell
Can NOT take variables, local or not.
PlayGroup , LoopGroup
Unlike what the note states about "crosswired" animation, function names do not give different results if they are used in the console or in scripts. They seemed to give different results because of scripts compiled in old mods (the compiled script is saved in the plugin along with the text of the script by the CS; what the game processes is not the text of the script but the compiled version). The explanation is that these scripts were compiled in an older version of the CS, before a change in Bloodmoon: see this page for the affected Opcodes. The NPC animation explorer linked in MSFD (MMH link) is one of these older mods and needs to be recompiled, otherwise it will fail or play wrong animations.

Additional notes:


the undocumented argument for Ai functions (AiActivate, AiFollow, AiEscort...):
It changes the behaviour of the "package done" flag. GetAiPackageDone normally only returns 1 for one frame, when the Ai function has been executed. The [reset] argument of Ai functions is optional. If it is given with any value (0 or 1), once the package is executed, GetAiPackageDone will NOT reset to 0 until a new Ai command is called on that NPC. The point of this is that scripted Ai sequences won't break if the "package done" frame is skipped for any reason - in vanilla it's for instance skipped if the PC waits/rests during the execution of AiTravel.

OnDeath / GetHealth
MSFD suggests GetHealth as an alternative to OnDeath. However, a NPC can be dead with a positive amount of health if they were healing, because magic effects still apply during death animations. While there may (?) need to be at least one frame on which the NPC's health is < 1 for them to die, using GetHealth is not a reliable way to tell that a NPC is dead afterwards.

is an extremely slow function if many different NPCs and creatures are recorded in the save. Make sure not to call it every frame.

- Disabled statics do keep their collision in interiors as well as exteriors and need to be reloaded/repositioned;
- On the caution about disabling lights: changing the position of lights instead as suggested is a good workaround, but additional warnings on scripted lights: for lights that do not have a mesh, changes to their positions and script variables will persist through reloading games or starting a new game without quitting first. Adding a mesh (EditorMarker, invisible/collisionless) to the light seems to solve this issue.

Note that using this function will modify then inscribe the current state of *all* faction properties of the first faction ID into the player's save. Includes faction and rank names, requirements, etc., which will overwrite the properties edits of any new mod that wasn't already installed when the function was used. The same is true of NPC functions Mod/SetFight, Mod/SetFlee, Mod/SetAlarm, which record all of the NPC's properties into the save.

PlaceAtPC , PlaceAtMe
Note that objects created by these functions aren't affected by ingame lighting until the player exits and reloads the cell.

Waiting or loitering (resting where sleep is forbidden) doesn't count as sleep. To detect it you can instead check if time changes while within MenuMode.

Some bugs (/features) that MSFD warns against are fixed by the most recent versions of the MCP, including:
- CellChanged not returning 1 for scripted teleporting or magic teleporting,
- "CellChanged doesn't always trigger, even if the player enters the cell via a normal teleport door": this comment likely referred to what happens when entering an interior through a load door that had a script with OnActivate on it, a known bug with the Vivec Arena (this is also fixed by MCP)
- RemoveItem subtracting weight from the character's encumbrance even if the amount of items is not in the character's inventory
- PlayGroup / LoopGroup being unreliable and having different animation on upper body and lower body is (?) fixed by MCP