You are on page 1of 42

Scripting With MWSE

A scripting guide for MWSE by Yacoby

Contents
Forward............................................................................................................................. 2
Introduction....................................................................................................................... 3
What is MWSE?............................................................................................................ 3
How do I run MWSE?................................................................................................... 3
How do I start scripting with MWSE? .......................................................................... 3
FAQ .............................................................................................................................. 5
Quickstart Guide ............................................................................................................... 7
Variables ....................................................................................................................... 7
Types of MWSE Variables........................................................................................ 7
Using setx.................................................................................................................. 7
Testing conditions ......................................................................................................... 8
Ifx, Whilex conditions............................................................................................... 8
Data Loss ...................................................................................................................... 9
Tutorial 1......................................................................................................................... 10
Tutorial 2......................................................................................................................... 13
Tutorial 3......................................................................................................................... 17
Tutorial 4......................................................................................................................... 18
Tips and Tricks ............................................................................................................... 19
Storing Cell/Position Data....................................................................................... 19
Sending Data to other applications (Programmers only) ......................................... 20
Morrowind Script Extender Function Reference ............................................................. 22
References................................................................................................................... 23
Math ............................................................................................................................ 25
AI and Movement ....................................................................................................... 26
Inventory ..................................................................................................................... 27
Attributes .................................................................................................................... 29
NPC Properties............................................................................................................ 30
Item Properties ............................................................................................................ 32
Keyboard Input ........................................................................................................... 34
File I/O........................................................................................................................ 36
Strings ......................................................................................................................... 38

Forward
This guide was written for the purpose of getting people to start scripting with
Morrowind Script Extender. It is a wonderful thing, but it can seem hard to make the first
leap. I hope people who read this find it easier to make that leap.
This isnt finished. It is nowhere near finished, so if anyone has anything that they would
consider adding, just drop me a note.
I would like to thank the MWSE development team, for writing MWSE, and especially
Fliggerty, for the feedback and scripts he provided.
Happy Scripting
~Yacoby

Introduction
What is MWSE?
Morrowind Script Extender (MWSE for short) does what is says on the tin. It extends the
number of functions available for use by modders.
For example, using the default scripting language, there is no way to change an objects
name. However, if we add MWSE into the mix, all you have to do is use the xSetName
function.
It makes things possible that are impossible or very hard with the vanilla scripting engine.
MWSE doesnt require a fast computer to run, in fact, when running MWSE on my old
computer (1.6 GHz CPU, 16Mb Gefore4 MX Graphics card, 256Mb of RAM) I didnt
notice any drop in my frames per second when running MWSE.

How do I run MWSE?


To allow MWSE functions and mods to work, you need to have MWSE running in the
background while you run Morrowind.
The most recent version of MWSE can be downloaded from here:
http://sourceforge.net/projects/mwse
With the most current version of MWSE, (0.9.4a) you need to run MWSE Launcher.exe
to run MWSE. However, as things change, always check the readme included with your
version of MWSE.

How do I start scripting with MWSE?


The first thing you need to know is how to write basic Morrowind scripts. This document
assumes that you at least know what if blocks are.
If you dont know how to script yet, I suggest you look at Morrowind Scripting for
Dummies, which can be found at places like
http://planetelderscrolls.gamespy.com/
Make sure you get version 8 or version 9. Unfortunately, you can still find version 5 on a
lot of places.

When you make a MWSE mod, you can do it in exactly the same way as you would a
normal mod. There is, however, one thing that you cannot do, and that is compile scripts
using MWSE functions in the Construction Set (CS).
This means that we need to use another editor called MWEdit to write MWSE scripts.
Although MWEdit is far better than the CS in some respects, it cannot edit cells, and I
wouldnt advise writing dialog with it.
This means that in most cases, you will still need to use the CS, as well as MWEdit, to
make your mod, so to make sure I get my point across:
You can edit a MWSE mod in the CS, as long as you dont edit any scripts containing
MWSE functions.
MWEdit can be downloaded from here:
http://sourceforge.net/projects/mwedit
Installing MWEdit is an easy matter. All you need to do is extract the files to a location
of your choice and run MWEdit.exe
As soon as you start MWEdit, you will notice that the layout is far different from the CS,
but once you get used to it, you will wish the CS had MWEdits layout. Trust me on this.

FAQ
(By Fliggerty, edited by Yacoby)
Is it stable?
MWSE itself is quite stable. Many people claim that they experience fewer CTDs while
using MWSE. However, as with anything involved with Morrowind, it seems that
depending on your hardware/software configuration, it may not run very well.
Does it eat resources?
While playing the game, MWSE.exe rarely uses up to 4% of the CPU. The most memory
I have ever seen it use is 1.6Mb. Upon initial load, before Morrowind starts, it is not
uncommon to see it momentarily use 100% of the CPU.
Can it work with other external programs?
Yes, in most cases. MGE has a built-in version of MWSE that is equivalent to v0.9.2 or
0.9.3 (Depending on which version of MGE you use).
MWSE and MWE are also compatible. However, some people have reported that they
will not run together at all. This seems to be system dependent.
There are also no known issues using both MWSE and the FPS Optimizer.
If so, how to configure?
MWE: If you use MWE to autolaunch Morrowind, change the path in "Autolaunch
Morrowind" to point to MWSE Launcher.exe rather than Morrowind Launcher.exe.
FPS Opt: No configuration required.
MGE 3.0.3: MWSE 0.9.4a is incompatible with MGE 3.0.3. If you want to use MGE
mods, use MGEs internal version (0.9.2)
MGE 3.3.2: MWSE 0.9.4a is incompatible with MGE 3.0.3. If you want to use MGE
mods, use MGEs internal version (0.9.3)
Are there longer loading times and/or reduced fps?
There are often longer loading times. MWSE scans all scripts when loading the game.
This is necessary to determine which scripts contain MWSE functions. Depending on
how script-intensive your mods are, this delay may be rather long.
As with any mod, if it runs a lot of scripts, an MWSE mod may cause an FPS hit. But
any such effect from MWSE itself is not noticeable.
Is there spyware?
No. There is no code that will intentionally do anything harmful to your computer. If you
dont trust me, you can download the source and see for yourself.
I can't install it!
Extract MWSE anywhere, it doesnt need to be in the Morrowind directory.

Why isn't it working?


Ensure that you are running Bloodmoon v1.6.1820 (If you use GOTY, you dont need to
patch it). You can get the patch here:
http://www.elderscrolls.com/downloads/updates_patches.htm.
Make sure you have the latest version of MWSE
Will it work with a no-cd patch?
Yes. It seems you have to have the proper one though. I use this one:
http://www.gameburnworld.com/dl/dl.php?file=MorrowindBloodmoonv1.6.1820NoCDF
ixedexeEng.rar

Quickstart Guide
Happy to jump in, ignoring the tutorials? This is the section for you. As much
information packed into as little text as possible. When you have read this, you will need
to look over the function list to get an idea of what functions are possible

Variables
Types of MWSE Variables
The MWSE functions make use of two new variable types, string and reference. Both are
actually declared in the scripts using the "long" type.
The ref, reference, variables provide a way to keep track of specific objects in the game
world. They are most commonly used on the left side of the -> operator with other
functions (new or old) to affect that object.
Long temp
Long var
Setx var to xGetRef, Player
;the variable var is now a ref, pointing to the player
Var->xItem, Gold_001, 2
Setx var to xStringBuild, Happy
;the variable var is now a string
Setx temp to xStringComapre, var, Sad
If ( temp == 0 )
Messagebox, Someone is sad
endif

All string and ref information is lost when Morrowind is closed.

Using setx
Unfortunately, the new functions can't be easily integrated with the standard script
functions and commands. A 'setx' command is provided as a substitute for 'set' when you
are using a new function. You can only put one function or one string value on the right
side of 'setx' but it does allow more than one variable on the left for functions like
'xInventory' that return multiple values.
The MWEdit compiler doesnt do any error checking on the number of variables on the
left hand side, so dont get it wrong.
A normal Morrowind function using set
Set health to GetHealth

A MWSE function using setx


Setx pcCell to xPCCellID

Comment [J1]: I think this


section needs a small section on
strings and refs losing their values
on load

Multiple returns using setx


setx invitem,invcount,invref to pcref->xInventory

Testing conditions
Ifx, Whilex conditions
The standard Morrowind script if and while commands do not work when the body of the
block contains extended commands, instead use ifx and whilex.
The ifx and whilex do not currently support a full syntax, it doesnt compile if a function
is used in the ifx statement itself
Ifx ( getHealth ) ;bad
Float tmp
Set tmp to getHealth
Ifx ( tmp ) ;good

The ifx/whilex block will be performed if the value is not zero. You can use 'else' with
'ifx' but not 'elseif' and there isn't an 'elseifx'.
If you have a multiple stage if/elseif section it's frequently possible to isolate the new
functions to only one or two sections, so check all of the others first then use statements
like the following.
OLD VERSION

NEW VERSION

if ( state == 5 )
; section for 5
else
; section for not 5
endif

set temp to ( state - 5 )


ifx ( temp )
; section for not 5
else
section for 5
endif

It's OK to leave the first section blank, so this also works:


OLD VERSION
if ( state == 5 )
; section for 5
endif

NEW VERSION
set temp to ( state - 5 )
ifx ( temp )
else
section for 5
endif

This makes some scripts very messy. If you have a lot of if statements that results in a
single block of code either being executed or skipped, sometimes it is easier to do
something like this, rather than a load of complex ifx blocks.
Set temp to 0
If ( player->getHealth > 0 )
If ( state == 5 )
If ( player->getLevel == 25 )
Set temp to 1
Endif
Endif
Endif
Ifx ( temp )
;do extended functions here
endif

Data Loss
When you exit and reload Morrowind, all string and ref variables become invalid

Tutorial 1
Open up MWEdit, and click OK to the warning screen that comes up. Dont disregard
what it says though; it is always worth backing up a plugin once every few days.
Press the New button (The one that looks like a white piece of paper).
Scroll down the left hand list box till you find an item that says Script. Click on it. Now
in the larger right hand box, right click and press Add New and a new script dialog
should come up.
We are going to write a small script that will tell the player what cell he or she is in
Start the script
Begin My_First_MWSE_Script
End My_First_MWSE_Script

The first thing we need to do is find and store the cell that the player is in. So we look at
the MWSE function reference (at the end of this document) and find:
cellid (string): xPCCellID
Returns a string containing the name of the current cell.

Which all looks rather confusing.


cellid is what is returned, basically the name of the cell the player is in
(string) is the type of the object that is retuned.
xPCCellID is the function name

So what is a string I hear you say. A string is a collection of characters; Hello World!,
I am 354 years old and a are all examples of strings. A string must always be
surrounded by quotes.
MWSE cheats a bit with strings, rather than have a new String variable type, it uses the
Long variable type.
So next thing we need to do is add the variable to hold the players cell.
Begin My_First_MWSE_Script
;stores the cell the player is in
Long playersCell
End My_First_MWSE_Script

Then, we need to set the variable to the players cell


One important thing about MWSE functions is that rather than use the set function, you
need to use the setx function
So with a normal function, you would use set:
Set myHealth to getHealth

With a MWSE function, you would use setx


Setx myCell to xPCCellID

Bearing this in mind, we will store the players cell in the playersCell variable
Begin My_First_MWSE_Script
;stores the cell the player is in
Long playersCell
;make the variable hold the players cell
Setx playersCell to xPCCellID
End My_First_MWSE_Script

Now, you may have noticed that this doesnt actual do anything, so we need to output the
players cell using the messageBox function
Unfortunately, you cannot output MWSE strings in normal messageboxs, but luckily
there is a fix, xMessageFix to be precise.
If we look at xMessageFix in the MWSE function reference, we find quite a lot of
information. However, not that much of it is useful here, as all we want to do is display a
string, not use choices.
Take a look at the xStringBuild function, you will see that the arguments are exactly the
same as xMessageFix, for the purpose of formatting messages; xMessageFix and
xStringBuild are exactly the same.
The most important thing to remember about xMessageFix is that it must be followed by
a messagebox, and the length of the message in the messagebox must be longer than the
length of the message in xMessageFix
xMessageFix message_format (string), ...
The first argument for the xMessageFix function is the message format, the second, third,
forth are the variables defined in the message_format argument (They can also be
choices)

What we want to do is display

You are in CellName in a messagebox


%s is used by the xMessageFix function to insert a string into a message. As we have two
strings, we would use two %s in the format argument
xMessageFix, %s%s, You are in , playersCell
Messagebox, ThisJustFillsTheMessageboxUpWithRandomJunk.ThisWillBeReplaced

However, there is a slightly tidier way of doing things, as we dont just have to put
references to strings in the format box
xMessageFix, You are in %s, playersCell
Messagebox, ThisJustFillsTheMessageboxUpWithRandomJunk.ThisWillBeReplaced

So integrating this into the main script, and we get


Begin My_First_MWSE_Script
;stores the cell the player is in
Long playersCell
;make the variable hold the players cell
Setx playersCell to xPCCellID
;tell the player what cell he or she is in
xMessageFix, You are in %s, playersCell
Messagebox, abcdefghijklmnopqrstuvqxyz0123456789abcdefghijk

End My_First_MWSE_Script

You may have noticed that the script will just contiusly output the message, so after the
messagebox, we need to stop the script
Begin My_First_MWSE_Script
;stores the cell the player is in
Long playersCell
;make the variable hold the players cell
Setx playersCell to xPCCellID
;tell the player what cell he or she is in
xMessageFix, You are in %s, playersCell
Messagebox, abcdefghijklmnopqrstuvqxyz0123456789abcdefghijk
stopScript, My_First_MWSE_Script
End My_First_MWSE_Script

Now press the compile button in the script editor. It should compile without any errors.
If you get an error about My_First_MWSE_Script being an invalid object, you need to
save the script so that it exists in the esp, open it again and then try and compile it.
Now give the script a test in game (dont forget to start MWSE as well)

Tutorial 2
In this next script, we are going to make a script that when you look at an NPC, it will
shrink it, and when you look at a creature it will make it grow in size.
The first thing we need to do is get the target of what the player is looking at.
Begin rescale_script
Long pcTarget
End rescale_script

The function xGetPCTarget returns the id of the object that the player is looking at. It
will only get the target of objects where the name box shows up, so it doesnt work
getting the target of things that are in combat with you.
If there is no target, it will return 0
Begin rescale_script
Long pcTarget
Setx pcTarget to xGetPCTarget
If ( pcTarget == 0 ) ;nothing targeted
Return
Endif
End rescale_script

The variable pcTarget now holds a reference to the players target. So with extended
functions, we can use the -> operator and the variable
Next we need to work out what type of object the player is looking at. For this we need to
use the xRefType function. xRefType returns a different set of numbers depending on the
object type.
If the object is a creature, it returns 1095062083, and if it is an NPC, it returns
1598246990
To hold the number we are going to create a new variable called temp, which we will use
to store the number. We will also create a variable to say if it is a creature or not, because
this variable will be 0 or 1, we can use it very easily with the ifx command
Begin rescale_script
Long pcTarget
Setx pcTarget to xGetPCTarget
If ( pcTarget == 0 ) ;nothing targeted
Return
Endif
Long temp

Setx temp to pcTarget->xRefType


Short isNPC
If ( temp == 1598246990 ) ;it is an NPC
Set isNPC to 1
Elseif ( temp == 1598246990 ) ;it is a creature
Set isNPC to 0
Else ;we dont want to rescale other objects, so return
Return
Endif
End rescale_script

So, to recap, we now have a variable that tells us if it is a creature or a NPC. If it is


anything else, we have used the return function so it wont be executing this part of the
script.
We also have a variable holding a reference to the object the player is looking at.
What we next need to check is the object hasnt already been scaled. (Changing the scale
of an object is a very expensive operation for the game engine to do).
Unfortunately, we cannot use the -> operator with a ref variable and a standard function
(any function that doesnt use setx)
Set temp to pcTarget->getScale ;Doesnt Work

Fortunately there is a workaround; xSetRef. xSetRef makes the next function called apply
to the ref argument given to xSetRef.
This code
xSetRef, pcTarget
set temp to getScale

Does exactly the same thing as this code does


Set temp to pcTarget->getScale

Except it works.
So we need to add what we have learnt into the script.
Begin rescale_script
Long pcTarget
Setx pcTarget to xGetPCTarget
If ( pcTarget == 0 ) ;nothing targeted
Return
Endif
Long temp
Setx temp to pcTarget->xRefType
Short isNPC
If ( temp == 1598246990 ) ;it is an NPC

Set isNPC to 1
Elseif ( temp == 1598246990 ) ;it is a creature
Set isNPC to 0
Else ;we dont want to rescale other objects, so return
Return
Endif
;get the scale
xSetRef, pcTarget
set temp to getScale
;if the scale is not 1, it has already been changed, so we dont need to change it again
if ( temp != 1 )
return
endif
End rescale_script

At this point in the script, we know we need to rescale the object, but we need to decide if
we need to increase the size (for creatures) or decrease the size (npcs)
Unfortunately, you cannot use extended functions within normal if blocks, you have to
use the new ifx blocks.
The ifx blocks have several disadvantages, the main one being that they dont do any of
the more complex checking that the normal if blocks have. It will execute the block if the
value in the ifx is true (anything other than 0), other wise it skips it.
There is more about ifx and whilex MWSE Quickstart guide

As we have a variable that holds whether it is an NPC or not in a single 1 or 0 variable, it


will be very easy to implement.
Begin rescale_script
Long pcTarget
Setx pcTarget to xGetPCTarget
If ( pcTarget == 0 ) ;nothing targeted
Return
Endif
Long temp
Setx temp to pcTarget->xRefType
Short isNPC
If ( temp == 1598246990 ) ;it is an NPC
Set isNPC to 1
Elseif ( temp == 1598246990 ) ;it is a creature
Set isNPC to 0
Else ;we dont want to rescale other objects, so return
Return
Endif

;get the scale


xSetRef, pcTarget
set temp to getScale
;if the scale is not 1, it has already been changed, so we dont need to change it again
if ( temp != 1 )
return
endif
ifx ( isNPC )
xSetRef, pcTarget
setScale, 0.5
else ;it is not an NPC, so it must be a creature
xSetRef, pcTarget
setScale, 1.5
endif

End rescale_script

The last thing we need to do is add some simple optimization.


As this script will not need to be run when there are is a menu open, we can make it skip
executing the script when there is a menu open by adding:
If ( MenuMode )
Return
Endif

Tutorial 3
Keycodes
Data loss
More of ifx
Look at NPC. Press button. Give Speedboost
Not look at NPC. Press button. Give PC speedboost
After x seconds, remove speed boost.

Tutorial 4
Maybe a scripted spell?

Tips and Tricks


Storing Cell/Position Data
As you know, all string data is lost when Morrowind stops running. If you want to store a
cell id, how do you do it?
If you know how many positions need to be stored, one solution is to use disabled NPCs
or Creatures. Place them in the position that you need to be stored. You can later retrieve
the information via xGetRef, then using getPos, and xMyCellID
Pros:
The data is stored in the save, so it is unique to that save
Cons:
You have to know how many positions need to be stored, and create an NPC for every
position

Another method is to write the data to another file. You could, in theory, store an infinite
number of locations. However, the problem comes making sure the data is unique to
every save. You could just include the PC name in the file name, but then what would
happen if you had to players with the same name? When you went back to a previous
save? You would have to include enough unique data in the file name that the file name
was unique. You could, for example, use the cell name and the players name, and rewrite
the data every time the player changed cell.
Pros:
Can store an unlimited amount of data
Cons:
You need to use a lot of information from the player to make sure the file is unique
As there is no delete function the MWSE directory may end up getting full of unneeded
files

Sending Data to other applications (Programmers only)


(By CDCooley)
// 2005-07-13 CDC This is a very simplistic example for creating a
named pipe.
// The MSDN documention for CreateNamedPipe gives a multi-threaded
demonstration.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#define BUFSIZE 4096
int main(){
HANDLE pipe;
DWORD size, i;
CHAR buffer[BUFSIZE+1];
//From Morrowind, this pipe is called demo1
pipe = CreateNamedPipe("\\\\.\\pipe\\MWSEdemo1",
PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, 20000, NULL);
while ( (pipe != INVALID_HANDLE_VALUE) &&
( ConnectNamedPipe(pipe, NULL) ||
(GetLastError() == ERROR_PIPE_CONNECTED) ) ){
// A simple echo server
while (true){
if (!ReadFile( pipe, buffer, BUFSIZE, &size, NULL) ||
(size == 0) ) break;
buffer[size] = 0;
// ensure it's null
terminated in case it's a string
printf("Request as float=%f as long=%d as
string=%s\n",*((float*)buffer),*((long*)buffer),
buffer) && fflush(stdout);
if ( !WriteFile(pipe, buffer, size, &i, NULL)
|| (i != size) ) break;
}
FlushFileBuffers(pipe);
DisconnectNamedPipe(pipe);
}
CloseHandle(pipe);
return 0;
}

begin mwse_pipeexample
long count
long numread
float sent
float received
if ( MenuMode == 1 )
return
endif
ifx ( count )
xFileWriteFloat "|demo1" sent
set received to 0.0
setx numread received to xFileReadFloat "|demo1" 1
if ( numread < 1 )
MessageBox "I sent %f, but the server didn't respond! Maybe it's just
slow. Or maybe it's not running." sent "OK"
else
MessageBox "I sent %f and received %f." sent received "OK"
endif
set sent to ( sent * sent )
set count to ( count - 1 )
if ( count == 0 )
StopScript mwse_pipeexample
endif
else
set sent to 3.14159
set count to 5
endif
end

Morrowind Script Extender Function Reference


January 28, 2007 - the MWSE team
Edited by Yacoby for use with the Scripting With MWSE guide

Types listed as STRING and REF are really stored in long variables. Functions listed
with ref-> operate on a target which might be provided by the -> operator, might be
provided by the xSetRef function, or could be the target of the script.
References

Math

xSetRef, xRefType, xGetRef, xGetCombat, xGetPCTarget, xFirstNPC,


xFirstItem, xFirstStatic, xNextRef
xDistance, xSqrt, xHypot, xDegRad, xRadDeg, xCos, xSin, xTan,
xArcCos, xArcSin, xArcTan

AI and
xAITravel, xPlace, xPosition, xPositionCell, xStartCombat
Movement
Inventory

xInventory, xNextStack, xContentList, xAddItem, xRemoveItem,


xHasItemEquipped, xEquip, xDrop, xAddSpell, xRemoveSpell

Attributes

xGetBaseStr, xGetBaseInt, xGetBaseWil, xGetBaseAgi, xGetBaseSpe,


xGetBaseEnd, xGetBasePer, xGetBaseLuc

xIsFemale, xIsTrader, xIsTrainer, xIsProvider, xGetService, xSetService,


NPC
Properties xModService, xGetBaseGold, xGetGold, xSetBaseGold, xSetGold
xGetValue, xGetOwner, xGetWeight, xGetEncumb, xGetQuality,
xGetCondition, xGetMaxCondition, xGetCharge, xGetMaxCharge,
Item
Properties xSetValue, xSetWeight, xSetQuality, xSetCondition, xSetMaxCondition,
xSetCharge, xSetMaxCharge
Keyboard
xKeyPressed, xTextInput, xTextInputAlt
Input

File I/O

xFileRewind, xFileSeek, xFileReadText, xFileWriteText, xFileReadShort,


xFileReadLong, xFileReadFloat, xFileReadString, xFileWriteShort,
xFileWriteLong, xFileWriteFloat, xFileWriteString

Strings

xPCCellID, xRefID, xMyCellID, xGetName, xSetName, xGetBaseID,


xStringCompare, xStringLength, xStringParse, xStringBuild,
xStringMatch, xLogMessage, xMessageFix

References
xSetRef reference (long)
This function provides a way of calling object functions where the syntax does
not allow for it, e.g.
set myalchemyskill to myobject->GetAlchemy
does not work because the original set statement does not allow the use of
variables as objects, in this case you should use:
xSetRef myobject
set myalchemyskill to GetAlchemy
type (long): ref->xRefType
Gets the object type of the reference and is literally the four byte of the type name
as a number.

1230259009 = ACTI (Activator)


1212369985 = ALCH (Alchemy/Potion)
1095782465 = APPA (Alchemy Apparatus)
1330467393 = ARMO (Armour)
1263488834 = BOOK (Book/Scroll)
1414483011 = CLOT (Clothing)
1414418243 = CONT (Container)
1095062083 = CREA (Creature)
1380929348 = DOOR (Door)
1380404809 = INGR (Ingredient)
1129727308 = LEVC (Levelled Creature)
1230390604 = LEVI (Levelled Item)
1212631372 = LIGH (Light)
1262702412 = LOCK (Lockpick)
1129531725 = MISC (Misc. Item)
1598246990 = NPC_ (NPC)
1112494672 = PROB (Probe)
1095779666 = REPA (Repair Tool)
1414546259 = SCPT (Script)
1195658835 = SNDG (Sound Generator)
1413567571 = STAT (Static)
1346454871 = WEAP (Weapon)

reference (long): ref->xGetRef object_id (string)


Returns a reference to one of the active objects matching the objectid or a 0 if no
active object is found. Active objects are in one of the loaded cells or are
persistent like NPCs. This is most useful to locate NPCs and unique objects. If
you try to find a mudcrab you could either find none (if you are far from the
coast) or one of the many nearby (if you are near the coast).
reference (long): ref->xGetCombat
Returns a reference to this NPC/creature's combat target or 0 if the NPC/creature
is not in combat.

reference (long): xGetPCTarget


Returns a reference to the object in the player's crosshair or 0 if the player is not
looking at anything that can be manipulated by the player.
reference (long): xFirstNPC
Returns a reference to one of the NPCs or Creatures in the players cell or 0 if
there are none. The reference is simply the one on the top of a list of all NPCs and
Creatures in the cell and you can use the xNextRef function to find the rest.
reference (long): xFirstItem
Returns a reference like FirstNPC except this one is the top of a list of ordinary
objects the player can activate (and usually carry).
reference (long): xFirstStatic
Returns a reference like FirstNPC except this one is the top of a list of static
objects (the non-carriable, non-interactive ones).
reference (long): xNextRef current (reference, long)
Returns the 'next' reference in one of the three lists of objects in the current cell
(NPC, Item, and Static) after the current one. If the player is outside, the list will
cycle through all 9 loaded exterior cells which may be too much to do in a single
frame.

Math
distance (float): ref->xDistance target (reference)
Similar to the original GetDistance function but takes a reference variable as the
target instead of an objectid string. Like the original, it uses the editor position not
the current position for non-persistent objects.
root (float): xSqrt x (float)
Returns the square root of the value. (Use Tribunal's GetSquareRoot instead.)
hypotenuse (float): xHypot a (float), b (float)
Returns the hypotenuse for sides a and b, c = sqrt(a*a + b*b). Unlike xSqrt this is
more efficient than calculating the formula inside the script.
radians (float): xDegRad degrees (float)
Converts a value from degrees to radians.
degrees (float): xRadDeg radians (float)
Converts a value from radians to degrees.
cosine (float): xCos radian (float)
Returns the cosine of the angle (which given in radians).
sine (float): xSin radian (float)
Returns the sine of the angle (which given in radians).
tangent (float): xTan radian (float)
Returns the tangent of the angle (which given in radians).
radians (float): xArcCos cosine (float)
Returns the arc cosine (in radians) of the value.
radians (float): xArcSin sine (float)
Returns the arc sine (in radians) of the angle.
radians (float): xArcTan tangent (float)
Returns the arc tangent (in radians) of the angle.

AI and Movement
ref->xAITravel x (float), y (float), z (float)
A wrapper function for the original AiTravel to allow variables.
new_object (reference): xPlace objectid (string)
Places an object of type objectid behind the player and returns a reference to the
new object.
ref->xPosition x (float), y (float), z (float), rotation (float)
A wrapper function for the original Position to allow variables.
ref->xPositionCell x (float), y (float), z (float), rotation (float), cellname (string)
A wrapper function for the original PositionCell to allow variables.
ref->xStartCombat target (reference)
A wrapper for the original StartCombat to take variables.

Inventory
objectid (string), count (long), next (reference): ref->xInventory
Returns three values based on the inventory of the current container, NPC, or
creature. The first is the objectid of one of the items in inventory. The second is
the number of that particular item found in the inventory. The third is a reference
that can be passed to the xNextStack function to find the rest of the items in the
inventory. All three results will be 0 if there are no items in the inventory (and
just the third will be zero if there is only one item in the inventory). (It is not
possible to get a normal reference to objects inside an inventory. The reference
returned by this function is of a unique type and should only be used with
xNextStack.)
objectid (string), count (long), next (reference): xNextStack next (reference)
Returns the next item in the inventory stack. The parameter to this function is the
third result from either xInventory or this function. Attempts to pass any other
kind of reference to this function or use this reference with other functions will
result in errors and possibly crash the game. If the inventory of the current NPC,
creature, or container is changed (items added or removed) it will make the
current stack reference invalid and you should get a new stack reference with
xInventory.
objectid (string), count (long), type (long), value (long), weight (float), name (string),
next (reference): ref->xContentList next (reference)
An alternative to both the xInventory and xNextStack functions, which returns
seven values based on the inventory of the current container, NPC, or creature
rather than three. If the input parameter value is 0, the first item in the current
container, NPC, or creatures is returned (like xInventory). The seventh (last) value
returned can also be used as the input parameter to access the next item in the
inventory (like xNextStack). Whenever the items in the container change, the next
reference may be invalid and you should start again with a value of 0 for the input
parameter.
The first return value is the objectid of one of the items in inventory. The second
is the number of that particular item found in the inventory. The third is the type
of that item using the codes listed for the xRefType function. The next three
parameters are the value, weight, and printable name of the item unless the object
is of the Levelled Item type. For LEVI objects, the value and weight will be listed
as 0 and the name field will contain a randomly selected object id for one random
item selected from the levelled list. The normal levelled list rules aren't followed
and lower level items are always more likely than higher level items. (In the
future, the selection of random items may be improved.)
ref->xAddItem objectid (string), count (long)
A wrapper for the original AddItem to take variables.
ref->xRemoveItem objectid (string), count (long)

A wrapper for the original RemoveItem to take variables.


equipped (long): ref->xHasItemEquipped objectid (string)
Returns 1 if the npc or creature has the object equipped or 0 otherwise.
ref->xEquip objectid (string)
A wrapper for the original Equip to take variables.
ref->xDrop objectid (string), count (long)
A wrapper for the original Drop to take variables.
ref->xAddSpell spellid (string), count (long)
A wrapper for the original AddSpell to take variables.
ref->xRemoveSpell spellid (string), count (long)
A wrapper for the original RemoveSpell to take variables.

Attributes
strength (float): ref->xGetBaseStr
Returns the base (unmodifed) strength for the NPC.
intelligence (float): ref->xGetBaseInt
Returns the base (unmodifed) intelligence for the NPC.
will (float): ref->xGetBaseWil
Returns the base (unmodifed) willpower for the NPC.
agility (float): ref->xGetBaseAgi
Returns the base (unmodifed) agility for the NPC.
speed (float): ref->xGetBaseSpe
Returns the base (unmodifed) speed for the NPC.
endurance (float): ref->xGetBaseEnd
Returns the base (unmodifed) endurance for the NPC.
personality (float): ref->xGetBasePer
Returns the base (unmodifed) personality for the NPC.
luck (float): ref->xGetBaseLuc
Returns the base (unmodifed) luck for the NPC.

NPC Properties
female (long): ref->xIsFemale
Returns 1 if the NPC is female and 0 otherwise.
trader (long): ref->xIsTrader
Returns a 0 if the NPC/creature doesn't barter for items, otherwise it is a value
that represents the combination of items the merchant will trade. New functions
for each individual type are needed.
trainer (long): ref->xIsTrainer
Returns a 1 if the NPC/creature is a Trainer and 0 otherwise.
provider (long): ref->xIsProvider
Returns a non-zero value if the NPC/creature sells spells, repairs armor and
weapons, or is an enchanter or spell maker. Otherwise it returns a 0.
service_mask (long): ref->xGetService service_mask (long)
Combines the features of xIsTrader, xIsTrainer, and xIsProvider in a single
function with one return value. The service values are shown in the following
table and if an NPC offers more than one service the sum of the service numbers
will be returned. The mask parameter can be used as a filter to limit the return
value to only consider the services indicated.
Value

Service

Barters for Weapons

Barters for Armour

Barters for Clothing

Barters for Books

16

Barters for Ingrediants

32

Barters for Lockpicks

64

Barters for Probes

128

Barters for Lights

256

Barters for Alchemical Apparatus

512

Barters for Repair Tools

1024

Barters for Miscellaneous Items

2048

Sells Spells

4096

Barters for Enchanted Items

8192

Barters for Potions

16384 Provides Training


32768 Provides Spellmaking Service

65536 Provides Enchanting Service


131072 Repairs Armor and Weapons
Use a mask of 16384 to see if the NPC is a trainer and the function will either
return 16384 or 0. Use a mask of 96 (32+64) to see if the NPC sells thieving
equipment. The value returned could be 0, 32, 64, or 96, but won't any other
values even if the NPC provides other services too.
ref->xSetService service_mask (long)
Uses the value parameter to change the NPC to offer the set of services
represented by the number. The service number values are used and any old
services are ignored, so using a value of 8 will make the NPC a bookseller and a
value of 131587 (1+2+512+131072) is typical for smiths. The values changed by
this function are not permanent and may be reset after 72-hours or a game reload.
ref->xModService service_mask (long)
Uses the value parameter to modify the services offered by an NPC. A positive
value adds that service (or set of services) to those already offered. A negative
value will remove a service or service. The changes are not permanent.
gold (long): ref->xGetBaseGold
Returns the base amount of barter gold assigned to the NPC (or creature) in the
Construction Set. This is the value that resets automatically each day.
gold (long): ref->xGetGold
Returns the current amount of barter gold possessed by the NPC (or creature). The
base gold amount is used if you haven't bartered with the NPC/creature recently.
ref->xSetBaseGold gold (long)
Changes the base amount of barter gold assigned to the NPC (or creature).
Unfortunately this change won't be saved with the save game so you will need to
reset it after each game reload or after the "72-hour bug" affects the merchant.
ref->xSetGold gold (long)
Changes the current amount of barter gold possessed by the NPC (or creature).
This value is stored in save game files so it will survive a game reload. Setting
this will have no effect if you haven't recently bartered with the NPC/creature.
(But setting both this and the base gold amount at the same time will likely do
what you want.)

Item Properties
value (long): ref->xGetValue
Returns the gold value of the object. Objects that can't be sold return 0.
owner (string): ref->xGetOwner
Returns a 0 if the object is not owned, the objectid of the owner of the item if it is
owned by a specific NPC or the string "unknown" if it is owned by a faction or
controlled by a variable.
weight (float): ref->xGetWeight
Returns the weight of the object for carriable objects. Returns the maximum
capacity of a container and 0 for all other objects. (When the player places
multiple copies of one item on the ground the stack is considered one item and
this function will calculate the value for the group not just a single item of that
type.)
encumberance (float): ref->xGetEncumb
Returns the total weight of all objects in the inventory of a container, NPC, or
creature. Levelled list items don't have a weight but they are assigned a weight of
0.001 by this fnction. If any of the items in the group are respawning items then
the resulting weight will be negative.
quality (float): ref->xGetQuality
Returns the quality of alchemical apparatus, lockpick, probe, and repair tool
items.
condition (long): ref->xGetCondition
Returns the current condition for armor and weapons and remaining uses for
lockpicks, probes, and repair tools.
condition (long): ref->xGetMaxCondition
Returns the maxium condition for armor and weapons and maximum uses for
lockpicks, probes, and repair tools.
charge (float): ref->xGetCharge
Returns the current charge on a 'cast when used' or 'cast when strikes' enchanted
item. Constant effect and non-enchanted items return 0.
charge (float): ref->xGetMaxCharge
Returns the maximum charge on an enchanted item.
success (long): ref->xSetValue value (long)
Sets the gold value of the object. Returns 1 if succesful, 0 if failed.
success (long): ref->xSetWeight weight (float)
Sets the weight of the object. Returns 1 if succesful, 0 if failed.
success (long): ref->xSetQuality quality (float)
Sets the quality of alchemical apparatus, lockpick, probe, and repair tool items.
Returns 1 if succesful, 0 if failed.

success (long): ref->xSetCondition condition (long)


Sets the current condition of armor and weapons. Armor must not be at 100% or
this function will fail. It must have already sustained some damage. Returns 1 if
succesful, 0 if failed.
success (long): ref->xSetMaxCondition condition (long)
Sets the maxium condition for armor and weapons and maximum uses for
lockpicks, probes, and repair tools. Returns 1 if succesful, 0 if failed.
success (long): ref->xSetCharge charge (long)
Sets the current charge on a 'cast when used' or 'cast when strikes' enchanted item.
May not work if the item has never been used. Returns 1 if succesful, 0 if failed.
success (long): ref->xSetMaxCharge charge (long)
Returns the maximum charge on an enchanted item. Returns 1 if succesful, 0 if
failed.

Keyboard Input
code (long): ref->xKeyPressed code (long)
Monitors the status of the keyboard (and mouse buttons). This can be similar to
GetPCSneaking, but actually detects whether a particular key is really being
pressed. If input parameter code is a Virtual Key Code (between 1 and 254) the
return value will indicate the status of that key and a non-zero value means the
key is being pressed. If the input code is 0, then on each call, the function will
return the key code for the key (or one of the keys) currently being pressed. The
specific values for the virtual key codes can be found in the Microsoft
documentation at http://msdn.microsoft.com. Some of the codes match different
keys on different keyboard layouts.
length (long), text (string): ref->xTextInput message (string), endcode (long)
This allows you to directly read keyboard input from the user and the results will
be returned as a string. Pass a string and a virtual key code to the function. The
function will wait for a key to be pressed and then take one of three actions. If the
key pressed matches the endcode parameter, the string and its length are returned.
If the key pressed is a printable ASCII character, the character is added to the
string and the string and the number 0 are returned. If the key is RETURN or
BACKSPACE, a new line is started or one character is removed from the string,
and the modifed string and a 0 are returned. The function returns after each key
press so that the current value of the string can be shown with xMessageFix and
MessageBox but the string should only be used normally after the length is
returned. Player controls should be disabled while this function is used.
Example:
long endchar
long message
long length
ifx ( endchar )
else
; Initialization needed when endchar
== 0
DisablePlayerControls
set endchar to 13
; RETURN key
setx message to xStringBuild ""
; Empty string to start
set length to 0
return
endif
ifx ( length )
else
; Actual string edit while length == 0
setx length message to xTextInput message endchar
; Three boxes, makes it appear as if there is one set that
changes.
MessageBox ""
; Spaces and trailing % hide old characters while using
Backspace.
xMessageFix "%s
%" message

MessageBox "
"
MessageBox "Enter a message and press ENTER when it is
complete."
return
endif
EnablePlayerControls
; The message is complete now

length (long), text (string): ref->xTextInputAlt message (string), endcode (long)


This function is identical to xTextInput except that the function simply checks the
status of keys and returns immediately rather than waiting for a key to be pressed.

File I/O
xFileRewind filename (string)
Moves the current reading position to the start of the file. Call this or xFileSeek at
the start of any script which uses file reading or writing functions, otherwise you
will have problems with the current file position not being as expected.
xFileSeek filename (string), offset (long)
Moves the current reading position to the specified offset in the file. You should
call this or xRewind every frame before using other file functions. (This function
isn't very useful if the file contains string data.)
matches (long), ...: xFileReadText filename (string), pattern (string)
Read a text string from from the file at the current reading position. The current
position is then advanced. The pattern string is then used to extract data from the
string just read; the first return value indicates how much of the pattern is
matched. The values matched by the pattern are also returned. The patterns and
return values are the same as for the xStringParse function with one addition:
placing a single % sign at the end of the pattern will cause the read routine to stop
when it gets to the end of a line (CR/LF) allowing you to use this to read a normal
text file instead of a binary file. Without the trailing % sign on the pattern this will
read up to the first NULL character or to the end of the file if it doesn't find a
NULL character.
xFileWriteText filename (string), format (string), ...
Writes formatted string to the file at the current position and advances. The file is
then truncated at the current position (just after the end of the new value), so you
cannot use this to modify the values in the middle of an existing file. The
formatting rules are the same as for the xStringBuild function with one addition.
Placing a % at the end of the pattern will suppress the NULL that is normally
printed, so a format string ending with "%N%" can be used to create a normal text
file.
count (long), ...: xFileReadShort filename (string), count (long)
Reads the number of SHORTS (2 bytes) requested from the file at the current
reading position. The current position is then advanced. Returns the number of
values actually read followed by the values.
count (long), ...: xFileReadLong filename (string), count (long)
The same as xFileReadShort but reads LONGS (4 bytes).
count (long), ...: xFileReadFloat filename (string), count (long)
The same as xFileReadShort but reads FLOATS (4 bytes).
text (string): xFileReadString filename (string)
Similar to xFileReadShort but reads a single 'C'-style NUL ('\0') terminated string
from the file. If a string cannot be read it returns a 0.
xFileWriteShort filename (string), value (short)

Writes a (2 byte) SHORT value to the file at the current position and advances.
The file is then truncated at the current position (just after the end of the new
value), so you cannot use this to modify the values in the middle of an existing
file.
xFileWriteLong filename (string), value (long)
The same as for xFileWriteShort but stores a (4 byte) LONG value.
xFileWriteFloat filename (string), value (float)
The same as for xFileWriteFloat but stores a (4 byte) FLOAT value.
xFileWriteString filename (string), text (string)
The same as for xFileWriteShort but stores a 'C'-style null terminated string to the
file.

Strings
cellid (string): xPCCellID
Returns a string containing the name of the current cell.
objectid (string): ref->xRefID
Returns the objectid string of the object.
cellid (string): ref->xMyCellID
Returns a string containing the name of the cell the object (intended to be used
with references to unique NPCs) inhabits. So fargoth"->xMyCellID would
return "Seyda Neen" unless you've lured him into the wilderness for some reason.
Useful for locating that missing companion. Can't locate items stored in
containers or inventory.
name (string): ref->xGetName
Returns a string containing the name (suitable for display, not the objectid) for the
object or 0 if the object doesn't have a name. The NPC who falls from the sky
near Seyda Neen has an object id of "agronian guy" but his name is "Tarhiel"
when you look at his corpse.
ref->xSetName new_name (string)
Uses the value parameter to change the NPC's name. The values changed by this
function are not permanent and may be reset after 72-hours or a game reload.
Currently only works for NPCs.
objectid (string): ref->xGetBaseID
Returns the base part of of the objectid for the object. This is really intended for
use with NPCs. There are 36 diseased Dreamers who share the object id
"dreamer" but if you use the xRefID function on one of them you will get an id
that is unique to that particular NPC such as "dreamer000002", this function
would only return "dreamer".
order (long): xStringCompare s1 (string), s2 (string)
Compares the two strings based on alphabetical order and returns 0 if they are
equal, a negative number if the first string would appear first, and a postive
number if the second string would appear first.
length (long): xStringLength text (string)
Returns the number of characters in the input string.
count (long), ...: xStringParse pattern (string), source (string)
Identifies and extracts data from the source string based on the pattern string. The
first return value is a long indicating how much of the pattern matched
successfully. The values matched by the pattern will then be returned in order. For
example, the following statement will put value of 37 in the long variable lval, a
value of 2.4 in the float variable fval, the string "Golden Egg" in the string
variable sval, and the value 4 into matches to indicated that all of the pattern
successfully matched. For example:

set matches lval fval sval to xStringParse "%d %f %s"


"37 2.4 Golden Egg"
In the pattern string, all of the special features begin with a % symbol. Some,
simply match special characters that can't otherwise be typed in the pattern string.
%% matches a single % sign.
%n matches the new line marker, CR/LF.
%q matches the " quotation mark.
The rest return the values matched so they can be stored in variables with setx.
%d matches a decimal integer and the value is returned as type long.
%h matches a hexadecimal integer and the value is returned as type long.
%f matches a real number and the value is returned as type float.
%s matches the rest of the string and returns it as type string.
%l matches exactly four characters and returns them as type long.
The uppercase forms %N, %Q, %D, %H, %F, %S, and %L also work. Only one
of these takes a precision specifier, and it is best explained by examples:
set matches sval lval to xStringParse "%.0s_%d"
"gold_001"
In this case, the special pattern "%.0s" is followed by a "_" character, so only
"gold" will be stored in the string sval, a value of 1 will be in lval, and matches
will be 3. Matches is normally one more than the number of values returned to
indicated that in addition to filling all of the variables the entire pattern was
matched successfully. You could use a pattern simply for string comparison.
set matches lval to xStringParse "%d Apples"
somestring
If the somestring variable really holds the string "43 Apples" then matches will be
2 to indicate that the pattern was matched completely. If somestring were "47
Pears" then matches will be 1 to indicate that the first variable was filled (with 47)
but that the rest of the pattern failed to match. If somestring were "Hello" then
matches will be 0 to indicate that not even the first variable was filled correctly.
result (string): xStringBuild format (string), ...
Returns a new string that is constructed based on the format string and any other
variable values as needed. The format string is similar to those for MessageBox
with % indicating some special character or variable substitution. Some patterns
can be used to place special characters into the string:
%% a single % sign is placed in the string.
%n a new line marker (CR/LF) is placed in the string.
%q a " quotation mark is placed in the string.
The rest are used to insert values from the remaining parameters into the output
string.
%d a short or long value is inserted as a decimal integer.
%h a short or long value is inserted as a hexadecimal integer.

%f a float value is inserted as real decimal number.


%s a string value is inserted.
%l a long value is inserted as a four character string.
The uppercase forms %N, %Q, %D, %H, %F, %S, and %L also work. The float
specifier takes a precision specifier just like the MessageBox command. The
format "%.3f" will print a floating point value with three digits after the decimal
point. The string specifier can take two numbers in its specifier.
%2s
skips the first two characters of the string, but inserts the rest.
%.3s inserts only three characters of the string.
%4.5s skips 4 characters, then inserts the next 5 characters of the string.
To put "World, Hello!" into str, you could use the following statement.
set str to xStringBuild "%7S%5.2s%.5S!" "World, Hello
The compiler doesn't currently support more than 12 parameters at a time.
match (long): xStringMatch source (string), pattern (string)
Performs a Regular Expression (R.E.) match on source using the pattern in
pattern. Regular expressions are pattern matching expressions. MWSE uses the
RE library from the Boost C++ library, from www.boost.org. The regular
expression style is the Perl syntax; please see the Boost documentation for full
documentation. However, here is a partial quick summary:
In regular expressions, a number of characters have special meanings:
.
^
$

Matches any one character.


Matches the beginning of the string.
Matches then end of the string.
Groups a sub-expression (see below).
( and )
*
Makes the preceeding item or group match zero or more times.
?
Makes the preceeding item or group match zero or once.
+
Makes the preceeding item or group match one or more times.
Makes the preceeding item or group match exactly integer times.
{integer}
{int1,int2} Makes the preceeding item or group match from int1 to int2 times.
Alternation; makes the pattern match either the item on the left of
|
the | or the item on the right.
Matches a single character from the set character set. The set can
contain individual characters, or ranges of the form a-b, which
[character matches all characters between a and b, including a and b. (For
example, [A-Z] will match upper case letters.) If the character set
set]
begins with ^, then it will match any character except those in the
character set.
[[:name:]] Matches a single character from the pre-defined set name.

\character

\d
\l
\s
\u
\w
\D
\L
\S
\U
\W
\<
\>
\b
\B

Matches the character; that is, removes the special meaning, if any,
from character. (For example, "." matches any single character,
but "\." matches the period character.)
Match a digit (0-9).
Match a lower case letter (a-z).
Match whitespace (space, tab).
Match an upper case letter (A-Z).
Match a word (a string of letters, digits, and underscores)
Match anything but a digit.
Match anything but a lower case letter (a-z).
Match anything but whitespace (space, tab).
Match anything but an upper case letter (A-Z).
Match anything but a word.
Match the start of a word.
Match the end of a word.
Match the end or start of a word.
Match anything but the end or start of a word.

Examples:
"(^Mage's Guild)|(, Guild of Mages$)" This will match any string
that starts with "Mage's Guild", or ends with ", Guild of Mages".
"( Tomb(, level \d+)?)|( Barrow)$" This will match any string
ending with " Tomb", " Tomb, level digits", or " Barrow" - in other words, just
about any tomb/barrow type location.
xLogMessage format (string), ...
Writes out formatted strings to the log file (MWScriptExtender.log) Works much
like MessageBox but with the additional formatting options described for
xStringBuild. A trailing % in the format string will suppress the printing of the
new line sequence allowing a single line of text to be created with two or more
xLogMessage calls. The number of parameters specified in the formatstring
MUST match those supplied or there will be trouble.
xMessageFix message_format (string), ...
This function allows you to use strings from variables with the MessageBox
function with a few restrictions. First, the MessageBox command must
immediately follow this one. Second, the number of strings for this function must
match the number of strings for the MessageBox. Third, the MessageBox can
have buttons but it can't use variables. And finally, the values of the strings used
on the MessageBox will be replaced with the values from xMessageFix, but the
MessageBox strings set a maximum size for each of the xMessageFix strings (it's

OK if the MessageBox strings are longer than the MessageFix ones). Using
aMessageFix can take both the STRING variable and literal string types and each
string acts as a format string as described for the xStringBuild function. If a string
ends in a single % and the formated string takes less space than the matching
string from MessageBox, the remaining characters of the MessageBox string will
be used.
While it is possible to use formatted messages and buttons, it is best to format
strings with xStringBuild if there are buttons involved because of the limit of
12 parameters per function.
Example:
long thiscell
setx thiscell to xPCCellID
xMessageFix "Teleport Fargoth Where?" thiscell "Seyda Neen" "Red
Mountain"
MessageBox "Send Fargoth to Location" "My Cell" "His Original
Location" "Vos"

If you are in Caldera, the Arena in Vivec, or Ald-Ruhn the MessageBox would
show:
Teleport Fargoth Where?
Caldera
Seyda Neen
Red

Teleport Fargoth Where?


Vivec,
Seyda Neen
Red

Teleport Fargoth Where?


Ald-Ruh
Seyda Neen
Red