Common Mistakes

From the Oblivion ConstructionSet Wiki
Jump to navigation Jump to search

These are things that all mod-creators should know not to do.

AddTopic Dialogue Bugs[edit | edit source]

Even though it's well-known and documented in the wiki, the 'add topic' bug regarding dialogue continues to be one of the most common mistakes mod-creators make.

If two or more mods try to alter the same topic, only the changes in the mod loaded last will take effect. This causes serious problems because the GREETING topic is shared by all NPCs.

The problem occurs even if you have removed unwanted GREETING dialogue from your NPC.

Motub has written a detailed description of the AddTopic problem with steps for solving it.

Also, you should avoid having a topic added by both a script and in the AddTopic box. This can sometimes cause problems where NPCs may suddenly start conversing with you from far away, through objects, etc., as if they had been given a "forced greeting" directive (i.e., StartConversation).

Moving the addtopic lines out of the NPC's script and into the topic's result script box will avoid the issue.

GetBaseActorValue Includes Ability Fortify Effects[edit | edit source]

The GetBaseAV function does not accurately report the unmodified base value of stats that are changed by constant ability fortify effects. To get the true base value, you'll have to check for any constant ability fortify effects and subtract them from the result of GetBaseAV. This is a common problem with many player leveling mods.

One approach to solving this is to write a script that iterates through all the player's spells and their effects to find fortify abilities and adjust the base values accordingly. You can find a good example of this solution in the Realistic Leveling mod.

A simpler approach would be to use the GetTotalAEAbilityMagnitude function, but this appears to actually be slower than doing it yourself.

Altering Persistent References[edit | edit source]

Persistent references such as doors are tricky to alter in a mod since their position is stored in the player savegame data. Modders should try to avoid moving doors and other persistent objects from the original game if possible. If you do have to move them, the only reliable way to do it without requiring a new savegame is to use a script to force the updated locations to be recorded in the savegame.

Changing Script Variables[edit | edit source]

This issue is best described in Wrye's ESF thread "Overriding Scripts and CTDs", but that thread is now expired. Fortunately, a summary of the issue survived here.

The big problem with script variable changes is not which mod wins the conflict in a specific configuration, but that it can change over time. Suppose someone is using a hypothetical BaseModA.esm, which defines MyScript to have the variables VarA, VarB and VarC. These variables get the indices 1, 2 and 3. The savegame will just contain the information:

  script FormID = xxxxxx
  value for variable index 1 = x
  value for variable index 2 = y
  value for variable index 3 = z

In other words, only the position of the variable is stored.

Now if the player after some time decides he would like to add OptionalAddOnB.esp, and it contains slight alterations to MyScript, then it may still have the variables VarA, VarB, and VarC, but they now have the indices 3, 2, 1. When the savegame is loaded, it sees that the script FormID is still the same, so it loads variable index 1 into VarC, index 2 into VarAB, and index 3 into VarA (i.e., in the wrong positions). Depending on the meaning of these variables, serious problems can arise.

It gets even worse if VarA is a ref variable and VarC is a float variable. You now have the binary representation of that float value in the ref variable and the contents of a ref variable in the float variable. Complete chaos!

The only way to resolve this is to start the game without ANY mods active that define that particular FormID, load the savegame (which strips out everything), save, add the files you want in the order you want, and start again. Unfortunately, this solution won't work for changes to scripts that originated in Oblivion.esm (since you can never load without those FormIDs).

This is a critical issue that can cause a lot of CTDs, but somehow people still don't seem to know about it.

Changing a Quest Script[edit | edit source]

When creating a quest, often times a script is needed in order to keep track of things or perform condition checks to update stages. If the script being assigned to a quest has any variables in it, you cannot later change the quest to then point to a new script.

Doing so will cause the indexes on any variables to be wrong (see above). This can lead to all manner of confusion as features in the quest stop working correctly, AI packs stop functioning, dialogue breaks, etc. Any other scripts that were previously compiled with references to this quest will also become broken as they will no longer be pointing to the proper indexes. This includes dialogue results and quest stage results as well.

Since the new script will likely have variable types in the wrong place, this can also lead to CTDs in addition to the unexplained behavior.

Savegame Bloating[edit | edit source]

Your savegame contains info about changes to the gameworld. The more changes that occur, the more info that needs to be saved, thus the bigger your savegame file becomes.

One big culprit is the placeAtMe function. New objects that are created in the world using placeAtMe never disappear. This is particularly a problem with mods that use invisible activators to cast spells at the player or enemies - you end up with lots of invisible activators which are no longer used but persist in the savegame indefinitely.

Items stored in inventories are another common culprit, especially with the negative item count bug mentioned below.

Avoid Using PlaceAtMe[edit | edit source]

Early versions of the high-profile tutorial Casting Spells From An Activator used PlaceAtMe extensively, which apparently was very bad advice because the script examples will leave garbage in your savegame. At the time it was written, PlaceAtMe was thought to be safe. The article has since been updated to use MoveTo, but many mods were created using the PlaceAtMe technique.

Unfortunately, using disable doesn't remove the reference from your savegame. It's mentioned on Modding Etiquette, but this is a pretty weak warning:

... avoid using PlaceAtMe to create new copies of an object when you could simply use MoveTo on an existing object.

The PlaceAtMe page has a good warning and the Talk:PlaceAtMe page has some additional details, but these issues are not mentioned in the places where people really look for answers (i.e., tutorials), so I'm not sure how effective this is.

Quite a few mods still use this technique to repeatedly place hidden activators near the player when a MoveTo would work just as well without any negative side effects.

Perhaps the reason this issue hasn't been more widely discussed is that it's just not as easy to use MoveTo on a persistent object as it is to use PlaceAtMe/disable on a temporary reference. There's some discussion about this on the Talk:MoveTo page, but it's far from being concise or clear.

We really need a good tutorial on how to properly use MoveTo instead of PlaceAtMe/disable.

One of the main issues with MoveTo is that the collision shape doesn't always move with the object. Calling disable after moveTo, and then enable a frame later, may fix this problem.

The bloating caused by PlaceAtMe is not as severe as some of the other problems, but a single mod using it repeatedly can still add several megabytes to a savegame over time. If you have several mods that all do this, it starts to add up rather quickly.

Note that using PlaceAtMe as a way to spawn extra enemies is fairly safe because the reference does get cleaned up once the actor is dead and the respawn time has elapsed. The only risk in this case is if a large number of actors are spawned with PlaceAtMe and never get killed, in which case the references do not get cleaned up.

Avoid Using DuplicateAllItems on a Companion[edit | edit source]

This seems to be by far the major offender in savegame bloating problems.

Some Companion Share mods have caused outrageous savegame bloating problems by using DuplicateAllItems excessively. The most common example is a mod using DuplicateAllItems (duplicating them to a duplicate of the NPC) in order to calculate and display encumbrance. If any of the NPC's items are scripted items, then they become permanently duplicated (and impossible to destroy) every time the DuplicateAllItems call is made. Since that call is made every frame while the companion's inventory screen is open, you get bloat very quickly (tens of megabytes in a few seconds).

Instead of duplicating items, you can use RemoveAllItems to transfer items to the companion and then back. That does fix the original bug (scripted items don't cause bloat anymore), but it still leaves the negative items bug with RemoveAllItems (see below).

Avoid Using RemoveAllItems on a Companion[edit | edit source]

This can also cause savegame bloating problems, but it is easier to avoid than the DuplicateAllItems issue.

Calling removeAllItems on an actor or container that has a negative count of one or more items will cause those items to be duplicated. Negative quantities mean the item is restocked when it's depleted.

You can avoid the problem by not giving the companion any items with a negative quantity.

So, you should avoid doing:

 NPC.RemoveAllItems NewContainer

then

 Newcontainer.RemoveAllItems NPC

on a NPC that has a negative item count. This doubles the items every time you do companion share. That means that the NPC will have 65536 items of a kind after 16 shares, 16777216 items after 24 shares and 4.2 bilion after 32 shares. Serious bloat!

Don't Do These Things[edit | edit source]

Here's a list of more things to avoid:

  • Don't ever hit the CS button "Recompile All"
  • Don't run "Generate All" pathgrids or "Generate Entire World"
  • Don't try to copy things from one ESP into another ESP unless the items come from Oblivion.esm
  • Don't modify cells in Oblivion.esm in another master.
  • Don't modify cells by accident. Cells not intentionally changed by your mod shouldn't have an asterisk next to them (use TES4Edit to "clean" your mods before release)
  • Don't use underscores in primary resource filenames. Underscores are reserved by the game for finding various file types, such as normal maps (xxx_n.dds), glow maps (xxx_g.dds), etc.
  • Don't use full paths when creating retextured items. Texture paths need to be relative to the Data folder, not higher (not C:\Program Files\...). You can use NIBlE's "Strip Texture paths" Tool to fix this.
  • Don't change the ownership of an item in the CS. If you need to change the ownership of an item, make it persistent, and change it via script. This prevents a bug where items aren't removed properly. Ignore this if you're changing a lot of item's ownership - the probable loss of FPS caused by 1000s of persistent items is not worth it.
  • Don't use a number as the first character for a Reference EditorID; this confuses Oblivion and it will sometimes work, sometimes not. This includes naming quests, factions, items, etc. This also applies to the names of script variables.
  • Don't refer to an object in scripts using its FormID. This can cause compatibility issues. Use the object's EditorID. The FormID should only be used when necessary, and it is only necessary to use the FormID when using the in-game console.

Tips[edit | edit source]

  • Package mods so they can be unzipped in the Data folder without extra subdirectories.
  • The README should be named ModName-README.txt so as not to overwrite existing READMEs from other mods.
  • .7z (7-zip) is the currently preferred format for mod distribution [This can cause a debate, but new modders need to know about it.]

Avoid Using Common IDs[edit | edit source]

Although this is less of a problem in Oblivion than it was in Morrowind, it's still good advice.

Do not create objects or variables with generic names, such as "SECRETPASSAGEDOOR". Use a unique identifier that you prepend/append to the name of the stuff you create, such as: "IchininSECRETPASSAGEDOOR".

This will make your mod less likely to collide with other mods when merging.

Vanishing Landscape in Tamriel[edit | edit source]

This problem is also listed under Common Bugs because it can also be caused with new worldspaces whenever the current modindex for the plugin differs from the modindex of the plugin during creation in the CS. In this case, however, it happens when you try to use an ESM to alter the landscape for another master (such as Oblivion.esm), causing landscape in Tamriel to vanish (rather than in your plugin), for example.

The easy solution?. Never use a master to modify another master. The solution is explained in an old tutorial about Creating Clean Masters. Fortunately you can now do this automatically by using TES4Gecko to split a mod into ESM/ESP components.

Game Settings[edit | edit source]

Game settings are not like global variables. If you use

set SomeVar to fiSomeGameSetting

your script will save, but won't run in game. You have to use the GetGameSetting function, as such:

set SomeVar to (GetGameSetting fiSomeGameSetting)

Common MessageBox Mistakes[edit | edit source]

  1. The script has to run every frame to catch the button press. For persistent objects (activators, containers, tokens, etc.) this means the object needs to be loaded in memory (i.e., in the same cell as the player). For quests, this means you have to set fQuestDelayTime to a low number, like .001. For all of them, you also have to place the code inside a blocktype that runs every frame (i.e., GameMode, MenuMode)
  2. If you plan on having multiple menus displayed from one script, you need to use a governing variable to tell which menu you're currently displaying. For instance, make a short MenuShowing variable and set it to 1 to display your first menu, and 2 to display the second menu.
  3. If any part of your code after the button catch (that is, after if (Button > -1)) requires more than one frame to process, and you've set up your code to set the button variable every frame, such as:
...
if (MenuShowing == -1)
  MessageBox ...
  set MenuShowing to 1
elseif (MenuShowing == 1)
  set Button to GetButtonPressed
  if (Button > -1)
	if (Button == 0)
...

then you need to change it to catch the button only when the player's decision hasn't been caught yet and make sure to reset Button after displaying the menu:

...
if (MenuShowing == -1)
  MessageBox ...
  set MenuShowing to 1
  set Button to GetButtonPressed
elseif (MenuShowing == 1)
  if (Button == -1)
	set Button to GetButtonPressed
	return
  elseif (Button == 0)
...
  1. If you're using a scripted magic effect for your messagebox, make sure to make it last a couple of seconds (at least). It is strongly advised to use another method. You can have the scripted magic effect start up a quest, or an activator, or add a token to the player and run the messagebox from those.