AniMisc
Previous Next


Morrowind modding



I'm not really a Morrowind modder. Morrowind modders are like hackers, only for Morrowind and its Construction Set. I'm intimidated by their highly technical discussions on how to produce a certain effect that should be easy to produce, only the gamemakers, having made an RPG, thought that fans would want to create RPG-type mods with a few monsters to kill, some treasure to snatch, perhaps some dialogue and text for the diary. What fans in fact want to create is a complete personalized virtual playground using Morrowind's game engine. It's a bit like how Maxis underestimated the kind of customization that Sims fans wanted to make. Morrowind is slightly worse: firstly, not all syntactical features are covered in the helpfile, and some are broken. Secondly, conditions that should be easy to test for, are not. Take swimming. When a character is deep enough in water, the wading animation changes to a swimmming animation. So the game "knows" the character is in water. Now I need a script that asks "is the character swimming or not" because I've added a bottle that can be filled with water, but only when there is water near, and water is certainly very near when you're up to your neck in it. Well, even though the game "knows", there is no way of asking it. The only, very roundabout, way of knowing if your game character is swimming, as I learned on a forum discussion concerning a bathing mod, is to ask the game whether any of the splish-splash swimming sounds are being played. For your own character, that is. I don't know how I would go about testing this for a companion character. (I do now.)

What I am is, in all senses of the word, an amateur. The game booklet said I could add and change things, so I did. Or rather, I tried to. I made a relatively easy mod to set things right concerning a certain Fargoth, and embarked on a much more difficult mod to teach the arrogant Dunmer (or rather, one arrogant Dunmer) a lesson in humility, which I soon became stuck on. I don't even know if I'll ever finish it. But in the course of doing so, I educated myself on scripting, mostly through version 9 of the fan-written Morrowind Scripting for Dummies (MSFD9) and discovered a few things, not all of them mentioned in this document. So, for anyone surfing on the quirks of Morrowind modding, I thought I'd share.

After using the latest patch and finding out it wasn't really the latest patch (which means some quirks may have due to not having used the most up-to-date executable) I've split the list up into real quirks and technical issues.

Technical issues:

Modding quirks:

Undocumented keys

Not to do with modding itself, but handy when testing mods. Two keyboard shortcuts I found on Morrowind sites while surfing: if you want to take something out of your inventory of which you have more than one, for instance: 9 Cure Disease potions, holding down the Ctrl key while clicking on the item will pick up only one item while skipping the usual question of how much to take, while holding down the Shift key picks up the whole lot without question. I also read that as long as you hold down the Ctrl key, the number of times you click on the item will be the number of items picked up, but that didn't quite work for me; Ctrl-click did pick up only one of a bunch of items, but Ctrl-click-click picked it up and put it back again. Ctrl-click-click-click picked it up, put it back and then picked it up again. I was never able to pick up more than one item this way.

Not undocumented, but simply a default keybinding that I discovered by accident before I saw that it can be changed in the game options: pressing Q once is the same as keeping W pressed down: the character keeps walking. Press W, or Q again, to stop the walking. Opening a menu temporarily stops the walking. Q also works with Shift (run) and Ctrl (sneak). Using Q and Capslock saves wear on the keyboard. (The Q key functionality was added in a game update, and is mentioned in the game's "readme.txt".)

Back to technical issues

Crash caused by battery

When the game has a CTD (Crash To Desktop) this can have a number of causes, like script errors and trying to delete an object that is inside someone's inventory. Or the laptop battery may be almost empty. I work on a laptop and, to conserve the battery, let it run empty before recharging it, instead of having the laptop plugged in all the time. While playing, I can't see the state of the battery, and I tend to forget the time, so often either the computer announces that it will go into hibernation - and when waking it up, the game will crash after a while - or the screen just goes black and when I have my desktop back, I see the battery icon with a red cross through it. Sudden unexplained script errors can also be a matter of the battery running empty. A CTD can also occur just before an extra bit of animation is about to occur, notably the player dying in a fight with many creatures and/or NPCs, even when the battery is not almost empty. It seems that whenever the graphics card doesn't get the power it needs, the game shuts down.

When a dialogue screen (especially the character creation dialogue) is opened while the computer goes into hibernation, the game may, after a restart, continue without problems. When a book or journal screen is open, it will crash. I've replaced the "low battery" popup with a jarring system sound (can be heard even through the background music) to reconnect the laptop to a power source on time and not lose all unsaved changes due to the computer going into hibernation.

Back to technical issues

The Siege at Firemoth plugin

The official plugin "Siege at Firemoth" causes problems with a lot of fan-made plugins. This doesn't mean that there is anything wrong with the fan-made plugins. I'm still thinking what to do about that. Changing the file date to make that plugin load last hasn't helped. (The problem mysteriously resolved itself, see DaysPassed turns up in Morrowind-only installation.)

Back to technical issues

Game lag in Windows 7

I thought this was a problem caused by playing an old 32-bit era game on a computer with a 64-bit processor and a 64-bit version of Windows 7, until I found I had a 64-bit processor and a 32-bit version of Windows 7. I'm still not sure what the exact reason is, but it has to do with "rundll32.exe". Usually, the game starts without problems. Sometimes, I have to click the icon twice before the game runs, and it will be slow and choppy, a Desktop gadget showing the CPU at 100%. Using Ctrl-Alt-Del to find what was running, I saw that the process hogging the CPU was "rundll32.exe". Deleting this process did not stop the game, but sped it up to its normal framerate. So I found a workaround: start Morrowind (click icon twice if necessary), this opens the Morrowind Launcher. Open the Task Manager and delete the "rundll32.exe" process. Then start the game.

I revisited this problem when I wanted to install the Morrowind Script Extender. This is as simple as putting the MSE executable in the same directory as the Morrowind executable and clicking the MSE executable, which will then start Morrowind. If I clicked the MSE executable, nothing happened; if I then clicked the Morrowind executable, it would start, but crash if I wanted to start a new game (as there were no save games to load). So I looked again at what happened if I started the standard Morrowind: first "rundll32.exe" is run but exits, it runs a second time and stays in memory this time, then the Morrowind Launcher opens and the game can be started from there. If I don't use the Morrowind shortcut but double-click on Morrowind.exe, the game starts directly without loading "rundll32.exe", and without lagging. So the problem is the Morrowind Launcher. Fortunately, the textfile included with the Morrowind Script Extender explains how to make a shortcut that will bypass the Launcher and start Morrowind directly.

Update: I've found that Oberon Media games ran slowly under Windows 7 because Windows was constantly checking for a network connection; disabling all network devices in the system settings solved the problem. It also seemed to solve the "rundll32.exe" problem with the Morrowind Launcher, although I haven't tested that further because nowadays, I only run the game directly from "Morrowind.exe", and only start the Morrowind Launcher to change what mods are loaded, then shut it down again; neither causes lag, and I get to keep my internet connection.

Another update: having bought a new laptop with a 64-bit processor and installed a 64-bit version of Windows 7 on it, I get the "rundll32.exe" problem rarely, if at all; the game may take a bit of time to start, but even if I click its icon twice, the first instance doesn't hang in memory but simply quits with a "game already running" message.

Back to technical issues

The no-CD patch that wouldn't run the Morrowind Script Extender

What it says on the tin: I'd downloaded a no-CD crack for the complete game including expansions by GimpsRUs, and MSE would not run with it. After many tries and much frustration, I spotted the cracked executable's version number, which started with "15"; although it claimed to be the latest patched version, clearly the final patch (number 1820) had come out after it was made. So I found another crack by DRUNK which did use the right version. (Maybe this is why PositionCell with float variables hadn't worked; it's supposed to work from Tribunal onwards, but maybe it was broken and the latest patch fixed it. Then again, PositionCell and variables is an iffy proposition.)

Back to technical issues

Collision boxes and the quicksand effect

Collision boxes are the invisible boundaries of a 3D model's "personal space". If a 3D model had the shape of a cube, its collision box could be exactly as big as its outline. But 3D models often have very irregular shapes. Take a bush, for instance. It will be widest in the middle. But if one were to draw a box around the bush that would totally contain it, there would be plenty of free space at the top and bottom that is not occupied by the bush, yet falls within this box. Collision boxes serve, as the name suggests, to detect collision: to see when shape A touches shape B. If a real person walks into a wall, the solidity of that wall is enough to stop that person moving, and the person will be sensitive enough to be (often painfully) aware of having just collided with a wall. But 3D objects rendered in a computer game are neither solid nor sensitive, and their collision boxes are used to fake both.

I found this out when constructing a cosy little dungeon that starts with a slope leading into a main room which then sends out several corridors into other, lower rooms. One of the corridors ran exactly under the slope, but with plenty of room between them. Nevertheless, when a character walked down the slope, I would see that character sink into the floor up to the armpits, to finally drop into the corridor below. How could this happen?

Looking at the collision boxes in the editor made everything clear. The collision boxes of the slope and underlying stairway touch each other. This is because both collision boxes are very high to stretch from the highest to the lowest point of these diagonal shapes. Since they touch, the game is confused about where one ends and the other begins, and the character drops from one into another.

I replaced the slope with sections of straight corridor, which, being almost cube-shaped, had collision boxes barely bigger than themselves. No more touching. Problem solved.

Needless to say, this also happens in the unmodded vanilla game, when bounding boxes overlap. That's why, after some jumping around, I found myself buried up to the waist in the walkway leading to Seyda Neen's lighthouse; I was standing on a rock just underneath it. Continued jumping got me out and on the planks again.

As an amusing aside, collision detection seems to be turned off between NPCs who are following the PC; they tend to all wind up in the same position, especially after passing through loaddoors (doors that teleport the PC to another cell). Their overlapping meshes lead to funny visuals like a Khajiit with Argonian horns.

Back to technical issues

Cursor keys and the console command line

This is really silly, but something that took me years to discover, and all this time I've been typing my fingers off. The console command line, being a command line, doesn't accept Windows-style copy and paste with Ctrl-C and Ctrl-V. What it does accept, like a bash or in some cases MS-DOS command line, is the cursor-up and cursor-down keys to scroll through the history of commands. So, if I need to issue a series of similar commands, I just go to the previous command, alter it and press Enter.

Back to technical issues

Confused followers

It can happen to any companion, ie. NPC in AIFollow mode. I'm briefly out of reach and the companion runs up to me and then keeps running around as if chasing an invisible rabbit. Or I use Almsivi Intervention, remember I've left a companion behind, go back using PositionCell in the console and the companion is dashing around, madly trying to get to some unreachable point and ignoring me. No amount of approaching them and starting dialogue to make them follow will cure them of this behaviour, so I've always reloaded the latest save. Apparently, judging from other modders' companion scripts, StartCombat will break them out of this rut. If so, typing "NPCname->StartCombat NPCname" in the console, followed by a StopCombat command, should safely calm them down.

Back to technical issues

Vanity mode versus 3rd person view

Vanity mode and 3rd person view seem to be the same thing, and they do overlap, so I'll explain what either does. Toggling between 3rd person view ( looking down on player character's whole mesh) and 1st person view (looking straight in front of the player character and seeing just its wrists, hands and any held shields and weapons) is done with the Tab key. In either mode, moving the mouse makes the player character look around; holding down Tab in 3rd person view while moving the mouse changes the camera, allowing the player to be looked at from different angles. The related script/console commands are PCGet3rdPerson (which returns 1 if the view mode is 3rd person), and the view mode changers PCForce3rdPerson and PCForce1stPerson.

Vanity mode is a special type of 3rd person view that happens when the user hasn't interacted with the game for a while, in the same way as a screensaver, and only when it has been enabled. It shows the player character in 3rd person view with a slowly rotating camera. Pressing Tab, or any key at all, will end vanity mode view just as it would end a screensaver, and return to the previous view mode, although while in vanity mode, PCGet3rdPerson will return 1. This mode's commands are EnableVanityMode, DisableVanityMode and GetVanityModeDisabled. The enabling and disabling commands don't instantly start or stop the vanity view mode, they just tell the game whether to have this screensaver feature. Switching to vanity view is done with the strictly console command ToggleVanityMode, or its shortened version TVM, as using any key inside the game itself will instantly end this mode.

Back to technical issues

Different versions installed: the snowflake glitch

The snowflake glitch is the error message that a snowflake texture can't be found, when starting Morrowind with Bloodmoon installed. It can mean that the Bloodmoon.bsa file is damaged, or (especially if installed to C: under Windows Vista or later) the user doesn't have the rights to view that file (which is why the game should be installed as administrator). Or it can mean that there are two parallel installations of Morrowind, and Windows is looking in the wrong directory.

I have vanilla Morrowind and Morrowind GOTY Edition (Game of The Year, contains both Tribunal and Bloodmoon) installed side by side. First, Morrowind was installed, and all changed/added keys were saved in a .reg file. There are various utilities to track registry changes, or the whole registry can be saved to file before and after installation, and the two files compared. Then, GOTY was installed to a different directory, the relevant registry keys were saved to a .reg file again, the two files were compared, and the important differences saved as "MW.REG" and "MWGOTY.REG". This had to be repeated any time I reinstalled the game on a newer computer, as I found the registry key formats differed subtly between different Windows versions.

There are a few registry keys essential to the game, namely those that tell it where to look for its game files. Starting "MWGOTY" while the path in the registry points to "MW" is one way to produce this error. So, before I start either game version, I first have to click on the right regfile to adjust the game path.

A double install may also do strange things to the Morrowind entry in the Game Explorer. I searched for "GameUX" in the Windows utility RegEdit (beware, Game Explorer entries are stored under both general and user-specific headings) and fiddled around in the registry until I had two separate, functioning shortcuts, which took at least one reboot.

NB. the "MW.REG" and "MWGOTY.REG" from a 32-bit Windows can't simply be transplanted to a 64-bit Windows (or from one Windows version to another, probably) because installing the game changes the registry in a different way (in the case of 64-bit Windows, the game goes under a special "32-bit programs" heading). I had to go through the whole installation and registry key saving again to make a new set.

Back to technical issues

Textures, faces and books

Morrowind mesh files contain the names of their textures. In the case of textures that are directly in the "Data Files\Textures" directory (or the equivalent place inside the game BSA files), only the texture filename is needed, without a path. However, if the textures are in a subdirectory, say, "Data Files\Textures\Mystuff", the texture name in the mesh file should include "Textures\", as in "Textures\Mystuff\MyTextureFile.dds". If mods include meshes that look white in the game, as in Horny Buddha's pack zebra mod, this is probably because the textures are in a subdirectory, and the mesh's texture file path doesn't include "Textures\". Fortunately, this can be easily changed in the fan-made NIF tool NifSkope.

The Better Heads textures that I use as editing bases are in the low-quality DDS format DXT1, and so a bit blocky. Apparently, to get the highest quality, I should save in "888 DDS" format without mipmaps. This does give best quality at the cost of a huge increase in filesize, but here I discovered something strange: the texture must have an alpha map. I tried saving as DDS 888, (24-bit colour) but it had to be 888.8 (32-bit colour of which 8 bits alpha) or the texture wouldn't show up in the game. A good compromise is to save face textures in DXT3 format, which includes an alpha buffer, and is the format used for book illustrations.

Books, whose content is written in simple HTML, need their last sentence finished with a line break (<BR>), or the text won't appear. They don't display tables. And they are very fussy about illustrations. Simply using "<IMG SRC="Mystuff/pic.tga">" with a Targa file "pic.tga" in subdirectory "Data Files\Book Art\Mystuff" will not work. Although the game uses Targa files for their alpha buffers, which make the image's background transparent so it can overlay the page, the only format accepted from modders seems to be DDS, although I did get TGA files to work using the method below. One online piece of advice was to grab a book art TGA from the game files, paste your own picture over it and save, but that didn't work for me.

Instead, I used a fan-made DDS editing utility called DXTBmp which, as the name implies, can convert between BMP and DDS/DXT. In the utility's Prefs menu, I selected Paint Shop Pro (any editor will do, ability to use layers a plus) as external editor.

Then I extracted a random book art file in DDS format from the file "Morrowind.bsa" using BSA Browser, in this case "boethiah_256.dds", which, like most book art files, is in DXT3 format, with an alpha buffer, and opened it in DXTBmp. From the menu, I chose Image, then Send to Editor, which opens the DDS as "norm.bmp" (ie. one layer, no alpha, no transparency) in the editor set under Prefs.

I then pasted the image over "norm.bmp". An easy way to do this is to copy the previously prepared image (in this case a screencap with the background whited out, then posterized to 3 bits to make it look more like a book illustration) and paste it into norm.bmp as a new layer, then delete the bottom layer. The image can be cropped to any size, a book art DDS doesn't have to be a multiple of 8x8 pixels like textures do. Having saved the BMP file, I loaded it back into DXTBmp by choosing Image, Reload after Edit. As the screencap below shows, the file still has its old alpha buffer.

So, the alpha buffer needs to be wiped clean. This is done by simply making a new one. I chose Alpha from the menu, then Create Alpha Channel (Green). This makes a new, blank alpha channel, deleting the old one. The choice for a green alpha channel was because the image contained little green, and much near-black, and with a black alpha channel, any completely black pixels become transparent, which was not my intention.

If I directly save the resulting picture in its old DDS format, then, presumably because I cropped it and pasted over it, the end result may be a skewed mess of pixels. In that case, I save it as 24-bit BMP, open the BMP again and save that as DXT3. Since that means I'm saving a BMP file directly to DXT3, and it works, why did I have to go through the process of loading a DDS, then having the program export it to another program as BMP and import it again? I've no idea, but that is what I had to do to make it work.

If I wanted a solid-coloured picture, I would be done now. But I want the area around the portrait to be transparent. Conveniently, that area is solid white, so if there are no other white pixels in the image, all I need to do is choose Alpha, Create Alpha from Colour, and choose that colour in the palette that appears. If there are white pixels in the image, I have to go back to the graphics editor to flood the to-be-transparent areas with another colour, one that isn't used by any part of the image, and base the alpha buffer on that colour instead. However! Since DXTBmp wants the alpha buffer image to be 256x256 pixels (because that was the size of the original DDS?), and will first make it that size and then rescale it to the image's actual size, the alpha buffer will have ragged edges unless the image is also 256x256. So I had to change the canvas size of that image (not resize it, as that would alter the proportions and make the outline fuzzy) back to 256x256.

To go all the way and see the transparence, I can choose Apply Alpha to Image, although this isn't needed for transparence in the game. It can be handy to make a smaller picture, though; make the alpha buffer at 256x256, apply to image and save image as TGA (to retain the alpha buffer), crop the TGA in the graphics editor, open it in DXTBmp again and save as DDS of type DXT3. Alternately, leave the picture at its full size and enter the desired size in the book's HTML code. It's also possible to simply use the TGA file instead of the DDS, but the file will be about four times as big.

The image is put into the book in the following way, where "IN" is a subdirectory of "Data Files\Book Art" (note the forward slash!):

<IMG SRC="IN/mugshot01.dds" WIDTH="256" HEIGHT="256"><BR>

Since the picture was far too big, I scaled it down to half its size by using WIDTH="128" HEIGHT="128" instead.

Back to technical issues

Wearables and Better Bodies

The standard way clothing and armour work is like this: Morrowind NPCs have a segmented body, with every segment or "body part" (Chest, Groin, Upper Leg, Lower Leg andsoforth) having its own mesh. In case of segments that are paired limbs, the segment is further specified as Left Upper Leg or Right Upper arm, but the lower limbs are symmetrical whereas the upper limbs are not, ie. it's possible to wear a bracer on one arm but not on the other, but boots are always worn in pairs. The clothes are segmented using the same pattern. All segments are registered under Body Parts, with a mesh name, a segment type (the body part, but not specifying left or right) and a flag to say whether they are Skin, Clothes or Armour. So, if a NPC dons a shirt that uses the chest segment, this replaces the body chest segment. Armour goes over clothes, so if the NPC next puts on a cuirass, the shirt chest mesh is likewise replaced by the cuirass chest mesh. If a segment spot is no longer occupied by any wearable segment, the body segment pops back into view.

Since a wearable segment always replaces the equivalent body segment, all wearable Body Parts are further categorized by "Type" under Clothes or Armour, this Type roughly indicating what segment(s) they are supposed to be swapped out with. Wearables are registered not per segment, but as a collection of segments that is swapped out with a similar collection. For instance, the Clothes entry for the "shirt_chest", "shirt_right_sleeve" and "shirt_left_sleeve" segments could be named "common_shirt_example", of the type Shirt, ie. it displaces any other wearable of the type Shirt, and the three segments are assigned to it under the "Biped object" drop-downs, where the "Biped object" is the segment type assigned under Body Parts, plus a qualifier of Left or Right if applicable. In this way, long-sleeved shirts will displace the body's arm segments, while sleeveless shirts leave the arms alone. If no segments were assigned, wearing the shirt would simply displace any other shirt and leave a naked upper body (or a cuirass if the NPC was wearing that over the shirt). An exception is the unsegmented clothes that go over other clothes: the skirt and robe, even if not assigned their own segments, automatically make certain segments disappear, whether body or wearable. Skirts make the groin and upper legs invisible, so they should never be shorter than knee-length, while robes blank out the groin, chest, and upper limbs.

To make matters more confusing, the segment or "biped object" categories clearly refer to the bones in the mesh skeleton, but don't have to correspond to them. It is possible to define several body parts that all use the same NIF mesh file. To make this work, the mesh parts have to be correctly named internally. For instance, there is a mesh of an imperial cuirass (chest part and skirt part) combined with gauntlets, called "a_imperial_skins.nif". The imperial gauntlet body parts and the imperial cuirass body part both refer to this mesh. Internally, the parts of the mesh must have the same name as the Biped object, if they are to show up as that body part. So, while the gauntlets are remarkably complicated, consisting of various parts, their naming is fairly straightforward: the "header" or NiNode for the right gauntlet is called "Right Hand", and the bits of mesh or NiTriShapes are called "Tri Right Hand 0", "Tri Right Hand 1" andsoforth. The cuirass is more complicated: it has a Chest NiNode with two NiTriShapes for the chest and skirt part, and a Groin NiNode for the girdle above the hips, even though the skirt vertices are attached to the Pelvis bone, or Groin as it's called under Body parts. The skirt part of the cuirass has Chest in its name, rather than being called Groin and defined under Body Parts as a separate Groin segment, because otherwise it would make (the groin segment of) the greaves disappear rather than just hanging over them.

In NIF mesh files that don't serve more than one body part, the NiNode doesn't have to be named after a body segment, and is generally named after the wearables type (ie "Pants", "Shoes") or the mesh name. In fact, the NiNode can be called whatever you like. The NiTriShapes must always have a body part name and a number.

So, the situation is: Morrowind characters have ugly insectoid bodies made up of separately moving parts, and can't wear revealing clothing. Enter Better Bodies, final version: 2.2. Every humanoid race (there are separate beast race replacers based on the same meshes) now has one single mesh rather than a collection of little ones. Since, for all the leg objects, only one of the pair is needed, the other pair is reserved for clothes of the type that only partly cover the body segment, and shouldn't blank it out. So, each body mesh now has two right legs and feet; the Left equivalent of these body parts is defined but has no vertices, while the Right body part has the vertices of both (still attached to the correct bones in the skeleton, of course) as shown in the screencap below, with an added arrow pointing out the "Ankle" meshes, which take up the whole lower leg.

The Better Bodies documention phrases this as "freeing up slots" and lists the following freed slots: Left Foot, Left Ankle, Left Knee and Left Upper Leg. It also lists the Skirt, although that isn't a body segment, but a special type of wearable. Each slot is meant to be used for a wearable Type that shows the body mesh. To quote from the Better Bodies readme:

If you can use a slot that replaces a part, please do so, as this cuts down on the total number of polygons. However, if you can't or don't want to replace a body part, we've made four new slots available with Better Bodies. These slots are "Left Foot", "Left Ankle", "Left Knee", and "Left Upper Leg." The following guidelines should be used when using these slots:

On messing around a bit with the meshes of Better Bodies and its follow-up mod, Better Clothes, I've found that the way to use these slots is 1. internally name the NiTriShapes after the right slot, ie. "Left Ankle" and "Tri Left Ankle 0", and 2. use a mesh that contains the whole skeleton, so that there actually is a left foot, left knee etc. even if they have no vertices. The game itself uses the skirt slot for skirts, but since Better Bodies doesn't stop clothes of the Skirt type from blanking the groin and thigh segment, revealing skirts have to be "Pants". The way to make revealing skirts that go over pants is to either make them part of a shirt, or assign the mesh and body part to the skirt slot and make them Greaves. (NB. This is theory and has not been tested.)

Back to technical issues

Why importing an OBJ in NifSkope can ruin the UV map

NifSkope is a fan-made utility that can open NIF files and show their meshes and other data. It also allows the adding and deleting of blocks within NIF files and the editing of data within these blocks, such as the vertex values and UV coordinates. It can even export the vertices and UV maps of NIF meshes to a file in OBJ format, or import an OBJ file and have its vertices, faces and UV coordinates overwrite those of the NIF mesh block into which it is imported.

That is to say: NifSkope version 1.0.22 nicely exports to OBJ format. The later version that I use, 1.1.3 (build 36ebfdd), supposedly doesn't export to OBJ. It does in fact write an OBJ file, but with an excessive amount of numbers behind the decimal point. The older version wrote just six-figure decimals, which is the standard.

What both versions have in common is that they botch the UV map when importing OBJ files. Here's why, and a laborious workaround: the OBJ format is a 3D format in ASCII form, so any OBJ file can be opened and edited in Notepad. There are four basic types of line in an OBJ file: vertex data, starting with "v", normals starting with "vn", UV coordinates starting with "vt" and faces starting with "f". The first block is vertices, the last block faces, the order of the two blocks between varies per 3D program. Additional info may be written like the object's name and material, and if the 3D program supports object groups, then every group will have its own four blocks of 3D data. If I open a simple OBJ file, the first vertex line will look line this:

v -1.00000000 1.00000000 -1.00000000

and the first UV line like this:

vt 0.0000000e+0 0.33333333

and the first normals line like this:

vn -0.57735027 0.57735027 -0.57735027

and the first faces line like this (note that although vertices, normals and UV coordinates are numbered starting at 0, when defining the faces they start at 1)

f 1/17/1 5/13/5 6/12/6 2/16/2

The three figures separated by slashes are the vertex number, the UV coordinate number and the normal number, which are usually but not always the same, since their three blocks don't have to be sorted in the same order. In this case, vertex 1 has UV coordinate 17, even though the OBJ is a simple cube with only 8 vertices. This is because of something called "unwrapping", where a three-dimensional object is cut at the seams and laid out in a flat shape, like a flayed skin. This only happens to the UV map, so several UV coordinates can belong to the same vertex: if every vertex had its own point on the UV map, this might be visible as a seam-like line in the 3D object, and/or extra faces might be needed. However, this is necessary, because NifSkope can't handle more UV coordinates to one vertex. The object will have to be remodelled and re-UV- mapped until there are as many vertices as there are UV coordinates. The seamy effect that happens when a line of vertices has exactly the same positions as another line of vertices with which it is not connected, can be counteracted by smoothing the normals of these vertices, by whatever means the 3D program allows.

But that's not enough. Even if there are now 17 vertices and 17 UV coordinates, a face starting with "1/17/1" will throw NifSkope off, because it expects the first number to apply to all three blocks. So, it wants "1/1/1", and will in any case attach the first UV coordinate in the "vt" block to the first vertex in the "v" block. (It will do the same with normals, but normals are more likely to have the same order as vertices, while UV coordinates tend to get sorted by their position.) As a result, the points in the imported UV map are correct, but the lines that connect them are wrong. The only thing to fix this is to edit the OBJ file by hand: find out from the "f" block what order the UV coordinates should be in; for instance, the 17th "vt" line should be at position 1, the 13th at position 5, the 12th at position 6 andsoforth; it helps to add the number at the start of the "vt" line. Then, using this information (and keeping a backup of the original in case something turns out to be wrong), reorder the lines in the UV block. Finally, edit the faces block so that every "point" of a face - the three numbers separated by dashes - consists of the same three numbers. Depending on the object's complexity, be prepared for a lot of search'n'replace. After all this, the OBJ file may be imported and its UV map will stay intact.

Back to technical issues

DaysPassed turns up in Morrowind-only installation

It is common knowledge that the global variable DaysPassed only exists, and is only kept up-to-date by the game engine, in installations that include Tribunal. Having created, on a new laptop, two side-by-side installations - plain Morrowind, and Morrowind plus both expansion packs - from the Elder Scrolls Anthology (as opposed to the Morrowind GOTY pack that I'd used to install the games to an older laptop), and added all of Bethesda's official plugins and the Unofficial Morrowind Patch, plus a few essential mods like legible signposts, I found that not only did the Siege at Firemoth plugin suddenly work without problems in both installations, but plain Morrowind had a global DaysPassed (seen by using "showvars" in the console) and it was being updated, too! I opened Morrowind.esm and the Unofficial Morrowind Patch and mods in the TESCS to see which one had added this global, but none of the data files displayed it. So how and in what file was it fixed? I'm baffled.

NB. Along with the global DaysPassed, some scripts use a local variable daysPassed, which, by being declared local, hides and blocks the value of the global variable from the script, because you can't have a local and a global variable with the same name. Morrowind simply chooses the local over the global and lets it slide, but OpenMW, up to version 0.39, seems to have a problem with this, given that scripts using the local daysPassed (the ones that make Maurrie and Nelos elope, and put Glathel in Gadayn's shop) are not working.

Back to technical issues


TESCS, Morrowind and GOTY

The TESCS that comes with the original Morrowind does not ask to save a changed plugin before reloading. The TESCS with Morrowind GOTY fortunately does.

The GOTY TESCS also lets me indicate which journal line is the quest title, and which line is the quest ending. This is for the ordered display of quests which was so sorely lacking in the original, and was introduced in its expansions. The space used for these indications is space left blank in a Morrowind-only journal, so a plugin with journals created in the GOTY TESCS can probably be safely used in plain Morrowind, providing that the plugin does not contain any Evil GMSTs (expansion game settings) or startscripts.

Here's something that both TESCS's do: I add a lot of dialogue for Fargoth, about half of it also for the cell "Seyda Neen, Fargoth's house" since it has to be said in the privacy of his own house. I filter all dialogue for "fargoth" to check it. The dialogue that is also connected to a place, like Fargoth's house, does not show up. That's strange, because otherwise I get all Fargoth-related dialogue, not only what Fargoth personally says, but also lines for anyone of his race and/or faction.

I've read that the different TES versions compile animations differently because the animations are coded in a different way internally not only between Morrowind and Tribunal, but also between patched versions of the same game.

One funny thing that happened in the GOTY TESCS: I load a Morrowind-only plugin, so of course the TESCS automatically adds all Tribunal/Bloodmoon GMSTs (the so-called Evil GMSTs) to the file. Discovering this, I load it again, this time with Wrye's "GMST vaccine" plugin which ensures that these GMSTs are not added to the active plugin. Clicking on Data Files in the menu and then on Details in the data files box, I select, and mark for deletion, all GMSTs in what I think is my plugin, only there is a suspiciously large number of them, and they cover many basic settings; yes, I didn't select my plugin properly, and am now marking GMSTs in Morrowind.esm. The TESCS will not save changes made to an ESM, but to be sure, I unmarked the deletions again before loading my own plugin, marking the Tribunal/Bloodmoon GMSTs, reloading it and saving it to be rid of those GMSTs forever.

Or so I thought. Because the next time I started a game, menu buttons suddenly had "s" prefixed to them, for instance "sWait" in the sleeping menu and "sGold" in the bartering menu. Extra "s" characters turned up in other places as well, like the dates in the journal. I saved the game, quit, looked at Morrowind.esm which did suddenly have today's date even if its size hadn't changed, copied the original from a backup installation over it to be sure, opened the TESCS again, chose my plugin and looked at the details. There they were: all the GMSTs that I'd "deleted" from the Morrowind ESM, even if I'd cancelled that action, even if they could never be deleted in the first place, had been instantly added to my plugin, and it didn't even show until I'd closed the TESCS and opened it again. Of course, deleting them solved the problem.

Again in the GOTY TESCS, although this probably applies to the Morrowind-only version too: it's said that the script compiler is too lenient, which I'd already discovered regarding GetDeadCount (see GetDeadCount and the prefix) and not complaining about the use of local variables which do exist, but were not declared in that particular script (see Local, global, targeted, variables, somewhere in the middle of that big block of text). But when I checked all the scripts I'd made in MWEdit, a fan-made editor which emphatically informs the user on startup that it's a BETA, I saw the following three errors that the TESCS ignores:

if ( Condition = true ) ; AAGH! single "=" instead of "=="

  set localvar to localvar + 1 ; should be "( localvar + 1 )", game doesn't seem to mind

  if ( Condition = true )
    ModSomething 50
  endif
; GAH! Extra endif not detected because there's no check whether if- blocks start with "elseif"!
  elseif ( OtherCondition == true)
    ModSomething -50
  endif
endif

Especially the third mistake can really break a script. MWEdit, given its beta status, isn't perfect either; in targeted scripts it fails to see that "mycompanion.RemoteLocalVar" might actually exist, it calls big outdoor areas like "Ascadian Isles Region" not a cell and won't accept such a string with PositionCell, and in the result field, it refuses to process any lines under a "Choice" line, even if they have nothing to do with it, saying that you can't process anything within a Choice function. Well, that is true: I did once try to set a global variable to 1 in a result field line starting with "Choice", and Check Errors reported that this global didn't exist, even though it clearly did.

I've since encountered two other really stupid mistakes that the TESCS script compiler (both versions) let pass without comment, although the game rightly balked at them:

if ( Variable <> 0 ) ; should be "!="

set Var1 to = ( Var2 + Var 3 ) ; unwanted "=" sign

The second was a stupid copy/paste mistake causing a "Set" error message, the first was a matter of using an operator that the game engine does not recognize, and alternately interprets as "greater than" or "smaller than", leading to inconsistent behaviour.

Back to modding quirks

Syntax, and lazy syntax

Syntax is putting inverted comma's around all object IDs, using a comma after each numerical argument, using capitals to mark the beginnings of words (ie. "StartScript" instead of "startscript") and starting and ending each script with "Begin Scriptname" and "End Scriptname". Lazy syntax is using inverted comma's only around IDs with spaces or apostrophes in them, skipping the comma and the capitals, and ending a script simply with "end". There is an argument for using lazy syntax: less chances of making mistakes. The comma thing, for instance:

Khinjarsi->PositionCell -172 -506 263 245 "Suran, Desele's House of Earthly Delights"

is the same as:

"Khinjarsi"->PositionCell, -172, -506, 263, 245, "Suran, Desele's House of Earthly Delights"

just less typing, and no errors just because a comma was forgot or typed double. And the cryptic errors (the script sometimes ran and sometimes didn't) caused by a script ending on "End Begin Scriptname" (I'd copied and pasted the starting line to the ending line) make a case for always ending a script with just "End". For legibility, I do use capitals as in "StartScript" and "doOnce", but not of course in "if" and "endif".

Back to modding quirks

Deadly hyphens, apostrophes and numbers

What I found out through lazy syntax: NPC names with hyphens in them also need to be enclosed in inverted commas. For instance, the following line in a script:

if ( player->GetDistance Zurgim_gro-Burug > 1024 )

refuses to compile, saying that "Zurgim_gro-" doesn't exist. The same happens with Hleif_Strong-Arm, making a case for putting inverted commas around all Orc and Nord names. But Khajiit are affected, as well: "S'Bakha" can't do without them because of the apostrophe in his name, which similarly acts as a break. And a name starting with a number absolutely needs its quote marks, or the number in it will not be read at all. Using the spell 1gr_comp2_wb from Grumpy's companion script led to the error:

Could not find variable or function "gr_comp2_wb"

This is why, in the original script, it's written like this:

if ( GetSpell "1gr_comp2_wb" == 0 )

The above applies to NPC names, spell names, presumably cell names, and apparently variables, too; underscores in variables are fine, but they don't like hyphens.

Back to modding quirks

Script says it doesn't exist

If you create a new script, save it once before putting a StopScript command with its own name in it. Alternatively, create your MyNewScript with "StopScript MyNewScript" somewhere near the bottom, "save" (ie. compile) it once, get an error message that said script does not exist, save again, all is well. Because of the incomplete way scripts are compiled, they should, for safety's sake, always be saved twice.

I've found a second and even more amusing error. I create a new spell and, in the same editing session, add "AddSpell spell-name" to an existing script. Before saving (ie. compiling) the script, I change the spell's name in the spell editor (open spell, change ID, choose No to question "create new object"). Then, I try to save the script. It claims the spell doesn't exist! Because I hadn't compiled the script for the old spellname, I don't know whether the step of changing the spell ID was even necessary; apparently if you open a script window and then start adding spells and other objects, the script compiler won't know about the new objects added since the script window was opened. The only solution was saving the whole data file (with the script window still open, so I don't lose the script changes) and then reloading the whole file. Then I opened and saved the script again, and it compiled.

Back to modding quirks

Missing persons and scripts

An object, whether NPC or creature or anything else, cannot be referred to in a script unless it has been put in the game with the game editor and is loaded when the game starts, as anyone who makes a script to adjust the AI settings of Ranes Ienith can tell. The TESCS shows that there are 0 references of him in the game, and he is only dropped into it with a PlaceAtPC when his brother is attacked. The only way to refer to them in a script is to place them in the game and then find a way to make them disappear until they are needed. From Tribunal onwards, they can be disabled in a user-made start script. In a Morrowind-only installation, which runs only the game's own startup script, statics and containers are best disabled by their own script, items are best inserted on-the-fly with the PlaceAtPC method, and unique NPCs, although they can clearly be inserted with the PlaceAtPC method, are best put in some hidden cell and then teleported to the right spot from a global script or dialogue box result field. Although using PositionCell to teleport a NPC into a cell where the player is will result in a crash if the player then addresses the NPC, because its dialogue hasn't been loaded yet, see Position and PositionCell: observations.

Something else that can't be referred to in scripts: new instances of persons. The first instance of a NPC, say Fargoth, may appear to be "fargoth" but is in fact "fargoth0000" (I don't know exactly how many zeros, it might be up to 8). If I create a new Fargoth in the console or in a script, that will be "fargoth0001". The next one will be number 2. Andsoforth. And these instances cannot be separately addressed in a script. I cannot, for instance, kill off both copies and keep only the original. Which is understandable since, like Ranes Ienith, these copies have not been placed in the game by the editor. It might be that a script can refer to instances that are placed in-game with the editor, like the many guard clones.

Back to modding quirks

Missing objects and scripts

If an object ID referred to in a script doesn't exist or hasn't been placed in the game (or was created after the script was opened for editing but before saving the plugin file, see Script says it doesn't exist) then of course the script won't compile in the script editor. If such an object is referred to in the little script known as the result field, I can only compile it with "Check error results", which, instead of giving an error message, shuts down TESCS. Fortunately, I had saved the file before running the check and so didn't lose any changes.

In this case, I used GetDistance on Aurane Frernis's three alchemical formulas. The first lies on a table/counter. The second is in a chest. The third is in her personal inventory. The second and third don't count as "placed in the game" since they are only in an inventory, therefore, I can't use GetDistance on them in a script.

Back to modding quirks

"Error check results" changes global variables

It is possible to set the value of global variables in the dialogue window's result field. When the TESCS dialogue "Error check results" is run, all code in the result fields is carried out, possibly changing the global variables; if so, they are not set back to their initial value and the plugin can be saved with a global having a starting value of, say, 5, which can produce strange results for scripts and replies that depend on this global variable. The solution is to i. always check global variables and manually reset to 0 if needed before saving (don't alter any standard globals!) and ii. save before "Error check results", then run the check, then reload the plugin without saving.

Back to modding quirks

MessageBox

The results field is the box under the dialogue response used for comments and scripted commands, like MessageBox. The syntax for the text-displaying command MessageBox is:

MessageBox "all the text you like"

or:

MessageBox "text text text %g text %g" variable1 variable2

where %g indicates each numerical variable to be inserted in the displayed string. Comments, on the other hand, are lines, or the end parts of lines, that begin with a semicolon:

; comment beginning at start of line

or:

set GlobalVarName to 2 ; comment to say that a global var is set to 2

The whole MessageBox line, ie. the command, variables and everything between quotes must not exceed 512 bytes. If it is longer, and in a results field, and you run "Error check results", a MessageBox line that is too long causes a loop which can only be left by shutting down the TESCS with Ctrl-Alt-Delete; another reason to save the plugin before running "Error check results".

Since a semicolon is always seen as the start of a comment, even in the quotes-enclosed text of a MessageBox line, using a semicolon in the MessageBox text causes a "quotes mismatch" error.

The variables that can be displayed are: in a script, global variables or local variables from the script itself; in a result field, global variables or local variables in the script of the NPC/creature addressed. In a result field, it is not possible to declare a new local variable, and no local variables from other scripts can be displayed. In a status-reporting script, I tried to display local variables from a NPC's script directly in the following way:

MessageBox "INB level %g willp %g" "npcname".inblevel "npcname".inbwillpower

but presumably because of the quotes, the variables were seen as buttons. So in the script with the MessageBox, I declared a variable "helpval1" and "helpval2", filled these with the values of "npcname", and used them in the MessageBox line.

Back to modding quirks

Standard display variables

There are a number of standard variables like %Name, %Class, %Race, %PCName, %PCRace. Using these in dialogue will see them replaced with the variable's value in the game. So "I am %Name, %Class" will appear in the game as "I am Yokel, Commoner" or "I am Fatcat, Merchant" depending on who says it. Now, "dialogue", ie. displayed text, can also be put in the result field, using "MessageBox" and the text string; the text will be displayed in a different colour and the same variables can be used, but with a caret instead of a percent sign: ^Name, ^Class, ^Race, ^PCName, ^PCRace. I haven't tested them all, but for ^PCRace, this does not work. No race was displayed for my PC, just "^PCRace". Now this may have been because I didn't use the variable with MessageBox, but with Choice, another command that displays text from the result field.

As said in MSFD9, ^Name will just display the value of ^PCName, so in result fields the name of the addressed NPC should be used, while in a script a paraphrase is needed ("your companion", "your slave"). ^Cell applies only to the cell the player is in, and can't be used to locate companions gone missing. Since it is strictly for display, neither can it be used in the following way:

"npcname"->PositionCell 0 0 0 0 "^Cell"

Too bad, eh. But see
Position and PositionCell: observations below.

Back to modding quirks

Dialogue strings: allow yes to all

The following is explained in Bethesda's own "readme.txt", which I didn't bother to re-read after installing the expansions, so I found it through websurfing:

When opening any plugin in the GOTY TESCS, be ready for many error messages about preceding and following strings being different. And when error-checking dialogue, expect a lot of errors too. For the first, a setting is needed which is not in the Morrowind.ini, so this whole line has to be added:

AllowYesToAll=1

If you get text string errors on loading in the TESCS, a third "cancel" button is added to the "yes/no" buttons, and clicking on this button skips the other error messages.

For the second, the only real errors are the name of Fons Beren's journal and the nonexistent stock certificate journal, which ought to be a global variable. The other "errors" disappeared after I'd added a lot of code to result fields of my own.

Back to modding quirks

Doors and their instances

Just as "Guard->SetHealth" may not do anything with multiple references of the NPC "Guard" in the game, so the inevitable multiple instances of the same door are hard to influence just using the door's name. But doors seem to be worse than NPCs in this respect.

If (discovered in the Suran Slave Market) four instances of the same basic door all have "opened by key X" in their reference data, then key X will only open the first of these doors. Even if I set the instances to be opened by four different keys X, X1, X2 and X3, only one these keys will open only the first door. On the other hand, the same key can be used for different doors with different IDs, but if used for different doors with the same ID, it only works for the first instance of that door ID. So three of the four doors had to be replaced by doors with unique IDs.

A door can't be (un)locked with an external script. If I use "lock door_x 50" in a result field, the game crashes; if I use it in a global or local script, the script aborts, and most or all of the code in it is not executed. (A Morrowind-only installation actually displays a message at startup that "reference door_x not found", while GOTY loads silently and the game either crashes or the script aborts silently, too.) A door can only be safely (un)locked from its own local script, so, to remotely (un)lock it, I let its script check for a global variable or journal entry.

Back to modding quirks

Health and death

For testing purposes, I sometimes quickly kill off a NPC by opening the console and typing "npcname->SetHealth 0", or selecting the NPC by clicking on it with the console open, and typing "SetHealth 0". In the second case, "SetHealth 1" will also do the trick. It is not possible to kill NPCs with "npcname->SetHealth 0" if they aren't in that cell and haven't been loaded by the game yet (npcname->ForceGreeting won't work either, although npcname->PositionCell will) because nothing will change; in that situation a script using GetHealth will act as if the NPC's health is 0, so it should use GetDeadCount for a more accurate reaction to the situation.

It is also not possible to remotely kill NPCs from a script with "npcname->SetHealth 0". If they are in the same cell or already loaded, their health will at least be set to 0. If they are in the same cell as you, they will even go through the motions of dying and become corpses. But their "dead count" will not be augmented, so if you use the "Dead" condition in dialogue, you won't get the right dialogue responses. I've tried this with an NPC whose health was set to 0 before he was disabled: even teleporting him to the cell where the PC was for his little death-grunt before disabling him didn't make him "dead" to others. So instead of the "Dead" condition, I used a "he's dead, folks," journal entry to get the right responses.

I think it's the "fight" situation that increments the GetDeadCount counter. In one mod, I have to kill a bonelord to free some people. While testing, I am an unarmed level-1 character fresh out of Seyda Neen, so I bring up the console, click on the bonelord and "sethealth 0" just as it lets fly its first fireball. The script that does a GetDeadCount of this monster reacts, and the story continues. However, if I use the console to kill it while it's still peacefully hovering around, before it sees me and engages in combat, GetDeadCount remains 0 and the story stalls for lack of a body count. So if the NPC is close enough - although I'm not going to test this - using StartCombat and then SetHealth to 0 might just do the trick.

Back to modding quirks

Odd things when resting and levitating

It should be obvious: you can't rest and levitate (or rest and swim) at the same time. So if you ask for a blessing at the Shrine of Daring, which confers levitation for a long period, you will not be able to sleep until the blessing wears off. You can't even use T to wait and make it wear off more quickly. However, you can also lose companions. When teleporting by opening a door to another cell, or by making use of travel services, if the PC is levitating, any following NPC is left behind. The "Decius and Vorwoda" plugin addresses the door issue by replacing all doors in the game with "companion-friendly" doors which have to be clicked on twice. Without this feature, testing a mod can be a headache as you wonder where that companion went. Another solution is to have the companion stop following when you start levitating. (I found later that the companion does follow the player into the cell, but can't materialize in the same spot as the player and so goes "elsewhere", wherever that is.)

When using T to wait in jail, I found that jail doors (or any non-teleporting doors?) are not good at keeping NPCs confined. I would rest for 24 hours before a prison cell door and find an Ordinator behind bars, while the jailbird I'd been watching was somewhere up the corridor. When putting NPCs behind bars, it's best to set their AIWander distance to 0.

Back to modding quirks

Position and PositionCell: observations

The best way to put a NPC somewhere is PositionCell. Unlike GetPos/SetPos, which set the coordinates within the cell the (N)PC is in, and don't seem to work over large distances, PositionCell states not only the coordinates but also the facing angle and the cell to which these arguments apply, all in one line. There is one disadvantage: unlike SetPos, PositionCell doesn't take variables. From Tribunal and upwards both are said to accept float variables, which must be local and not global variables, but when I transported Desele's dancing girls upstairs and back, storing their original positions in variables to use for their return, they always ended up near the door, which, I later found, corresponded to the coordinates 0, 0, 0. Not even SetAtStart could return them to their original positions, so I looked up their original coordinates and used these values with PositionCell in the teleporting script. Maybe, for PositionCell, "local variable" means it has to be a variable declared in the script of the NPC, rather than a local variable in a global script? (This has been tested by altering the slavescript and DOES NOT WORK.)

(NB. That SetPos does take variables as of Tribunal, is proven by the many companion mods in which the companion teleports to keep up with a speedy player character. That it doesn't take variables in plain Morrowind, is a bit of a setback for companion mods.)

PositionCell will work in cells that haven't been visited yet, and for NPCs that haven't been loaded yet - as opposed to SetPos, which only works if the NPC is loaded and in an active cell (ie. the cell the PC is in, and the preloaded surrounding cells, how many cells are preloaded depends on some game setting somewhere) or is still in the PC's "memory" (where it stays for, by default, 72 game hours). There is a potential problem with this. If a NPC is teleported, using PositionCell, to a cell the PC has yet to visit, the PC will enter the cell, the NPC will be loaded along with the cell, and all will be fine. But if a not-yet-loaded NPC is teleported to a cell where the PC is already standing, and this NPC has a script, the script will not run properly, because the NPC has been placed in the cell, but not loaded along with it. And if this script is the famous NoLore-script or another script to do with dialogue, then if the PC addresses the NPC or vice versa, the game will crash. I had this problem when teleporting a few NPCs including Fons Beren and m'Aiq to Desele's House of Earthly Delights; they either showed up as black shadows, or looked normal but caused a CTD when greeted. Disabling and re-enabling the NPC sadly doesn't fix this. The two possible solutions are: have the NPC teleported to some hidden corner of the cell the PC is about to enter and brought out as necessary, or, but this is rather ugly, teleport the PC to the NPC's cell and both of them back to the cell where the NPC is supposed to appear. Blacking out the screen with FadeOut or a spell of blindness during this jump back and forth did not work.

(The solution was to create a custom unlit interior cell and use a script which teleports first the NPC and then the PC to that cell, then places them both in Desele's house. Since that unlit cell would be already in memory when summoning the next NPC, I made four unlit cells and scripted a different cell to be used for each summoning, using a global variable called DeseleRotation. However, since there were eight NPCs, which would have required eight cells, I scrapped the unlit cell approach and went back to teleporting the PC to the NPC's cell, but to coordinates in the ground/wall for the blinding effect.)

Using PositionCell from the result field instead of a script is supposed to crash the game. I wonder if this has anything to do with the problem above, because I haven't had crashes as long as I don't teleport "new" NPCs into the PC's cell.

That I can use PositionCell on unloaded NPCs in faraway cells sometimes makes me forget what I can't do. I had three slaves teleported from Clutter Warehouse to an island on the Bitter Coast, all three paralyzed by adding the disease Witchwither to their inventories, and one hurt by using SetHealth -20. Unfortunately, neither AddSpell nor SetHealth had an effect, and I had to use AIWander settings (something else that does work on unloaded NPCs in faraway cells) to immobilize them. I then added code to the first greeting to add the disease and decrease in health.

I used to think that Position and PositionCell were for absolute coordinates - where PositionCell was only meant for interiors - while SetPos and GetPos were only for coordinates within cells. I was wrong on all counts. Firstly, both Position(Cell) and Get/SetPos report relative coordinates within interior cells. Secondly, all exterior cells are in one big grid with absolute coordinates. Outside, GetPos X/Y/Z return those absolute coordinates regardless of what cell I'm in, and "Position X Y Z angle", "PositionCell X Y Z angle cellname" and "SetPos x X, SetPos y Y, SetPos z Z" all put the object in the same location. Moreover, when PositionCell is used for an outside location, it doesn't matter what cellname is used. I once used PositionCell with a nonexistent cellname and ended up in the heart of the Ashlands, which corresponded to "0 0 0" on the big grid; I don't remember what coordinates I used then, and whether I teleported from an indoor or outdoor location, but have since found out that, in the console, I can use "PositionCell 0 0 0 0 "Vivec"" and end up in that same Ashlands location, or "PositionCell 32870 -99470 1091 0 "Ashlands Region"" to go straight to the Temple entrance in Vivec. In the console and in scripts, it doesn't matter what goes in the cellname field, I can use "Wilderness", "MadeUpCellName" or even " ". I've tried putting these options in a script that teleports the player to various outdoor locations, using wrong or nonexistent cellnames, and it worked.

Position should NEVER be used on NPCs. It messes up their rendering and collision detection to the point that you can walk through them, they don't have faces when seen from the front, and their teeth show through their cheeks when viewed from the side. Leading them into an interior cell, which has the effect of reloading them (I don't know if taking them into another exterior cell would have the same effect) fixes all this, but it looks scary. Always use PositionCell even if you're not sure of the cellname, because as long as the coordinates apply to an outside location, the cellname is ignored anyway.

Two quirks discovered while working on a companion: if, in an active cell, a script teleports an NPC towards, for instance, a shopkeeper, and adds shopping items to his inventory to the point of overburdening him, he snaps back to his old position. Teleporting and adding items in two different scripts would probably prevent that. If, again in an active cell, a script makes him cast a spell and then teleport, he casts the spell, but PositionCell doesn't happen, as if the spellcasting cancelled it. I tried making him cast a spell in the result field and then use a script to teleport him; this caused a CTD. Finally I put the spellcasting back in the script and made him wait 4 seconds (too short and the spellcasting cancels the teleporting, too long and he starts greeting the PC) before teleporting with PositionCell.

The fourth numerical argument for PositionCell is the Z angle, the direction in which the NPC faces. This is said not to work, but it does. This is because solely with PositionCell and NPCs, not degrees but minutes are used. One degree is 60 minutes, so the number in degrees has to be multiplied by 60, or the rotation is too small to notice. PositionCell for the PC uses degrees, and Get/SetAngle for both PC and NPC also uses degrees. But simply using "SetAngle Z 180" on a NPC will not make the NPC turn round and face a different direction.

There is a command "Face x y" but if I use this on a NPC newly placed close to the player, the NPC will start to circle the player. And since PositionCell doesn't seem to take variables, I can't use those to change a NPC's facing direction either. If the NPC is not following and the PC approaches, the NPC will automatically swing around to face the PC (even if the NPC is lying down).

Lastly, using PositionCell in the console to move a NPC standing next to me somewhere on the Bitter Coast to Balmora caused a CTD. Which is funny, since companions can be teleported away from the PC by any means without problems.

Back to modding quirks

Armour quirks

GetArmorType won't work for NPCs, in either a script or the result field. Correction: I've found it will work in a script, if I put the value returned by GetArmorType in a (local) variable and use this variable where needed. It is not possible to use local variables in the result field, so here I would need to use global variables. I opted to run a script instead. That's how I found out that if the first GetArmorType call in the script is for the helmet ("GetArmortype 0") no value is returned, possibly because of the 0. If I start with "GetArmorType 1" or any value higher than 0, and then use "GetArmorType 0" to check for the helmet, it does work. I know that GetArmorType only works since Tribunal, but this was discovered in a GOTY installation with the latest patch applied.

Companions (NPCs in "follow" mode) are like an extension of the PC. They will not speak out when the PC commits a crime, and when they attack something, the PC bears the blame. (And gets the experience points?) But companions also somehow inherit the PC's armour skills. If I give a slave bracer to a companion to carry, he will not auto-equip it, as it is technically heavy armour, and his highest armour skill is Light Armor. But when I play as an Orc and have a high Heavy Armor skill, my companion, with his higher Light Armor skill, nevertheless equips the slave bracer. Perhaps useful information for modders who want to make a Morrowind-only companion, as Morrowind-only NPCs can't be told to equip something. Although this is a GOTY-requiring companion, so I can't test what he does under Morrowind alone.

Although a piece of armour has "health" just like a (N)PC, I can't "damage" a piece of armour with ModCurrentHealth, ModHealth or SetHealth, either as a command from a script or result field, or in a script attached to that item. Since the script would act directly on the reference, I deduce that these commands simply don't work for armour (and possibly weapons). I can only "damage" armour by placing it in the game with the editor, and then editing its reference data.

Back to modding quirks

Straight from the result field

Code in the result field is executed immediately, while the dialogue menu is still open. If sounds are played, they are played straight away, all at the same time. SetPos or PositionCell are executed immediately, which may cause crashes if the object being teleported was doing something else. Objects are added to or removed from the inventory with AddItem and RemoveItem instantly, and Journal just as instantly adds journal entries.

This mainly matters for its effect on dialogue topics. I could take the commands from the result field and put them in a script called DoStuffNow, and put "StartScript DoStuffNow" in the result field instead. Now, any teleporting will not happen until the dialogue window is closed, and even though the dialogue will say "Your journal has been updated", if the journal update affects the available topics, the topics will also not be updated until I click on them or close and reopen the dialogue menu; a now obsolete topic will instead get a reply like "I don't trust you enough to tell you about that". I haven't tested topics that depend on items in the inventory, but conclude that any action which should update topics belongs in the result field, not in a script.

Although, when a script is run from the result field, its actions (teleporting, activating or deactivating topics) will only become visible once the dialogue window is closed, the script itself does run instantly, without waiting for the dialogue to end, which is annoying if, for instance, that script sets variable values which are not meant to change while the characters are "talking". The order doesn't matter: both

Goodbye
set INPCPositionCell to 1
StartScript INPCPositionCellScript


and

set INPCPositionCell to 1
StartScript INPCPositionCellScript
Goodbye


don't make the script wait until the talking is done. Now, the seasoned modder may say: just add a "menu is open" condition in the script, as below:

if ( MenuMode == 1 )
  return
endif


which will constantly set the script back to its first line until not just the dialogue window, but all menus are closed. I did this and it didn't work, not even after recompiling all scripts. Apparently, when a Greeting (as opposed to a line of dialogue hanging under a topic) has a Goodbye in its result field, the opening of the dialogue window doesn't set MenuMode to 1 fast enough. I had to create a delay with a local variable, which makes the script wait four milliseconds and then turns itself off until the script finishes:

Begin INPCPositionCellScript
; to teleport PC from dialogue only after dialogue window has closed
; and other post-goodbye stuff

short waitabit

; since Greeting->Goodbye is too short to set MenuMode:
if ( waitabit < 5 )
  set waitabit to ( waitabit + 1 )
  return
endif
set waitabit to -1 ; reset to 0 at bottom of script

; now the script responds to MenuMode
if ( MenuMode == 1 )
  return
endif

Back to modding quirks

The PlaceAtPC method

Once, I needed a damaged helmet to materialize on a counter. There was no way to place and then damage it while the game was running, so I had to put it on the counter damaged in TESCS, disable it in a startup script, and enable it when needed.

Much later, I needed three books to appear in Thieves Guild halls as part of a quest, in a mod that should work in Morrowind only, so I couldn't add startup scripts. I tried to put them in the game and have their internal script disable them, then poll for a certain journal entry to enable them. Their polling took so much time that it slowed the game. It would be better not to create them unless/until needed, and the simplest way to put an object in the game is to either add it to someone's inventory, or use PlaceAtPC which creates an instance of it near the PC. But how to teleport them to the place where they're supposed to be? I decided to attach a script containing a one-time PositionCell command to the books. They teleported themselves so promptly that I didn't even have time to bend down and see if they were lying at my feet. So I decided that if I ever needed to pop an item into the game, I would use PlaceAtPC and let the item's script take it to where it was needed.

For the same plugin, I also needed three crates of moon sugar to appear on a dock. I tried the PlaceAtPC method again, but for some reason (containers don't like being teleported?) it didn't work. So I used the helmet trick again: pre-placed and disabled them, although, still not being able to do this in a startup script, I had to let them disable themselves and then enable themselves at the right time by polling for a journal entry again. For some reason, this worked well with the crates. Maybe it was because the crates were in a thinly populated exterior, while the books were in interior cells with plenty of NPCs.

The crates were less stable in Morrowind only than in the GOTY installation. When I placed them in the console, I got memory pointer errors and a message "Trying to Runfunction .. greater than index count". When I emptied them, which is the cue for their own scripts to make them disappear, they didn't, but when I left the cell and then revisited it later, they did disappear, but with an error message.

Back to modding quirks

The lights method

A page with scripting tips related to Josh's Farmer Mod says that global variables sometimes update too slowly to be usable in scripts - which I've found to be true - and that another way to quickly test for a condition is to add lights (not candles or torches, but actual lights) to an inventory, as they can be tested for with GetItemCount, but won't show up in the inventory. I thought I would use this principle for a quest in which, depending on my actions, two groups of people would be behind bars for a specified number of days. A script would count the days and position them back in their old spot once they'd done their time. It couldn't be a global script because then it would not restart after saving and reloading. It couldn't be a local script because I didn't want to tamper with the NPCs' scripts. Besides, it had to keep running and counting as long as the PC was active. I hit on the idea of putting the script in a new kind of light and adding this light to the PC's inventory, where it would do its counting invisibly and then remove itself from the PC's inventory, not in its own script because that has been shown to cause a CTD, but from another little script that it would call. That's how I discovered two things: first, deleting an item with a script from one's inventory even through an external script will make the game crash, and second, the lights method only works for NPCs, and I'll explain in the next paragraph why. I ended up using a global script which does stop running when the game is saved and reloaded, but which can be restarted by addressing the jailed NPCs.

If a light is added to the player's inventory, it will be invisible if it has no icon art, but a cryptic message will appear: " has been added to your inventory". A light has a togglebox saying whether it can be carried. If this toggle is off, it's impossible to name the light. I checked the togglebox and called the light "A mission" so the message would be "A mission has been added to your inventory". But then I got a default "missing art" icon in my inventory! The light doesn't have a mesh either, so if I dropped it, I could never pick it up again. Incidentally, if its own script makes it drop itself from my inventory, this counts as deletion and crashes the game. So if I put lights in the PC's inventory, either to keep a script running or as an alternative to a global variable, I will get either unwanted messages or unwanted icons, and the risk of littering the game with invisible objects. If used for scripts, the lights also risk littering the PC's inventory, as there is no safe way to delete them.

Adding lights to a non-standard (ie. not running "slaveScript") slave's inventory to show his "freed" status, I also found that even when the "carryable" setting is off, the slave will still carry the light when it gets dark, meaning, the slave's arm will take the carrying position even though holding nothing visible, and light will reflect off the slave. So I stored the slave's status in a global variable. In short: lights are fine for transferring the value of local script variables (which can't always be queried directly) in short interactions, but should preferably be cleared from the NPC's inventory when no longer needed.

Back to modding quirks

Lying down

I wanted to make the PC train his/her own companion. This is pretty unbalancing, so I added a malus: it would be very, very tiring. The first time, they would even drop from exhaustion together to drive home the point. How to get them horizontal?

Playgroups have been differently implemented between versions of the game executable, but let's just assume everyone out there has a completely updated game. I used playgroup Death1 and Death5 (lying face up and face down). This only changes the legs; if the arms were in a fighting or shooting position, they stay that way. If the NPC was running, they even continue to move. So the arms must already be made "idle" (not engaged in a different animation) before those playgroups are used. And the playgroup command will not work on the player.

So, let's use Fall! Set Fatigue to 0, tell NPC to Fall. First, all ongoing animations must be stopped by setting the playgroup to Idle, or the NPC will simply keep going and flop over unexpectedly later. Secondly, the NPC will only fall when trying to move and finding there is no energy to even keep upright. The moving happens when the NPC is in following mode. I thought I had to switch off following mode, but the problem turned out to be that Fatigue was rising and with it, the NPC's ability to stand upright. (Of course I used ModCurrentFatigue, not SetFatigue which changes the base value.) So I had to make a script that kept the NPC's Fatigue below zero by constantly lowering it. The NPC does have to stay in following mode to fall down at all. Also, the falling shouldn't happen until the talking dialog is closed, so the script should check if all menus are closed before continuing. Now, I have a NPC lying at my feet. The script that keeps lowering his Fatigue has a timer and will stop running after, say, 60 seconds. (What position you get from Fall seems to be random; when falling to the side, I noted the arms do change, otherwise, they may stay in the last position they were in before falling.)

An observation here is that ModCurrentFatigue used on the NPC does not automatically minimize itself to 0; a command "ModCurrentFatigue -100" on a NPC with 40 Fatigue sets the Fatigue to -60. I don't know if this applies to all characters or only to those with "auto-calculate" unticked. A Fatigue of 0 or less forces the NPC to fall but still allows the NPC to follow when the PC gets too far away.

Since follow mode is what keeps my companion down, the companion will rise to follow me and then drop again if I walk away. The companion will also rotate if I walk around him. I've since found a better alternative to AIFollow: use AIWander with a wandering distance value (the first number after "AIWander" of, say, 512. The companion, freed from following mode, will immediately walk away and, therefore, flop over, and remain down as long as the Fatigue-draining spell or script is running. Apparently, issuing the AIWander command also resets animations, because I didn't have to bother with setting playgroups to Idle, and no longer needed Fall.

There was another problem: the companion, though now immobile, would still address and greet me, and if I clicked on him to talk, even with companion share disabled, any nearby NPC would hiss at me for supposedly trying to steal! The solution was to not only set the companion's greeting distance to zero with "SetHello 0", but to also deflect such clicks by adding "OnActivate" to his local script, plus code that would let me activate him only if he was conscious; to know when that was, I let the companion-dropping script set a global variable to one value when he fell down, and another when the timer ran out and he got up again. (Instead of a global, I could have used a local variable or a light, but I wanted the value to be set even if I walked away, and a NPC's local variables stop updating once the PC is too far away.)

Here is an example of OnActivate in a companion script:

if ( OnActivate == 1 )
  if ( GetFatigue > 0 )
    Activate
  else
    return
  endif
endif

A warning about Fall: its purpose is to impart the effect of smacking on the ground after a drop from a certain height. It will have no effect if the NPC just keels over, but a NPC who is scripted to teleport to a lower location with PositionCell and then Fall, may fall all the way down and die as a result. Since Fall changes a teleport downwards into a fall downwards, the NPC may also get caught on any obstacles in the fall's trajectory. More reason to just use AIWander (or AIFollow towards some stationary actor) with Fatigue below zero.

So that's how to make an NPC lie down for any length of time. Making the PC lie down doesn't require Fall or AIWander, but has its complications. I can use ModCurrentFatigue to lower the PC's Fatigue below 0, but this will only work for a moment. I tried to use SetFatigue 0 on the player and ended up with a player stuck to the ground with a worm's eye view of the surroundings until drinking a potion from its inventory, after which it had full Fatigue again - recalculated from the stats? - but before that, the PC couldn't move, and for some reason I couldn't even switch to third person mode to check its position. If the PC's inventory had been empty, I don't know what I would have done.

The solution was a spell, in the form of an Ability that always succeeds, which drains an enormous amount of Fatigue. Using the old method - a timer that drains fatigue every frame to keep it below zero - not only made it hard to fully restore Fatigue after the timer is done, because it may be deeply in the negative by that time, which somehow interferes with calculation (maybe the value was too large to fit in a variable of the short type?), but also, specifically for the PC, blocked third person view through both tabbing and scripted Force3rdPersonView. Simply adding the ability with AddSpell, and removing it after the timer runs out, made the PC fall down, stay down and get up again without side effects.

Back to modding quirks

Evil twins: duplication of a unique NPC

Beware, beware of accidentally making two or more instances of a unique NPC. By working on a companion mod and loading an old game with an updated version of the mod, for instance, so that the companion who is already tailing you also appears anew in the deserted mansion where you're supposed to meet him. Two companions: twice the fun! Only, this companion had a number of external scripts running on him which now apparently ran on his clone, since he no longer kept himself fed and watered from his own inventory. Invisibly to the user, instances of any NPC are numbered; when a running global script refers to a NPC, apparently it takes the newest instance of that NPC.

So I disabled the clone with the console, opened the mod in TESCS, and added

if ( GetDisabled == 1 )
  setdelete 1
  return
endif


and then reloaded the game, hoping to be rid of the clone for good. The single companion I now had, had the NPC's starting inventory; the game had considered the older instance "disabled" while loading the newer one that I'd disabled with the console! Either that, or the older instance had somehow been reset, losing all the loot I'd given him to carry. (Or I'd been really stupid and disabled the older instance, when I thought I'd clicked on the new one.)

After that, teleporting the remaining NPC instance had the effect of disabling it. I tossed the game and started a new one.

Since then, I've found another way of creating evil twins: make a mod that influences the Ienith brothers. Oops, Ranes Ienith can't be altered through an external script because he hasn't been placed in the game; he is created the moment the player enters the basement to kill them. So, in the mod, place him in the game. Now you can reference him in scripts. Next, make another mod which also references him in scripts and which also places him (in fact, copy the first mod, strip out what you don't need and add new stuff). If you add the second mod to an old game, the basement has already been loaded, complete with one single new NPC. But if you start a new game where both mods contribute to the building of the basement, they will both put their instance of the NPC in it, and the scripts will only affect the first one, so while the first Ranes gives you a laid-back greeting, the second one will still attack. It is not (officially) possible to make the first mod depend on the second one. It is impossible to tell one mod to not load the NPC if another mod has already loaded it. The only solution: make an ESM which does nothing but place the NPC in the cell. Then have both plugins depend on the ESM, by loading each plugin in TESCS while the ESM is ticked, and then saving it.

Back to modding quirks

Journal error in result field

A stupid mistake that had me tearing my hair out trying to find it:

if ( GetJournalIndex <= 40 )

Note, no journal name. This was used in a result field for a response of a certain NPC. When that NPC responded, I had an EXPRESSION error message for that NPC's script, though the NPC's script contained no errors. Apparently the result field is latched onto the NPC's script in-game.

Another stupid mistake in the result field:

if ( GetJournalIndex IN_Journal 40 )

Note, no operator. "Error check results" does not report this. In the game, when the response with this code in the result field comes up, there is a ringing error sound, which shows that something is looping, until finally the game crashes.

Another one, in a script this time:

if ( GetJournalIndex Journal IN_Journal 40 )

Note the extra "Journal", result of a careless copy/paste action. This gave me a "LeftEval" error when the script was run.

A non-journal result field error worth mentioning here: I used a global variable in the result field that had not been defined, ie. did not exist. So in the game, the line where I used this variable and all the code under it, was ignored. Strangely enough, "error check results" gave no warning.

Back to modding quirks

Topics, the blue stuff

Making topics appear blue on time, so that they can be clicked on: I ask Fargoth about "(The imperials have) taken everything", which sets my journal to 10, and he tells me he would die for some nix-hound meat, which reply leaves a line in my journal, setting it to index 20. The topic "nix-hound meat" is programmed to turn blue at journal index 20, but doesn't. This is because the journal index is set to 20 after the dialogue is displayed, and the dialogue is not updated to make an already displayed phrase turn blue. To keep the conversation flowing smoothly, I have to program the topic "nix-hound meat" to appear even before the journal index goes to 20, in order to make it light up in blue when Fargoth mentions it. If another character has mentioned it previously, it will now appear as a topic in the topic column even before Fargoth brings it up, but fortunately he is the only one who does.

The dialogue is updated to change blue lettering back to normal lettering when a topic is no longer valid, for instance, if I bring Ajira the flowers she wants while she tells me to go to lake Amaya, my chances of finding out more about lake Amaya are shot as the letters lose their colour.

See also Straight from the result field for the effect on topic processing of letting a script add the journal entry.

If one plugin (esp file) has a certain topic, say "skills", and another plugin has that same topic "skills" (though obviously with different lines) and that topic does not exist in an esm (master) file, then the topic will only have the lines of the last-loaded plugin. This means that a topic may no longer turn blue when you expect it to, because it has been superseded by a newer version of that topic with new conditions for when the topic is supposed to be blue. The solution is said to be using "AddTopic skills" in the result field to at least make the topic appear in the list of topics, although whether this will produce the desired response is another matter. AddTopic can also be used in Fargoth's example to make "nix-hound meat" appear in the topics list before it turns blue, where hopefully the player notices it being added. Which may not be the case if the list is already quite long and the topic starts with a letter way at the back of the alphabet.

Speaking of modders' topics, an informal standard set by the "Got The Time" plugin is to have completely generic but often used topics start with a double dash, to place them above all other topics. I decided to adopt this standard with the "Coordinates please" plugin.

Related to blue (ie. active) topics: if a topic's condition is, say, a journal entry having appeared or a global variable having been set, then as long as this condition is not met, the topic will simply not be active. However, if a topic's only condition is Disposition, meaning, it should only appear when a NPC likes the PC well enough, the topic will always be active, but until the disposition is at the right number, the NPC will say things like "I don't like you well enough to talk about that". So to make a topic rely on disposition yet keep it absolutely hidden until the disposition is right, extra measures are required.

Back to modding quirks

Deleting and importing topics

On a modding forum, I found the method to remove unwanted parts of a plugin using TESCS: go to Files to open the dialog that loads a plugin, select that plugin and click on the button Details. A list appears of all additions the plugin contains; selecting an item on the list and pressing Delete puts an "I" ( Ignore) before that item, and when the plugin is saved, that item will be flushed out. This method is mainly used to clean up dialogue. However, each dialogue string is linked to a string before and a string after it, and deleting added dialogue can have unexpected results. I had added a number of strings somewhere in the middle of a Greetings section (Greetings 1, if I recall correctly), and set the topmost string to Ignore. When I tested in the game, the expected greetings did not appear, and no wonder: after saving, which flushed out that topmost string connecting the rest of the strings to the standard strings above them, these strings had been relocated to the very bottom of that Greetings section.

Journal entries are usually ordered from 0 to whatever their highest number is. But sometimes, the order is reversed. I can now guess why. When I export an added topic to file, completely delete that topic and all its strings with Ignore, then import that topic again from file - in other words, when the import creates a new topic in the dialogue database, rather than adding the strings to an existing one - the strings are ordered backwards. This is not a problem with journals, but can be with topics because the dialogue conditions are evaluated from the top down, with the most generic response at the bottom.

On the other hand, when responses under an existing topic are re-imported into a plugin, possibly after a spellcheck of the export file, and this is a standard topic that the plugin adds strings to, the standard strings above and below the added strings will be marked with an asterisk and added to the plugin as "changed", so the dialogue has to be cleaned up again by setting any string that isn't added or genuinely changed to Ignore. This happens with every import, so, importing dialogue is a pain.

Back to modding quirks

Local, global, targeted, variables

There are three kinds of scripts: local, global, targeted. A local script belongs to an actor or other object and runs as long as that actor/object is close enough to the PC (main game character); it can't be stopped with "StopScript". A global script is not attached to any actor or object, so there is no default target, as it were, to apply commands to; also, it runs non-stop no matter where the PC is, although it can be stopped with "StopScript". A targeted script, which is a form of global script, is like an ad rem local script: it is not attached to anything, but can be told to attach itself to an actor with "Actor->StartScript TargetedScript" and then acts like a local script, with limitations. Being basically a global script, it also keeps running no matter where the PC is, and can also be stopped with "StopScript". This info is straight out of MSFD9, but here's why I'm repeating it:

I use a script, StayWithCrassius, to have my companion stay with Crassius Curio for a while. The script tells the companion to stop following me and go stand next to Uncle Crassius. It also fills his health and magicka bars to their original value, which I know because that value has been stored in variables in the companion's local script. The script StayWithCrassius does not have direct access to the companion's local script variables, so I code it with the qualifier "mycompanion.":

SetHealth mycompanion.basehealth

This doesn't work. And if I put this line in a result field, I would get a complaint that SetHealth (and by extension any Set/Mod command) can only take local variables. I can't define variables in a result field, but this is a script, so I add variable "tempval" to StayWithCrassius:

short tempval

set tempval to mycompanion.basehealth
SetHealth tempval

This compiles without problems, but still doesn't work. Oh wait, the script is not targeted (it's called once and terminates itself after running) so maybe I ought to specify whose health should be set?

short tempval

set tempval to mycompanion.basehealth
mycompanion->SetHealth tempval

This will produce an expression error of the LeftEval type when the script is run in the game. The only way to get around that is to make the script targeted. So in a result field I put:

mycompanion->StartScript StayWithCrassius

instead of just

StartScript StayWithCrassius

and now the script will work. The "mycompanion->" bit in "mycompanion->SetHealth tempval" is now optional, but the "mycompanion." qualifier is not, and neither is the tempval variable; Set/Mod commands don't like directly being assigned other scripts' variables.

Trying to make an expression work too hard also causes eval errors, and I'm not always sure what causes them, too many arguments or the arguments being mixed local/global variables. Here, the cause has to be too many arguments:

set tempval to ( tempval + ThisActor.localvar1 + ThisActor.localvar2 )

The error was an EXPRESSION error, maybe from using the same operator twice? Or because I queried a local variable in the the same script twice?

This causes a LeftEval:

if ( ThisActor.localvar - AGlobalVar <= 0 )

And this causes a RightEval:

if ( ThisActor.localvar <= AGlobalVar )

But if I change the second example to

set tempval to AGlobalVar
if ( ThisActor.localvar <= tempval )


it works. As the examples suggest, this was a targeted script using a global variable, a NPC script's local variable, and its own local variable tempval to make them cooperate. In a local script, the following

if ( localvar - AGlobalVar <= 0 )

can also cause problems, so it's best to combine the two values in another local variable, which I'm again calling tempval, before proceeding:

set tempval to ( localvar - AGlobalVar )
if ( tempval <= 0 )

At this point I should mention that there are also three kinds of variables: global, local to the script you're dealing with, and local in other scripts. Actually, there are just two types of variables, global and local, and I only divided the local type into "local" and "remote local" because of problems like the case at the top of this section, where one script can't access the local variables of another. Global variables are accessible by all scripts, and always keep their value, but can update a bit slowly (eg. I can set the global variable that changes a NPC's responses from normal to happy, but it takes a while for those happy responses to appear). Local variables in local scripts assigned to objects/actors also keep their values, and can be accessed through "ThisActor.localvar", although, as shown above, this doesn't always work. Local variables in global scripts (whether targeted or not) retain their value as long as the script runs, which is generally throughout the game if the script is not stopped with StopScript, and are accessed through "ThisScript.localvar" which likewise doesn't always work. The crux is that local variables can be set from the outside, but not queried from the outside; with an extra caveat that follows below. In any case, all these types and subtypes of variable don't like being mixed. To avoid strange LeftEval and RightEval error messages, it's best to define a "short tempval" in every script that interfaces with other scripts and/or global variables, and transfer any outside variable's value to this tempval for further processing.

I should also repeat something else from MSFD9: if a script contains a local variable defined in another script, but not in itself, the compiler doesn't report this error, and the script malfunctions in the game. Because I use tempval and helpval in various scripts, I don't get a warning if I use tempval in a new script that has no "short tempval" at the top. This had me tearing my hair out and cussing the TESCS until the penny dropped.

Back to the caveat: I can set variables in other scripts, but not get them. So, this works:

set StayWithCrassius.ALocalVariable to tempval

and these two don't:

set tempval to StayWithCrassius.ALocalVariable
set StayWithCrassius.ALocalVariable to (StayWithCrassius.ALocalVariable + tempval )

so in global scripts, there is no way to directly augment a local variable from the outside; the only way to do it would be for the other script to get the value of StayWithCrassius.ALocalVariable into tempval, augment tempval and then set StayWithCrassius.ALocalVariable to tempval, but how do you get the value of StayWithCrassius.ALocalVariable into tempval in the first place? By having StayWithCrassius set it in your other script that contains tempval, but since scripts all run at the same time, the script needs more variables to keep track of when the value has been transferred, and when the augmented value can be transferred back. And that is why global variables were invented...

When it comes to local scripts, their local variables can be read (and augmented), but only by a targeted script. And in this targeted script, prefixes are not needed, but I do need to specify what script the variable belongs to. So in the aforementioned "mycompanion.basehealth", the "mycompanion." bit is essential. The compiler won't complain if it's missing, but the game will. Now for that caveat! Getting values from the "mycompanion" script is harmless. Setting values in the "mycompanion" script in the dialogue result field is also harmless. Setting values in the "mycompanion" script from a global script that runs all the time, even when the companion is not present and the script is therefore not necessarily running, can have at least two fatal outcomes:

1. The global script is targeted and has lost its target (can no longer access the mycompanion script) but still tries to assign a variable in that script.
2. It's an untargeted, constantly running global script, and it tries to assign a variable in "mycompanion" on entering that companion's cell, ie. when the companion is refreshing itself because the player is entering a new cell (with that companion in it).

In both cases, the game crashes. Presumably, the same would happen if I set a variable in a global script that's not running. I've found that the following code in the result field won't work (but causes no crash):

StartScript AGlobalScript ; automatically targeted since run from dialogue
set AGlobalScript.localvar to 2


presumably because the script, having just started, isn't properly underway yet. For targeted scripts, and this is straight out of MSFD9, it's best to start the script with a targeting test:

if ( GetHealth == 0 ) ; note, no prefix
  return
endif


because when it is, the actor is dead, or the script is without target. For global scripts, any assigning should be done on the following condition:

if ( ScriptRunning TheGlobalScript == 1 )
  set TheGlobalScript.localvar to AValue
endif


As for setting variables in local scripts running on actors, it's safest to do that when you're right next to an already loaded actor, ie. through dialogue or a script run from the dialogue result field. "ScriptRunning" doesn't work with such scripts, and the clearest indication that they're not up and running is that ForceGreeting won't open a dialogue menu, but that's a bit cumbersome to test for.

Sometimes it will seem as if global and local variables don't work together when, in reality, a function simply won't accept a type of variable (SetPos which won't accept globals) or any variable at all. In my experience, AddItem and RemoveItem will not accept variables. This is annoying when trying to empty an inventory of, say, all arrows: it is possible to use GetItemCount to put the number of arrows in a variable, but it is not possible to use RemoveItem with that variable to have that many arrows removed. The only solution is to remove arrows in a loop, one at a time, either checking with GetItemCount in each iteration whether all the arrows are gone yet, or putting the total number of arrows in ALocalVar and using a "while" loop (which is said to be slow) to keep deleting an arrow and decreasing ALocalVar by 1 until ALocalVar is zero.

Perusing MSFD9 turned up the following on page 37:
Notes on using Additem / Removeitem in dialogue:
These functions can accept global variables, but only in dialogue results,
and only if you don’t set the global variable in the same dialog result (Forum info / Argent; According to Argent, the maximum amount he has been able to add using AddItem, var was 65534 (using a long var=2147483520)). In addition to Argent's info about AddItem/RemoveItem accepting variables in dialog action boxes: make sure that the variable in question doesn't change in the same box.

So using GetItemCount to set the variable to be used with RemoveItem still wouldn't work.

What is funny about accessing remote local variables is that, without targeting, you can set their values but not get their values, but sometimes, strangely enough, you can't even set them! But that may be a matter of brackets. These two lines of code in a script targeted on an NPC (where the NPC has its own script and local variables) will work:

set companion.INBintelligence to ( companion->GetIntelligence )
set companion.INBathletics to companion.realathletics


But this line will not:

set companion.INBintelligence to ( LocalVarIntelligence )

because of the brackets around the variable name. And I suspect that

set companion.INBathletics to ( companion.realathletics )

wouldn't work either. Normally, brackets are required, as in

set companion.INBathletics to ( player->GetAthletics )
set companion.INBathletics to ( tempval + 4 )

although the game is forgiving about a lack of brackets; far less so, however, about brackets with no space between the bracket and the expression within, eg. "(player->GetAthletics)".

Back to modding quirks

Block if-endif too large

Sometimes I get a RightEval or LeftEval error message in the game from a script that compiled just fine in the editor. And I don't always get the same error.

The problem is with if-endif blocks that are too large. The compiler doesn't check for this, but if I have a huge if-elseif-elseif-etc-endif block that has about twenty elseifs, and the script finds the twentieth elseif to be true, and this is beyond the amount of code that the game can oversee in one block, the game suddenly realizes that this bit of code is "cut off", and the equation is no longer complete. It's like lopping off the end of a long sentence that doesn't fit on the line, and then realizing you can't find the period. If the first or second elseif is true, the rest of the block is not evaluated, and the error doesn't occur.

The solution is smaller blocks, for instance, five if-elseif-etc-endif conditions, then, if one of these has been satisfied, a StopScript/return, then the next five if-elseif-etc-endif conditions, and so on.

Back to modding quirks

Dialogue and greyed-out fields

The dialogue editing screen allows me to add responses to a topic for everyone (all speaker fields empty) or for NPCs of a certain race or class or other group (choose race/class/etc. from drop-down boxes). Or I can choose an actual NPC ID, which makes the race/class/etc. choices moot, so, if these were already filled in before I chose the NPC ID, they become greyed out. However, they are still in effect! I added a response for the class Slave and changed the NPC ID from "blank" to a NPC who was not a slave. Consequently, that response didn't appear in the game. I had to go back to that response, set the NPC ID to "blank", then set the now editable class field to "blank", then select the right NPC ID again. In this case my mistake was to leave a value in the Class field, but no doubt the same applies to the other speaker fields.

Back to modding quirks

Special local variables

This is a continuation of Local, global, targeted, variables but was given its own header because that block is already quite large. Most slaves in Morrowind have a local script called "slaveScript" which keeps track of whether they are owned or freed. The slave called Yakov (found at the Suran Slave Market) does not. So I made a script called something like YakovSlaveScript and ran it targeted on Yakov. That's how I discovered three things:

1. There are special local variables that can be defined in an NPC's local script to give that NPC certain abilities: nolore, companion, stayOutside. They can't be defined in a targeted script. Well, they can, but they'll have no effect.

2. And, of course, if you define a local variable like slavestatus in the targeted script and then make a response in the dialogue editor depend on that variable, it won't work either because dialogue responses can only depend on local variables in the local script of the NPC being interacted with. Moreover, the variable can't be used in the result field. I tried something like "MessageBox "Slavestatus %g" YakovSlaveScript.slavestatus", without success.

3. And, even more importantly, local variables from a targeted script can't be queried by another targeted script. Makes sense, as both scripts are targeted on an object (which does not have these local variables) and not on each other. The other targeted script could do something with, for instance, "YakovSlaveScript.nolore", but that way, it affects the script and not the individual NPC (as opposed to the slaves with "slaveScript", who each have their own instance of this variable). Not that it matters, as a targeted script is still a global script and only one instance of a global script may be run at a time, ie. there would be no other YakovSlaveScript running.

In vainly trying to give Yakov normal slave features (other than by adding the slavescript to the NPC, a change that might be made undone by a newer plugin changing, say, his appearance or abilities) I discovered, in an effort to add choices to slave dialogue through a script that displayed the same choice options after every response, what is mentioned in Local, global, targeted, variables: local variables from a local script can only be queried by a targeted script if the actor that the script belongs to is specified. As an example, say I add companion and stayOutside to "slaveScript", which means every slave can now carry my stuff and be told to wait outside. I then add a dialogue topic "follow" with a response for Khajiit slaves (the "third person" people) and other slaves. So I don't have to put the same list of choices (including: "Follow, but stay outside") in the result fields of both responses, I stick them in a script called "SlaveFollowChoices" (which terminates itself as soon as it has displayed the choices) and put "StartScript SlaveFollowChoices" in both result fields, which means the script is targeted on the speaker. This script is run for every slave with whom the PC talks about "follow" and so it uses the slave's local variable stayOutside (added to the enhanced slavescript) without identification:

if ( stayOutside == 1 )

instead of

if ( menelras.stayOutside == 1 )

since it should work for every slave. It won't. When the script encounters this remote local variable, it stops running. I had to ditch the script and put the choices directly in the result fields instead.

Most special local variables, particularly stayOutside, were added in Tribunal. Another local variable added in Tribunal, specifically for Calvus Horatius, a mercenary that the player can hire, is minimumProfit. This variable keeps track of everything the companion NPC carries - both possessions and money - that wasn't part of the companion's base equipment. Hm, so if I created a companion with no money or possessions, but with "minimumProfit" defined in its script, this would work like the function "PC Clothes Modifier" which returns the value of what the PC is wearing, and so is zero when the PC is naked. It wouldn't quite work because minimumProfit also counts non-wearables and money; still, maybe this could be an easy way to check for dialogue options like "PLEASE put on some pants".

It is not. The base value stored by minimumProfit has values added to or subtracted from it when the player uses "companion share" to put things in or take them out of the companion's inventory, but the base value itself is raised each time something is added to the companion's inventory by an AddItem command in a script or dialogue result field. For the average companion mod, that means the base value of minimumProfit bounces all over the place, and "minimumProfit == 0" says nothing about how much the NPC is wearing or carrying.

Special local variables that were not present in plain Morrowind, and would therefore have no effect even if defined in a NPC's script, may be made to work by importing the related GMST from Tribunal into the companion mod, even though this GMST only holds the string value for the variable, and doesn't contain any code. I understand that this is how a Morrowind-only companion mod can make companion work, allowing the player access to the companion's inventory, although I haven't gotten this to work yet.

Back to modding quirks

SetChameleon

Apart from the Get/Set/Mod commands for skills and attributes, there are also Get/Set/Mod commands for certain effects, like Attack and Chameleon. If I use "player->SetChameleon 100", either in a script or from the console, the PC should become undetectable. I used it in a script to give the player total undetectability for 60 seconds. It didn't work. I thought Sneak was also needed, added a variable to store the player's Sneak skill, used "player->SetSneak 100" and saw that, again, it didn't work.

(At least, it seemed not to work. The PC doesn't become transparent but does apparently become invisible to NPCs. My player character was still detected by NPCs, however.)

So I created an Ability - a spell that, when you add it to the player, instantly affects the player, instead of going into the player's list of spells - which sets Chameleon to 100 and fortifies Sneak by 100. No need to store the old Sneak value now, the game will take care of that. And the script added the spell, counted to 60 and then removed the spell. This time, I saw the PC become see-through as a sign that it worked.

Back to modding quirks

GetDeadCount and the prefix

GetDeadCount works like GetItemCount. The object to be counted comes after it. Yet I had the idea that it worked like GetHealth and had the object before it, with a prefix:

if ( yakov->GetDeadCount > 0 )

This was at the top of a script, and all code under it was ignored. I soon discovered the correct syntax:

if ( GetDeadCount yakov > 0 )

The funny thing is that the syntax with prefix was not reported as an error either when compiling the script or when making the same mistake in the result field and then running Error Check Result.

Back to modding quirks

Expansions and missing dialogue

The following will never happen when simply adding dialogue to a Morrowind-only plugin in a Morrowind-only installation. I was making a Morrowind-only plugin in a GOTY installation using Wrye's GMST Vaccine ESP to prevent unwanted GMSTs in the plugin. Now Tribunal and Bloodmoon, as well as adding GMSTs, add a lot of dialogue, especially under generic topics like "someone in particular" and "specific place". My plugin also added dialogue under these two topics. And those under "specific place" never showed up. I didn't understand why, as I'd hung both inserts somewhere under the topmost line in the dialogue present in the original Morrowind gamefile. For "someone in particular" the dialogue was ordered like this: first a block of expansion dialogue, then the old dialogue. That's why my added dialogue for this topic showed up. For "specific place", the original and expansion dialogue were not so neatly separated. That's why, although I thought I'd added lines in the "old dialogue" section, they were in fact under an "expansion dialogue" line. The plugin relied on "Morrowind.esm" only, but the line ID that my added lines started under did not exist in this ESM, hence, the lines were not shown.

Conclusion: when adding dialogue to a Morrowind-only plugin in a GOTY installation, make sure the dialogue is inserted under a Morrowind-only line. I moved the lines so they came under Elone's reply about places the player should know about, and that solved the problem.

Back to modding quirks

Two ways to cause a CTD through dialogue

The first way to crash the game through code in the dialogue result box is one that I could have seen coming. MSFD9 warns that two or more text displays in the same frame could cause a crash. I have the PC do something for an NPC. And the NPC says a big "thank you" and gives the PC a bundle of stuff. So far, so good. But because there is so much to receive, all the "XX has been added to your inventory" makes the dialogue window scroll upwards so fast that the big thank-you is completely lost from sight. So I split the response up into two parts and put "Choice "Continue" 1" under the first part. The idea is: text1->Continue->text2 and give stuff. But now I make a mistake: I put the code to give stuff in the result field of text1, not text2. So, while the dialogue window is waiting for me to click on "Continue", the messages about all the stuff I'm getting pop up in separate little windows. Then an error message pops up saying something about "menu pointer error", followed by a CTD. Note to self: always put alter-inventory code in the result field of the dialogue line that comes after a "Continue".

The second way requires a script to dynamically generate choices. Normally, choice code is put in the result field and there are two or more choices. In this case, I want the player to be able to train a companion in all skills the game knows (that's an awful lot of choices) as long as the player has more points in that skill than the companion (that eliminates a few choices). So for every skill, I have to compare the player and the companion to determine if the choice will show up. For this, I write a script (something like CalculateChoices) which is run from the result field and shows the appropriate choices. When they've just met, the companion's skills will be poorly developed, hence the number of choices shown is so big it makes the dialogue window scroll upwards, and... CTD. The solution is to subdivide the choices: first have the player ask what attribute to work on, then what skill belonging to that attitude to train in. That means a crash-safe maximum of seven choices per question. Both sets of choices are presented by the same script, which also allows the companion to offer training to the player (again, only for skills that the companion is better at). Oooh, I'm so clever.

Back to modding quirks

What NPCs will and won't use

The case for this tip is Mistress Dratha. This venerable old magic user has maybe two spells in the game. That's not much, so in a general startup script I added more spells to her character. Then, I added some dialogue so that she wouldn't just get the ring of Black Jinx delivered to her; she would have to work for it, by battling three atronachs in the Arena. And they killed her every time, because she just wouldn't use the spells that were added.

So in the script that made her fight the atronachs on entering the Arena, I also added scrolls to her inventory that she might find useful. She only had two scroll types in her original inventory, one for spell absorption and one for a shock attack, to which the storm atronach was, of course, immune. No wonder he kept finishing her off. Checking her corpse, I found she had used the extra spell absorption and shock attack scrolls I gave her, but did she use the sixth barrier scroll? Noooo! I've noticed with companions also that they will not use healing scrolls on themselves in a fight, although they will use healing potions, which is a shame as NPCs tend to drink all healing potions at once but will only use one scroll at a time. At any rate, I conclude that as with spells, NPCs only use scrolls that they were given in the game editor.

So I added potions to protect against frost and shock attacks (being Dunmer, she was already fire-resistant, and the flame atronach was always the first opponent to go down) and lo and behold, she used them. So game AI will let NPCs use "strange" potions, at least during combat and defensively, and I assume if the potions are standard and not a player-brewed concoction (but this hasn't been tested).

With weapons and magical items, the opposite appears to be true, ie. attacking items are used instead of defending ones: NPCs will use a shock or frost ring in a fight, but not a healing ring. They do use a barrier ring, but not, it seems, a robe that casts Reflect. Sadly, guaranteeing an effect by letting them wear a "constant effect" item (a belt of Feather so they can carry more?) is a bad idea as "constant effect" starts to work backwards on an NPC after a while. Having an item that constantly regenerates health, but letting them wear it only during battles, might be a safe way of keeping them alive.

In addition, I gave Dratha three soul gems and let her cast Soul Trap on the atronachs (NPCs can cast any spell when the script tells them to, whether they have that spell in their inventory or not). This worked, that is to say, when she killed the first atronach, I received a message "you have captured a soul". I didn't check whether the soul had gone into a gem of mine or into the soul gems I had added to her inventory, but it was a moot point as, apart from the undesired message, she could only cast Soul Trap once before combat commenced and she skipped the next two times in favour of defending herself. So I just let her give me fully charged soulgems out of nowhere with AddSoulGem if she survived the fight.

Back to modding quirks

Shushing a companion

A NPC in following mode is with you all the way. Kill someone? The NPC will help you without question. Grab stuff that isn't yours? The NPC stays mum and will even carry your loot, companion share permitting. But put the NPC in Wander mode by telling them "stay here", and their conscience returns. Ooh, thief, murderer! Worse, their outraged cries attract others, and if you're unlucky, those others will be guards. Ditto the NPC who is intended to be your companion: do anything wrong before you've asked the NPC to follow you, and you may find yourself running from, fighting or killing your intended companion. The following is info that I got from MSFD9, put to practical use:

I can add the standard local variable "nothief" to the NPC's script and set it. What this does is block the uttered accusations, not the mounting rage itself. This rage is programmed as the NPC's Alarm value: the higher the Alarm, the more likely the NPC is to attack. The commands dealing with the Alarm value are GetAlarm and SetAlarm (default value: 30). The above scripting guide tells me that the variable OnPCHitMe is set to 1 not only if the PC actually hits the NPC, but also if the NPC sees the PC doing something naughty. So, in the NPC's personal script, I add code that sets Alarm to 0 whenever ONPCHitMe is triggered.

For this particular companion the script only sets Alarm to 0 before the companion and the player are properly introduced, as the companion is supposed to criticize the player later. It may be useful in the script of a companion not meant to block the player. Usually, companions will follow the PC so closely that the PC ends up getting jammed in doorways. Some, like Princess Stomper's "Breton Hunk Companion Lite", will always obligingly step out of the way, and others have an option to let me choose between these two modes of behaviour. What happens when the companion gives the player some space is that this companion is set to Wander, which turns on a personal collision detection, until the distance has widened enough and then switched back to Follow. In that interval, the companion may suddenly subject the player to a barrage of accusations and even become aggressive, unless subdued using nothief and SetAlarm based on OnPCHitMe.

Back to modding quirks

Script quirks in a Morrowind-only mod

So I had a big messy unfinished mod that needs Tribunal and Bloodmoon, and I wanted to take out some stuff that didn't need Tribunal or Bloodmoon and put that in a Morrowind-only mod. But the big mod used a startup script to dress some nude people the first time it was run, and to check if any pilgrims needed to be removed from the shrine after a finished pilgrimage, every time it was run. And Morrowind uses only one startup script, which I'd rather not alter. A recommended solution for a script that only needs to be run once is to attach it to a ring or other small object, and then hide the ring in Seyda Neen, so it will be loaded, and its script run, when the player first steps out of the Customs and Census office. But my script needed to be run preferably at least once per game. So I attached it to four rings and hid these in Seyda Neen and three other places where the player was bound to go every so often (Vivec, Ghostgate, Balmora near Caius Cosades' house). They worked like this: if a CellChanged occurred (the player either wanders into or out of the cell where the ring is) then the script would run, and relocate NPCs if needed.

And it didn't work. When I started a new game, Morrowind responded to the script as it often does to scripts when Tribunal/Bloodmoon are not installed:

Trying to RunFunction index greater than function count

And the script aborts. This is apparently because the ring's script doesn't wait for the intro and tutorial to finish, but runs straight away; a problem I've never had with the startup scripts that the expansions allow me to add. So in this Morrowind-only workaround-startup script, I have to add code to stop it running until the game has properly started:

if ( CharGenState != -1 )
  return
endif


That took care of the error message, although the script still didn't run due to a copy/paste error that produced a LeftEval error. That the CharGenState-related error message has something to do with the difference between Morrowind and Morrowind plus expansions is shown by a "Skip Tutorial" mod that I always use which works perfectly under GOTY, but whose altered "CharGenDoorExitCaptain" produces the same RunFunction message under Morrowind.

Having found that "startup" scripts need to be stopped from running too soon, I found another Morrowind-only quirk: CellChanged doesn't always work. In the Arena in Vivec, there is a hidden ring with a script attached, just like my "startup script" rings. And, just like those rings, the script only runs when "CellChanged == 1", in this case, when the PC steps into the Arena. Then, if there is any fight scheduled, the appropriate opponent(s) will be teleported into the ring. But I wanted to bring Dratha over to fight some atronachs. So I made a second ring based on the first, that also ran after a CellChanged event (but only if the first ring hadn't started any duels). In the GOTY plugin, I tested this and it works. In Morrowind, it did not. Apparently, if two scripts in one cell check for CellChanged, only the first one gets accurate feedback. So the second one has to use another method. Fortunately the second ring was only needed for one fight, so I could define a variable "doOnce" and use that instead of CellChanged.

Conclusion: the expansion sets not only add new features, but fix stuff that is broken: stuff that the Morrowind-only game patch doesn't fix.

Back to modding quirks

CellChanged, GetPCCell and cellnames

The following information is in MSFD9 and in various places on the web, but I somehow missed that and found out for myself: CellChanged happens in the frame when the PC walks or doorports (teleports through a loaddoor) into a new cell, and any local scripts registering CellChanged do so only when the PC enters the cell where their object exists. CellChanged can be used by two or more scripts in the same cell, although in plain Morrowind I've found this unreliable. CellChanged is NOT triggered by scripted (eg. the Propylon indexes) or magical (Almsivi or Divine Intervention) teleportation, by travel (eg. silt striders), when using "coc" in the console, or when the change in cell could lead to a ForceGreeting, as with the chargen door (the final door out of Seyda Neen's office), which never raises a CellChanged when used, even though the script on it only leads to a ForceGreeting if the PC is newly created and tries to leave without handing over the identity papers. (This was the case for the first time I installed Morrowind from the GOTY Edition; I've since installed it from the Elder Scrolls Anthology, where CellChanged does happen once the script no longer causes a ForceGreeting, so this may have been patched.)

There is no reliable way to find out whether the PC has changed cell. It is possible to deduce whether the PC has left or entered an interior cell with a script that uses GetInterior every second, and compares the new value with the previous one; this doesn't work when the PC moves from one interior cell to another. Doorports can be detected with a companion in following mode, and a script that checks GetDistance between the PC and the companion every frame: immediately after the doorport, GetDistance will return 0, as the companion materializes in exactly the same spot as the PC. Teleports in the exterior can be guessed by a global script that keeps track of the PC's coordinates and sets a variable if the PC has moved "too far" in one frame, although what constitutes "too far" is anyone's guess.

GetPCCell is said to take part of a name, as in "Fort Frostmoth" which will return true for all cells whose names begin with "Fort Frostmoth,". Using "Old Mournhold" it did not return true for all of Old Mournhold's cells, which begin with "Old Mournhold:" - note the colon instead of the comma. I tested if the cell "Vivec, Jeanne: Trader" would return true for

GetPCCell "Vivec, Jeanne"

and it didn't. Neither did

GetPCCell "Old Mournhold:"

with colon included, for any cells in Old Mournhold. My initial conclusion was: if there is a colon in the cellname, GetPCCell can't recognize it unless it's written out in full.

I have since figured it out, from wondering why the Tribunal expansion contains three unused interior cells, one of them even completely empty: the string used to refer to all cellnames starting with it, also has to exist as a cell itself. Those three unused dummy cells allowed GetPCCell to cover almost all of Tribunal's added cells: due to the dummy "Mournhold" cell, GetPCCell "Mournhold" did not only return true for the Mournhold town cells (Palace, Bazaar) but also for "Mournhold Temple: Reception Area" and all other Temple rooms with colons in their names. Due to the dummy "Mournhold Temple", I could also use GetPCCell "Mournhold Temple" to check if the player was present only in the Temple part of Mournhold. The first two dummy cells contained unfurnished buildings, but the third, "Sotha Sil,", was empty, just a defined interior cell and nothing more. Creating another such a cell with the name "Old Mournhold", I could suddenly use GetPCCell "Old Mournhold" (colon not needed) for any Old Mournhold room, instead of having to write all the room names out in full and testing every one of them separately.

Finally, if GetPCCell (or coc in the console, or PositionCell to an interior cell) doesn't work even though the cellname looks correct, it may be that the cellname contains extra spaces. In the script editor, with its proportional font, two spaces often look like one. Solution: type out the cellname in an editor using a font of fixed width, like Monospace or Courier New (the "typewriter" font), copy, and paste.

Back to modding quirks

Distance and NPCs

When querying in the console (and probably in a script) how far away an NPC is from the PC, GetPos X/Y/Z only works if the NPC is in memory, which is true when the PC has recently talked to or entered the same cell as the NPC (or if the NPC is in a cell near enough to be loaded; how many adjacent cells are loaded is determined by the game settings). As long as the NPC is loaded, GetPos will work no matter how far removed the PC is from the NPC, although they should be outside or in the same interior cell, else the coordinates are useless to calculate distance. GetDistance always works.

Likewise, SetPos only works when the NPC is in memory, while GetCurrentAIPackage and GetHealth (and I assume SetHealth) always work. I tried to use GetPos, GetCurrentAIPackage and GetHealth to see if a companion 1. is loaded in memory and 2. is still following me, but have decided that to check the first, I should use a targeted script containing GetHealth without prefix, since that will return 0 when the companion is no longer loaded, while GetPos seems to return nothing at all.

When PC and companion are in totally different worlds, ie. at least one of them is in an interior cell, GetDistance will always return:

340282346638528860000000000000000000000.00

which, I've found, can't be stored in a variable, maybe because an ordinary float can't store a value that big. So when comparing the outcome of GetDistance to a value to see if a companion is in a different (interior) cell, I have to write this value out in full every time.

Both "NPC->GetDistance PC" and "PC->GetDistance NPC" only work on the FIRST INSTANCE of the NPC, and can't be used to check how far away the PC is from multi-instance NPCs like guards. For such NPCs, it is possible to use "GetDistance PC", without prefix, from a targeted script, but then the problem is how to target the script at the right instance; the only way I know is to start the script from a result field, which means the PC has to talk to the NPC, in which case the NPC is close enough to be in the PC's line of sight. A second possibility is to use "GetDistance PC" in the local script of the NPCs, which isn't a problem when adding new NPCs in a mod, but which in the case of already existing NPCs, like guards, means adding or altering a standard script, and hoping another mod won't undo the changes.

Back to modding quirks

GameHour

The global variable GameHour wraps. All by itself. This occurred in Morrowind with all expansions installed, and wasn't tested further, but this is what I discovered through a script to advance the game time. If it's 23:00 and I add 2, the game time automatically becomes 01:00 - no need to calculate the value.

Global variables pertaining to date - Day, Month, Year - also run from 1 to a certain number and then go back to 1, although I haven't tested whether they wrap around automatically when their value is raised in a script. According to MSFD9, Month wraps around wrong in the game itself: it goes from its highest number to 1, even though the first month's number is 0, so basically a month is lost every year. Maybe this has been fixed in a fan patch, I haven't checked.

Because the aforementioned script calculated the date 8 hours into the future, which meant that I also needed to know the new day if the 24-hour mark was passed, and, due to wraparound, today's Day might be 30 and tomorrow's Day might be 1, I used DaysPassed instead. This global variable, introduced in Tribunal, keeps track of the days passed since the start of the game, so tomorrow's value will always be higher than today's. It should also work in Bloodmoon, but hasn't been declared there, so anyone who uses DaysPassed with BloodMoon alone has to add it in the TESCS. Whether DaysPassed would be updated by the game if declared in a Morrowind-only mod, I don't know. (In a test in an older installation, it did not. However, see DaysPassed turns up in Morrowind-only installation.)

Back to modding quirks

Innate spells interfering with learned ones

Beggar's Nose is a spell that may be added to the player through a birthsign; it exists only in the birthsign "the Tower", and has a placement count of zero in the editor. This is a problem when using GetSpell. Say, a NPC offers to teach the PC spells, but not, of course, the spells that the PC already knows. And the PC has been given Beggar's Nose by choosing the right birthsign. The following:

player->GetSpell, "beggar's nose spell"

will return 0. After using

player->AddSpell, "beggar's nose spell"

GetSpell will still return 0. If the player didn't get that spell through a birthsign, GetSpell and AddSpell will work as expected.

How did I know this? Because I had a dialogue option to make a NPC teach the PC a number of spells in a specific order, Beggar's Nose being something like the fifth, and I noticed that for PCs with a birthsign that already conferred this spell, there was no way to learn the spells after it. I couldn't test for the spell, and I didn't know how to query the birthsign - besides, other mods might add new birthsigns with that spell - so I just scrapped the spell from the list.

Back to modding quirks

Witchwither and paralysis

There are two commands, GetParalysis and SetParalysis. And one would think that this means paralysis is an on/off setting: 1 means paralyzed, 0 means not. But no. I discovered this when adding code to a companion script to make the companion auto-cure himself of diseases, poison and paralysis, if he had the right spells and number of magicka points, or items like scrolls and potions. Mostly, the code worked. The problem lay with paralysis, and particularly Witchwither, a common disease that causes paralysis.

Paralysis usually happens when fighting scribs and/or magic users. So as to be able to test the self-curing code without getting into a fight, I opened the console and used "mycompanion->SetParalysis 1". He didn't cast an unparalyzing spell because he was paralyzed, but he did "drink a potion" against paralysis, which means a script had something cast the potion's spell on him, and it didn't work; GetParalysis still returned 1. Apparently SetParalysis works differently from paralysis caused by spells.

So, in the console, I used "AddSpell witchwither", since a disease, like an ability, is a kind of constantly self-casting spell, and casting a regular spell on him myself would have made him hostile, and was not guaranteed to succeed. This led to a catch-22, as he had both a disease and paralysis. He couldn't cure the disease first because he was paralyzed, and if he had loads of potions of Cure Paralysis (and not Paralyzation, Bethesda), he would drink them all, because the still active common disease would reparalyze him as soon as he deparalyzed himself. The only solution in this case was to use SetParalysis to set his paralysis to zero, then have him cast a spell or drink a potion against disease.

But since paralysis is not an on/off setting, it is unwise to have GetParalysis test whether paralysis is 1 or 0. Firstly, paralysis can run from 1 to... well, I don't know what the maximum is, but at least 5. A potion or spell of Cure Common Disease will get rid of paralysis completely, but NPCs can't reliably use potions, nor can they cast spells when stiffened. Especially with Witchwither which keeps incrementing paralysis, it's unwise to code something like "if GetParalysis=1 then SetParalysis 0". Similarly, paralysis can be below zero, ie. negative, so a companion unparalyzed by using up a stack of potions or having paralysis decremented by 1 several times over, can't be tested with "if GetParalysis=0". I had to check whether paralysis was above zero, or less than/equal to 0.

Back to modding quirks

How to detect if an actor is in water

This is the same for PC and NPCs, and depends on whether the current cell is inside or outside. However, unless the script is targeted or local, prefixes are needed for both the localizing and the sound-detecting commands.

In an outside cell, it's easy: the waterlevel is always at 0. In this game, the Y and Z axes have changed places, so the vertical coordinate is the actor's Z coordinate. This coordinate determines at what height the actor's feet are, so if it is below 0, the actor is standing (anywhere between ankle-deep and totally submerged) in water. To put it in code, using a variable InWater which may be global or local:

if ( GetInterior == 0 )
  if ( GetPos Z < 0 )
    set InWater to 1
  else
    set InWater to 0
  endif
endif

This example is from a NPC's local script with a local variable. It could also be a targeted script running on the actor, or even a global script; in the latter case, GetPos needs a prefix ("player->" or "npcname->") but GetInterior doesn't, because GetInterior always refers to the cell the PC is currently in. This code should only need to be executed after a CellChange, but there are many ways of cellhopping that don't trigger CellChange. Therefore, it has to be checked every frame.

Inside, the waterlevel can be any value and, from Tribunal onwards, may also be altered with SetWaterLevel. Tribunal has also added the command GetWaterLevel, so in interiors I can replace

if ( GetPos Z < 0 )

with

if ( GetPos Z < GetWaterLevel )

but as well as being unsuitable for Morrowind-only mods, this still doesn't help, as regardless of waterlevel, the cell doesn't necessarily contain water. The only way to test if an actor is in water is by checking swimming sounds. The code below may slow framerate if checked every frame, but must be checked every frame regardless, or the code may execute too late to catch the sound being played. The best thing to do is, each time the actor enters a new interior cell, unset a flag "water in here", test for water if the actor is below GetWaterLevel (Tribunal and higher) or all the time, and the moment splashing is detected, set the water flag, record the water level (in plain Morrowind, this never changes) and QUIT TESTING FOR SOUNDS (especially with many companions all running the same water-test script), instead using GetPos Z as long as the actor is still in the same cell. This does mean that in Morrowind, in a waterless interior, the code keeps running until the cell is exited, but a solution is to keep storing the actor's lowest point at which water still hasn't been encountered, and not test while the actor is above that point.

; The more difficult inwater test (doesn't work in Vivec Canalworks!!)
if ( GetInterior == 1 )
  set InWater to 0
  if ( GetSoundPlaying, "DefaultLandWater" == 1 )
    set InWater to 1
  elseif ( GetSoundPlaying, "Swim Right" == 1 )
    set InWater to 1
  elseif ( GetSoundPlaying, "Swim Left" == 1 )
    set InWater to 1
  elseif ( GetSoundPlaying, "FootWaterRight" == 1 )
    set InWater to 1
  elseif ( GetSoundPlaying, "FootWaterLeft" == 1 )
    set InWater to 1
  elseif ( GetSoundPlaying, "drown" == 1 )
    set InWater to 1
  elseif ( GetSoundPlaying, "drowning damage" == 1 )
    set InWater to 1
  endif
  if ( InWater == 1 ) ; For next time in this cell
    set WaterInCell to 1
    ; In case you can't use GetWaterLevel
    set WaterLevelInCell to ( GetPos Z )
    return ; Only run this code again after cell change!
  endif
endif

The variable WaterInCell is the flag that determines if water is tested for, and should be set to 0 or -1 (under Tribunal, it can be set to 0 if the actor is below the level returned by GetWaterLevel, yet not in water) after every new entry into an interior cell, which is a problem in itself as CellChange is not reliable, so WaterInCell should simply unset itself every minute just to be sure. The variable WaterLevelInCell, used where GetWaterLevel is unavailable, should be defined as a float, and also reset on entering another cell. These variables can be set to 1 and 0 if the actor goes outside. The return, or some way of quitting this code, is necessary under Morrowind because if the actor walks deeper into the water, lowering the value returned by GetPos Z, the sound of walking into water will still be recorded and detected, and WaterLevelInCell will be reset to lower and lower values.

Unless the script is targeted or local, GetSoundPlaying, like GetPos, needs a prefix, or the sound will not be detected. This is because lots of sounds play all the time, and the script needs to specify who's making them. This means that I can't, frustratingly enough, set WaterInCell by detecting ambient water sounds ("water Level", "Underwater"). A sound needs to be made by an actor or object - something that can be used for a prefix - in order to be detected, and I don't know what prefix, if any, would work with running water sounds.

I thought I could test the degree of immersion (wading, swimming, submerged) from the sounds detected, but for "Swim Left/Right" and "FootWaterLeft/Right" this doesn't work, possibly because they all refer to the same soundbyte. "DefaultLandWater" (the splash of falling in) is a different soundbyte, as are "drown" and "drowning damage". To cover all possible situations of immersion, these sounds should be tested for, but if the player goes from "dry land" to "submerged" from one frame to another, then clearly "set WaterLevelInCell to ( GetPos Z )" will not accurately detect the water level. Ditto the "fall in water" sound, where the actor may already be some distance below the actual water level when the sound is detected.

Back to modding quirks

How to make a NPC drink a potion

The short answer is: you can't. Neither in Morrowind alone, nor with Tribunal. Apparently NPCs could be made to use a potion with Equip in Morrowind, where the function is broken; I haven't seen this myself. In Tribunal/Bloodmoon, where Equip does work, the PC can be made to "equip" (drink/eat) potions and foodstuffs/ingredients, but not put on wearables, while NPCs can be made to equip wearables (clothes and armour) but not potions - they are "equipped", ie. separated from the stack like a worn item of clothing, but not drunk - or scrolls, or ingredients/edibles, to which the same applies; and all "equipped" scrolls, potions and ingredients are unequipped as soon as any of them are lifted from the inventory via companion share. The only item type both PC and NPC can be made to equip is weapons.

So, how about AIActivate? Apparently this can make NPCs open loaddoors and pick up weapons. This function was likewise broken and said only to work with potions before Tribunal, although it doesn't seem to work with potions at all. I tested some situations and the results were inconsistent, probably because I didn't know what I was doing: did the item have to be in the NPC's inventory, or (as with loaddoors) outside and close to the NPC? AIActivate was said to make NPCs pick up a weapon, which suggested the latter. In any case, AIActivate will not work with a potion name (if the code was in the result field, an error check in TESCS produces a message that a creature/NPC of that name can't be found; the same message also appears when typing the code in the console) and won't do anything while the dialogue window is open. In the console, while leading Menelras (a buyable slave) around, I used PlaceAtMe to create a Scroll of Vigor and "menelras->AIActivate sc_vigor" to make him pick it up and read it: this caused a loop in which new scrolls were being opened for taking or closing (by the PC!) all the time until the game crashed - because scrolls (like soulgems, see What NPCs will and won't use) are always aimed at the PC? Maybe that's why NPCs won't use scrolls that were not in their inventory when they were created. When a potion is placed near the NPC and the NPC is told "NPC->AIActivate potion" in a script, nothing happens.

On a potion in a companion's inventory, AIActivate seemed to work if there was only one of the chosen item in the inventory. If it wasn't in the inventory at all, then AIActivate didn't work unless I used AddItem to add something different as well. To quote my (tidied-up) notes:

Case: NPC has no potions in inventory, "NPC->AIActivate potionname".
The first time this is used, nothing happens. After a different potion is added and used with AIActivate, it works. This seems to be reset by changing the NPC's health from the console.
Case: NPC has no potions in inventory, "NPC->AddItem potionname 1", "NPC-> AIActivate potionname".
It works and the potion disappears from the inventory.
Case: NPC has no potions in inventory, "NPC->AddItem potionname 1", "NPC-> Equip potionname".
It works and the potion disappears from the inventory. (Equip should not need AddItem, but else the encumbrance might be messed up.)

But then it didn't work any more, or maybe it never really had worked, so I gave up and tried a different approach.

I took up the suggestion of MSFD9: make a spell that does the same as the potion (which is a spell cast on the drinker) and use that spell instead, also removing one potion from the inventory to give the impression of having used it. There were several options:

What absolutely doesn't work: giving the NPC a weapon with a "cast once" enchantment. Say, a sword that, each time it's wielded, makes the NPC's health go up by 20. That would stack every time the sword was re-wielded, right? Just make the NPC wield the sword with StartCombat, quickly followed by StopCombat to nip the accompanying verbal abuse in the bud. Nope. Apparently such enchantments can't be cast, least of all on self, except through a scroll, which NPCs can't be scripted to use. Weapons only have "cast when used", so the NPC has to clock someone, or "permanent effect" which is no use when simulating potion-quaffing. Or there's the option where the actor casts a spell added to the spell list by wielding/wearing an item (like Fargoth's healing ring), which actors also can't be scripted to do.

Back to modding quirks






Previous Top Next