Morrowind Mod:MWE Dev Kit Intro

The UESPWiki – Your source for The Elder Scrolls since 1995
Jump to: navigation, search

MWE Version 1.21 Scripting Manual (WIP 2nd Edition)[edit]

Written by Tonto, blame him for the errors.
Uploaded by Halo, Tonto can blame him for putting up esoteric documentation too early and for taking editorial liberties.
For extra info or advice, head to http://aerelorn.1.forumer.com/.

Introduction[edit]

It's about time I came out with a second edition (still WIP) manual for MWE. I'll attempt to fix any glaring errors in documentation, and clear up what I can. The changes to this document should be minor, but users of the previous dev kit may notice that the Spell Modifier has been removed. This is because the spell modifier has been improved and expanded upon. A separate document, dedicated to the use of the spell modifier is included with the dev kit. Check out the archive this file came in.

Here are the rules:[edit]

  1. You may use MWE in your mods as you see fit, remembering to give credit to Aerelorn for programming MWE.
  2. You will not ask Aerelorn or Tonto for the source code. Tonto doesn't have it, and Aerelorn won't give it.
  3. You will not ask Aerelorn or Tonto directly for new functions. There's a process for getting new functions, and you need only head over to the MWE forums (http://aerelorn.1.forumer.com/) and open up a thread there. If the idea isn't very useful or just too hard it will probably be struck down. If it's a good idea, Tonto can research it, and Aerelorn has the time, it may be programmed.

Stuff You Should Know[edit]

First of all, if you can't script, you can't use MWE. Using MWE is much more advanced than Morrowind scripting, but it shouldn't be too hard for the intermediate scripter or programmer. Anyone who can read and understand GhanBuriGhan's Morrowind Scripting for Dummies should be able to use it. Possibly the most important thing to understand is how to work with "fixes". Infix and postfix operators are an integral part of working with MWE. Know them very well if you intend to use MWE.

Secondly, MWE needs to have certain code inserted into every script. These are generic scripts, some of which I will provide at the end of this document. Before you go off to compile and try out your first script, make sure that you add this initialization code to your scripts.

Lastly, MWE has a peculiar way of calling functions. Certain functions, post MWE version 1.01 or so, use variable "flags" in order to be called. This way, a single Morrowind debugging function can be replaced by multiple other functions. An example would be this:

set MWE_Vars01 to 10000
ToggleLoadFade       ;TontoFunction, Item Presence ( V01 -> 1 ), NEXT Infix Player

set MWE_Vars01 to 10000
ToggleDebugText                 ;SetupObject, Postfix Modified
AddItem "DummyObject" 1

set MWE_Vars01 to 20000
ToggleLoadFade      ;TontoFunction, NEXT Infix Null, Rpt Prev Modified Postfix

set MWE_Vars01 to 10000
ToggleDebugText         ;SetupObject, Postfix Modified
RemoveItem "DummyObject" 1

Notice that ToggleLoadFade, known as the TontoFunction, is preceded by two different values for MWE_Vars01. When MWE_Vars01 is set to a certain value, the TontoFunction performs a different set of actions.

How Do I Script with MWE?[edit]

Scripting with MWE isn't all that different from normal Morrowind scripting. You'll just find yourself using a few debugging functions that would normally have no relevance in a script. These debugging functions are placeholders for MWE functions. To get MWE to actually work its magic, you'll need to compile the scripts using the program included with the dev kit.

The compiler, though very simple in operation, has one flaw. It only works with a file having a specific name "health suite.esp". Blame it on me, blame it on Aerelorn, but the compiler distributed with this version of MWE is just that way. After saving your plugin in TESCS, you can either manually rename your plugin or you can write a batch file to automate the work for you. There should be a generic batch file which I use in the package, edit it to the appropriate file name and save yourself some time. If I can get a hold of a different compiler, I'll distribute it in an updated package.

One final need-to-know thing. When making a plugin for MWE you should have MWE_Base.esp loaded in TESCS, but not set as your active plugin. Also, you should add this script snippet to the beginning of any script calling an MWE function:

;MWE LOAD SECTION

if( GetJournalIndex "MWE_LoadIndex" < 20 )
     return
endif

if( MWE_Loaded < 100 )
     return
endif

if( MWE_Loaded < 110 )
     if( Flag == 0 )
          set Flag to 1
          return
     endif
     set Temp to ( MWE_Loaded / 100.0 )
     Messagebox "This version of the [Mod Name] requires Morrowind Enhanced v1.21
\ or greater.  You are currently running Morrowind Enhanced
\ v%.2f  Please go to www.freewebs.com/aerelorn/ to upgrade
\ to the latest version.", Temp
;;WARNING! the editor doesn't support line wrapping :(
;;fix the above messagebox call to only use one line if you're cutting & pasting
     StopScript "[Script Name]"
     return
endif

if( MWE_Vars00 >= 10000000 )
     if( Flag == 0 )
               ;Any accompanying initialization scripts should go here
               ; i.e. sound detection
          Set Flag to 1
          return
     else
          Set MWE_Vars00 to 0
     endif
endif

set Flag to 0

What's All this Garbage, Anyway?[edit]

I use a few terms that aren't necessarily common Morrowind modding lexicon. A few terms are related to MWE, others are related to the data structures found in Morrowind data. I've listed a few here for your convenience.

    MWE
    Morrowind Enhanced, anyone?
    ACE
    Aerelorn's Combat Enhanced
    JEN
    Journal Enhanced
    AWE
    Aerelorn's Writing Enhanced
    BEN
    Blocking Enhanced
    LAG
    Less Annoying Guards
    REFR
    Reference. All objects in the game have a reference. MWE has the ability to target certain references.
    REFR Scan
    Also known as the REFR Living Scan. Since it is the only function that scans references for MWE, I refer to it generally as the REFR scan. Users should keep in mind, however, that it only scans and targets "living REFRs", both NPCs and Creatures, and not every REFR in a cell.
    NPC
    Non-Player Character in some schools of RPG gaming. It may also be referred to as NPC_ in some documentation. The player and other humanoids in Morrowind are objects of this type.
    CREA
    Creatures. This is the name of the object template used by creatures.
    Infix
    In the line of code "Player -> GetHealth", "Player" is the Infix. MWE in some instances alter infix and postfix operators.
    Postfix
    In the line of code "Player -> GetTarget 'Fargoth'", "Fargoth" is the postfix. MWE can in some instances alter infix and postfix operators.

Functions[edit]

REFR Living Scan (function set)[edit]

This function set works in three components. No variable syntax.

The REFR Living Scan checks the player's current cell, and in the case of exteriors, all adjacent cells for instances of "living" references. A living reference would be either an NPC (NPC_) or Creature object (CREA). In the event that a living reference is found, the reference becomes the infix for the next line of code. In the next line of code you can then do anything you would normally do with an infixed object. If for some reason the infixed object does not meet a certain criteria, the script can then pass on to the next reference in the cell. It can do this again and again until all living references in the cell have been exhausted, after which the function set will give a null return. Here is an example script snippet from ACE's hand to hand hit detection:

if( Timer2 >= Timer )
  if( Struck == 0 )
    ToggleBorders                                               ; ClearLiving
    set Found to 0
    while( Found == 0 )
      if( HandToHand == 1 )
        ToggleSky                                               ; NextLiving
        set Found to ( GetSoundPlaying, "Hand To Hand Hit" )
        if( Found == 0 )
          ToggleWorld                                           ; SetReference
          set Found to ( GetSoundPlaying, "Hand To Hand Hit 2" )
          if( Found == 0 )
            ToggleWorld                                         ; SetReference
            set Found to ( GetSoundPlaying, "Health Damage" )
          endif
        endif
      else
        ToggleSky                                               ; NextLiving
        set Found to ( GetSoundPlaying, "Health Damage" )
      endif
      if( MWE_Vars01 == -1 )
        set Found to -1
      endif
    endwhile
  endif
endif

NextLiving[edit]

Function Call – ToggleSky
MWE_Vars Syntax – None
Version – 1.0 and above
Action – This function targets the next Living reference in the current interior cell or the current exterior cell and its surrounding cells. In the event that no REFR has been previously targeted, this function will target the first living REFR. The targeted object becomes the infix for the next line of code. If there are no more living REFR to be targeted, the function returns a -1 to the global variable MWE_Vars01.

SetReference[edit]

Function Call – ToggleWorld
MWE_Vars Syntax – None
Version – 1.0 and above
Action – This function is used in conjunction with NextLiving to renew the infix on the targeted REFR. Calling this function will set the infix to the REFR targeted by NextLiving in the next line of code.

ClearLiving[edit]

Function Call – ToggleBorders
MWE_Vars Syntax – None
Version – 1.0 and above
Action – This function resets the count on the REFR Scan's references. Using it will clear any REFR instance targeted by MWE. This is useful in ending or restarting a scan.

Sound Scan (function set)[edit]


This function set works in two components. Variable syntax and data initialization is required.

The Sound Scan is used to check if certain sounds are active. While Morrowind does provide sound detection, it will not work on sounds that do not originate from an object reference. This function can be used to pick up those elusive interface sounds, as well the water layer. It cannot, however, determine if the sound is originating from an object. A frame-per-frame check for the "weapon miss" sound, for instance, would detect any and all swings by the player, his allies, and his enemies. Use with caution.

It should be noted that, unlike other functions, the Sound Scan requires that it be set up in two different scripts. One script will tell MWE which sounds to look for, and the other will actively check for those sounds. It is suggested that the user create a startup script alike-so:

Begin MWE_HealthSuiteRegistry

if( GetJournalIndex "MWE_LoadIndex" < 10 )
     return
endif

if( MWE_Loaded < 1 )
     return
endif

 Set MWE_Vars01 to 10000
 TestInteriorCells ; RegisterSound
 StopSound "Swallow"

 Set MWE_Vars01 to 20000
 TestInteriorCells ; RegisterSound
 StopSound "Item Ingredient Up"

Set MWE_Vars01 to 50000
TestInteriorCells ; RegisterSound
StopSound "Item Potion Up"

Set MWE_Vars01 to 60000
TestInteriorCells ; RegisterSound
StopSound "Water Layer"

StopScript "MWE_HealthSuiteRegistry"

End

This script uses MWE_Vars01 and a function known as RegisterSound to register with MWE the memory addresses of certain sound flags. The script first assigns a number to the sound to be checked for (Set MWE_Vars01 to #0000). Then it calls RegisterSound, followed by StopSound "SoundID".

Once these addresses have been established, the script may cease running for the remainder of the game or savegame session. Since these addresses will change each time Morrowind is run, and sometimes between game loads, the script must be a Start Script. Once this script has run, you must execute a few simple lines of code to check for the sounds.

set MWE_Vars01 to 5
ShowSceneGraph ; CheckSound

if( MWE_Vars01 == 1 )

        [Code]

endif

Assuming the script used to register the sound and this script are the same, MWE_Vars01 should be set to 1 if the sound "Item Potion Up" is played.

RegisterSound[edit]

Function Call – TestInteriorCells
MWE_VarsSyntax – MWE_Vars01 must be set to a number followed by four zeros. For readability's sake, these numbers should be ordered sequentially. Currently there are six registered sounds in the various MWE mods. Please head over to the MWE forums and state if you wish to register a sound number. If the demand is high enough, I may simply register all of the sounds in a separate plugin.
Version – 1.01 and above.
Action – This function registers a sound for detection with the CheckSound function. This function requires extra syntax.
Example –       Set MWE_Vars01 to 60000         ;Water Layer, sound #6
                TestInteriorCells               ;RegisterSound
                StopSound "Water Layer"

CheckSound[edit]

Function Call – ShowSceneGraph
MWE_VarsSyntax – MWE_Vars01 must be set to the number previously registered by RegisterSound. In the case that RegisterSound set MWE_Vars01 to 10000, CheckSound would set MWE_Vars01 to 1.
Action – If the sound registered sound is playing, CheckSound will return a value of 1 to MWE_Vars01. It is unknown at this time what value is returned if the sound is not playing, but it is most probably a value of 0.
Example -       Set MWE_Vars01 to 5     ;"Item Potion Up"
                ShowSceneGraph          ;CheckSound

Target Function[edit]


This function is used to get the player's current target and/or to modify the infix or postfix of an operation.

GetReferenceType[edit]

Function Call 
ToggleLoadFade
MWE_VarsSyntax 
MWE_Vars01 == 50000

Setting this variable before calling ToggleLoadFade will call the target function. This function will return a number to signify the targeted reference's type through MWE_Vars02. A full list of the supported types is below. This function will also allow the scripter to append the targeted reference as either an infix or a postfix to the following line of code. See the uses of MWE_Vars02, below.

AppendInfix[edit]

Function Call 
ToggleLoadFade
MWE_VarsSyntax 
MWE_Vars02 == 0

Setting MWE_Vars02 to this value before calling the target function will cause MWE to append the targeted reference's ObjectID as an infix to the next line of code. The results of this function should theoretically work with any standard Morrowind functions.

AppendPostfix[edit]

Function Call 
ToggleLoadFade
MWE_VarsSyntax 
MWE_Vars02 == 1

Setting MWE_Vars02 to this value before calling the target function will cause MWE to append the targeted reference's ObjectID as a postfix to the next line of code. The results of this function will not theoretically work with every stock Morrowind function. See #1 in the warnings section, page 3.

MWE_Vars02 will return X for:

1 NPCTYPE
2 CREATURETYPE
3 CONTTYPE
4 LIGHTTYPE
5 BODYTYPE
6 DOORTYPE
7 ACTIVATORTYPE
8 INGREDIENTTYPE
9 WEAPONTYPE
10 ARMORTYPE
11 AMMOTYPE
12 CLOTHINGTYPE
13 APPARATUSTYPE
14 BOOKTYPE
15 LOCKPICKTYPE
16 PROBETYPE
17 REPAIRTYPE
18 MISCTYPE

Warnings[edit]

Due to the complexities of Morrowind script, the target function's infix and postfix affecting functions are not guaranteed to work. Certain functions will simply not be compatible with the changes made to them on-the-fly. It is unknown what these functions are, but incompatibilities will most likely exist. If the target function continually crashes Morrowind when used in combination with a certain function, it is probably because the two are simply incompatible.

Though not fully confirmed, it appears the target function does not take well to new games. It is highly possible that starting a new game will result in a crash while using the target function. If you must use the target function at all times, place a hold in your script that prevents the function from running until the player has cleared the character generation process. This crash may also be due to movie playback. User input on the nature of this possible glitch would be much appreciated.

Though a small oversight, the current version of the target function does not support interaction with potions. This will likely be fixed in future versions.

As with most of the newer MWE functions, make sure that you set MWE_Vars01 directly before calling the function. In the case of this and other functions, MWE makes use of MWE_Vars01, and it must be placed directly before the function call in order to work.

Encumbrance Function[edit]


Function Call 
ToggleLoadFade
MWE_VarsSyntax 
MWE_Vars01 == 30000
Returns 
MWE_Vars01, MWE_Vars02

This function determines the player's current and maximum encumbrance. Upon calling this function, the player's current encumbrance will be returned to MWE_Vars01. The player's maximum encumbrance will be returned to MWE_Vars02. At this time it is unknown whether magical encumbrance is included in the current value. It is probably so, but user input on this would be helpful.

Warnings[edit]

As with most of the newer MWE functions, make sure that you set MWE_Vars01 directly before calling the function. In the case of this and other functions, MWE makes use of MWE_Vars01, and it must be placed directly before the function call in order to work.

It should go without saying, but please be reminded. Morrowind stores your encumbrance as a floating point number. Don't try to store the data as a short or long integer. Your humble author has made this mistake before.

Item Removal (function set)[edit]


This set of functions will allow you to transfer items between container objects (the player, boxes, NPCs) with far more ease than was previously possible. While it doesn't work in transferring specific "named" items, it allows scripters a quick and easy way to remove all items, or even individual item types and combinations of item types, from a container. A scripter could conceivably make a function to remove all of the players ingredients, or various other items, and sort them in boxes automatically, without the need to call each ObjectID individually.

Users should note that subtle changes to MWE_Vars02 can affect what sort of items you want to affect. The item removal function uses this variable as its syntax, telling MWE what sort of item(s) should be included in the search and transfer processes. MWE_Vars02 is used as a bitmask, which isolates the sort of item type(s) should be affected. For instance, a player might want a function to transfer all of their books and miscellaneous items to a treasure chest. The bit value assigned to books is 64, and the bit value assigned to miscellaneous objects is 1024. To remove only these item types, the user would set MWE_Vars02 to ( 64 + 1024 ) or 1088. Upon initiating the function, MWE would search only for books and miscellaneous objects, ignoring all others.

As a final note, this function is admittedly misunderstood in many ways. It is by far the most complex function for MWE to date, and it can be hard to decipher just what the functions are up to. Though innovation is fine, it would probably just be best for most users to stick to the example provided in this document.


MWE ItemScan[edit]

Function Call
ToggleLoadFade
Syntax
MWE_Vars01 (Below)
MWE_Vars02 (BitField, pages 3 and )
ItemScan – Player Target[edit]
MWE_Vars01 == 10000
This function sets MWE's internal target to the first object in inventory of the calling object that meets the criteria in MWE_Vars02. That is, if MWE_Vars02 were set to 1 upon calling this function, the first ingredient in inventory would be targeted for use with SetupObject. When this criteria is met, MWE_Vars01 will be set to 1. If it is not met, MWE_Vars01 will be set to 0. This function also sets the infix to "player ->" for all SetupObject function calls. Do note that this function will only scan the calling object. This will either be set to the script's default calling object, or whatever object reference's infix is placed in front of the function. The only way to scan the player's inventory is to use the line of code: Player -> ToggleLoadFade.
ItemScan – Default Infix[edit]
MWE_Vars01 == 20000
This function nullifies the infix changes made by 'ItemScan – Player Target'. In effect it restores the infix to the default provided by the script. There is no need to set MWE_Vars02 when calling this function.
ItemScan – Bitfield Reference[edit]
Set MWE_Vars02 to XXXX for
1 INGREDIENTTYPE
2 WEAPONTYPE
4 ARMORTYPE
8 AMMOTYPE
16 CLOTHINGTYPE
32 APPARATUSTYPE
64 BOOKTYPE
128 LOCKPICKTYPE
256 PROBETYPE
512 REPAIRTYPE
1024 MISCTYPE
2048 ALCHTYPE

MWE SetupObject[edit]

Function Call
ToggleDebugText
Syntax
MWE_Vars01 (Below)
MWE_Vars01 == 10000 
This function uses MWE's internal target, set by ItemScan, to modify the postfix of the following line of code. For example, after using the ItemScan function, MWE is targeting a piece of Corkbulb Root in the player's inventory. SetupObject will change the postfix in the next line of code to the ObjectID of the Corkbulb Root. Also, if the ItemScan was using the syntax MWE_Vars01 == 10000, the next line of code will be appended the "player ->" infix.

Warnings[edit]

  1. Make sure that you set MWE_Vars01 as the FINAL line before calling an MWE function. Many MWE functions will not work if MWE_Vars01 isn't beside them.
  2. When transferring items between containers, the items placed in the new container will be in flawless condition. Currently it is not a good idea to use MWE to make objects such as armor storage chests, as the transferred object will get automatic, free repairs.
  3. Avoid using the Item Transfer Function with MWE's REFR Scan. Both the Item Transfer Function and the REFR Scan use the same internal space in MWE to store their targeted reference. Using them together can lead to anomalies. It's conceivable that the game could crash because someone put Fargoth in their inventory.
  4. Removing objects directly from the player is possible, but when done, avoid removing equipped objects. This can be the source of major slowdowns and graphical glitches with the "paper doll" in the inventory menu. It may be possible to use HasItemEquipped with the Item Scan, but this has not been tested.


Example Script[edit]

This script is to be placed on a box which will remove all of the player's alchemy apparati, placing it inside the box upon activation. When the player activates the box again, the apparati will be restored to the player.

Begin ApparatusStorageScript

Short Removed
Short Restored
Short Activated

Set Activated to OnActivate

If ( Activated == 1 )

  Set Activated to 0

  If ( Removed == 0 )
    Set Removed to 1
    Set Restored to 0
    Set MWE_Vars01 to 1
  Elseif ( Removed == 1 )
    Set Restored to 1
    Set Removed to 0
    Set MWE_Vars01 to 1
  Endif

Elseif ( Activated == 0 )
  Return
Endif

If ( Removed == 1 )
  While ( MWE_Vars01 != 0 )
    Set MWE_Vars02 to 32        ;bit value, APPAType
    Set MWE_Vars01 to 10000     ;syntax, Item Scan – Player Infix
    Player -> ToggleLoadFade ;Item Scan – Player Infix (Scan Player Inv)

    ;Step 1 - Scan the player for an apparatus

      If ( MWE_Vars01 != 0 )

        ;Step 2 – If the item is detected, remove it from the player

        Set MWE_Vars01 to 10000 ;syntax, SetupObject
        ToggleDebugText         ;SetupObject
        RemoveItem "dummyobject" 1

        Set MWE_Vars01 to 20000 ;syntax, Item Scan – Default Infix
        ToggleLoadFade          ;Item Scan - Default Infix

        Set MWE_Vars01 to 10000 ;syntax, SetupObject
        ToggleDebugText                 ;SetupObject
        Additem "dummyobject" 1

        ;Step 3 – And add it to the box

        Set MWE_Vars02 to 32    ;bit value, APPAType
        Set MWE_Vars01 to 10000 ;syntax, Item Scan - Player Infix
        Player -> ToggleLoadFade     ;Item Scan - Player Infix (Scan Player Inv)

      Else
        Set MWE_Vars01 to 0
      Endif
    Endwhile

Elseif ( Restored == 1 )

  While ( MWE_Vars01 != 0 )

    Set MWE_Vars02 to 32        ;bit value, APPAType
    Set MWE_Vars01 to 10000     ;syntax, Item Scan – Player Infix
    ToggleLoadFade      ;Item Scan – Player Infix

    ;Step 1 - Scan the container for an apparatus

    If ( MWE_Vars01 != 0 )

      ;Step 2 – If the item is detected, add it from the player

      Set MWE_Vars01 to 10000   ;syntax, SetupObject
      ToggleDebugText           ;SetupObject
      AddItem "dummyobject" 1

      Set MWE_Vars01 to 20000   ;syntax, Item Scan – Default Infix
      ToggleLoadFade            ;Item Scan - Default Infix

      Set MWE_Vars01 to 10000   ;syntax, SetupObject
      ToggleDebugText           ;SetupObject
      RemoveItem "dummyobject" 1

      ;Step 3 – And remove it from the box

      Set MWE_Vars02 to 32      ;bit value, APPAType
      Set MWE_Vars01 to 10000   ;syntax, Item Scan - Player Infix
      ToggleLoadFade    ;Item Scan - Player Infix

    Else
      Set MWE_Vars01 to 0
    Endif
  Endwhile
Endif

End

Document Status[edit]

MWE Manual
Encumberance Function Reference
Target Function Reference
Item Removal Function Reference
Spell Function Reference
Trigometry Reference