Morrowind Scripting For Dummies 8
Morrowind Scripting For Dummies 8
(8th Edition) A manual for the TES Construction Set Scripting Language by GhanBuriGhan
(and many others)
Table of Contents
Foreword to eigth edition................................................................................................9 Introduction.........................................................................................................................10 Using this guide...............................................................................................................10 What is a script? .............................................................................................................10 What can scripts do? ......................................................................................................11 What scripts can't do:.....................................................................................................11 Scripting tutorial..................................................................................................................12 Let's get going!................................................................................................................12 The scripting window .....................................................................................................12 What do we want? ..........................................................................................................13 Writing a script...............................................................................................................13 Naming a script: Begin and End....................................................................................13 Detecting an action by the player ..................................................................................14 Writing text and obtaining decisions from the player ....................................................14 How local scripts are executed......................................................................................15 Your first bug ...............................................................................................................18 Putting a spell on the player ..........................................................................................18 How to learn more ...............................................................................................................21 General Information: Scripts, Commands and Syntax........................................................22 Types of scripts ...............................................................................................................22 Local scripts .................................................................................................................22 Global scripts................................................................................................................22 Syntax..............................................................................................................................23 Beginning and ending scripts ........................................................................................23 General syntax for functions: ........................................................................................23 General syntax: Commas, parantheses and spaces.........................................................24 Comments ....................................................................................................................24 Indentation / using tabstops...........................................................................................24 Variables .........................................................................................................................25 Types of variables.........................................................................................................25 Local variables .............................................................................................................25 Global variables............................................................................................................25 Referencing variables on other objects and scripts ........................................................25 Using variables in functions..........................................................................................26 Operators / mathematical calculations...........................................................................27 Testing conditions ...........................................................................................................28 Use of if elseif conditions..........................................................................................28 While conditions...........................................................................................................29 Constructing Boolean operations in TES Script.............................................................30 2
List of TES-script functions.................................................................................................31 Explanation of the format .............................................................................................31 Working with objects ...........................................................................................................32 Working with inventory items .......................................................................................32 Adding and removing items from the inventory ............................................................32 Dropping items to the floor ...........................................................................................33 Monitoring inventory activities: Adding, dropping items and using soul gems ..............34 Force-equipping an Item ...............................................................................................35 Detecting if an item has been equipped .........................................................................35 Disabling ability to equip an item..................................................................................36 Checking for presence of items in inventory .................................................................37 Repairing objects ..........................................................................................................38 Worn / equipped object information..............................................................................38 UsedOnMe function......................................................................................................41 Moving and placing objects............................................................................................41 Moving along an objects axis........................................................................................41 Moving along the world axis.........................................................................................42 CellUpdate....................................................................................................................43 Setting position (the other way to do movement) ..........................................................43 Positioning an object in the world or in an interior cell..................................................45 Resetting an object to its original position.....................................................................46 Placing an item near the PC ..........................................................................................46 Place items near an object .............................................................................................46 Creating new object-references with PlaceItem.............................................................47 Rotation and angles ........................................................................................................48 Making an object spin...................................................................................................48 Setting Angles ..............................................................................................................48 Scale Functions ...............................................................................................................49 Determining location, relative position and movement.................................................50 Detecting if player is indoors or outdoors......................................................................50 Determining the players cell .........................................................................................51 Distance of one object to another ..................................................................................51 Determining an objects position and facing...................................................................52 Line of Sight.................................................................................................................53 Determine whether an Actor is detected by another Actor.............................................54 Determining when the PC leaves a cell .........................................................................54 Detect player traveling..................................................................................................55 Triggers for Actors standing on an object......................................................................55 Hurting an Actor standing on an object .........................................................................56 Object Collision Functions............................................................................................57 Checking activation of an item and activating it ...........................................................57 Locking and Unlocking doors or chests .........................................................................60 Animating objects ...........................................................................................................60 Enabling and disabling objects ......................................................................................62 Deleting a reference completely....................................................................................63 Dont save changes to an object .....................................................................................64 3
Scripting NPC's: AI and Movement ....................................................................................65 Make an NPC walk to a new location ............................................................................65 Checking whether an NPC has performed his movement ..............................................65 Make an Actor turn or face a certain direction.............................................................67 Define random Actor movement....................................................................................67 Making Actors activate objects ......................................................................................68 Following and Escorting.................................................................................................70 Checking which AI package is currently executed........................................................71 Forcing sneak movement................................................................................................71 Forcing running and jumping: Tribunal NPC Movement Functions ..........................72 Detecting players action: running, jumping, sneaking?................................................73 Detect combat readiness .................................................................................................74 Making someone fall.......................................................................................................74 Equipment sharing and other companion functions .....................................................75 Race, Faction and Rank ......................................................................................................76 Determining Race ...........................................................................................................76 Determining the PC's Faction status: ............................................................................76 Modifying faction standing and reaction.......................................................................77 Determinin and changing reputation and disposition .....................................................79 Werewolf-specific functions ...........................................................................................79 Set the werewolf attributes............................................................................................79 Change the color of Secunda.........................................................................................79 Determine how many kills a werewolf has ....................................................................80 Check to see if the creature is in werewolf form............................................................80 Change to a werewolf ...................................................................................................80 Special werewolf global variables.................................................................................80 Text and Dialogue ...............................................................................................................82 Brief dialogue how-to .....................................................................................................82 The concept of MW dialogue........................................................................................82 How dialogue works .....................................................................................................83 A few golden rules........................................................................................................84 Dialogue 101 ................................................................................................................84 Dialogue-related functions .............................................................................................86 Displaying messages.....................................................................................................86 Displaying variables and text defines in a message box.................................................87 Adding a dialogue topic ................................................................................................88 Initiating and ending dialogue.......................................................................................89 Allowing forced Dialogue with Werewolf player (Bloodmoon) ....................................89 Multiple choice asking questions ...............................................................................90 Adding to the journal and testing journal entries ...........................................................90 Special dialogue-only functions ....................................................................................91 Changing the Hello setting............................................................................................92 Useful dialogue variables..............................................................................................93 4
Changing and testing Skills, Attributes, and other Stats .....................................................94 Get, Set, and Modify stats - general remarks ................................................................94 Determining and changing Actor and player stats: ......................................................95 Determining and changing Attributes:...........................................................................95 Determining and changing Health, Magicka, Fatigue: ...................................................95 Determining and changing Skills: .................................................................................95 Determining and changing Level ..................................................................................96 Combat ................................................................................................................................97 Initiating and ending combat .........................................................................................97 Detecting Attack .............................................................................................................97 Comabt related Get/Mod/Set AI functions: Fight, Flee, Alarm....................................99 Keeping track of kills and knockouts...........................................................................100 Resurrecting a dead Actor ...........................................................................................101 Crime .................................................................................................................................103 Determining and changing Crime Level......................................................................103 Jailing the PC................................................................................................................103 Clearing the PC of crime ..............................................................................................103 Detecting crime .............................................................................................................103 Useful global variables..................................................................................................104 Magic.................................................................................................................................106 Limiting the use of teleport ..........................................................................................106 Limiting the use of levitation........................................................................................107 Checking and managing souls and soulgems...............................................................108 Adding and removing spells and cursing.....................................................................109 Casting spells ................................................................................................................109 Managing and testing for spells...................................................................................111 Managing and testing spell effects ..............................................................................111 Testing disease ...........................................................................................................112 Explosion.......................................................................................................................112 Magic Get/Mod/Set effects functions: ..........................................................................113 Sound.................................................................................................................................115 Make Actors speak an audio file ..................................................................................115 Playing music ................................................................................................................115 Playing sounds ..............................................................................................................116 Controling sound ........................................................................................................116 Sound file formats ......................................................................................................117 Keeping track of time.........................................................................................................118 Timer.............................................................................................................................118 Morrowind's time related global variables..................................................................118 5
Keeping track of days passed ......................................................................................119 Moon phases...............................................................................................................119 Weather .............................................................................................................................121 Changing weather.........................................................................................................121 Changing weather settings for a region .......................................................................121 Determining current weather.......................................................................................121 Detecting wind speed ....................................................................................................122 Player Controls..................................................................................................................123 Player sleeping ..............................................................................................................123 Enabling and disabling player control and interface ..................................................124 Disable player control functions..................................................................................124 Enable player control functions...................................................................................125 Check player control status .........................................................................................125 Force first or third person view ...................................................................................125 Functions for character generation menus ...................................................................125 Determining if player has menus open ........................................................................126 Using MenuTest to open and close menus ...................................................................126 Miscellaneous functions and variables..............................................................................128 Breaking of script processing .......................................................................................128 Controlling global scripts .............................................................................................128 Fading the screen in and out ........................................................................................129 Adding a location to the map .......................................................................................129 Assigning random values to variables..........................................................................129 Playing videos ...............................................................................................................130 Levelled List functions..................................................................................................130 Square root ...................................................................................................................131 Water Level Functions .................................................................................................131 Tips and tricks ...................................................................................................................134 Little helpers: Text search, copy, paste........................................................................134 Alternative scripting editors.........................................................................................134 Script with style for safer scripting..............................................................................135 Cleaning up your mod ..................................................................................................135 On References Persist...................................................................................................137 Limits of the Script Editor ...........................................................................................137 Saving CPU time...........................................................................................................138 Targeted scripts: running "global" scripts tied to an object ......................................139 Detecting when the player does a load from saved game:...........................................141 Uses of the CharGenState variable - Disabling saving and menus .............................142 6
Detecting use of scrolls or books ..................................................................................143 Making Actors switch between weapons .....................................................................145 Arrow- or magical traps ...............................................................................................146 Scripted teleporting ......................................................................................................148 Testing for the presence of another Mod .....................................................................150 Safely starting global scripts- avoiding the main script ..............................................151 Use sound to detect events ............................................................................................152 Large battles .................................................................................................................152 A guide to making ridable objects ...............................................................................153 Selecting objects .........................................................................................................153 Creating/Deleting objects............................................................................................153 Falling off from objects ..............................................................................................154 Collision detection......................................................................................................155 Savegame issue...........................................................................................................155 Trigonometry script - fast sine and cosine...................................................................156 Mannequins ..................................................................................................................165 Is she looking at me?.....................................................................................................168 Cinematic sequence ......................................................................................................170 Troubleshooting ................................................................................................................171 General hints.................................................................................................................171 The Console...................................................................................................................171 Using the Console to check variables:.........................................................................171 Using the Console to quickly test scripts:....................................................................171 Error messages, malfunctions and common causes ....................................................172 In the game, when script executes:..............................................................................172 In the editor ................................................................................................................172 In game error messages:..............................................................................................172 Appendix............................................................................................................................174 New functions that come with TRIBUNAL .................................................................174 Changes / fixes to Morrowind scripting: .....................................................................174 Index of new Tribunal Script Functions: .....................................................................174 New functions that come with BLOODMOON ...........................................................175 Index of new Bloodmoon Script Functions and variables: ...........................................175 Previously undocumented functions ............................................................................176 Variable-type functions: ...............................................................................................177 Local variables that get set by the game: .....................................................................177 Local variables that you can set as a flag:....................................................................177 Special Globals...........................................................................................................177 Game units:...................................................................................................................178 Magic Effect List...........................................................................................................179 List of console commands.............................................................................................180 7
Disclaimer: The Elder Scrolls, Morrowind, Daggerfall, Arena, Tribunal, Bloodmoon the TES Construction Set etc. are property of Bethesda Softworks, a ZeniMax Media company. The author of this manual makes no claims to these names and trademarks. In all other respects I maintain the copyright for this document. This guide is fully inofficial and in no way am I, nor is Bethesda, responsible for any damages or loss of data, patience, hair, or sanity inflicted through the use of this manual. You can freely distribute this document as long as you keep it intact and unmodified.
If you find older versions of this document on the web for download, please inform the webmaster about the new version.
Introduction
Using this guide.
If you are new to scripting, you should probably start by reading this introduction and especially do the tutorial. It is my best attempt at explaining scripts, what they do, and how to program one, in simple terms. Secondly this is a manual, a reference, a handbook. The bulk of this document is a documentation of the available functions. This part is not written for the beginner, you are expected to know the basics of scripting allready. I have however tried to provide a lot more info, explanations and sample scripts than the original helpfile, to make it easier to use these functions correctly in your scripts. Use the index at the end of the document to find info on a specific function, or the table of contents to find functions related to a general area of interest. If you run into errors, the Troubleshooting section may help you a bit. In the Appendix you find lists that may also come in handy as a reference. Thirdly, as an advanced scripter you may find the Tips and Tricks section interesting that covers both basic advice and advanced scripting techniques. Finally a word of advice: don't take what's written here as gospel. The info in this guide represents the best of my knowledge and forum wisdom, but that doesn't mean that there arent mistakes and oversights, etc. E.g. if I write that a function doesn't take variables as arguments it probably doesn't but if it is important for your mod, by all means try anyway. It may have changed with a patch or maybe simply nobody checked before. So run a test, and if you find something new, let me know, and I will add the info in a possible future update.
What is a script?
Scripts are basically pieces of code written in a special scripting language (I will call it TES script from here on). These little "programs" will run during the game and can perform certain things in the game, lots of things actually: Trigger events, control time and place, make things and creatures vanish, appear or move, give messages to the player, change stats, even change the weather the possibilities are great. TES Script is a unique scripting language, it is not used outside the TES Construction Set. As a scripting language it has certain limitations compared to a "real" programming language, like, e.g. C++: 1. The scope of TES Script is limited dont expect to be able to program anything that is not already in the game in one way or another which is not to say you can not achieve new and unusual things with scripting! But you cant use TES script to, say, program a word processor. 2. TES Script is also not an SDK (software development kit) that lets you actually work with and change (parts of) the games source code. Thats why you cant use TES script to, for example, add new weather-effects. Those are hardcoded and you would need to change the actual game .exe to do that. 3. Its an interpreted language not a compiled one the code needs a separate program (in this case Morrowind) to run unlike compiled code that could be run by itself, like an .exe application.
10
11
Scripting tutorial
If you are completely new to scripting and programming in general, the thought of using TES script might be a little daunting I have therefore written an extended tutorial that will walk you through making your first script. I will also explain the main elements of the scripting language as we go. There will be other explanations on the way, but the key instructions will be in bold print.
12
Let's have a look at the buttons in the taskbar, from left to right: Open lets you select a script to edit. Save error checks the current script and compiles it or gives out error messages note, however, that the plugin and thus the script is not really saved to disk at this time. When programming large scripts frequently use the save command in the main TESCS window after you have saved the script here, just in case the TESCS crashes. Note that if you edit the script and suddenly hit "save plugin" to backup in the middle of the work, your updated script will NOT be saved with it. You must save it manually first. Also, if you just close script window, it doesnt mean that script will be saved. You must take care of it yourself (Thanks to Kir for this tip). Forward and Backward arrows jump to the next or previous script, respectively (alphabetical order). If you give your scripts a common tag, that will make it easier to jump between the different scripts of your project, e.g. start every script name with AA_Scriptname this will put them right at the beginning of the list and keep them neatly together. Compile all recompiles all scripts (what's this good for? I don't really know). Finally, the delete button deletes a script and the last "arrow down" button closes the script window. The help menu gives quick access to the function and command pages of the helpfile (of moderate utility, hence the creation of this manual!) You can cut, copy, and paste from and into the editor window by using the windows standards ctrl-c for copy, ctrl-x for cut and ctrl-v for paste.
What do we want?
Before we really start writing our tutorial script we should decide what we want it to do. For this tutorial I decided we are going to make a Riddle Chest: The chest will ask a riddle and only the right answer will open the chest. If the player provides the wrong answer, a trap will go off, hurting the player, and the chest can't be opened. Thats a fairly complex undertaking, but we will take it step by step.
Writing a script
Ok, once you've got the Edit Script window open, click into the main part of the window. That is where you will write your script.
into the editor window. Note the underscores: Your name should be one word. Also note that the script language is not case sensitive, so Begin could also be written without the capital letter: begin. This name is the handle by which the script will be known in the TESCS. Try hitting the save button now: you will get an error message about "you need to end your script with end scriptname. So, for the editor to recognize the script we also need to indicate an end: next, write
End
in a new line below the above. As you see we can omit putting the name of the script in this line again, just end will do. When you hit safe now, you will see the name appear in the title bar of the script editor, indicating that the script has been accepted. This is the shortest script possible - and of course it doesnt do anything at all.
13
A couple more things need to be explained here: The "if" command is there to check a condition whenever the expression in the parantheses is "true" the following lines of code will be executed until the "endif" command is encountered. The "==" checks if an expression (in our case the "OnActivate" function) on the left of it is equal to the expression on the right of it (in our case to 1). If you forget the endif command after an if command, the editor will complain with an error message. The ";" semicolon denotes a comment whatever you write behind the semicolon will be ignored when the script is run. If you ever write larger scripts you should learn to love this possibility.
14
The first text is the text actually displayed in the box, the other texts, separated by commas tell the game to make "buttons", with the text given displayed. But how do we ensure that the riddle is asked only the first time we try to open the chest and not every time? We now come to a very central point: the use of do-once conditions and state variables. Most of the problems that beginners encounter with scripting for Morrowind have their roots in misunderstanding how the scripts are actually executed and how scripts should accordingly be structured. So let's have a look at this.
This is the reason why the following script spits out a continuous stream of messages (if attached to an Object or NPC in the same cell as the player). Try it, if you want:
Begin Message_script MessageBox Thousands of useless Messages End Message_script
This example is relatively harmless, but imagine what happens if you would use a line of code that adds an item to the players inventory, or places a monster next to him, etc.! For this reason, Do Once constructions are very essential and something you will probably use a lot while scripting for Morrowind. So, let's go on with our tutorial script: we need to declare a variable and use it to make sure the message is only displayed once. Change the script to the following:
Begin my_first_script Short controlvar If ( OnActivate == 1 ) If ( controlvar == 0) MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith" Set controlvar to 1 endif endif End
(Please note that the MessageBox command should be in one line in the editor!) "Short controlvar" declares a new variable I called "controlvar", of type short. For the moment it's enough to know that this is variable that will contain integers (whole positive or negative numbers). A variable is a "placeholder" that can take on different values. The if command we already know, the set command is new, but simple enough it sets our variable that had the value 0 before (all variables start out at zero when declared) to 1. This, in 15
connection with the if ( controlvar == 0 ) command provides a do-once condition the next frame the script is executed after the variable was set to 1 the if condition will be false and the message box will not be displayed again. Now our script is already capable of being run, so lets test it: Save the script and close the script editor window. Go to the TES construction set, Object window, select the container tab and open "chest_small_01". Change the ID of the chest to "tutorial_chest" In the script dropdown field, select my_first_script Save the object as a new object, save the mod, and quit the construction set. Start Morrowind and load a savegame. Now bring down the console (usually the ~ key, or whatever you have to the left of the "1" on the main keyboard) and in the console window, type: PlaceAtPC tutorial_chest 1,1,1 and hit return. Take a step back (err, let your player character step back, that is!); you should now have a little chest sitting on the floor right in front of you. Clicking on it should bring up our message, which should look like this:
Clicking on those buttons will just close the messagebox for the moment, and clicking on the chest again, nothing should happen either which is good, it means our do-once condition works. Ok, leave Morrowind and go back to the editor, and load your plugin again. We now need to figure out which answer the player selects, and script appropriate reactions for right and wrong answers. The function to test the selected answer is "GetButtonPressed". This function returns a number depending on which of the buttons of a message box has been clicked on with the mouse. It will return "0" for the first button ("bat" in our example) and 1, 2, 3 etc. for the following buttons, in the order you listed them in the messagebox function. While no answer has been selected, the function will return 1, so we have to take care of that, too. The "Activate" function will make our chest open, in fact activate will simply trigger the standard action that would usually be performed when you "use" the selected object e.g. doors would swing open, NPCs would initiate dialogue etc. The following update to our script also demonstrates how you can use a control variable to force MW to process functions one after the other, although the complete script is processed every frame of the game: simply increment the control variable and test it in a series of if elseif statements. This is a very safe way of scripting for MW it may not always be necessary, but it's safe.
16
Take a look at the part that starts with "if (controlvar == 1)". We have set controlvar to 1 as soon as the chest got activated. Now we test for which button is being pressed. We do this by assigning the new variable "button" a value returned by GetButtonPressed. Since the script is still running, even while the game seemingly pauses to await your decision, we first test if no button has been selected yet return tells the game engine to stop processing the script for this frame. Our correct answer was "wind" which corresponds to button number two if button number two gets pressed, we will tell the player that he gave the right answer, and "activate" will open the chests inventory in the usual way. All other values of button mean that the player has selected a wrong answer, so we can use the "else" command here. In this case we tell the player what a fool he was and the chest is not activated. Now look at the little addition at the top of the script:
If ( OnActivate == 1 ) If ( controlvar == 0) MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith" Set controlvar to 1 elseif controlvar > 1 activate endif endif
This means that, whenever the chest is activated in the future, it will only open if controlvar is greater than 1. Check above: when the player provides the wrong answer in the riddle, controlvar is set to 1, so he will never be able to open the chest. But if he knew the right answer, controlvar is set to 2, and from now on the player can open the chest as often as he likes. Save and run your plugin, and test as described above.
17
See how I moved the activate command to the section that tests for controlvar == 2? This provides a cleaner sequence of events, and as I mentioned above, this can be very important when scripting for Morrowind always try to avoid doing too many things at once! Well, run and test it. Great, now the inventory opens as we wanted, but what is this? The cursor is real slow, and we can't close the inventory! Look above controlvar was set to two, and remains there, we do not change it again therefore the game now gets continuous "Activate" commands each time the script is processed (every frame)! Thats why we can't close the inventory it gets reopened immediately. So change the following part of the script:
elseif ( controlvar == 2 ) Activate Set controlvar to 3 endif
Test again: now everything works the way we wanted. I hope I have not confused you with the above excursion into the process of debugging, but it is a very important thing to know about you will constantly have to rethink your scripts and try different ways of doing it to be successful. What is still missing? The trap effect of course!
18
Now, we need to put this curse on the player. For this we use the AddSpell function. After some time we will remove the curse again using the RemoveSpell function, for this we need to make a timer. Edit your script again:
Begin my_first_script Short controlvar Short button Float timer If ( OnActivate == 1 ) If ( controlvar == 0) MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith" Set controlvar to 1 elseif controlvar > 1 activate endif endif if (controlvar == 1) set button to GetButtonPressed if ( button == -1 ) return elseif ( button == 2) MessageBox "The answer was correct" Activate set controlvar to 2 else MessageBox "The answer was wrong" Player -> AddSpell, "Frost_Curse" set controlvar to 1 Endif elseif ( controlvar == 2 ) Activate Set controlvar to 3 elseif ( controlvar == -1 )
19
Set timer to ( timer + GetSecondsPassed ) if timer > 10 Player -> RemoveSpell, "Frost_Curse" set controlvar to -2 endif endif End
Let's go over this. Player -> AddSpell, "Frost_Curse" puts the curse we created earlier on the player. Note how we need to use "Player -> " to make sure the effect really targets the player. Otherwise we would curse the chest (which is the default object, because the script is attached to it), which wouldnt make a lot of sense This bit:
Float timer Set timer to ( timer + GetSecondsPassed ) if timer > 10
that is how you make a timer in Morrowind. GetSecondsPassed is a function that returns the time in seconds that has passed since the last frame. Since this is usually a fraction of a second (as the script gets called every frame), it is only natural that we need a float variable for this purpose a variable that can store numbers with decimals. So when the timer has been running for 10 seconds we remove the curse again, and make sure we do this only once:
Player -> RemoveSpell, "Frost_Curse" set controlvar to 2
Ok, save and test your mod. Works fine now, doesnt it? Well, almost. Try the following: let yourself be cursed, and then open your inventory. Wait. See how the curse terminates after some time, without hurting you? Of course: the script is still running, but spell effects are only calculated while in game, not while you are in the menu. We dont want the player to get off the hook so easily, so we need to put something in our script that stops it from processing when we are in menu mode. Luckily there is the MenuMode function, which returns 1 when you enter the menu. So we can put this at the start of our script:
If ( MenuMode == 1 ) Return Endif
Remember, return tells the game to stop processing the script for this frame. Ok, now we have our final working script. Congratulations! If you want, experiment a little more with this script: Put the chest into a location in the game and lock it. Then try unlocking it (Unlock function) with the script in addition to activating it. Try adding a sound, when the riddle is successfully solved (e.g. PlaySound3D, "skillraise"). Try using the "Cast" function instead of "AddSpell". Previous users of the Tutorial have spotted a potential bug in it: what happens if the player leaves the area with the scripted chest before the curse is removed again? How would you fix this?
20
21
Global scripts
Any script that is not attached to any object is a global script, and is by default not executed until you call it (see below). Note that there is no default object for a global script to work on, so objects must always be specified: while the following will work in a local script attached to an NPC:
AITravel 1150, 8899, 1110
Global scripts are active all the time once they have been activated and until they are specifically terminated. Thus, once activated, they will be processed every frame as described for locals scripts above. That is why they should be used with caution, as too many, or too complicated global scripts can easily slow the game down a lot. The command to start a non-active script is:
StartScript, "Script ID"
With Tribuanl and Bloodmoon you also have the option to make a script start automatically with the game. In the TESCS under the menu Gameplay/Edit starting Scripts/ you can add any script to the list of automatically started scripts. The function to terminate a global script is:
StopScript, "Script ID"
It is possible to use the StartScript function to run global scripts that are tied to an object or Actor. These are called "targeted scripts".
"Object_ID" -> StartScript "Script_ ID"
These scripts resemble both local scripts (in that the functions called always default to the object or Actor the script targets) and global scripts (in that they are always running and can be terminated with StopScript). Note: read more on the special case of "targeted scripts" in the Tips and Tricks section.
22
Syntax
There are some unique features in TES script that should be explained before we go into more detail.
Every script must have the Begin and End tags. The specified name will also be the ID you will reference the script by (be it from other scripts or inside the TES CS object windows). A script may start out with comments, but the first line of real code must be "Begin xxxxxxxxx". As with other objects, it is recommended that you give your scripts a unique tag. I usually use GBG_Scriptname. This ensures that your scripts are easily identified, they all are neatly listed in one block in the scripts list, and there is little danger of conflicts with other mods using the same name. Using leading underscores e.g. _Scriptname is not recommended.
This is the format for all functions that act on or refer to a specifiable object in the game world. The "arrow" or "fix" designates which object a function will be performed on. The "object_ID" is the unique ID that is given to each object in the editor (usually the first field in any object window). You need this ID, not the Name! If you call a function without a designated Object-ID, the function will be performed on the default object, which is the object the script is attached to. This is not to say that there might not be another object referenced as a parameter:
"Object_ID1" -> Function, "Object_ID2"
Note: Functions with a "fix" will only compile if the object has alredy been placed into the game world in the editor (with at least one reference), otherwise the script will not compile. In some functions using the fix is meaningless or may even produce errors, e.g. in functions that default to the player (e.g GetDetected, GetPCRank, etc.) Referencing non-unique items with the "fix" will perform the function only on the first reference of the object! So using this in a global script:
"cliff racer" -> SetHealth, 0
will not have the desired effect, it will only kill one of the annoying bastards. However attaching a script to the creature with just Would do the trick, because every refernce of the cliff racer will have the script running, and apply the function to itself. A number of functions refers only to the player or not to an object at all, and are therefore never used with a "fix". E.g.:
If ( GetPCRank == 0 ) If ( CellChanged == 0 ) FadeOut, 2 SetHealth, 0
23
works fine, but causes error messages. At least one of the standard guides or tutorials on modding recommends using leading underscores for Object IDs so they sort to the top of the Object window lists and thus are easy to find. I followed that advice, and so have a lot of other people (from looking at other people's mods).Leading underscores for variables also are unpredictable in scripts: someplaces they work, other places they don't. So my policy now is to NOT use leading underscores for anything in the Construction Set.
_dt_Racial_ClothierNord -> PositionCell, -348, 48, -221, 0, "Vivec, Agrippina Herennia: Clothier"
Comments
Comments are marked by a semicolon ;. Comments can be added in their own lines or behind lines with code
; enter sneak mode Fargoth->ForceSneak Fargoth->AiTravel -11468.595,-71511.531,173.728 ;goes to tree
is better than
If ( variable1 ) If ( variable2 ) [do something] endif endif
24
Variables
Types of variables
There are three types of variables in the TES script language: short, long and float. According to the manual these cover the following data ranges: Short Long Float -32,768 to 32,767 (signed integer) -2,147,483,648 to 2,147,483,647 ( long signed integer) 3.4E +/- 38 (float, 7 digits)
Apparently the boundaries for Long given here are only partly correct, in the TES-CS you can assign a maximum value of 2147483520 (Forum info / Argent). Theoretically there should be string variables too, but to my knowledge these are not implemented. Unfortunately there are also no data types to store Object_Id's, which limits the power of the scripting language to a certain extent. Variables can be grouped into local variables (valid only in the script that declares them) and global variables (valid in every script). Note: A long global is effectively a float! In a script, local to that script a long will have a full 32 bits of precision. But used as a global, the number of bits of precision drops to 24, as when it exists globally a long *is* a float. Mental Elf discovered this when attempting to use "bit packing" to get 32 flags into a global long (forum info / mental elf).
Local variables
Local variables these have to be declared in the script:
Float floatvarname Short shortvarname Long longvarname
Local variables are unique to a specific instance of a local script. This means that the local variables in multiple objects with the same script do not influence each other. The names you use for variables are pretty much up to you as long as they start with a letter, but you have to avoid using function names (this will result in errors during runtime) and reserved characters (e.g. - + / * = " )( etc.) which will result in compiler errors. E.g. "variable-1" will not work as a variable name. Underscores as in "my_variable" are ok, but avoid leading underscores. A dot has a reserved meaning as well (see "Referencing variables in other local scripts" below).
Global variables
To declare a global variable go to the Gameplay menu and select Globals. Right click for "new", name it, and set the type and starting value for the new global variable, if one is needed. By default it will be 0. Global variables are very useful for involved quests when you need to keep track of things over an extended time and space. They are also a simple way to share information between different scripts Note: if you declare a local variable with the same name as a global variable, the global variable will become invisible for this scipt. Do NOT declare a global variable as a local!
or
This method changes a local variable in the objects script. The object must have a script on it for this to be valid, and of course it must be active (e.g. a local script in the same cell). Note: The scripting system looks at the first object in the database, thus you should only reference objects that are unique (exist only once). Note that the reverse does not work:
Set local_variable to MyObject.variable ;this doesn't work!
Use a global variable to transfer information in this way, or set local_variable from the other script using the syntax above.
if ( anotherobject.x > 0 )
apparently works. Furthermore I realized only recently that this syntax also works for global scripts:
set Global_script_name.variable to 1
This is useful to avoid using more global variables then necessary or also as a console command to debug global scripts.
26
+ * /
Instead of variables, literal values are also allowed. I assume that standard operator precedence applies ( * and / are calculated before +/- ). Since it has not been properly tested I usually always use parantheses to be on the safe side. You can use parantheses according to standard mathematical rules:
set ln to ( ln + ( k10 * math_ln10 ) + ( k2 * math_ln2 ) )
A warning: There are different opinions on the forums on the use of several operators in one line. Some people report a lot of problems with this, I myself have successfully used at least four operators and variables in a single line. There appears to be an issue with very long additions (e.g. adding up more than 20 variables in one line of code) that causes a mod to crash the game upon loading. If this happens, split the calculations to several lines. There isn't much in the way of dedicated mathematical functions in TES script. There is the 'Random' function and Tribunal added the 'GetSquareRoot' function (see below). If you need more complex functions, I suggest downloading Soralis' Math Mod (available from Morrowind Summit). Its a collection of scripts that allow you to do complex calculations. Here is a short excerpt from the readme to give you an idea: "This mod adds the ability to use various math functions within Morrowind's scripts. Specifically, these are the scripts that are added:" Name Check/Done Inputs Outputs Accuracy
MathScripts MathConstants SquareRoot SineScript ArcsineScript NaturalLog LogScript intPower intRoot Modulus Antiln Antilog AbsoluteValue PowerScript N/A N/A 1 2 3 4 5 6 7 8 9 10 11* 12 N/A N/A math_sqrt math_angle math_arc math_log math_log, math_base math_value, math_power math_value, math_root math_value, math_mod math_log math_log, math_base math_abs math_value, math_power N/A N/A math_result, math_imag math_sin, math_cos, math_tan math_sin, math_cos math_result, math_imag math_result, math_imag math_result math_result, math_imag math_result math_result math_result math_abs math_result, math_imag N/A N/A 7 7 6-7 4-5 3-4 7 6-7 6-7 4-5 2-3 7 2-3
Unfortunately many of these functions are rather slow, and not suited for real time calculations. For sine and cosine in particular, check out JDGBOLT's script in the tips and tricks section, which uses pre-calcuated values for a very rapid calculation. 27
Testing conditions
Use of if elseif conditions
If (condition) Elseif (condition) Else Endif
Much of TES scripting relies on the use of if elseif conditions and variations thereof. It is very important to fully understand these, and the conditions that can be used in them to test conditions of the game world to trigger events. In general a condition is "true" when it has the value of 1 (or simply "not 0" (e.g. -1 is "true" in TES Script too) and "false" when the value is 0. There are thus certain functions in the game that return "true" under certain conditions. For example see the GetAIPackageDone function further down. It returns "true" (= 1) for one frame when an AIPackage has finished. All lines of code between the if-statement and endif (which concludes a so-called "if block") will be executed only when the condition is true. Thus:
If ( GetAIPackageDone ) ;[do something here] endif
will be only executed when the GetAIPackageDone function currently returns the value 1. In addition to just a value, a condition can also be a more explicit test of conditions. The conditions, such as "A equals B" or "A is greater than B" will be evaluated, and the whole expression will be true (equals 1) when the condition is fulfilled. E.g.:
if ( GetAIPackageDone == 1 ) ;[do something here] endif
Is equivalent to the example above. This second syntax tests a condition and returns "true" if the condition is met. You can check for the following condions: Verbose
"Equal to": "not equal to" "Greater than" "Smaller than" "Greater than or equal to" "Smaller than or equal to"
Conditional operator
== != > < >= <=
If you have several independent if blocks each will be evaluated separately. If, e.g. the following if blocks are in your script:
if ( timer >= 2 ) ;[Block A,do something here] endif if ( timer <= 3 ) ;[Block B, do something else here] endif
Both will be true and the code in the blocks will be executed when timer is between 2 and 3. 28
You can nest if-blocks if you want to make sure that two conditions are fulfilled simultaneously:
if ( timer >= 2 ) if ( controlvar == 0 ;[do something here] endif endif
The code in the inner if block will only be executed when both conditions (timer >= 2 and controlvar == 0 ) are fulfilled at the same time. For more elaborate constructions you can use Else and Elseif. Elseif tests for a separate condition if the preceding condition has failed (but not if the previous condition was fulfilled)
if ( timer >= 2 ) ;[Block A,do something here] elseif ( timer <= 3 ) ; [Block B, do something else here] endif
unlike the example above, both blocks can not be true at the same time now. Either timer is >= 2, then block A gets executed, or timer is not >= 2 but <= 3, meaning effectively timer is < 2, then block B gets executed. In all other cases, neither block will be executed. You can have several elseifs behind each other:
if ( counter == 1 ) ;[Block A,do something here] elseif ( counter == 2 ) ; [Block B, do something else here] elseif ( counter == 3 ) ; [Block C, do something else here] endif
An else creates a "default condition". The code following else will be executed if all previously tested condionts are false:
If ( foo_var == 1 ) [Block A: do elseif ( foo_var == [Block B: do else [Block C: do endif something] 2 ) something else] something completely different]
In this example Block C will be executed it foo_var is neither 1 nor 2. Note: In my experience it is safest to use elseif instead of multiple separate if statements if you test different states of one variable. There is a maximum of the total if-elseif conditions that can be processed in one script. Else also counts as a separate if-statement. According to the latest info the limit is close to 127 (as opposed to the 256 mentioned in earlier issue). The distance between an "if" and an "endif" being too far can cause a problem as well. apparently, somewhere between 120 and 240 lines is a break point (Forum info / MentalElf)
While conditions
While ( condition )
; things to do
EndWhile
29
The while command differs from the if command in that it is repeated within one frame until the condition is fulfilled. This is best explained with an example:
Short desiredAmnt SetStrength 0 while( GetStrength < desiredAmnt ) ; non-literal value to match modStrength 1 endwhile
This will set strength to the value in variable desiredAmnt after one frame. The following script however would need an undetermined amount of frames to do this, because the if condition is only called once each frame:
if(getStrength < desiredAmnt) ; non-literal value to match modStrength 1 endif
On the other hand the first example can potentially cause "freezing" (if the value would be very high) while the second won't. Note that this is a workaround for some functions to the problem of functions not accepting non-literal values (variables) as arguments.
For OR constructs:
if ( variable1 OR variable2 ) [do this] endif
30
[no fix] Indicates this function can never be used with a "fix" meaning it can not be called by a specified actor. Functions without this tag can be called by an actor, an object, or both. Code: Name of the function Arguments of the function: "string" indicates a literal string, such as an object ID. arg_enum indicates a literal value (no variables taken) var_float indicates a variable of the specified type (in this case float). Brackets [] indicate optional parameters. (returns short) or (returns float) indicate that the function returns a value and of what type the value is. I will use the designation (returns Boolean/short) to indicate a function that returns either 1 or 0 (a Boolean variable although the game strictly speaking still uses a float) Examples of usage follow in italics and are indentated:
Code "ID", var_enum, var_float
From the 8th edition onward the functions added with Tribunal and Bloodmoon have been moved into the suitable sections of the reference section. They are now marked with: for Tribunal functions and for Bloodmoon functions. To use these functions the respective expansion must be installed (but not necessarily active). Bloodmoon (and GOTY edition) incorporates all functions from Tribunal as well.
31
These functions are simple enough, adding or removing items from the players or any other inventory, including containers. A RemoveItem call will remove the item from the inventory, it will "vanish". Notes: Removing items that are not present in the inventory does not crash the game, but the 'RemoveItem' function will subtract the removed item's weight from the character's encumbrance, EVEN IF the item is NOT in the character's inventory. So if a script uses 'RemoveItem' to remove a 4 lb. item that the character doesn't have, the character's encumbrance will wind up 4 lbs. lower than it should be. The workaround for this bug is to always check for the presence of an item before using 'RemoveItem' to delete it (Thanks DinkumThinkum for this info). Don't remove an item that is executing a script, from the items own script, that will crash the game, see the example script. A workaround for this is to use a separate global or local script to remove the item. However, if the player has two or more copies of an object with an attached script in their inventory, using RemoveItem on that Object ID will frequently corrupt data for one of the remaining copies (you may e.g. see corrupted health or count data). Equipping or using that corrupt object may cause the game to crash (Forum infor, DinkumThinkum). To avoid the two known RemoveItem bugs: 1. If the object is not scripted, use GetItemCount to be sure the player has at least 1. 2. If the object is scripted, use GetItemCount to be sure the player has exactly 1, or make sure the object is unique. The drop function does not have this bug. It does, however cause doubling, if used with OnPCEquip / SkipEquip, which can be fixed by adding and removing any item as described for these functions. Notes on using Additem / Removeitem in dialogue: Apparently these functions can accept global variables, but only in dialogue results, and only if you dont 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. Say, var_a equals 3 at the moment when the line is selected in dialogue. If the result field looks like this:
set var_a to var_a + 10 ; AddItem gold_001, var_a
32
three drakes will be added to NPC's inventory, and not thirteen. If such need arises, put all calculating operators into one dialogue response's result box, add "choice" operator, and process the AddItem function in the following response. Also, even with long variables, I couldn't correctly add values above 32767 (2^15). (tested on pure Morrowind without expansions) (Forum info / Kir). Notes on usage with containers: It has been reported that only the first AddItem call will always work on a container, but after that, the player has to manually access the container from within the game (e.g. add an item), before another AddItem function call will show any effect (untested forum info). Containers can't be affected by AddItem once they are empty (after containing stuff). If you want to be able to add something to a container that might have been emptied, the only way to do it seems to be to delete the item and place a new empty one in its place (the new one will work until it has something put in it and is then emptied. Then it needs to be replaced as well). Unfortuantely, the only way to check if a container is empty is to check that every single item in the game isn't in there (Forum info / ThePal). Example script: The following script was discussed on the forums (sorry dont remember who first made it). It was supposed to ask the player if he wanted to recycle an item when it was equipped, and then replace that item with the "recycled" version.
Begin scr_thing short button short OnPcEquip short state if ( MenuMode == 1 ) return endif if ( OnPCEquip == 1 ) ; when the item is equipped set state to 1 set OnPCEquip to 0 ; do this once per equip event endif if ( state ==1 ) MessageBox "recycle?" , "yes", "no" set state to 2 elseif ( state == 2 ) set button to GetButtonPressed if ( button == 0 ) PlaySound "mysticism cast" player->RemoveItem "item_a", 1 ;this line crashes the game!!! player->AddItem "item_b", 1 set state to 0 elseif ( button == 1 ) set state to 0 ; once done, reset everything endif endif end
It worked nice enough without the RemoveItem function in it, but with that line it would crash. The reason was that this script was attached to item_a, and thus the running script would be removed with it, which apparently crashes the game. So the above idea had to be handled via a global script.
33
This function is supposed to drop the item from the inventory "to the calling Actor's feet". This seems to work correctly only for the player character, dropping the item to his feet. When I used it for NPC's, the items would get removed correctly from the NPC, but still dropped at my own player character's feet. Note: An interesting note on this is that if they really have that item, they will drop it, with charges and condition intact. If they don't really have that item, a new instance will be created. If the player drops an item he doesn't have, his weight will still be reduced by the weight of that item - same as the encumberance bug for RemoveItem (Forum info / DinkumThinkum). Examples of the use are found in Bethesda's SlaveScript
Monitoring inventory activities: Adding, dropping items and using soul gems
[no fix] OnPCAdd
Short OnPCAdd If ( OnPCAdd == 1 )
This variable is set to 1 when the PC added the object to inventory. Must be reset manually for multiple use (set OnPCAdd to 0 ). Example: This is an excerpt from the script attached to Fargots ring, that gives you the magic menu during character creation:
if ( OnPCAdd == 1 ); Player has added the item to the inventory if ( State == 0 ) EnableMagicMenu MessageBox "You now have a Magic Menu, where you can see all your powers, spells, and magic items." "Ok" set state to 10 return endif endif
This variable gets set to one when the PC drops the object. Must be reset manually for multiple use (set OnPCDrop to 0 ).
[no fix] OnPCSoulGemUse
Short OnPCSoulGemUse If (OnPCSoulGemUse == 1 )
This gets set to one if the calling Object is a soulgem and it has been used in either recharging or item making. Must be reset manually for multiple use (set OnPCSoulGemUse to 0 ). Example: this is how Azura's star becomes an inexhaustible soulgem:
begin AzurasStarScript ;this is for Azura's Star. A never ending soulgem item. Mucho good. Kids love it. short OnPCSoulGemUse ;they use it, so give them a new one if ( OnPCSoulGemUse == 1 ) Player->additem, "Misc_soulgem_Azura" 1 endif end
34
Force-equipping an Item
Equip, "Object_ID"
"Actor_ID" -> Equip, "p_restore_health_q"
(Also see OnPCEquip function below) Pre-Tribunal: Partly Broken. This could have been an immensely useful function. Unfortunately, most of the potential uses do not work: You can NOT autoequip anything on the Player. You can NOT force the Actors to equip weapons or armor with this (this is completely governed by their skills with armor or weapons). You can NOT make "nonremovable" items, like cursed armor, etc. You CAN make Actors swallow potions, or so I heard. This Function was fixed in Tribunal. You can now force Actors to equip armor, weapons and clothing. So you now CAN do all of the above . Praise to Bethesda. Note: The Equip function can make someone equip an item they aren't carrying, and it will add it to their inventory. However, if you do that then any scripts on the items won't be run. So you need to use AddItem first, then Equip, even though Equip does seem to add them. The script will start if you take the item off the person or out of your inventory and drop. But while it is in inventories the script doesn't start (Forum info, ThePal). Sample Script: This script (Tribunal required) curses an item (a Chitin Club) so that it can't be unequipped anymore. Not even using quick-keys. Bugger! Now you have to fight with a chitin club to the end of your days, which will probably come soon The player can still use magic however.
Begin cursed_item short state short OnPCEquip if ( OnPCEquip == 0 ) ; item is not equipped if ( state == 0 ); if club has never been equipped, don't do anything yet. return else Player -> Equip, "cursed_club" ; reequip the item! MessageBox "The item is cursed, it doesn't leave your hand" ;taunt the player endif else if ( state == 0 ) ;first time equipped. The trap snaps shut set state to 1 endif endif End
The PC has the object equipped (remains true while object is equipped) This game variable (needs to be declared!) gets set to 1 if the player is equipping the calling object. It will remain "true" while the item is still equipped, but gets reset to 0 if the item is unequipped. So, in some cases you might want to manually reset it: 35
if ( OnPCEquip == 1 ) ; when the item is equipped [do something] set OnPCEquip to 0 ; do this once per equip event endif
The next time the item is unequipped and equipped again, the functions in [do something] will be performed again. You can also use a status variable to control when an effect will be executed. Note that this can also be processed while in Menu mode:
If (MenuMode ==1) if ( OnPCEquip == 1 ) ; when the item is equipped [do something] set OnPCEquip to 0 ; do this once per equip event endif endif
This script will execute while you are in the menu, as soon as the item is equipped, while the following will be executed only after you leave the menu:
If (MenuMode ==1) Return Endif if ( OnPCEquip == 1 ) ; when the item is equipped [do something] set OnPCEquip to 0 ; do this once per equip event endif
An additional Sample Script can be found above with the Equip function. Notes: OnPCEquip was successfully tested with the following item types: Clothing Armor Weapons Books/Scrolls (see tips and tricks for correct use, though) Miscellaneous items Usable lights Probes Potions and Ingredients will only register with OnPCEquip when you use SkipEquip at the same time, otherwise the item is apparently "destroyed" before the function registers! Repair objects suffer from this too, and weirder still, apparatus (or alembics anyway) work the reverse way. They only seem to trigger OnPCEquip when PCSkipEquip is NOT set (Forum info / ManaUser). Apparently books (and maybe some of the other item types that behave strangely?) set SkipEquip to 1 instead of OnPcEquip! See the tips and tricks section on this issue.
Set this to 1 to skip equipping object. Good for popping up messages for breaking seals on books and such. For an extended example look at the SealedTreasuryReport script in the editor. Its also great for using e.g. clothing objects as script triggers in conection with the OnPCEquip function (see my climbing mod for an example, the climbing gear is actually a belt, but of course cannot be equipped).
36
Note: Apparently equipping a book in inventory set this to one (instead of setting OnPCEquip to one, as it should. See tips and tricks section. There is a bug associated with using this, that leads to duplication of the item that has the SkipEquip function. I have seen this happen both with QuickKey usage and when normaly equipping items from the inventory when OnPCEquip is also called. To bypass this, reset the inventory by adding and removing a dummy item (from within the section of the script that checks the OnPCEquip function). Do not remove the item with the script itself, as this causes a crash (see RemoveItem function). If you have a lot of SkipEquip items, make the item call a global script (StartScript) that adds and removes the item, e.g.:
Begin doubling_fix Player -> Additem "Item ID", 1 Player -> RemoveItem "Item ID", 1 StopScript doubling_fix End
Sample Script: Here is a short script I made for a werewolf mod, it makes an item nonequippable under certain conditions:
Begin non_equippable ; keeps lycantrophic PC's from equipping werewolf hunter items for balancing reasons ; if the PC equips these before becoming a werwolf, he can wear them until he takes them off ; but then can't reequip them. So after the first transform he can't equip them again short PCSkipEquip short OnPCEquip if ( PCWerewolf != 1); if player is not a ww, he can use the armor set PCSkipEquip to 0 return else set PCSkipEquip to 1 endif if ( OnPCEquip == 1 ) MessageBox "This item is enchanted with werewolf bane-spells. You can not wear it!" set OnPCEquip to 0 endif End
This function checks the inventory of the calling object and returns the number of objects of type "Object_ID" it owns.
37
Repairing objects
[no fix] OnPCRepair
Short OnPCRepair If ( OnPCRepair == 1 )
A game variable that gets set to 1 when the PC repairs the object with the script. Requires manual reset.
RepairedOnMe, "Object ID" (returns Boolean/short)
if ( "daedric_mace"->RepairedOnMe, "repair_journeyman_01" == 1 )
This function returns 1 if the calling item is repaired by an item of type "Object ID". Object ID has to be of type "Repair Item" and the calling object must be either weapon or Armor.
OnRepair
The similar function OnRepair is apparently broken. It should get set to 1 when any repair is attempted at the object: "returns true if calling object is repaired at all".
These functions are called on an Actor to gather information regarding what the Actor has equipped. GetWeaponType returns the weapon type (see Table 1.1) of the Actors current weapon. GetArmorType returns the armor weight (see Table 1.3) of the Actors currently equipped armor part. The armor parts are coded by the numbers listed below (see Table 1.2). HasItemEquipped returns 1 if the Actor has the given item currently equipped and 0 if it does not.
38
Weapon types (Table 1.1): Weapon Type Name Type Number Unarmed -1 Short blade, 1 hand 0 Long blade, 1 hand 1 Long blade, 2 hand close 2 Blunt, 1 hand 3 Blunt, 2 hand close 4 Blunt, 2 hand wide 5 Spear, 2 hand wide 6 Axe, 1 hand 7 Axe, 2 close 8 Bow 9 Crossbow 10 Thrown weapon 11 Arrow<?> 12 Bolt<?> 13 Armor parts (Table 1.2): Armor Part Name Part Number Helmet 0 Cuirass 1 Left Pauldron 2 Right Pauldron 3 Greaves 4 Boots 5 Left Gauntlet 6 Right Gauntlet 7 Shield 8 Left Bracer 9 Right Bracer 10
Armor types / weight (Table 1.3): Armor Type Name Type Number Unarmored -1 Light Armor 0 Medium Armor 1 Heavy Armor 2
39
Sample Script: When this script is placed on an object, Activating a reference to that object does damage to it based on the PCs current weapon and strength. If the weapon is the specific weapon Rock Splitter the object is fully damaged in one hit. When the object is fully damaged, it explodes sending shards into the PCs face unless he has a shield or a helmet equipped.
Begin breakme float float short short short short short short short hitsleft hitpercent damage tempdamage weapon doOnce shieldType hasHammer hitRock
if ( doOnce == 0 ) set hitsleft to 10000 set doOnce to 1 endif if ( OnActivate ) set hasHammer to ( player->HasItemEquipped "RockSplitter" ) if ( hasHammer == 1 ) MessageBox "Rock Splitter unleashes its mighty force..." set hitsLeft to 0 else MessageBox "You hit the rock with your current weapon..." set weapon to ( player->GetWeaponType ) set damage to ( player->getstrength ) set tempdamage to 5 if ( weapon == -1 ) set tempdamage to endif if ( weapon >= 9 ) set tempdamage to endif if ( weapon == 4 ) set tempdamage to endif if ( weapon == 8 ) set tempdamage to endif 1 2 10 8
set damage to damage * tempdamage set hitsleft to hitsleft damage endif if ( hitsleft <= 0 ) disable set shieldType to ( player->GetArmorType 8 ) if ( shieldType == -1 ) set shieldType to ( player->GetArmorType 0 ) if ( shieldType == -1 ) MessageBox "...and the rock shatters sending jagged shards into your eyes." Player->ModHealth 50 else MessageBox "...and the rock shatters, deadly shards glancing off your helmet." Endif else MessageBox "...and the rock shatters, deadly shards glancing off your shield." Endif else set hitpercent to hitsleft / 100 set hitpercent to 100 hitpercent
40
MessageBox "...and the rock is %.2f percent damaged but remains intact.", hitpercent endif endif
UsedOnMe function
UsedOnMe, Object ID (returns Boolean/short)
if ( UsedOnMe, Misc_pot_redware_01 )
According to helpfile: "Returns true if the Object ID has been used on the calling object. This is used for scripts that make objects do certain things of the player uses an object on it." According to current knowledge this function is broken.
Moves the object along the selected axis (x, y, or z) at the speed selected. This speed is in units per second (21.3 units per foot). Thus, the distance moved per frame will depend on your frames per second, while the distance moved in a unit time will not. This movement is based on the objects local coordinate system. Thus, a positive y movement will always move the object along its local forward vector:
Note: Move will not work on Actors, including the player. However, it will work on dead actors (Forum info / Argent). As with all functions using a "fix", move requires that the object is placed into the game world in the editor, before you can use it in a script:
PlaceAtPC "My_Object", 1,1,1 My_Object-> Move x, 10
will not work if "My Object" has not alredy been placed, but you can have a local script running on "MyObject" that just uses
Move x, 10
41
Moves the object along the selected world axis (x, y, or z) at the speed selected. This speed is in units per second (21.3 units per foot). This movement is based on the world axis, thus a positive z movement will always move the object up, regardless of its local rotation: In world coordinates Z is always up / down (increasing upwards), X is east / west (increasing to east) and Y is north / south (increasing to north).
Note: MoveWorld will not work on Actors, including the player. Use SetPos for actors. This is an example after a script I once picked up on the forums that makes a platform slowly move out and back once the player stands on it:
Begin platform_script Short PlatformMoving Short ActivateMe Float Timer If ( GetStandingPC == 1 ) Set ActivateMe to 1 Endif If ( ActivateMe == 1 ) If ( PlatformMoving == 0 ) Set Timer to Timer + GetSecondsPassed If ( Timer <= 15 ) "floating_platform_01"->MoveWorld X 10 Else Set Timer to 0 Set PlatformMoving to -1 Endif Endif If ( PlatformMoving == -1 ) Set Timer to Timer + GetSecondsPassed If ( Timer <= 15 ) "floating_platform_01"->MoveWorld X -10 Else Set Timer to 0 Set PlatformMoving to 0 Set ActivateMe to -1 Endif Endif Else "floating_platform_01"->SetAtStart Endif End platform_script
42
CellUpdate
CellUpdate
Broken! According to Bethesda: Updates the current objects cell position. This should be called when moving objects over large distances. The game keeps tracks of objects based on what cell they are in, and if an object moves a cell over from its starting position, it may not get processed correctly when running its script. The part about not processing correctly is certainly right. Objects can disappear or "warp" if moved too far from the place they were created in. Unfortunately my attempts to use this function always resulted in a runtime error: "need to add function code for function CellUpdate". Note: a way around this problem (requires Tribunal) is to disable and delete (SetDelete) the object on a regular basis (for ridable objets upon entering a new cell) and immediately placing a new version (PlaceItem) at the very same position using a global script (seen in MadMax boat script from the Fishing Academy Mod). See the Tips and Tricks section for an in-depth explanation by MadMax himself. This works like a charm, because this way the object never really leaves the cell it was created in.
This function (unlike the move and moveworld functions) also works with Actors, including the player. Axis is x, y, or z. The float value sets the position of the calling object to that value. This always refers to the local coordinate system the object is currently in. Note: With Tribunal, this function accepts local float variables, but only within the currently active cells. This is relevant for exteriors, you can not move objects an arbitrary distance, the target location must be within the active cells (current cell of player plus surrounding cells). (Forum info / reposted by Srikandi). Also note that while objects can be SetPos to any position (without collision being detected), Actors will still check for collision, and may not move as expected in case of collision (which can be used to good effect for collision detection). SampleScript: This script is made for floating crates in the Mournhold sewer (Tribunal). It demonstrates how SetPos and SetAngle can be used instead of MoveWorld and Rotate to produce fluid movements:
begin floatAboveStartHeight float float float float float float float float float float float timer swingTime startAngle startHeight currangle xvalue zvalue zoffset tmpoffset weightoffset waterlevel
43
if ( initialized == 0 ); this section stores the starting height and facing of the object set startAngle to GetAngle, X set startHeight to GetPos, Z set swingTime to 1 set initialized to 1 endif if ( MenuMode == 0 ) set waterlevel to GetWaterLevel if ( waterlevel > startHeight ) if ( timer == 0 ) if ( reset == 0 ) set timer to Random 100 set timer to timer / 4 endif endif set timer to ( timer + GetSecondsPassed ) set currangle to GetAngle X ;These set the amount to move or rotate depending on framerate: set xvalue to 10 * GetSecondsPassed set zvalue to 5 * GetSecondsPassed ; the crate sways around its x axis: ;rotate up if ( timer < swingTime ) set currangle to currangle + xvalue SetAngle X currangle set zoffset to zoffset + zvalue ;rotate down elseif ( timer < (swingTime * 3) ) set currangle to currangle - xvalue SetAngle X currangle set zoffset to zoffset - zvalue ;up again elseif (timer < (swingTime * 4 ) ) set currangle to currangle + xvalue SetAngle X currangle set zoffset to zoffset + zvalue ;reset timer to zero else set timer to 0 set reset to 1 set zoffset to 0 SetAngle, x, startangle endif set tmpoffset to waterlevel set tmpoffset to tmpoffset + zoffset ; The crate bobs up and down SetPos Z tmpoffset Else ; Waterlevel is normal SetAngle, X, startAngle SetPos Z startHeight endif endif end
44
The classic application for this function is the teleport ring, transporting the player to certain locations. However, it can also be used to warp NPCs or objects to a new location. Note that in original Morrowind this function only accepted literal values as arguments. (This probably changed with Tribunal: not sure if in all versions or only with the expansions, but: Position/PositionCell can take float variables, but they must be LOCAL variables! (info by Indigo Rage). Z_Rot is not set in degrees (0-360) but in minutes (1 = 60 min): So, if you want the person to face east, use 5400. South, 10800. West 16200. Note: One thing to be aware of is that using PositionCell in dialog results isnt reliable, and may cause crashes. The way Bethesda does this correctly is to use StartScript to start a script that does the teleporting. (Forum Info/Emma). You should not use this function on items that are in the players inventory, this causes MW to crash (Forum info/Nigedo). Sample Script: A simple teleport ring could look like this:
Begin TeleportScript ;Attached e.g. to a ring short status short button short OnPCEquip if ( MenuMode == 1 ) return endif if ( OnPCEquip == 1 ) Set Status to 10 Set OnPCEquip to 0 Endif If ( status == 10 ); Display menu MessageBox "Teleport me to", "Balmora", "Vivec", "Cancel" Set Status to 20 Elseif ( status == 20 ); wait for response Set button to GetButtonPressed If ( button == -1 ) ; no answer yet Return Elseif ( button == 0 ); selected Balmora Player -> PositionCell -21278, -17613, 534, 0, "Balmora (-3, -3)" Elseif ( button == 1 ); Selected Vivec Player -> Position 29872, -82108, 578, 180 Elseif ( button >= 2 ) ; selected cancel Set status to 0 Endif Endif End
Note that both targets are outdoor cells and the different formats used. If you try to teleport to an unsafe place (clipping with an object or out in the void), you will instead be placed at the next safe location. You can also relocate NPCs or objects with this function. 45
This resets the object to the original position it was given in the editor, before any movement or rotation occurred. For an example, see the moving platform script example under the topic "moving along the world axis". See the Move function for a sample script.
This function places a new reference of "Object_ID" near the player. The function lets you define a direction relative to the player where the object is going to appear and a distance (in units). If that location is not safe (in the air, in a wall, etc), the object will be placed at one of the other axis or at the players exact location (feet). (Erratum: Thanks to Isildur and Esteban for pointing out that number_enum and distance_enum were switched around in previous versions) direction is: 0 = front 1 = back 2 = left 3 = right
The PlaceAtMe function works the same as PlaceAtPC without it being centered on the PC. Bloodmoon uses this to place attackers in different places depending on the players distance at the time. This allows the script to make it appear as though there is a large number of opponents that just keep coming, among other things.
;THIS POPS IN A HUNTER AT APPROPRIATE SPOT, INCREMENTS if ( popA == 1 ) "active_BM_hunter1"->PlaceAtMe skaal_hunter 1 1 set huntercount to ( huntercount + 1 ) set timer to 0 elseif ( popB == 1 ) "active_BM_hunter2"->PlaceAtMe skaal_hunter 1 1 set huntercount to ( huntercount + 1 ) set timer to 0 elseif ( popC == 1 ) "active_BM_hunter3"->PlaceAtMe skaal_hunter 1 1 set huntercount to ( huntercount + 1 ) set timer to 0 endif HUNTERCOUNT, AND RESETS TIMER 1
46
These functions are used to create new references to objects. PlaceItem will create a reference to object "Object ID" at coordinate (X, Y, Z) with Z rotation Zrot in the current cell. Z_Rot is not set in degrees (0-360) but in minutes (1 = 60 min): So, if you want the person to face east, use 5400. South, 10800. West 16200. The function accepts (local) float variables. PlaceItemCell does the same thing as PlaceItem except it allows you to specify a cell other than the current one in which the object should be created. With either function, if the target cell for the reference is an exterior cell and the given coordinate is outside of that cell, then the reference will be added to the cell containing the coordinate. This is a nice addition that allows you to add things to the world without previously placing them in the editor. JOG posted the following interesting info on PlaceItemCell: Well, When I first tried PlaceitemCell, I thought it's a great function to place items instead of having a "storage-cell" where the objects lie around until the game needs them. I soon realized that you can't refer to those objects by script. (To disable them for example.) The script won't compile until at least one of the objects is in use, and then the disable command would refer to that object,so you still need PositionCell. (Note by GBG: you can circumvent this for many applications by having a script on the placed item, so that you can omit the "fix" and have functions such as disable reference to it by default.) DinkumThinkum adds: PlaceItemCell would have been perfect for what I wanted to do, until I discovered that the placed NPC disappeared if I saved and reloaded before going to the cell they were placed in. (Note by GBG:This can be avoided in most cases by making the placing of the NPC conditional on the player entering the cell. I still think PlaceItem is a very useful function.) Sample Script: Putting this script on an object causes it, on activation, to ask the user for an object type and then to create a reference to the specified object at 100 units above the activated reference with 45 degree Z rotation. If the key is selected, it is created at that same coordinate and rotation in the cell key room rather than the current cell.
Begin makethingsimple short short float float float questionAsked button myX myY myZ
if ( MenuMode ) return endif if ( OnActivate == 1 ) if ( questionAsked == 0 ) MessageBox, "Create new..." set questionAsked to 1
"...Pot"
"...Key"
47
set myX to GetPos X set myY to GetPos Y set myZ to GetPos Z + 100 endif endif if ( questionAsked != 0 ) if ( questionAsked == 1 ) set button to GetButtonPressed if ( button == -1 ) else if ( button == 0 ) PlaceItem "Misc_pot_redware_01" myX myY myZ 45 elseif ( button == 1 ) PlaceItemCell "misc key" "key room" myX myY myZ 45 endif set questionAsked to 0 set button to 1 endif endif endif end
Axis can be x, y, or z. Notice that like the move functions the value you are giving Rotate or RotateWorld is a speed setting (not an angle), if you want to turn an object by 90% either use set angle (for an instantaneous change) or use Rotate together with GetAngle to check how far the object has already been turned. These functions can not be used with Actors.
Setting Angles
SetAngle, axis, float_enum_angle
SetAngle, z, 30 Object_ID -> Setangle, z, 25
This function sets the object to a specific world angle. Axis is x, y, or z. The float value sets the angle (in degrees) of the calling object to that value. This always refers to the local coordinate system the object is currently in. 48
Note: According to console test, this does not affect Actors. With Tribunal, this function accepts local float variables, but only within the currently active cells. This is relevant for exteriors, you can not move objects an arbitrary distance, the target location must be within the active cells (current cell of player plus surrounding cells). (Forum info / reposted by Srikandi). For actors, see the "Face, x, y" function Example script: See SetPos function
Scale Functions
GetScale (float) SetScale newScale_float ModScale scaleChange_float
If (doonce == 0 ) Object_ID -> SetScale 0.1 Set doonce to 1 endif
These functions are used to determine or modify the scale of a reference. Any scale you can set must be within (exclusively) 0 and 10 (so you can set it beyond 0.5 and 2, contrary to what was written in the original description by Bethesda)(info by Mode Locrian). The above sample script can thus be used to set scale beyond the limits of what the TES CS itself allows. Notes: You shouldn't call "setscale" in every frame, at least not in exteriors or other FPScritical situations. The scale will be reset to a value within the 0.5 - 2.0 frame when you reload. So don't use a done-flag to call it only once. Either call it regularly (about all 10 frames) or test for "getscale" and reset the scale when it doesn't fit:
if ( GetScale != 5 ) SetScale, 5 endif
Another way is to set it in a Tribunal or Bloonmoon start script. This can be done once, and will make sure the scale is set each time you load a game. (Forum info / JOG). Sample script: A more complex sample script by Bethesda shows how to grow and shrink an object. When this script is placed on a reference, activating that reference gives the user the ability to change that references scale.
Begin scalescript short questionAsked short button float direction float currscale float tempscale if ( MenuMode ) return endif if ( OnActivate == 1 ) if ( questionAsked == 0 ) MessageBox, "Make this object..." set questionAsked to 1 endif endif
"...Grow"
"...Shrink"
49
if ( questionAsked == 1 ) set button to GetButtonPressed if ( button == -1 ) else if ( button == 0 ) set direction to 1 elseif ( button == 1 ) set direction to 1 endif set questionAsked to 0 set button to 0 endif endif if ( direction != 0 ) set tempscale to .3 * GetSecondsPassed set tempscale to tempscale * direction ModScale tempscale set currscale to GetScale if ( direction == -1 ) if ( currscale <= .5 ) set direction to 0 endif else if ( currscale >= 2 ) set direction to 0 endif endif endif end scalescript
Undocumented function! (Thanks XP-Cagey and Killgore) This function will return 1 if the current cell is an interior cell and 0 if it is an exterior cell. The following is a global sample script by Killgore. If you want to try it out start it by typing "StartScript Outside_Check" in the console.
Begin Outside_Check short doonce if (MenuMode == 1) Return EndIf if (doOnce == 0) ;if youre in some brand new cell ;or it just started if ( GetInterior == 1 ) MessageBox "1: inside" elseif ( GetInterior == 0 ) MessageBox "0: outside" else MessageBox "mystery else" endif set doOnce to 1 Return endif if (doOnce == 1) if (CellChanged == 0) Return else ;if the player changes cells that frame.. set doOnce to 2 ;it waits an extra frame endif Return
50
endif if (doOnce == 2) ;then starts over and prints set doOnce to 0 Return endif End Outside_Check
(returns Boolean/short)
The GetPCCell function tests for the players presence in the specified cell. It returns 1 if the player is in the specified cell, 0 if not. Partial matches are supported, e.g. GetPCCell, "Vivec" will return true for the cells "Vivec", "Vivec, foreign quarter waistworks" and "Vivec, temple", etc. Sample Script: This small Bethesda script checks for the PC leaving a certain area until removing a certain item from an NPC:
Begin DrothPost if ( GetJournalIndex "MS_EstateSale" >= 70 ) if ( GetPCCell "Mournhold, Geon Auline's House" == 0 ) "Geon Auline"->RemoveItem "silver dagger_droth_unique" 1 Journal MS_EstateSale 80 StopScript DrothPost endif endif End DrothPost
This function returns the distance (in units) of one object to another. In syntax one, that is the distance between the calling object (to which script is attached to) and the named object. This can be used to trigger attacks or other events, or simply to roughly determine the player's whereabouts for use in a script. Here is a snippet from an original Morrowind script:
; From a script attached to an NPC Ashamanu: ; Ashamanu will give journal entry 60 when player is near if ( GetDisabled != 1 ) if ( GetDistance Player <= 256 ) if ( GetDistance "guar_white_unique" <= 256 ) if ( GetJournalIndex "MS_WhiteGuar" <= 50 ) Journal "MS_WhiteGuar" 60 endif endif endif endif
Limitations: GetDistance requires that the object given as parameter is placed in the gameworld (in the editor) and has references persist checked (or is naturally persistant such as a NPC) 51
Note that you should use this function only with unique ID's or in environments where you exactly know that there is only one instance of the ID otherwise the Game engine will just grab the first instance of the ID it finds and report that distance most likely not the distance to the object you want. Thus, a script that warns the player of the presence of a slaughterfish that is closer than 800 units would have to be attached to the ID of the slaughterfish, and check the distance to "player" (which is unique), not vice versa. If you determine distance to an object you are moving with Move or MoveWorld, GetDistance will still report the distance to the original location of the object (the one you set in the editor). Use GetPos and good ol' Pythagoras (c2 = a2 + b2) to determine distances in these instances.
When you are moving objects with the Move/MoveWorld functions described above, you might want to obtain information on its current whereabouts. This functions work on Actors and objects. In the following sample script I used this function to control the movement of a light source (a fire) to make a fire pit where the flames actually start slowly and die down in the evening on a daily schedule the fire objects original Z position is 511:
Begin _HB_Scheduled fire short control_fire ; The script is attached to an NPC that guards the fire. ;******* this controls the fires schedule: if ( GetDistance, "HB_Furn_De_Firepit_camp" < 600 ) If ( GameHour < 17 ) if ( HB_Light_Fire_camp -> GetPos Z >= 400 ) HB_Light_Fire_camp -> MoveWorld z, -0.1 ; Move fire down else HB_Light_Fire_camp -> disable endif elseif ( GameHour >= 17) HB_Light_Fire_camp -> enable if ( HB_Light_Fire_camp -> GetPos Z < 511 ) HB_Light_Fire_camp -> MoveWorld z, 0.1 ; move fire up else HB_Light_Fire_camp -> enable endif endif endif end
GetAngle , axis(x/y/z)
If ( Object_Id -> GetAngle, z == 180 )
(returns float)
The GetAngle function returns the world angle, not the local angle. World angles are from 0 to 180 and 0 to -180 (see figure for z axis). Note: This works on actors and objects, however for the player (and I assume other actors) only the z axis is relevant - GetAngle, x or y always return 0.
52
N
0
-90
90
180 / -180
Line of Sight
GetLOS, ObjectID (returns Boolean/short)
Actor_ID -> GetLOS, Player
Undocumented:
GetLineOfSight
(returns Boolean/short?)
These functions determines whether the calling object has line-of-sight to the referenced object. It does not seem to work for non-Actor type objects, as far as I could determine. It does not take facing into account, so don't take the "sight" part too literally. (See "Is she looking at me? In the Tips and Tricks section.) Note: GetLOS is a very slow function, don't let the script call it every frame. Sample Script:
Begin balynScript float timer short doOnce []; references to journal settings Set timer to ( timer + GetSecondsPassed ) if ( timer < 5 ); A timer to avoid testing to often (avoids performance problems) Return endif Set timer to 0 if ( doOnce == 0 ) if ( GetDistance Player <= 1024 ) if ( player->GetDistance "hlaalu_loaddoor_ 02_balyn" <= 256 ) if ( GetLOS Player == 1 ) ForceGreeting Journal DA_Mephala 55 set doOnce to 1 endif endif endif endif End
53
(returns Boolean/short)
Returns true if any calling Actor can detect "Actor ID" (thanks for the correction, ThePal!). This function will return 0 if the Actor is hidden in some form, e.g. is sneaking successfully, or has an invisibility or chameleon spell active. According to the helpfile this is a slow function, do not call it a lot (e.g. make a counter to only call it every 3 seconds). Sample script: The player must approach an object undetected if not he is "caught"
Begin jeanneScript float timer short nolore if ( GetJournalIndex "EB_Bone" < 20 ) Return endif if ( GetJournalIndex EB_Bone >= 40 ) Return endif Set timer to ( timer + GetSecondsPassed ) if ( timer < 5 ) ;this makes sure GetDetected is only called every 5 seconds Return endif Set timer to 0 if ( GetDistance Player <= 1024 ) if ( player->GetDistance "com_chest_02 " <=128 ) if ( GetDetected Player == 1 ) ForceGreeting ;The player has been caught and will be punished Journal EB_Bone 50 endif endif endif End jeanneScript
CellChanged returns 1 for one frame when player changes cells. If the script calling this function is local, this function will trigger when the player enters the cell where the script is active leaving the cell will not trigger the function, because the script terminates before the cell change registers (Thanks to Klinn for this correction). There seems to be a slight bug: teleporting out of a cell reportedly does not trigger this function (unconfirmed). Sample Script: In the SlaveScript, which governs freeing slaves in the game, CellChanged is the trigger to disable the slave the slave has left for a better future:
Begin SlaveScript [] if ( slaveStatus == 3 ) if ( GetCurrentAIPackage == 3 )
54
AIWander 512 0 0 0 0 0 0 0 0 0 0 0 endif if ( GetItemCount Slave_Bracer_Left > 0 ) Drop Slave_Bracer_Left 1 endif if ( GetItemCount Slave_Bracer_Right > 0 ) Drop Slave_Bracer_Right 1 endif if ( CellChanged == 1 ) Disable endif endif end slaveScript
another nice example is the Gateway Haunt's scrip. This specter always comes back just when you are not watching:
Begin ResurrectHaunt ;town_Sadrith quest ;gateway_haunt resurrects until journal town_Sadrith >= 35 if ( CellChanged == 1 ) if ( gateway_haunt->GetHealth < 1 ) gateway_haunt->Resurrect endif endif end ResurrectHaunt
Bloodmoon adds a functions to check whether the PC is travelling (i.e. on a Silt Strider). Will return 1 if traveling/in jail, zero otherwise.This is used in the werewolf change script to stop the PC from changing if either of these are true:
if ( PCWerewolf != 1 ) ; DON RUN IF PLAYER ISNT WEREWOLF return endif if ( GetPCinJail == 1 ) return endif if ( GetPCTraveling == 1 ) return endif
(returns Boolean/short)
55
These are great functions to trigger events, especially for interior cells. It is also an excellent function to build traps. You can make an "activator" object using the nif files of any static object (including hallway, carpets etc., and trigger certain events once the player (or another Actor) steps on that object. My sample script is used to light fires in a hall on as soon as the player steps on a particular piece of floor:
Begin HBHallLighting if ( GetStandingPC == 1 ) set HB_hallfire to 1 endif end
HB_hallfire is a global variable, used to turn on the fire. This is the script for the fire:
Begin HBHallfireon if ( HB_hallfire == 1) if ( GetPos, z, < -736 ) MoveWorld, z, 3 ; fire rises, until its reached full height if ( GetPos, z, > -780) enable endif endif else disable endif end
This function affects the health of an Actor (including the PC) that stands on the object. Positive values will reduce health, negative values heal (hitpoints per second). Using negative values will modify your health even beyond your normal maximum helath, so be careful to test this if you want to use this functionthis way. This function accepts float variables Sample script: The effect is probably best known from the lava fields:
begin lava if ( menumode == 1 ) return endif if ( CellChanged == 0 ) if ( GetSoundPlaying "lava layer" == 0 ) PlayLoopSound3DVP "lava layer", 1.0, 1.0 endif endif HurtStandingActor, 20.0 end lava ;20 pts of damage a sec
56
HurtCollidingActor, damage_enum
HurtCollidingActor, 100 Object_ID -> HurtCollidingActor, 100
These functions go on an object to allow it to interact with Actors colliding with it. GetCollidingPC returns 1 if the PC is currently colliding with the object and 0 otherwise. GetCollidingActor works the same as the PC version of the function but will return 1 if any Actor (other than the PC) is colliding with the object. HurtCollidingActor lowers the colliding Actors health Damage points every second. Sample script: When this script is placed on an object, any Actor touching that object will take damage. A different message is given depending on whether the Actor is the PC or someone else.
Begin hurtActor if ( GetCollidingPC == 1 ) MessageBox "You scream in pain as you touch the rock." Elseif ( GetCollidingActor == 1 ) MessageBox "Nearby someone screams in pain." Endif HurtCollidingActor 100 End
This get set to one for one frame when the object is activated. OnActivate resets itself as soon as the function is called, so only one script can report OnActivate successfully, and you should only have one OnActivate call in your script at each moment. OnActivate shortcircuits the normal behavior of the object -to perform the standard action of the object once OnActivate has been called, you have to use the activate command:
Activate
activate (if script is on the object to activate)
57
Activate can be used to trigger the standard action of an object, after OnActivate has been called. Standard actions called by Activate are: Doors -> Open (Possibly broken in Original MW, with v1.6.1820 it definitely works). LoadDoors -> Nothing (broken?) Containers -> Open (show contents) Books/scrolls -> Display text to read *. Activators -> Nothing Actors -> Dialogue Weapon -> Pick up Armor -> Pick up Miscellaneous -> Pick up Not tested, but I assume: Equip. Lights -> Pick up Other Lights -> Nothing Probes -> Pick up Aparatus -> Pick up *(but seems to disable the "take" option thats usually displayed. Can also cause a lockup when used without a do-once condition. See tips and tricks section for solutions) Example script: The following script demonstrates the use of OnAtinicely. It is attached to a container object, a chest that does NOT advertise its trap like the normal in-game ones do:
Begin Trap_script short done if ( OnActivate == 1 ) if ( done == 1 ) ;do-once condition Activate return else Cast, "flame", Player ;damage to player set done to 1 Activate ; Call standard action: the chest opens endif endif End trap_script
Notes: According to my testing, the activate function can not be used by itself, without OnActivate in the same script. The OnActivate and Activate functions can be in different parts of the script, though. However, Activate will not work before OnActivate has not at least been called once. There have been reports that the object also must have been manually activated at least once within the last 72 hours, so apparently the game eventually forgets that OnActivate has been called previously. Play around with this testscript (I had it attached to a door) to see for yourself:
Short done if ( OnActivate == 1 ) MessageBox "Thank you for activating" endif
58
if ( done == 0 ) If ( GetDistance, Player < 100 ) set done to 1 MessageBox "Player close" endif endif if ( done == 1 ) If ( GetDistance, Player > 200 ) MessageBox "Sesame" Activate set done to 0 endif endIf End MessageBox "Player close" endif endif if ( done == 1 ) If ( GetDistance, Player > 200 ) MessageBox "Sesame" Activate set done to 0 endif endIf End
Begin GBG_closing_door
Begin GBG_activate Short done if ( OnActivate == 1 ) MessageBox "Thank you for activating" endif if ( done == 0 ) If ( GetDistance, Player < 100 ) set done to 1 MessageBox "Player close" endif endif if ( done == 1 ) If ( GetDistance, Player > 200 ) MessageBox "Sesame" Activate set done to 0 endif endIf End
There have also been various reports about difficulties with on OnActivate in general, in my experience, avoiding to use more than one OnActivate in a script is the safest way to go. Also be aware that for items in your inventory, OnPCEquip may be the function to use instead of OnActivate, as OnActivate does not get called by moving the item over the Player icon. Info from the UESP: There is an undocumented feature in the Activate function by specifying the player after the function, for example:
begin RemoteContainer short OnPCEquip if ( OnPCEquip == 1 ) set OnPCEquip to 0 "dh_remote_chest_01"->Activate, player endif
59
end
If the container is persistant (references persist) this script should open the container wherever the player is. This is a great way to create 'carryable' containers by attaching a script similar to the above to a ring or similar item.
GetLocked
(returns Boolean/short)
(only Door and container objects) These functions are used to lock and unlock doors or containers. The GetLocked function returns 1 when the calling object is locked. Lock locks the object with the lock level specified (0-100). Lock 0 has an odd effect though. The door/container will be neither openable nor pickable. Unlock removes any lock, regardless of lock level. Example script: Here is a sample script by qwert, which makes a chest function as a security skill-training device by constantly relocking it:
Begin PC_Security_Skill_Trainer float timer if ( menumode == 1) return endif set timer to timer + GetSecondsPassed if ( timer > 10 ) set timer to 0 endif if ( timer == 0 ) ;using a timer to relock after 10 seconds pass "Storm_Chest_Trainer"->Lock 50 endif End
Animating objects
There is a group of functions that allows you to play specific animations that are defined in a model (.nif file). You can find out about the animation group names by loading a model into the preview window and then skipping through the different animation groups or by looking at "base animation" windows in the "Character" menu. An excellent summary of Actor animation groups can be found here: http://morrowind.preik.net/animationgroups.html but only the ones listed in the base animation window can be called by this function. Additional animations can be loaded to a model via the animation button in the object window. See the Dancing girls in "Suran, Desele's house of earthly delights" for an example.
60
Not all models have animation groups, but the different banners (under activators) are good examples to see what is meant (see example below). Examples for GroupName are: idle, idle2, idle3, walk, etc. These functions do not work on the player character.
PlayGroup, GroupName, [Flags]
PlayGroup, walk, 1
Plays the animation group defined by GroupName. Optional flags can be used to start the group in different ways (see below).
LoopGroup, GroupName, Number_enum, [Flags]
lays the animation group defined by GroupName. The animation will be looped the number of times specified, and then return to the Idle animation. Optional flags can be used to start the group in different ways (see below).
SkipAnim
Causes the current animation to not be played for this frame. Flags: 0 = Normal The current animation will finish its full cycle, and the new animation will start from its beginning. 1 = Immediate Start The current animation will stop regardless of the frame it is on, and the new animation will start from its beginning. 2 = Immediate Loop The current animation will stop regardless of the frame it is on, and the new animation will start at the beginning of its loop cycle. Note: PlayGroup does not work on the PC. With Bloodmoon installed (not necessarily Bloodmoon.esm selected) some of NPC animations are crosswired. When called from console, they may look correct, but if you insert NPC->PlayGroup, group, 1 into the script, you may be unpleasantly surprised to see a different animation than you expected (Forum info / Kir). You may have to experiment to find the correct animation (Check out the info in the section on AIWander for a list of NPC idle movements; Kir is working on a tool called "NPC Animation Explorer", keep an eye out for it!). Example Script: This original script is attached to all the outside banners and makes them move differently depending on the weather:
begin OutsideBanner ;this script is for a banner object outside that ;animates in the wind. ;Idle is still, Idle2 is a little breeze, and Idle3 is a large breeze short ran if ( MenuMode == 0 ) set ran to random 100 if ( ran < 30 ) ;30% chance the flag does something new if (GetCurrentWeather >= 5 ) ;thunder, ash, or blight LoopGroup, Idle3, 5 endif ;the last anim called in this script is the one it will play
61
if ( ran <= 10 ) PlayGroup, Idle elseif ( GetCurrentWeather < 5 ) PlayGroup, Idle2 endif endif endif end OutsideBanner
The Disable function makes an object completely vanish from the game world, meaning it's neither rendered nor processed (attached scripts are still active, however). The Enable function makes a disabled object visible and processed again. GetDisabled (returns 1 if object is disabled) can be used to obtain the current status of an Object. These functions are very powerful and could e.g. be used to swap different models of statics (normal house replaced by house burnt to the ground, etc). It is e.g. used for the stronghold building process. Example script: An example from the game is the SlaveScript that makes freed slaves vanish once the player leaves the cell:
begin slaveScript short slaveStatus short doOnce short NoLore [other slaves status checks check original script!] if ( slaveStatus == 3 ) if ( GetCurrentAIPackage == 3 ) AIWander 512 0 0 0 0 0 0 0 0 0 0 0 endif if ( GetItemCount Slave_Bracer_Left > 0 ) Drop Slave_Bracer_Left 1 endif if ( GetItemCount Slave_Bracer_Right > 0 ) Drop Slave_Bracer_Right 1 endif if ( CellChanged == 1 ) Disable ;****** Make slaves vanish once freed and player leaves endif endif end slaveScript
Caution: disabling lights There seems to be a game engine issue with disabled lights Actors and some other types of objects still seem to be illuminated, while the world around is not. I have not thoroughly tested if this can be avoided, but a suitable workaround is to physically remove the light to a remote location (e.g. a few meters below the floor) instead of disabling it. Another trick comes from Indigo: If you enable a light that is set to "negative" (which means its generating darkness instead of light) after you disable the normal light, the illumination problem goes away. 62
The SetDelete function can be used in combination with Disable to remove an object more completely. SetDelete 1 marks a reference for deletion and SetDelete 0 clears that flag. This can be useful in optimization. Certain objects have scripts on them which simulate picking them up by disabling the activated reference and adding a new object to your inventory. This leaves an ever-present, but disabled, reference at that location (which eats up memory and processor time since the script on the disabled reference is still run every frame). If the reference is marked for deletion then it is essentially gone. If the reference came from the master file, it is still there but knows it shouldnt be so has no art and no scripting. If was created in game, it will actually be deleted. Note: SetDelete will crash Morrowind if there is any other function operating on the object in the same frame. This Script will crash:
Begin _spell_effect float timer rotate y 120 ; crash caused by this if ( timer < 3 ) set timer to ( timer + GetSecondsPassed ) else disable setdelete 1 endIf
A solution is to use first disabling the object and then using GetDisabled and Return to safely delete the object:
Begin _spell_effect DontSaveObject float timer if ( GetDisabled == 1 ) setdelete 1 return endIf rotate y 120 if ( timer < 3 ) set timer to ( timer + GetSecondsPassed ) else disable endIf
Another solution was proposed by Soralis, using a local variable "deletobj" as a flag:
if ( deleteobj = 1 ) ;Local variable, set when you want to delete if ( deletetimer == 0 ) Disable endif if ( deletetimer < 10 ) set deletetimer to ( deletetimer + 1 ) endif if ( deletetimer == 10 )
63
Also, you should always call SetDelete from a local script assigned to the object you want to remove. Never use Object->SetDelete 1 as this usually causes crashes when Morrowind is running. If an item is in your inventory, it shouldnt be deleted since this may cause you encumberance to become wrong. If you really need to delete an item, and you know that the PC is carrying it, you can try using the Drop command before disabling and deleting. One last thing to be aware of is that sometimes magic effects can also cause problems with the SetDelete function.(Forum Info/Dan_Wheeler)
Call this function if changes to the object are not to be saved to the savegame. Use DontSaveObject on objects that: 1. Can be enabled/disabled during the game, such as the stages of building a stronghold. 2. Objects that might be moved, such as ridable objects. By using DontSaveObject you will avoid that annoying "save game data has changed" error message that will occur when load a saved game and the object's state has changed, ie: it has moved, or has been disabled/enabled. This is due to the fact that object data is stored in the save game data, such as if the object is enabled or disabled, or if it has been moved (like a ridable object) (Forum info / IndigoRage). In the original game, it's used in the SignRotate script and the following one: Sample Script:
Begin diseaseAscended DontSaveObject ;ascended sleeper has all the blight diseases for some reason... if ( CellChanged == 0 ) return endif AddSpell "ash woe blight" AddSpell "black-heart blight" AddSpell "chanthrax blight" AddSpell "ash-chancre" End
64
To make an NPC walk between different defined places in the game world you use the AITravel function. The variables x, y, z are world coordinates. You can determine these by moving your camera to the desired endpoint of the movement or by selecting a path grid point or an object nearby coordinates are displayed below the object window. The usage of the optional reset flag is unknown. When using this function in scripts it is important to provide conditions where the AI package is called only once. Consider the following NPC bound script
Begin Travel AiTravel, 1359, 2700, 1045 End Travel
The previous script will not work, as the script fires continuously, and the effect is that the NPC freezes and never performs the desired movement.
Begin Travel Short do_once If (do_once==0) AiTravel, 1359, 2700, 1045 Set do_once to 1 endif End Travel
This should work; the NPC will wander to the designated coordinates as soon as his script becomes active, meaning as soon as his cell is loaded.
To check whether an NPC has arrived at his location you can use the GetAIPackageDone function. This function returns 1 for one frame when the current AI package has finished. Use this to perform a check whether a movement has been finished. The following script is an example of how to link several AITravel commands within one script, using a state variable and an if-elseif structure:
Begin TravelLoop short state
65
float timer if ( menumode == 1 ) ; if menu is open don't process return endif ;start walking if ( state == 0 ) if ( player -> GetDistance HB_adros_darani < 5000 ) set state to 5 endif ;******************* He begins his trip elseif ( state == 5 ) SetHello 0 AITravel -8144, -19409, 728 ;new co-ords point 1 set state to 10 elseif ( state == 10 ) if ( GetAIPackageDone == 1 ) set state to 40 endif elseif ( State == 40 ) AITravel -9147, -19459, 720 ; new co-ords point 2 set State to 50 elseif ( state == 50 ) if ( GetAIPackageDone == 1 ) set state to 60 endif ;he's reached the point 2 ;he's reached point 1
elseif ( state == 60 ) AITravel -8144, -19409, 728 ;new co-ords point 1 set state to 70 elseif ( state == 70 ) if ( GetAIPackageDone == 1 ) set state to 80 endif ;he's reached point 1
elseif ( state == 80 ) AITravel -6640, -18496, 1040 ;new co-ords point 0 set state to 90 elseif ( state == 90 ) if ( GetAIPackageDone == 1 ) set state to 0 endif endif End TravelLoop ;he's reached point 0
Good examples of scripting using AITravel are also found in the lookoutscript (Fargoth hiding his treasure) and the CharGenWalkNPC script (The guard that walks you through the ship at the beginning of the game). Or look at my "Traveling Merchants" plugin for true AITravel madness ! If you plan on using this function extensively you should be aware of the following problems: When you leave a cell with an Actor that is just performing its AITravel command, or if you rest, the script will never detect the GetAIPackageDone signal, meaning your NPC gets stuck on its path once you return or finish sleeping. The following simple code can be used to get the script going again (this is for the above script)
; *************** Stalled Script rescue - recovers script after leaving a cell or resting If ( Player -> GetDistance, HB_adros_darani < 5000 ) if (GetCurrentAIPackage == -1) ; check for idleness set timeout to ( timeout + GetSecondsPassed )
66
if ( timeout >= 3) ; wait some time. ; Short instances of idleness always occur set state to (state - 10) ; stall will occur at ; AIPAckageDone - jump to "wander" again. set timeout to 0 endif else set timeout to 0 endif endif
To my knowledge this function does not accept variables (at laeast under version 1.6.1820), but there have been reports that it did - possibly this is version dependent. This function Makes an NPC face towards a specified x/y coordinate. Apparently interrupts current animations. Using this on wandering NPCs makes them stop, face wherever, then continue on wherever they were wandering to, as soon as the facing movement is over. (Forum info / JOG, Dan_Wheeler).
This is the random movement algorithm that most of the NPCs in the game are using. The NPC travels along the path grid, changes direction randomly, and performs idle movements in between. Range: determines the distance the Actor or creature will roam from his origin. Duration: probably the time (in hours) the mob will perform the package (before it is reset, which seems to happen if you leave or sleep, not sure?) time: presumably determines the start time for the package if it has a duration [idle1], [idle9]: chances of idle movements. The Idles are (as tested in game): Human male: Idle1: Stand still Idle2: Shifting weight from one leg to the other Idle3: Looking behind Idle4: Scratching head, shake head Idle5: Shifting clothing or armor on shoulder Idle6: Yawning and stretching Idle7: Looking at fingers and looking around furtively Idle8: Putting hand to chest, as if having heartburn Idle9: Reaching for weapon, then touching head Human female - as above but: Idle5: Hand on hip Khajiit female - as Human male but Idle9: Scratching head, shaking head
67
To let an Actor stand in one spot you can use: AIWander, 0, 0, 0 Note: the number of idles and some of the descriptions were listed wrongly in previous versions (corrected with 8th edition - credits go to Whoopa). Here is an example script that displays all idles in series (this my be useful to check out which ones you want your NPC to use):
Begin Animtest float timer short count set timer to ( timer + GetSecondsPassed ) if ( timer > 10 ) set timer to 0 set count to ( count + 1 ) if ( count >= 18 ) set count to 0 endif endif if ( count == 1 ) AIWander 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0 MessageBox "Idle 1 , 100" set count to ( count + 1) elseif ( count == 3 ) AIWander 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0 MessageBox "Idle 2 , 100" set count to ( count + 1) elseif ( count == 5 ) AIWander 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0 MessageBox "Idle 3 , 100" set count to ( count + 1) elseif ( count == 7 ) AIWander 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0 MessageBox "Idle 4 , 100" set count to ( count + 1) elseif ( count == 9 ) AIWander 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0 MessageBox "Idle 5 , 100" set count to ( count + 1) elseif ( count == 11 ) AIWander 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0 MessageBox "Idle 6 , 100" set count to ( count + 1) elseif ( count == 13 ) AIWander 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0 MessageBox "Idle 7 , 100" set count to ( count + 1) elseif ( count == 15 ) AIWander 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0 MessageBox "Idle 8 , 100" set count to ( count + 1) elseif ( count == 17 ) AIWander 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100 MessageBox "Idle 9 , 100" set timer to 0 set count to ( count + 1) endif End
In the words of Bethesda: "This package tells the Actor to activate the specified ObjectID. A powerful and admittedly underutilized and undertested package." 68
In standard Morrowind this function appeared to be mostly broken, except for making an NPC quaff a potion. With Tribunal it seems to have been fixed, at least to some extent. I could successfully use it to get an NPC to pick up a weapon, open a normal door and go through a load door. LoadDoors only work if the door marker it teleports to is in the same interior cell, or within the loaded (PC's current and surrounding) cells in exterior cells otherwise the game crashes. I also tested it successfully with an activator (switch to open Ghostgate). The usual precautions with AI functions apply (make sure the Actor is not too far away, have a good AI grid in place, make sure nothing can get in the way, etc.). Although not thoroughly tested, I didn't seem to get an AIPackageDone signal, but other conditions can be constructed (see examples below) to set the NPC to a different AIPackage again. Object Type NPC Container Door Load door Weapon, armor, misc., etc Book/Scroll Activators Activation Dialogue Opens Opens Opens/teleports (same cell only) Picks Up Reads <meaning what to an NPC?> Execute as defined by script
Sample Script: these are just a few testing scripts I made. They show how you can set conditions to determine when the NPC has finished his action.
Begin TT_opendoor short doonce short AIState if ( doonce == 0 ) if ( GetDistance, Player < 400 ) AIActivate TT_door set doonce to 1 endif elseif ( doonce == 1 ) set AIState to GetCurrentAIPackage MessageBox "Package = %g", AIState if ( TT_door->GetAngle, z != 180 ); As soon as door starts rotating MessageBox "Done" AIWander 30, 5, 0, 0,20,0,0,10,30,0,0 set doonce to 2 endif endif end
Begin TT_pickmace short doonce short AIState if ( doonce == 0 ) if ( GetDistance, Player < 400 ) AIActivate TT_daedric_mace set doonce to 1 endif elseif ( doonce == 1 ) set AIState to GetCurrentAIPackage MessageBox "Package = %g", AIState if ( GetItemCount, TT_daedric_mace >= 1 ); when NPC has the mace in his inventory MessageBox "Done" AIWander 512, 5, 0, 0,20,0,0,10,30,0,0 set doonce to 2 endif
69
endif end
Begin TT_openloaddoor short doonce short AIState if ( doonce == 0 ) if ( GetDistance, Player < 400 ) AIActivate TT_door set doonce to 1 endif elseif ( doonce == 1 ) set AIState to GetCurrentAIPackage MessageBox "Package = %g", AIState if ( GetPos, y > 2000 ); position has changed. Loaddor target is in same cell MessageBox "Done" AIWander 30, 5, 0, 0,20,0,0,10,30,0,0 set doonce to 2 endif endif end
The "Follow" AI-package makes an Actor closely follow another. You can use this to make an NPC or creature follow the player, but you can also use it to make NPCs and creatures form a caravan. The following excerpt from one of my own scripts shows the unconditional use of the function:
elseif ( state == 20 ) HB_guar_pack_adros_ -> AIFollow, HB_adros_darani, 0, 0, 0, 0 AITravel -8144, -19409, 728 ;new coords point 1 set state to 30
since there is no duration or destination location given, the guar will follow the NPC until another command is given. As with other AI-commands, make sure you set conditions so that each AIFollow command is issued only once, not each time the script is executed every frame. The duration, CellID and x, y, z destination coordinates set conditions that once fulfilled will terminate the AIPackage (which you can test with the GetAIPackageDone function as describe for AITravel above). The AiFollowCell function allows you to set an interior cell as the destination. The meaning of the optional reset option is currently unknown.
AIEscort, "Actor ID", duration, x, y, z, [reset] AIEscortCell, "Actor ID", "Cell ID", duration, x, y, z, [reset]
This function allows to program an Actor to lead the player to a certain point. The Actor will wait for the player if the disctance becomes too great, and will resume its path when the player approaches again (Thanks to Kir for this info). You see an example of this in character 70
generation -- the guard who escorts you up from the ship's hold to the ramp on the second level. (Thanks to MisterSmileyFaceDude). The meaning or use of [reset] is unknown.
The returned values are: None -1 Wander 0 Travel 1 Escort 2 Follow 3 Activate 4 Pursue 5
GetForceSneak
( returns Boolean/short)
The ForceSneak command puts the Actor in sneak mode, all movement will be performed in sneaking. ClearForceSneak terminates ForceSneak mode. Unfortunately there does not seem to be a corresponding command to force running (added with Tribunal). GetForceSneak returns one if ForceSneak mode is active on the calling Actor. Check the LookoutScript script for an example. Here's a snippet:
elseif ( walkstate == 2 ) Fargoth->ForceSneak ; enter sneak mode Fargoth->AiTravel -11468.595,-71511.531,173.728 set walkstate to 3 elseif ( walkstate == 3 ) if ( Fargoth->GetAiPackageDone == 1 ) ;Fargoth->Equip "torch_infinite_time_unique" set walkstate to 4 ;MessageBox "SHOULD BE AT TREE" endif elseif ( walkstate == 4 ) set timer to timer + GetSecondsPassed Fargoth->ClearForceSneak ; terminate sneak mode Fargoth->AiWander 0 0 0 0 0 0 0 0 0 if ( timer > 3 ) Fargoth->ForceSneak ; reenter sneak mode Fargoth->AiTravel -11410.590,-72057.188,133.644 set walkstate to 5 endif
;goes to tree
;goes to wall
71
These functions all control the specified NPCs movement. The ForceRun function makes the NPC always run when they move, the ForceJump function makes the NPC constantly jump, and the ForceMoveJump makes the NPC always jump when they are moving. The Get versions of the functions return one if the specified NPC currently is forced into the given action and zero otherwise. The Clear functions are used to turn forced movement modes off. An NPC can only be forced to do one movement at a time. The priority for forced movement is Sneak > Running > Jump > MoveJump. Sample Script: This script lets an object control the movement type of Athlete, an NPC set to Travel endlessly in a four-point square.
Begin AthleteControl short short short short questionAsked button isrunning isjumping
if ( MenuMode ) return endif if ( OnActivate == 1 ) set isrunning to ( Athlete->GetForceRun ) set isjumping to ( Athlete->GetForceMoveJump ) if ( questionAsked == 0 ) if ( isrunning ) MessageBox, "Make Athelete stop running? " "Yes" else MessageBox, "Make Athelete run? " "Yes" "No" endif set questionAsked to 1 endif endif if ( questionAsked == 1 ) set button to GetButtonPressed if ( button == -1 ) else if ( isrunning == 0 ) if ( button == 0 ) Athlete->ClearForceMoveJump Athlete->ForceRun endif else if ( button == 0 ) Athlete->ClearForceRun endif endif if ( isjumping ) MessageBox, "Make Athelete stop jumping? "
"No"
"Yes"
"No"
72
else MessageBox, "Make Athelete jump? " endif set questionAsked to 2 set button to 1 endif endif if ( questionAsked == 2 ) set button to GetButtonPressed if ( button == -1 ) else if ( isjumping == 0 ) if ( button == 0 ) Athlete->ClearForceRun Athlete->ForceMoveJump endif else if ( button == 0 ) Athlete->ClearForceMoveJump endif endif set questionAsked to 0 set button to 1 endif endif end
"Yes"
"No"
These functions returns 1 if the PC is performing the appropriate action and 0 if he is not. Since Morrowind doesn't have functions to directly test for keyboard input, these functions provide an alternative to check if the player has a certain button pressed. They have accordingly been used extensively for control puposes, e.g. for movable ships, ridable creatures, or in my climbing mod. Sample script: When this script is placed on an NPC, and the player has an item equipped called scissors, MessageBox warnings will be given based on the players current actions.
Begin momscript short warn if ( player->HasItemEquipped "scissors" ) if ( warn != 1 ) if ( GetPCRunning ) MessageBox "Dont run with scissors!" set warn to 1 endif endif if ( warn != 2 ) if ( GetPCJumping ) MessageBox "Don't jump with those scissors! You'll put your eye out!" set warn to 2 endif endif if ( warn != 3 ) if ( GetPCSneaking ) MessageBox "You can't hide those scissors from me!" set warn to 3 endif
73
These functions can be used to determine whether or not an Actor has their weapon out or whether or not they have a spell readied for casting. Sample Script: This global script gives notification messages based on the players weapon and spell states.
Begin player_notifications short weapstate short spelstate if ( player->GetWeaponDrawn ) if ( weapstate != 1 ) set weapstate to 1 MessageBox "The player's weapon is drawn." Endif else if ( weapstate != 0 ) set weapstate to 0 MessageBox "The player's weapon is sheathed." Endif endif if ( player->GetSpellReadied ) if ( spelstate != 1 ) set spelstate to 1 MessageBox "The player's spell is readied." Endif else if ( spelstate != 0 ) set spelstate to 0 MessageBox "The player's spell is put away." Endif endif end
Seems to give an NPC the extra nudge they may need even after you yank the floor out from under them. It also brings down flying creatures. Used by the Icarian Flight guy. When I tried to use this on the player in my climbing mod, it seemed to sometimes "warp" the player directly to the ground below. 74
Tribunal introduced the option to "share" equipment with NPC's or creatures. To enable this option, you must define a local short variable named "companion" and set it to 1. Setting it to 0 will disable sharing. This method is used both for mercenaries and for pack animals.
[no fix] minimumprofit
Float minimumprofit If ( minimumprofit < 0 )
Seems to be another variable set by the game, it is probably the difference between current value of all goods and gold minus starting value. If this gets negative, the mercenary can be scripted to quit. Sample Script: here is the relevant part from Calvus' script (the mercenary in Mournhold). This section handles changes in state when Calvus leaves a contract, either because the contract expires, or because the player has taken Calvus' stuff. The sharing is initiated from dialogue (setting companion to 1), not in the script itself
if ( GetJournalIndex Merc_Calvus_Quit < 1 ) ;if Calvus has already quit, don't do this if ( Contract_Calvus == 1 ) ;if Calvus doesn't have a contract, don't do this if ( minimumProfit < 0 ) ;Calvus is quitting because player took his stuff AiWander 128 6 0 40 30 20 0 0 0 0 0 0 Set Companion to 0; stop sharing StopScript Contract_Calvus Set Contract_Calvus to 0 ForceGreeting return else if ( Contract_Calvus == 0 ) ;handles Calvus after a contract expires AiWander 128 6 0 40 30 20 0 0 0 0 0 0 Set Companion to 0; stop sharing if ( GetJournalIndex Merc_Calvus < 10 ) Journal Merc_Calvus 10 ;first contract expired else Journal Merc_Calvus 20 ; most recent contract expired endif endif endif endif endif
A useful variable for use with companions. When used in a script, it causes whoever it's assigned to to automatically remain (and wait) outside of any interior the player may enter (automatically rejoins upon return).(Forum info / Grumpy)
75
Returns 1 if the object is of the race indicated by RaceID. Sample Script: This is a global script Bethesda uses to set a variable that can be used to determine the PCs race in dialogue:
begin RaceCheck ;global script that gets run once to check the PC's race, so it can be used in dialogue if ( Player->GetRace "Argonian" == 1 ) set PCRace to 1 elseif ( Player->GetRace "Breton" == 1 ) set PCRace to 2 elseif ( Player->GetRace "Dark Elf" == 1 ) set PCRace to 3 elseif ( Player->GetRace "High Elf" == 1 ) set PCRace to 4 elseif ( Player->GetRace "Imperial" == 1 ) set PCRace to 5 elseif ( Player->GetRace "Khajiit" == 1 ) set PCRace to 6 elseif ( Player->GetRace "Nord" == 1 ) set PCRace to 7 elseif ( Player->GetRace "Orc" == 1 ) set PCRace to 8 elseif ( Player->GetRace "Redguard" == 1 ) set PCRace to 9 elseif ( Player->GetRace "Wood Elf" == 1 ) set PCRace to 10 endif StopScript RaceCheck end
(returns short)
Returns PCs rank in faction. This will default to the Actors faction if FactionID is not defined. Returns 0-9 and -1 if not a member. Sample Script:An Actor/object with the following script is only enabled if the PC is not a member of House Redoran:
Begin bandenIndarysScript if ( CellChanged == 0 ) Return endif if ( GetPCRank "Redoran" == -1 ) Enable else Disable endif End
76
Probably returns reputation with the faction. Not used by Bethesda, not tested.
SameFaction (returns Boolean/short)
Returns 1 if PC has been expelled once from calling object (NPC) Faction, or a faction can be defined to get a specific one. For an example script look below, PCClearExpelled function.
Makes the PC a member of the specified faction. FactionID is optional if it is not added it will use the faction of the NPC who called the function
LowerRank RaiseRank
Raises or lowers the objects rank in its current faction. In the original game, this was only used in dialogue.
[no fix] PCLowerRank [no fix] PCRaiseRank
Raises or lowers the PC 1 rank in the NPCs faction. If PC is not part of the faction, it will set the rank to 1. Example Script:
Begin treboniusScript ;if you're both in the Arena ;and if the guildmaster quest is active... ;sets a journal and raises the player's rank ;when trebonius dies. short doOnce short nolore if ( doOnce == 1 ) Return endif if ( GetJournalIndex MG_Guildmaster < 50 ) Return endif if ( GetPCCell "Vivec, Arena" == 0 ) Return endif if ( duelActive == 0 ) Return endif if ( OnDeath == 1 ) Set DuelActive to 0 Set doOnce to 1 PCRaiseRank "Mages Guild" PCRaiseRank "Mages Guild" Journal MG_Guildmaster 100 endif End
77
Clears "currently expelled" flag on the player. Example script: A script by Bethesda, which clears the Players expelled status after some time:
Begin expelledMG ;this is just a model ;it is supposed to be on an item in each of the Mages Guilds. short myDay short temp if ( PCExpelled "Mages Guild" == 0 ) return endif if ( ExpMagesGuild == 0 ) Set ExpMagesGuild to 1 endif if ( myDay == 0 ) Set myDay to Day endif if ( myDay == Day ) return endif if ( Day > myDay ) Set temp to ( Day - myDay ) else Set temp to ( myDay - Day ) endif Set myDay to Day Set temp to ( temp + 2 ) Set ExpMagesGuild to ( ExpMagesGuild + temp ) if ( ExpMagesGuild > 30 ) Set ExpMagesGuild to 0 PCClearExpelled "Mages Guild" return endif End
[no fix] ModPCFacRep, var_enum, ["FactionID"] [no fix] SetPCFacRep, var_enum, ["FactionID"]
ModPCFacRep, 5, "Imperial Legion" ModPCFacRep, 5, "Temple"
Modifies or defines the reaction modifier for members of the specified faction (towards the PC).
ModFactionReaction, "factionID1", "factionID2", var_enum SetFactionReaction, "factionID1", "factionID2", var_enum
Modifies or defines the reaction of one faction towards members of another faction. 78
Example: This is part of the MoonAndStar script. This part first makes the PC part of the faction "Nerevarine" and then sets two factions to react particularly to this change:
;faction reaction and journal stuff Journal "A2_6_Incarnate" 50 player->modReputation 5 PCJoinFaction, Nerevarine if ( GetPCRank, Redoran >= 0 ) modFactionReaction, "Redoran", "Nerevarine", 4 endif if ( GetPCRank, Temple >= 0 ) modFactionReaction, "Temple", "Nerevarine", 4 endif
probably referes to base disposition (as set in the TES CS, unaltered by any modifiers)
Werewolf-specific functions
Set the werewolf attributes
SetWerewolfAcrobatics
Actor -> SetWerewolfAcrobatics
This function set the attributes of the object to those of a werewolf. This sets the targets skills and attributes to match the fWerewolfxxxx gameplay settings. In most cases, this means a high strength, agility, acrobatics etc, and 0 in most other things.
Player -> AddSpell "werewolf vision" Player -> AddSpell "werewolf regeneration" Player -> SetWereWolfAcrobatics
These two functions are very simple they change the color of Secunda (The small, white moon) from white to red and back again. This doesnt have any real effect to gameplay, but it does make the sky look different. It is used during the Bloodmoon main quest hence the expansion title.
if ( doOnce == 0 ) TurnMoonRed set doOnce to 1 endif
79
This keeps count of how many NPCs killed by the werewolf. Each time an NPC is killed while the PC is a werewolf, one is added to this count. It is reset automatically when the PC changes back into human form.
if ( GetWerewolfKills > 0 ) ; Do code to stop the PC from being affected by the hunger. endif
This function allows to determines if the target is a werewolf or not. It can be used on the PC or other creatures.
if ( Player->IsWerewolf != 1 ) ;DON'T RUN IF PLAYER ISN'T WEREWOLF return endif
Change to a werewolf
BecomeWerewolf UndoWerewolf
Actor->BecomeWerewolf Actor->UndoWerewolf
These functions change the target object to a Werewolf or change them back to their original form. IMPORTANT: Using Becomewerewolf and Undowerewolf CAN break your game. Some quests and variables depend solely on on use of these, so if you use one to toy around.... you may be asking for it. (This message brought to you by your friendly dev WormGod).
if ( OnPCEquip == 1 ) Player->BecomeWereWolf Set OnPCEquip to 0 Endif Set timer to ( timer + GetSecondsPassed ) If ( timer > 10 ) Player->UndoWereWolf Endif
80
A multiplier for claw damage. Exact formula unclear, see werewolf scripts for reference.
81
by loading several mods that change the same topic. The game doesn't know for sure any more which entry comes after which. This sometimes doesnt matter, but it can also mean that certain responses are cut off, because the order isnt right any more this depends on the conditions). These entries come with conditions that you can set in the dialogue editor window. In the topic window you will find a list of general conditions on the left here you can define which Actor (Actor ID) or group of Actors (Race, Class, Disposition, etc.) potentially know this response. There are also two conditions for the PC (PC faction and rank). To the right you can set a maximum of 6 "free" conditions that can refer to the Actor, the PC or other things like the state of global variables lots of options here, you will have to see for yourself. Check for journal entries, player stats, local or global variables, items in inventory, and many other functions, some equivalent to script functions, some unique to dialogue (see below). An important and initially confusing feature of the dialogue editor is the filter option (lower left-hand corner). When you select an Actor ID here, you only see the topics that this Actor can possibly know (as described above). Remember that when you create a new topic (maybe specifically for that NPC) it contains no responses. Thus the Actor cannot "know" it and thus the freshly created topic does not appear! Select the empty slot on the very top to see all topics again, make a response for the new topic that your Actor can "know" then you can turn the filter on again, if you wish.
Special rule for Journal: there is only one condition here, the index (called by Journal function). It must be exactly met. Once a response has been selected, the game will Output the text string to the dialogue window (or play the mp3 for Voice responses) Execute any Script commands in the Results field (At the very bottom). You can use all scripting functions here. Conditions (if command) can also be used (Thanks to Kir and Manauser for this info). Be aware that the result field allows you to exchange information with scripts (e.g. by setting variables or adding journal entries) and that scripts can vice versa influence dialogue as well, by setting conditions that can be tested (e.g. you can check for local or global variables in the speaker conditions of dialogue). The simplest script that influences dialogue is the nolore script, which is just used as a flag to keep Actors from using standard dialogue. Note: Result field scripts are not compiled by CS. You may write any rubbish there and MW will not complain until the line is told by an NPC and its script is compiled on-the-fly. If the script is complex enough to worry about possible syntax errors, it is recommended to copy/paste it's text into a regular dummy script and try to save it. That is more reliable than using the "Error Test Results" button, as it can change preset values of global variables. On the other hand, the fact that action box scripts are compiled at runtime may allow some interesting effects, like addressing contents of another mod without duplicating it in the current mod, which can't be done with conventional scripts (Forum info / Kir).
Dialogue 101
The following summarizes some of the the most frequent problems with dialogue. This list was assembled from a forum discussion with contributions by Klinn, Emma and GarryB. Tip 1) My new topics disappear! Go to the Filter box at the bottom of the list of topics. Clear the filter by choosing the top empty line in the drop-down list. Recommend using the button on main toolbar to bring up the dialogue editor rather than from the NPC's properties.
84
Tip 2) My NPC keeps asking me a question over and over! Be sure to put the replies above the original question. Sounds backwards, but it works. Tip 3) My NPC talks about everything! To keep an NPC from having the standard topics about Morrowind lore, attach the script "NoLore" to him or her. If you already have a script on the NPC, add the declaration Short NoLore near the top. Tip 4) My NPC still has extra topics! Some other general topics may appear depending on an NPC's faction or class. For example, members of the Imperial Legion will always automatically have topics about that faction, the Empire, and more. Tip 5) How do I add topics for just my NPC? After creating the topic and it's Info/Responses, in the Speaker Conditions area, set the ID to your NPC. Tip 6) I added topics but my NPC doesn't have them! Two possibilities: the NPC must have already heard (read) that topic word or phrase before he can ask about it. Usually this is done by having the an NPC's greeting include the topic. Second posibility: there may be Speaker Conditions that prevent the topic from appearing. Even if it appears when you filter the dialogue for an NPC, some topics depend on the player having reached a certain point in the game, having a specific journal entry, and so on. Tip 7) How do I change the order of my Responses? Use the left-arrow and right-arrow keys to move an Info/Response up or down in the list Tip 8) How do I creat dialogue for creatures? Any creature can have its specific dialog. You do this exactly as you create the dialog for an npc, with one difference. You have to have the dialog UNFILTERED when making the dialog (i.e. the slot below the topics must be empty). Once you have created the dialog lines, you can filter them for your creature. Tip 9) What are typical uses for the dialogue result box? Emma lists these useful and frequently used commands for the result box: Player->AddItem "my item" 1 (a specific item is added to players inventory) Player->RemoveItem "my item" 1 (a specific item is removed from players inventory) ModDisposition 5 (npc will like player 5 points better) cast "my_new_spell" player (the npc will cast a certain spell) AiFollow Player 0 0 0 0 0 (npc will start follow player) AiWander 0 0 0 0 0 0 0 0 0 0 0 0 (npc will quit following the player) SetFight 100 (npc will start attacking the player) StartCombat->player (npc will start attacking the player) StopCombat (yep, you've guessed it. Stop combat) StartScript "my_global_script" (start a certain script) Set companion to 1 (if you have added a "short companion" command to your script, this will make the npc share with you; requires Tribunal) SetHealth 100 (will set the npc's health to 100 - same command can be used for setting other skills and attributes as well, i.e. SetMagicka, SetLongBlade etc.) disable (will make the npc instantly disappear) goodbye (will force the player to end the conversation. Can be useful for in stance in order to avoid further smalltalk with a npc that has already been disabled )
85
Tip 10) I have created so much dialogue, how can I possibly spell-check it? Checking spelling and grammar can be streamlined by using the export and import functions in the Construction Set. Export "new" dialogue to a file, use your favorite editor for automatic spellchecking and corrections and import the corrected dialogue . Much easier on the brain than jumping around in a myriad of topics, greetings and journal entries. (Forum info / GarryB)
Dialogue-related functions
Many of the following functions are not only used in scripts, but also in the result field of the dialogue editor window.
Displaying messages
[no fix] MessageBox, Message, [var1], [var2], [button1], [button2]
The MessageBox command lets you give out information to the player. Normally these appear as a small box with the text on the bottom of the screen that stays there for a few seconds or until the player has clicked a button if the message box has buttons. There is a limit of 9 buttons per message box. If a dialogue window is open, MessageBox will output to the dialogue window! This will be in a different color so it's a good way to show that text isn't part of dialog. For example, "Okay I'll take the curse off. He takes the curse off." MessageBox has several different modes of operation. The simplest one is just giving out an onscreen message that appears on the bottom of the screen for a few seconds, as in the following script that gives out a message when the item its attached to is equipped:
Begin informplayer Short OnPCEquip if ( MenuMode == 1 ) return endif if (OnPCEquip ==1 ) MessageBox, The sword vibrates in your hand Set OnPCEquip to 0 Endif End informplayer
The second mode of operation makes the message stay on the screen until the player presses a button:
MessageBox, Ulyah lifts her hands and speaks the formula. You will now be transported to Sheogorad, ok
In the third mode of operation you can use the messagebox to demand a decision from the player via a message box with buttons and the GetButtonPressed function:
[no fix] GetButtonPressed (returns short)
Pressed button if a message box with buttons is used, starting at 0. Will return 1 until button is pressed. Sample Script:
Begin choices Short button Short status Short OnPCEquip ;declare as variable otherwise there will be errors
86
if ( OnPCEquip ==1 ) MessageBox, The sword vibrates in your hand. Do you want to equip it?, yes, no Set OnPCEquip to 0 ;display the Message Box only once Set status to 1 Endif If ( status == 1); wait for player decision Set button to GetButtonPressed If ( button == -1 ); no button selected yet: do nothing return Elseif ( button == 0 ); continue normally Set status to 0 ; reset for next time Elseif ( button == 1 ) Player -> drop, "power_sword" ; makes the player drop the item Set status to 0 Endif Endif End
Note: If you use a Tribunal start script to give out a message box with a button as soon as the game is loaded, you should delay the MessageBox by one frame, otherwise the mouse pointer will not be displayed (Forum info / DinkumThinkum). You can enter carriage returns to message boxes, but it requires hex-editing the .esp. Put some unusual characters like ||, then save the esp. Then hex edit the || chracters and make them 0D0A (hex for carriagee return).(Forum info / qarl)
The % symbol indicates the variable. The number after the dot determines the number of digits displayed. "f" signifies a float variable. The helpfile lists several types (f for float, D for short or long and S for string variables), of these I could only get f to work. However %g and %G work fine for short and long variables (thanks Niyt Owl). You can use things like %.3g, but the digit designation will simply be ignored. The designators are not really specific to the variable type, %.3f will also display a short or long variable. String variables are mentioned in the helpfile but are to my knowledge not implemented, you can however use dialogue text defines in message boxes but do NOT use %: for text defines In scripts its ^instead (thanks Ragnar_GD): Text defines:
^PCName ^PCClass ^PCRace ^PCRank ^NextPCRank The The The The The player's player's player's player's player's name. class. race. rank in the speaker's faction. next rank in the speaker's faction.
The cell the player is currently in. Any global variable value. Floats display as 1.1, such as
Note: you can also display a Global variable normally, using the above syntax such as %.1f, which would yield the same result. If you use the ^Global text define in a book, Morrowind will usually crash if you access or change the global variable while the book is open. This should be avoided at all costs! (Forum Info/Chris_K)
^Name The speaker's name.
87
The speaker's race. The speaker's class. The speaker's faction. If they have no faction, it will be The speaker's rank.
Note: These last listed ones will not work quite as they do in dialogue, as the defines default to the PC's values by default, not to the calling Actor. So ^Name and ^PCName will both display the PC's name. Example Script: Stupid sample script demonstrating all possible syntax:
Begin test1 short var_1 long var_2 float var_3 ; GameHour is a global float variable set var_1 to 1 set var_2 to 2 set var_3 to 3 MessageBox "^PCName, you have %g head, %G hands, and %.5f gold. One could say the hour is getting late in ^cell. It's the ^GameHour hour or more exactly the %.2f hour!", var_1, var_2, var_3, GameHour End
Once you have set up a dialogue topic in the TESCS, you may find that you still cant talk about it with the NPC you have given the dialogue to, because for the game you don't know that particular topic yet. There are two ways to change that condition: either you introduce the topic in another conversation topic (e.g. a custom greeting) or you give it to the player via script, which makes sense when its an obvious topic the player would ask about without being brought to it by conversation (e.g. if you see and NPC standing under a waterfall, you might want to ask him about "aren't you getting wet?" even if the NPC doesnt bring up the topic. To do that, just attach a small script to the NPC:
Begin AddSpecialDialogue ;add possibility to ask about travel AddTopic, "aren't you getting wet?" End AddSpecialDialogue
Note: You must already have the topic with this topic ID set up before you make this script, otherwise the script compiler will complain. You can not remove a topic via script, you can however set a condition that refers to a local variable of the script as a speaker condition in the Dialogue editor, which can be used to achieve the same effect. AddTopic adds the topic to the players "known topics" list. So using "Actor_ID"->AddTopic "blabla" is wrong.
88
ForceGreeting can be used to make Actors initiate dialogue. When ForceGreeting is called the dialogue window will open, and the Actor will use a greeting according to his dialogue settings. Therefore, if you want a special greeting by the Actor, you have to provide it via the dialogue window in the TES CS. It does not matter where the NPC is, this function will always work, so its usually best used in connection with a GetDistance or GetPCCell condition Example Script: this script shows a nice set of condition being checked before initiating the ForceGreeting command
Begin balynScript float timer short doOnce if ( GetJournalIndex "DA_Mephala" < 40 ) Return endif if ( GetJournalIndex DA_Mephala >= 60 ) Return endif Set timer to ( timer + GetSecondsPassed ) if ( timer < 5 ) Return endif Set timer to 0 if ( doOnce == 0 ) if ( GetDistance Player <= 1024 ) if ( player->GetDistance "hlaalu_loaddoor_ 02_balyn" <=256 ) if ( GetLOS Player == 1 ) ForceGreeting Journal DA_Mephala 55 set doOnce to -1 endif endif endif endif End
Goodbye forces the end of dialogue. After calling this function (usually this function is used in the result section of a dialogue topic, not in scripts) the PC can only choose the goodbye option and thus closes the dialogue window.
This variable allows to use ForceGreeting on a werewolf character. Used on cariushuntscript, dulkscript, heartfanghuntscript. Apparently, the variable simply has to be declared, not set to a specific value. Example:
Begin dulkScript
89
short doOnce short playerwolf short AllowWerewolfForceGreeting if ( GetJournalIndex BM_FrostGiant2 == 10 ) if ( doOnce == 0 ) if ( GetDistance Player <= 512 ) if ( Player->IsWerewolf == 1 ) ForceGreeting set doOnce to 1 endif endif endif elseif ( GetJournalIndex BM_FrostGiant2 == 70 ) if ( doOnce == 1 ) if ( GetDistance Player <= 512 ) ;if ( Player->IsWerewolf == 1 ) ForceGreeting set doOnce to 2 ;endif endif endif endif End dulkScript
(Dialogue only!) This is used in dialogue result fields to ask a decision of the player or can be called just to "continue" a longer speech. After the PC makes his choice, the same topic will be checked again, and you can provide the correct response by using function / choice / = / choice_enum in the speaker conditions of the dialogue window. Not meant for scripts as far as I know. Some more info from Riiak: Unlike messageBox this one can be stacked. By this I mean you could have 2 choice calls in the same result box for a max of 10 choices or 3 Choice calls for a max of 15 choices etc... I don't know the stack limit for this, but I'm pretty sure there is one. (I think it's limited to 5 choices per call).
This adds a journal entry to your in-game journal, the journal entry must have previously been set up in the dialogue editor. Index references which part of a journal topic is added. Beware of using simple names for journal topics, adhere to Bethsofts two letter standard (see above example) otherwise the journal entry might show up as a regular conversation response, just like any other, if the topic title shows up in a conversation! (According to forum info / Melian)
Setjournalindex will set the index to the specified value, no matter if a journal entry exists for this value or not (useful for simple flags that don't need an own journal-entry).
90
Note: When you reload, the index will be reset to the highest value of the existing entries that are already in the journal. Therefore this can also be used to detecte if the player has reloaded the game:
if ( ( getjournalindex "dummy" ) != 100 ) Messagebox "You just reloaded, Cheater!!!" setjournalindex "dummy" 100 endif
"Dummy" is any journal-topic that has no text for index 100. Setjournalindex will set the index to the new value, no matter if an entry exists for this value or not (useful for simple flags that don't need an own journal-entry) but when you reload, the index will be reset to the highest value of the existing entries that are already in the journal. The best thing is that it's most easy to use this in dialogue: Send the player to the "test of courage", and set the journalindex in dialogue-result. When the player comes back, and the index differs, then the player has failed the test. (info on this function provided by JOG).
[no fix] ClearInfoActor
This is a function that is used in the results section of a dialogue topic using this function will stop the topic from appearing in the PC's journal (under "Topics"). Useful to avoid cluttering the topic section with useless information.
[no fix] GetJournalIndex, "JournalID"
If ( GetJournalIndex, MG_BCShroomsCombat == 10 )
(returns short)
This function returns the index of the highest (or the last?) journal entry for that journal topic that the player has received. This is very convenient for keeping track of quest advancement, and to have a script react according to what parts of the quest have already been performed. Sample Script: Here is a short script demonstrating the use of both functions from the game:
Begin attack_slave short nolore If ( GetDeadCount "Vorar Helas" > 0 ) return endif if ( GetJournalIndex "MV_SlaveMule" < 102 ); if PC has not yet reached a certain point If ( GetDistance, "Rabinna" < 512 ) Rabinna->AiWander 0 0 0 0 0 0 0 StartCombat, "Rabinna" Journal "MV_SlaveMule", 102 ; add journal entry endif endif End
91
This is 0 if the player is male and 1 if the player is female. Note: This is the only know way to determine e.g. the players sex - you could use this to set a globl variable that contains the Player gender - the most inconspicuous way would be to do this via voice dialogue, e.g. one could put a silent hello greeting for all NPC's on top of the list that sets a global variable "PC_sex" to 1 when the player is female, 2 when the player is male. The topic should be filtered to only be active when PC_sex equals 0. This is 1 if the speaker has ever talked to the player and 0 otherwise. You can use this to have someone say something the first time you speak with them or for our scripting purposes to mark this person as "known" by the player. It seems that Talked to PC will reset to 0 if the player has spent 72 game hours out of the NPC's cell. This time limit also applies to other NPC-related functions such as "forceGreeting": the NPC is available for a forceGreeting reference from a different cell only for 72 game hours. As a workaround, if you use PositionCell on the NPC once per day (even without changing their location), the 72 hour time limit no longer applies (Forum info /Time limit info from Cortex, thanks to Srikandi for bringing it to my attention). This trick to get around Actors breaking their connection to you after 72 hours seems to require the cell you send them to to not be the cell where you initially met them (Forum info / Cortex). This either implies it must not be their editor starting cell or that it must be a cell that you have not visited. In my fix I have an interior I send them to for this purpose so either explanation could be why it works. So basically after you have met them they get sent there each day even though they are already there after the first sending. This checks to see if you "qualify" for the next rank in the speaker's faction. This returns 0 if you do not have enough Faction Reputation and do not meet the skill requirements. This returns 1 if you meet the skill requirements, but do not have the Faction Reputation. This returns 2 if you have the Faction Reputation, but do not meet the skill requirements. This returns 3 if you qualify. This is the total value of all the clothing and armor the player is wearing. The value of your equipment changes the disposition of people in the game. Used in dialogue for when you attack a member of your group (like a follower) The return values are: 0 = never been hit 1 = hit by pc 1st time 2 = hit by pc 2nd time 3 = hit by pc 3rd time 4 = hit by pc 4th time and the npc/creature is not in combat with the PC
Friend Hit (dialogue) PC Clothing Modifier (dialog) Rank Requirement (dialog) Talked to PC (dialog)
(which defaults to 30) is multiplied by the game setting, iGreetDistanceMultiplier, which defaults to 7. Thus, a setting of 30 yields a hello distance of 210 (just under 10 feet).
This is true if the speaker does not have this local variable. Unlike most "Not" functions, this one does care what you set the variable to. Both the dialogue and the variable itself should be set to 0. This can be confusing. Here is a table of how this works: Not Local (in dialogue) =0 =0 =0 =1 = -3 Variable Exists (y/n) No Yes Yes No Yes Value (in the script) NA 0 5 NA -3 Pass? (speaker will say this) Yes No Yes Yes No
93
Set floatvar to ( Player -> GetHealth ) Player -> SetWillpower, 20 Player -> ModHealth, floatvar
This is really a whole family of functions that can alter player and Actor stats, AI settings and more. Replace Stat with any of the game stats, attributes, AI-settings, resistances, reputation, etc. (list see Appendix). positive values are added to current stat, negative values subtracted GetStat returns a float value with the current value of Stat (Not the maximum or base "natural" value of that stat for the player, but what is currently used by the game, e.g. it could be boosted by magic or reduced by disease). SetStat sets the stat's base and current value to the given value. ModStat adds (positive values are added to current stat, negative values subtracted) the given value to both the base and current value of Stat. ModStat can not set an attribute beyond its natural limit (100) while SetStat can. Presumably the behavior is equivalent for other Stat's Note: This is not true of some of the more unusual stats like resistances, which can be negative (weakness) and aren't limited to 100 either. There are so many things you can do with this set of functions that it is not very useful to provide a sample script. Take a look at the Marksman Toggle script in the Tips and Tricks section for a good example. The script given under "Resurrecting a dead Actor" below also uses ModHealth, as do many others. These commands have a wealth of applications. They could be used for special items, curses, blessings, to gain information on the players strengths and weaknesses, and to change AI settings (making an Actor more aggressive after player has insulted him, making an NPC uncommunicative at night etc.). Another popular use is to change armor or weaon stats to make NPC's switch their equipment. In the 8th edition of this guide many of these functions have been sorted into the appropriate chapters (e.g. magic, combat, etc. )
94
These return, change or set the vital functions of the PC. For NPC and the player the Get functions will report the current health/magicka/fatigue. GetHealth also works on weapons / armor, but only returns the maximum health. No function is known that reports current item health (forum info, Mana User). Special use with ModStat only:
While ModHealth changes both the maximum and the current health of an Actor for the same amount (e.g. even a healthy Actor would be affected), ModCurrentHealth affects only the current health and can not set health above the original maximum health value for that Actor (so doing ModCurrentHealth, 10000 to an Actor with 70 Health and a current health of 35 would set Health to 70 Doing ModHealth, 10000 would set him to 10035 health).
GetHealthGetRatio (returns float)
This function returns the health ratio of the Actor as a float value from 0 to 1, e.g. 1 means 100% health, 0.9 means 90% health and 0 means, well, dead I guess. This replaces the erroneously listed function GetHealthRatio listed in the original helpfile. If you want to know an Actors maximum health (Remember, GetHealth returns your current health points) you can use this:
Float MaxHealth Float CurrentHealth Set CurrentHealth to "Actor ID"->GetHealth Set MaxHealth to (CurrentHealth / "Actor ID" -> GetHealthGetRatio)
a skill, its not just 0-100 as you might expect. In fact skills appear to be stored as a float so you can set some large numbers in there, but there are some checks: you can't set negative values, and decimal points are discarded when saving/loading (Thanks FreshFish).
Get/Mod/SetBlock Get/Mod/SetArmorer Get/Mod/SetMediumArmor Get/Mod/SetHeavyArmor Get/Mod/SetBluntWeapon Get/Mod/SetLongBlade Get/Mod/SetAxe Get/Mod/SetSpear Get/Mod/SetAthletics Get/Mod/SetEnchant Get/Mod/SetDestruction Get/Mod/SetAlteration Get/Mod/SetIllusion Get/Mod/SetConjuration Get/Mod/SetMysticism Get/Mod/SetRestoration Get/Mod/SetAlchemy Get/Mod/SetUnarmored Get/Mod/SetSecurity Get/Mod/SetSneak Get/Mod/SetAcrobatics Get/Mod/SetLightArmor Get/Mod/SetShortBlade Get/Mod/SetMarksman Get/Mod/SetMercantile Get/Mod/SetSpeechcraft Get/Mod/SetHandToHand
96
Combat
Initiating and ending combat
StartCombat, "ActorID" StopCombat
"Actor_ID1" -> StartCombat, "ActorID2" "Actor_ID1" -> StopCombat
StartCombat and StopCombat are used to set an Actor into combat mode or back into normal mode. Start combat will make the calling Actor attack the Actor supplied as the argument. While StopCombat seems to be "safe" to use "every frame", you should supply a do once condition of some sort when issuing the StartCombat command, otherwise the Actor might not do anything. Nevertheless continuous StopCombat is very dangerous to use, because it makes the NPC completely helpless: it will not retaliate when attacked (which however allows you to create a real pacifist). Once in combat mode the AI settings of the Actor apply normally, e.g. if the Actor has a high flee setting, he will flee despite the StartCombat command. For this reason, you will often see that the Fight rating is also changed when initiating combat in many scripts:
If ( GetDeadCount, "My Friend" > 0 ) StartCombat, Player SetFight, 100 endif
Detecting Attack
[no fix] OnPCHitMe
Short OnPCHitMe If ( OnPCHitme == 1 )
A local game variable (not a function, you must declare it as a variable as shown above) that gets set to 1 when the player hits the calling Actor. Must be manually reset. It seems the use of the variable "short-circuits" normal NPC behavior in that an NPC with a script that uses this variable will not attack on its own accord. If you dont want the Actor to remain passive you have to manually StartCombat (see example below). Once the Actor is in combat mode, OnPCHitMe does not report any further hits by the PC. Except, according to information on the forum, OnPCHitMe gets reset (to 0) if another Actor hits the calling Actor after the PC did, then the variable gets reset to 1 if the player hits again. Note: According to info provided by Nigedo, OnPCHitMe also registers if the NPC commits a crime, and the Actor has a sufficiently high alarm setting. ExampleScript:An example from my traveling merchants mod, to make a guar handler defend his charge while not in AIFollow mode, I attached this to the guar:
Begin _HB_Adros_GuarDefend float timer short attackstate short OnPCHitMe if ( OnPCHitMe == 1 ) set attackstate to 1 set OnPCHitMe to 0 endif if (attackstate == 1)
97
StartCombat, player set timer to ( timer + GetSecondsPassed) if ( timer >= 1 ) set timer to 0 if ( GetLOS, HB_adros_darani == 1) HB_adros_darani -> StartCombat, Player set attackstate to 0 endif endif endif End
GetAttacked
(returns Boolean/short)
Returns 0 if the Actor has never been attacked and 1 if he has ever been attacked. Example script: Uupse protects Yagrum Bagarn:
Begin uupse_Bagrum short doOnce if ( doOnce == 0 ) if ( "yagrum bagarn"->GetAttacked == 1 ) StartCombat player SetFight 90 SetDisposition 0 set doOnce to 1 endif endif end uupse_Bagrum
(returns Boolean/short)
Returns 1 if objects combat target is ActorID (otherwise 0). This can be used to determine if an Actor is in combat with the player (or another unique Actor). Example Script: this shows how an Actor can be programmed to "not fight against the law". This is from the "frelene acques script" she is a Redoran follower and will not help the Player to fight Redoran guards.
[] if ( GetCurrentAiPackage == 3 ) ;if follow is the current package, set followNow and continue... set followNow to 1 SetHello 0 if ( GetTarget "ordinator wander_hp" == 1 ) StopCombat endif if ( GetPCCell "Vivec, Hlaalu Prison Cells" == 0 ) ;if follow is done, NPC has arrived... Journal HR_Stronghold 144 set followNow to 0 AiWander 256 0 0 40 20 20 0 0 0 0 0 0 ForceGreeting SetHello 30 endif []
98
These functions return true (1) for 1 frame if the calling Actor is successfully hit or if it was attempted to hit it with a specified weapon. HitOnMe is used only in the LorkhanHeart script (only look at that if you have finished the game or don't mind severe spoilers). I guess it could be a nice function to script any kind of fight of the "you need this special weapon to kill this particular monster" type.
Some info from the helpfile: An Actors fight setting determines how prone the Actor is to attacking the PC. Mod/Set Fight appear to also affect all new references of the actor you may add after calling this function. When an Actors fight setting hits 100, they will attack the PC. Player actions will increase (or decrease) an Actors fight setting. These are: PC Action PC Distance Attack Actor Disposition Stealing Pick Pocketing Trespassing Taunting Intimidation Bribery Default Value Game Setting Formula 20 - (Char Distance * 0.005) iFightDistanceBase - (Char Distance * fFightDistMult) 100 iFightAttack ( 50 - Disposition )*1 (50 - Disposition) * fFightDispMult 5 * Item Value fAlarmStealing * Item Value 25 iAlarmPickPocket 25 iAlarmTresspass From Persuasion Formula From Persuasion Formula From Persuasion Formula
The following table gives you the resulting general behavior: 100 Always Attacks 95 Will Attack as PC gets close (3000 units) 90 Will Attack as PC gets close (2000 units) 80 Will Attack as PC gets close or if he dislikes you (1000 units, 40 Disp) 70 Will Attack if close and strong dislike (1000 units, 35 disp) 60 Will Attack if he dislikes you and you get close (Disp below 30) 50 Will Attack if he hates you (Disp at 0) 40 Will attack if he dislikes you, and you get close. (500 Units, Disp 10) 30 Will Attack if hates you and you commit crime. 20 Will Attack if dislikes you and multiple crimes. 10 Will attack if he hates you and you do multiple crimes on him. 0 Will ONLY attack if attacked first.
Changing this changes it for ALL references of the Actor (see note). Setting this to a higher value will make the Actor more likely to flee, but this may not always be the result, as the Actor will also use other fActors like how much damage they can give out, or other strategies they may use such as magic and ranged combat. The behavior is strongly influenced by a number of GameSettings that are listed below, and a number of mods 99
Get/Mod/SetFlee
(e.g. by wakim and maxpublic) have tweaked these values to allow for more realistic fleeing behavior. Changing this changes it for ALL references of the Actor (see note). Some info from the helpfile: When a crime is committed, and it is detected by an NPC, they will shout something at the player, this also notifies other NPCs in the area. When the NPCs hear this, they adjust their settings based on their alarm setting. The higher the alarm setting, the angrier they will get. If an NPC has an alarm of 100, he will put gold on the PCs head if they hear of a crime. If the NPC with alarm 100 is also of class Guard, they will have extra behavior: Intercept the PC, by running up and arresting the PC. If the PCs CrimeLevel is over 10000, they will attack on site, instead of initiating dialogue. Guards will also attack any creatures they can see that are attacking people (including the PC). Note: When you use these functions to alter the settings for an actor, it alters the current reference of the actor AND the definition of the actor. What this means is if you encounter a new actor of that id that you haven't yet met, he will have the new alarm/Fight setting. Also, if you leave the cell where an actor still has the old value, rest for 3 days (to disconnect them from memory) then reenter the cell, he will take his value from the definition of the actor i.e. the new alarm setting (Forum info / Cortex).
Get/Mod/SetAlarm
Returns 1 for 1 frame when the Actor is killed. On death seems to reset itself once it is used. This also means that only one script can reliably detect death this way, if you have both a global and a local script using this function, only the global script will detect OnDeath. An alternative would be to use the GetHealth function. In the following script only the first message box will be displayed (forum info Argent/ThePal):
begin personScript if ( OnDeath ) messagebox "1" endif if ( OnDeath ) messagebox "2" endif end
OnMurder
(returns Boolean/short)
Returns 1 for 1 frame when the Actor is murdered. The conditions for OnMurder are not entirely clear to me from the context of its use in the game however, it seems that OnMurder gets set when you are reported as a murderer to the law ("your crime has been reported"). So a murder only happens when you kill someone illegally AND are seen.
100
Sample Script: this sets a variable that is used in the "Redoran Hortator" dialogue topic to determine if the player has killed a councilor:
begin RedoranCouncilor ;no lore... short noLore ;for HT_Monopoly short mageMonopolyVote ;for Hortator dialogue... if ( OnDeath == 1 ) if ( OnMurder == 1 ) Set RedoranMurdered to 2 else Set RedoranMurdered to 1 endif endif End
OnKnockout
(returns Boolean/short)
Returns true for one frame when the Actor is knocked unconscious (e.g. in hand-to-hand combat)
[no fix] GetDeadCount, "Actor ID"
If ( GetDeadCount "divayth fyr" > 0)
(returns short)
The function returns the number of references (individuals) of type "Actor ID" that have been killed. A useful function for quest scripting to keep track of which NPCs are still alive. Note that there is an equivalent function for dialogue as well. Other uses are imaginable, e.g. building a reputation with certain monsters that might flee you instead of fighting after you killed more than 100 of them, etc. Sample Script: GetDeadCount is often used to check if a certain NPC is dead. It is advisable to use "> 0" in such cases, as you never know if another mod might add another instance of that ID, so it's better to play it safe.
Begin araraUvulasScript short noLore if ( CellChanged == 0 ) return endif if ( GetDeadCount "Neloth" > 0 ) Disable endif End
This function brings an Actor back to life. His stats and inventory will be reset, basically he "respawns". There is a bug when you use this function on the player it will stop the PC (and all Actors) from casting magic. After saving and reloading this side effect goes away. 101
Note: The Puzzle Canal Script shows an alternative: it simply uses GetHealth <10 to determine when player is "nearly" dead and then "resurrects" him by giving him his health back so the player actually never really dies. Sample Script: some people are just tougher than others
Begin dandrasScript short deathbed float dandrasHealth if ( deathbed == -1 ) return endif set dandrasHealth to GetHealth if ( dandrasHealth <= 50 ) if ( dandrasHealth < 1 ) Resurrect ModHealth 100 endif set deathbed to 1 endif if ( deathbed == 1 ) ForceGreeting endif
End dandrasScript
102
Crime
Determining and changing Crime Level
PCCrimeLevel governs the gold you have to pay to be cleaned of crimes, influences NPC disposiotion and how guards react to you. See also the PayFine function.
Get/Mod/SetPCCrimeLevel (PC Only)
Jailing the PC
[no fix?] GotoJail
Sends the PC to the (closest available) prison, more exactly speaking to a PrisonMarker (Door object) and applies the usual prison penalties. SampleScript: Here is a cool little scripted item by B from the Modern Adventurer mod. The cursed Holiday Pants that send you to prison:
Begin Holiday_script Short OnPCEquip Short message if ( OnPCEquip == 1 ) if ( MenuMode==1 ) return else Set message to Random 2 if ( message==0 ) MessageBox "The holiday pants contain a mighty enchantment of happiness. Lots of happiness. When the guards found you doing the Can-Can on top of the nearest silt strider port, they were not very amused.", "ok" elseif ( message==1 ) MessageBox "The holiday pants make you scream and shout with joy as you relive the happiest days of your childhood. The guard that brings you back to your senses is in stark contrast to this experience", "ok" endif Player -> GoToJail endif Set OnPCEquip to 0 endif End holiday_script
The PayFine function removes the stolen items from the PCs inventory; it does not remove any gold. Call after paying a crime fee to clean AI. Also puts the PCs hands down (that is not ready to cast or fight).
[no fix] PayFineThief
Like PayFine function but does not remove stolen items from the PCs inventory. Call to "clean AI". May have incorrectly removed stolen items before one of the patchs. For examples check below, under "Useful global variables"
Detecting crime
[no fix] GetPCCrimeLevel (returns short)
103
Reports the current crime level of the PC. Can be used to detect whether a crime the PC has committed has been seen. See the "Bill_MT_writxxxxx" scripts for examples of its use. An alternative was reported by Nigedo:
OnPCHitMe
If you declare OnPCHitMe in an NPC's script, any crime that they are aware of causes this function/variable to return True. The crime does not actually have to be committed against that NPC, they just have to have a high enough Alarm setting, to care about a crime being committed within range, and the crime will count as a melee hit on them of zero damage. Although this makes OnPCHitMe less reliable for detecting just attacks on the NPC it is declared on (I had to use a different method for the script I was actually working on ), it is potentially useful for detecting crimes taking place. It is possible to use this to detect all crime events in one script, without needing an NPC to "report" them, i.e. increase Player's bounty, or needing to check or adjust PCCrimeLevel. I found that the following alarm settings will (usually) cause OnPCHitMe to return True for the these events:Event Any theft Assault of an NPC Murder of an NPC Minimum Alarm 10 90 10
(returns Boolean/short)
Bloodmoon adds a functions that can be checked to see if the PC is in Jail. The function will return 1 if traveling/in jail, zero otherwise.This is used in the werewolf change script to stop the PC from changing if either of these states are the case. Sample script:
if ( PCWerewolf != 1 ) ; DON RUN IF PLAYER ISNT WEREWOLF return endif if ( GetPCinJail == 1 ) return endif if ( GetPCTraveling == 1 ) return endif
Contains the amount of gold needed to pay the reduced fine at the thieves guild.
CrimeGoldTurnIn
Contains the reduced fee you have to pay when you turn yourself in. 104
PCHasCrimeGold
Used in dialogue conditions. Gets set to 1 if player has enough gold to pay for his crimes. Used in dialogue conditions. Gets set to 1 if player has enough gold to pay thieves guild discount on the "price on your head". Used in dialogue conditions. Gets set to 1 if player has enough gold to the reduced crime fee that is charged when turning yourself in. Example: A dialogue result field for the topic "price on your head", for paying a fine at the thieves guild:
Player->RemoveItem Gold_001 CrimeGoldDiscount SetPCCrimeLevel 0 PayFineThief
PCHasGoldTurnIn
For comparison, this is the result fields that guards use when you have a prize on your head and turn yourself in (you find this under Greeting 0):
Player->RemoveItem Gold_001 CrimeGoldTurnIn SetPCCrimeLevel 0 PayFine
Or if you get caught and have to pay the normal "fines and compensation":
Player->RemoveItem Gold_001 GetPCCrimeLevel SetPCCrimeLevel 0 PayFine
105
Magic
Limiting the use of teleport
[no fix] DisableTeleporting [no fix] EnableTeleporting
Rather self explanatory, these functions turn the ability to use teleporting magic on or off. Nice to keep those magic user types from wimping out of your dungeon . In the original game it's only used when the player encounters Dagoth Ur. I won't show the whole script as it would be quite a spoiler, but here is the part that uses the function:
short teleportDisabled if ( teleportDisabled == 0 ) DisableTeleporting Set teleportDisabled to 1 endif
This is later reset in the EndGame script. Note: when the original Tribunal is installed this function is effectively broken: One of the start-up scripts in Tribunal overrides all other teleport commands and forces teleporting on except within one specific area in Mournhold (thanks to Slink and Riiak for the info). Here is the culprit:
Begin TribunalMain ;check for teleporting if ( GetPCCell "Sotha Sil," == 1 ) DisableTeleporting else EnableTeleporting endif ;check levitate if ( GetPCCell "Sotha Sil," == 1 ) DisableLevitation elseif ( GetPCCell "Mournhold" == 1 ) DisableLevitation else EnableLevitation ; This is why teleporting was always on outside Mournhold endif end
With one of the updates this problem was fixed. The latest version of the script looks like this:
Begin TribunalMain short disablestate short newstate ;by default, enable teleport and levitate set newstate to 0 ;only need to check cells in interiors if ( GetInterior ) if ( GetPCCell "Sotha Sil," == 1 ) ;disable teleport and levitate here set newstate to 1 elseif ( GetPCCell "Mournhold" == 1 ) ;disable levitate only here set newstate to 2 endif endif
106
;if state should change if ( disablestate != newstate ) if ( newstate == 1 ) DisableTeleporting DisableLevitation elseif ( newstate == 2 ) DisableLevitation elseif ( newstate == 0 ) EnableTeleporting EnableLevitation endif set disablestate to newstate endif end
Note: DisableTeleporting does not disable scripted amulets etc. for teleporting. DinkumThinkum suggested the following workaround which uses GetPCCell to check the player's current location. As long as they're in one of the mod cells, nothing happens. If they're not where they're supposed to be, then the script teleports them back into the correct area: back to the initial entry point for the mod, for example. This wouldn't be exactly the same as blocking the teleports, but it should make the area totally inescapeable until you've fulfilled the modder's conditions for getting out legitimately.
Begin DT_Test_BalmoraTrap If ( GetPCCell, "Balmora" == 1 ) Return Endif MessageBox "Off to Balmora with you!" Player -> PositionCell, -21278, -17613, 534, 0, "Balmora (-3, -3)" End DT_Test_BalmoraTrap
These functions are used to allow and block Levitation magic effects. When DisableLevitation is called, all existing Levitation effects are canceled. When the player tries to cast a spell with a Levitate effect while Levitation is disabled, a notify message is displayed with the text in the GameSetting sLevitateDisabled. Currently this text reads Levitation magic does not work here. Sample scripts: This script is on an object in the room with levitation disabled.
Begin clampstone short turnedoff short gavemessage if ( turnedoff == 0 ) DisableLevitation if ( gavemessage == 0 ) set gavemessage to 1 MessageBox "A strange stone in the roof of this room prevents levitation here." Endif else EnableLevitation if ( gavemessage == 1 )
107
set gavemessage to 0 MessageBox "The stone has been disabled. You can now levitate in this room." Endif endif if ( OnActivate == 1 ) if ( turnedoff == 0 ) set turnedoff to 1 else set turnedoff to 0 endif endif end
This function checks if the player has a soul gem containing the specified soul in his inventory. A little used function that could allow some fun quests and new uses for soulgems. Sample: This is part of the StrongSoulCheck script:
if ( Player->HasSoulGem "atronach_storm" > 1 ) Set counter to ( counter + 2 ) elseif ( Player->HasSoulGem "atronach_storm" > 0 ) Set counter to ( counter + 1 ) endif
Removes a soulgem with the specified soul from the players inventory. Sample: this is the complementary part from RemoveStrongSoul script to the example above:
if ( counter > 0 ) if ( Player->HasSoulGem "atronach_storm" > 0 ) Player->RemoveSoulGem "atronach_storm" 1 Set counter to ( counter - 1 ) endif endif
Note, the player will not be happy if they get Azura's Star taken away by this. Here's a sample solution:
short StarCount ;They could have more than one I guess. if ( OnActivate ) if ( Player->HasSoulGem "Golden Saint" > 0 ) set StarCount to ( Player->GetItemCount "Misc_Soulgem_Azura" ) Player->RemoveSoulGem "Golden Saint" 1 if ( ( Player->GetItemCount "Misc_Soulgem_Azura" ) < StarCount ) Player->AddItem "Misc_Soulgem_Azura" 1
108
endif Player->AddItem Gold_001, 10000 MessageBox "Thank You, Come Again." else MessageBox "You have no Golden Saint souls." endif endif
AddSoulGem adds a soulgem of the specified type and with the specified soul to the players inventory. Not sure if it should have a number_enum as well.
DropSoulgem, "Creature ID"
DropSoulGem "atronach_storm"
I didn't test this yet I assume it makes the calling object drop a filled soulgem with the given soul.
[no fix] OnPCSoulGemUse
The Object is a soulgem and it has been used in either recharging or item making The soul gems in the game have the following ID's: Soul Gem ID's: Misc_SoulGem_Azura Misc_SoulGem_Grand Misc_SoulGem_Greater Misc_SoulGem_Common Misc_SoulGem_Lesser Misc_SoulGem_Petty This function was not used in the original game.
The AddSpell function will add the spell to the calling object. This can mean two things: normal spells are added to the players spell list. Curses, diseases etc, however will affect the calling object. The same is true for the RemoveSpell function: Normal spells are removed from the list, curses or diseases are removed as effects. Note: You can not remove racial abilities with this function (forum info).
Casting spells
Cast, SpellID, "TargetID"
Object_ID -> Cast, "flame", Player
The Cast function makes the calling object cast the spell "SpellID" on the target "TargetID", and Target will suffer or benefit from the effects normally. 109
Note: It was believed that Cast would only work on the PC. At least with Tribunal (not sure about earlier versions) you can use cast to cast a spell from an activator on an Actor probably other combinations would work too. Sample Script: The cast function can be used for traps, as in the following example attached to a Container. Note that there is a do once condition here, so that the effect is not cast continuously on the player.
Begin Trap_script short done if ( OnActivate == 1 ) if ( done == 1 ) ;do-once condition Activate return else Cast, "flame", Player ;damage to player set done to 1 Activate endif endif End trap_script
The added spell is a custom-made curse spell doing one point per second flame damage. Note that there is again a do once condition implicit in this script. Failure to have a do once condition can crash the game! Also, it appears that creatures killed with curse spell effects on them cause all other creatures of that type to have the same curse on them. This can be avoided by using RemoveSpell in an OnDeath section of the script. (Forum Info / Argent) 110
Some info on the various spell types: A health damaging Ability will damage MAX health, while a Curse does not. This does not seem to be true of drain or fortify effects, where it would make alot more sense (forum info / ManaUser).
Returns true if object has Spell_ID in inventory. However, this does not seem to work on spells of types. "Powers" and other race/birthsign related spells don't seem to register with this function, only the ones listed in the main part of the spellbook window. Sample script see below.
GetSpellEffects, "Spell_ID" (returns Boolean/short)
Returns true if Spell_ID is affecting calling object. The following could be added to the "trap_script" discussed under "casting spells" above:
if ( Player -> GetSpellEffects, "flame" == 1 ) MessageBox "You have been flamed" endif
This is the favorite possibility of adding new "spell effects". A dummy spell is created that does some minimal effect, e.g. raising luck by 1 point for 1 second. The GetSpellEffects function is used to detect if that spell has been cast on the player, and the script handles everything else. Sample script see below. Seems to work for Abilities and Diseases as well. Probably Curses and Blight Diseases for that matter but I didn't check.
This function returns TRUE if the calling Actor is being affected by the effect. Important: Effects are not spells, but the elements spells are made of. In the Appendix you can find a list of all spell effects
RemoveEffects, Effect_ID#_enum
Player -> RemoveEffects, 75
Removes all spells on the Actor that include the Effect. For this function you need the number of the effect-ID unlike the GetEffect function where you need the effect ID itself (Bravo, Bethesda!). Both can be found in the appendix. Important: Effects are not spells, but the elements spells are made of. In the Appendix you can find a list of all spell effects and their number.
111
Sample script: This is a demonstration script that lets you check if a spell is in inventory, if it's active on the player, if the effect it causes is on the player and then removes the effect. Start it in the console using "StartScript Magicscript" to try it out.
Begin Magictest short var_1 short var_2 short var_3 if ( Player -> GetSpell, "hearth heal" ) set var_1 to 1 else set var_1 to 0 endif if ( Player -> GetSpellEffects, "hearth heal" ) set var_2 to 1 else set var_2 to 0 endif if ( Player -> GetEffect, sEffectRestoreHealth ) Player -> RemoveEffects, 75 ;delete this line to see what happens normally set var_3 to 1 else set var_3 to 0 endif MessageBox "GetSpell: %.0f End GetSpellEffects, %.0f GetEffect: %.0f ", var_1, var_2, var_3
Testing disease
GetBlightDisease GetCommonDisease (returns Boolean/short) (returns Boolean/short)
Both functions return 1 if the calling Actor has the aproprate type of disease, otherwise 0. These are used in the disease scripts that give diseased or blighted creatures their disease: Sample Script:
Begin diseaseBlackHeart DontSaveObject if ( CellChanged == 0 ) return endif if ( GetBlightDisease == 0 ) AddSpell "black-heart blight" endif End
Explosion
ExplodeSpell spellName
ExplodeSpell "proj_trap_spell"
112
The ExplodeSpell function makes a reference cast the given touch range spell at itself. If an area effect touch range spell is used, this can make the reference explode. See the TrapProjScript, shown in the tips and trick section on the Arrow trap.
Setting this to 1 enables water breathing Setting this to 1 enables water walking
Get/Mod/SetSwimSpeed Get/Mod/SetSuperJump
These correspond to the Swift Swim and Jump spell effects, so they normally range from 0 to 100, but work with negative or higher values as well. I found the following info on the UESP: This sets the player's flying mode. To get this cheat to work, enter the console command and then cast a Levitate Spell. The effect should now last until you disable the flying with the console (thanks Dave Humphrey).
Get/Mod/SetArmorBonus Get/Mod/SetFlying
What it does is each paralysis effect you apply to the actor increments the number by one. Each effect you remove decrements it by 1. You can also alter these useing the set and the mod functions. Whenever its zero the actor can move. Try clicking on someone in the console and typeing setparalysis 1. Whats good about it is if you have multiple actors of the same ID, this allows you to paralyse an individual much like targeting them with a spell would. This is different from useing a paralysis ability which would paralyse all of that ID if you left the cell then went in again. Paralysing them using SetParalysis lasts until you set it to zero or have gone out of their cell for 3 days even if they are not autocalc npc's. (Forum info / Cortex
Get/Mod/SetInvisibile
113
(Later versions of MW, apparently spelling was fixed at some point (Forum info / Cortex))
Get/Mod/SetAttackBonus Get/Mod/SetDefendBonus
114
Sound
Make Actors speak an audio file
Say, file name, text
Actor -> say, "vo\Misc\CharGenBoat1.wav", "This is where they want you."
Make subject "say" the sound file, only works on animating objects. The .mp3 voice sound files can be found in "Data files\Sound\Vo\" folder and are ordered in subfolders by race and gender. You can browse through most of them in the dialogue/voice window as well. Text is what is displayed as a subtitle as the file is played.
SayDone
Returns true if the calling object is not saying anything. Sample Script: from character generation:
begin CharGenBoatNPC ;this is the guard on boat who says to move along short state float timer if ( menumode == 1) return endif if ( GetDisabled == 1 ) return endif if ( OnActivate == 1 ) return endif if ( GetDistance, Player < 180 ) if ( SayDone == 1) ;first greeting if ( state == 0 ) if ( timer == 0 ) ;using a timer so he doesn't talk ALL the time say, "vo\Misc\CharGenBoat1.wav", "This is where they want you. Head down to the dock and he'll show you to the Census Office." set state to 10 endif ;all other times after first else set timer to timer + GetSecondsPassed if ( timer > 6 ) set timer to 0 say, "vo\Misc\CharGenBoat2.wav", "Let's go. Move it along." endif endif endif endif end CharGenBoatNPC
Playing music
[no fix] StreamMusic, filename.ext
Plays the sound file "filename.ext", usually an mp3 file, as the current music file. The music file should by default be located in the data files/music/ folder. Stream music can also play MIDI files (JOG). 115
Note: Slightly bugged: Calling StreamMusic automatically sets the music volume to 100, and leaves it there even after the music has finished playing. Since there is no function to set the volume, the user has to reset to his desired volume manually through the options menu.
Playing sounds
[no fix] PlaySound, sound ID [no fix] PlaySoundVP,sound ID, volume_enum, pitch_enum PlaySound3D, sound ID PlaySound3DVP, sound ID, volume_enum, pitch_enum
"ex_gg_portcullis_02"->Playsound3DVP "Dwemer Door Open" 1.0 1.0
The PlaySound function plays a sound without any modification. It does not matter to which object the script using the function is attached, the sound will always play at full volume, directly in the player's ear, so to speak. The PlaySound3D function plays a directional sound source. The sound will seem to be emitted by the object to which the script with this function is attached. The "VP" variants of each of these commands allow setting volume and pitch for the sound that is played. Bethesda has not made much use of this, it seems and its only ever used with 1.0 set for both, which appears to be the standard anyway. My own experiments showed the sound not playing when I set volume to a variable, but this is no final verdict. The "sound ID" is the ID listed in the sound window accessed via Gameplay sounds menu. You can add sounds there (place the .wav file somewhere in Data files/sounds). A good source for sounds on the web is http://www.findsounds.com/. Sounds should be in a certain format (see below) so you might have to change the format in a suitable program if you don't hear a sound in game.
Controling sound
StopSound, "Sound ID"
Object_ID -> StopSound "Lava Layer"
Returns 1 when the specified sound is currently playing on the calling object. The sound ID's can be found in the Gameplay menu /sounds and /sound gen, where you can also set up your own (see below for formats). This function can be used to control sounds, but also to gain information, because certain sounds are tied to certain events in game, e.g. the "Critical Damage" sound or the "Disarm trap" sound. Sample Script: This simple script assures that lava always has its rumble sound playing:
begin lava if ( menumode == 1 ) return
116
endif if ( CellChanged == 0 ) if ( GetSoundPlaying "lava layer" == 0 ) PlayLoopSound3DVP "lava layer", 1.0, 1.0 endif endif end lava
117
Timer
[no fix] GetSecondsPassed (returns float)
A simple timer can be scripted with the GetSecondsPassed function. It returns the seconds passed since the last frame as a float value. To use this for a timer use something like the following example:
Begin TimerScript Float timer Short state Set timer to (timer + GetSecondsPassed) If (timer > 10) MessageBox Displayed every 10 seconds Set timer to 0 Endif End TimerScript
These globals get set by the game and contain the current date and time. The MW calendar is a little bugged (thanks to samois for the info): MW starts on Day 16, Month 7, Year 427. (16 Last seed) The months are as follows, with the days in each month. (Morning Star ???) Suns Dawn 31 First Seed 28 Rain's Hand 31 Second Seed 30 Mid Year 31 Sun's Height 30 Last Seed 31 Heart Fire 31 Frost Fall 30 Suns Dusk 31 Evening Star 30 So there are 334 days in a MW year!?! Basically it seems that Bethesda screwed up their code and lost a month, Morning Star / January It seems the mistake was simply making it "wrap" to the wrong month from Evening Star. If you manually set month to 0 it will correctly display Morning Star in the rest menu. So this could possibably by scripted around. 118
Sample Script: Checking the time of day with the GameHour function:
Begin AfternoonTea If ( GameHour >= 17 ) If ( GameHour <= 19 ) Cup of Tea -> Enable endif elseif ( GameHour < 17 ) if ( GameHour >19 ) Cup of Tea -> Disable endif endif End AfternoonTea
Day
This would usually be used for time-limited quests in a global script, to make sure the passage of time is correctly measured. Innovative scripting might also make use of it to trigger events after an item has been in the players possession for some time, etc.
Contains the number of days since the game started. In order to work, DaysPassed has to be declared as a global short variable. This declaration is present in Tribunal.esm, but not in Bloodmoon.esm. Thus, in mods that make use of it, and that do not depend on Tribunal.esm, DaysPassed MUST be declared explicitly. This may be one of the reasons that some people reported it to be broken with Bloodmoon, but for others it worked fine - it depends on whether they had Tribunal.esm checked or not (Forum info / Erstam).
Moon phases
Indispensable for any potential werewolf mod.
[no fix] GetMasserPhase (returns short) [no fix] GetSecundaPhase (returns short)
If (GetMasserPhase == 4) [enable werewolf monster] endif
Note: The helpfile lists GetSecundusPhase, the above syntax GetSecundaPhase is the correct one. Also note that GetMasserPhase and GetSecundaPhase return the value of the moon phases for the last exterior cell you visited (Forum Info / Elim). I only made a quick test with these, but they seem to work. Both functions return short with these values: 0 = MOON_PHASE_NEW (this is the default) 119
120
Weather
Changing weather
[no fix] ChangeWeather, "RegionID", short_Type_Enum
ChangeWeather, West Gash, 4
This function changes the weather in the indicated region to the weather type specified by TypeEnum, and will change again to according to the region settings after the time set by the game (I assume that is set in the Morrowind.ini file in the Weather section. In mine the entry reads:
Hours Between Weather Changes=20
The weather TypeEnum values are: 0 Clear 1 Cloudy 2 Foggy 3 Overcast 4 Rain 5 Thunder 6 Ash 7 Blight
Changes the weather chances for the RegionID. Used to get rid of, or add weathers to an area permanently. The values must add up to 100 or you will get odd results.
This returns the weather TypeEnum listed above. Sample script: Bethesda used this to make the banners move in the wind according to weather type:
begin OutsideBanner ;this script is for a banner object outside that ;animates in the wind. ;Idle is still, Idle2 is a little breeze, and Idle3 is a large breeze short ran if ( MenuMode == 0 ) set ran to random 100 if ( ran < 30 ) ;30% chance the flag does something new ;this will check the weather in the future if ( GetCurrentWeather >= 5 ) ;thunder, ash, or blight LoopGroup, Idle3, 5 endif
121
;the last anim called in this script is the one it will play if ( ran <= 10 ) PlayGroup, Idle elseif ( GetCurrentWeather < 5 ) PlayGroup, Idle2 endif endif endif
I have only very briefly tested this function and it returns values, 0 indoors and floats outdoors (varying quickly, in overcast weather the values seemed to oscillate around 2). (Thanks to XPCagey for finding this)
122
Player Controls
Player sleeping
[no fix] ShowRestMenu
Brings up rest menu, and allows the player to sleep. This is used e.g. for beds in cells where it is otherwise illegal to sleep. Sample Script: This is the standard script for beds:
begin Bed_Standard ;used for standard beds the player can activate and sleep in if ( MenuMode == 0) if ( OnActivate == 1 ) ShowRestMenu endif endif end
(returns Boolean/short)
Returns true (1) if pc is sleeping. Note: The sleep selector and counter you see while sleeping counts as a menu. So be aware of that, if you want to use this function, and the MenuMode function in the same script! The example script seems to come from a fairly useless item, but it demonstrates the use
Begin pillowScript short comfy if ( PCVampire == 1 ) return endif if ( comfy == -1 ) if ( player->GetItemCount "misc_uni_pillow_unique" > 0 ) if ( GetPCSleep == 0 ) set comfy to 0 return endif endif endif if ( comfy == 0 ) if ( player->GetItemCount "misc_uni_pillow_unique" > 0 ) if ( GetPCSleep == 1 ) MessageBox "Your sleep is very restful on your Extra-Comfy Pillow" set comfy to -1 return endif endif endif End pillowScript
Makes the PC wake up before the selected sleeping time is over. Sometimes creates a monster if the player was sleeping outside. This always happens if they try to sleep for only one hour, 123
with longer times it may or may not happen (Thanks to Manauser for this info). WakeUpPC interrupts the rest only when you actually *sleep*. It does not affect loitering in places where resting is forbidden (Forum info / Kir). Sample script: This is an edited excerpt from the lengthy "sleepers" script by Bethesda. It is responsible for giving you the dreams about Dagoth Ur that plague the player during the main quest. It shows how GetPCSleep and WakeUpPC can be used:
if ( GetPCSleep == 0 ) return endif Set dream to 0 if ( GetPCCell "Balmora" == 1 ) Set dream to 1 endif if ( GetPCCell "Ald-ruhn" == 1 ) Set dream to 2 endif [] if ( dream == 0 ) Set doOnce to 0 ;this makes sure you have to leave the city and come back for another attack to occur return endif AddTopic "Disturbing Dreams" ;add this topic, doesn't matter if you do it over and over ;THE FIRST DREAM... if ( GetJournalIndex A1_2_AntabolisInformant >= 10 ) if ( GetJournalIndex A1_Dreams < 1 ) WakeUpPC MessageBox "You had a disturbing dream. Bla bla bla", Ok" Journal A1_Dreams 1 return endif endif
These two functions seem to be unreliable according to forum information: If the player holds a weapon or has a spell readied he can continue to use it and quick-keys for weapons and spell likewise still seem to work. I currently don't know of a reliable solution for this problem.
[no [no [no [no fix] fix] fix] fix] DisablePlayerJumping DisablePlayerLooking DisablePlayerViewSwitch DisableVanityMode
124
queue the change to 3rd person mode (this may have to wait for the animation to finish) same as above but 1st person mode (See also the console command "ToggleVanityMode" (TVM).
There is no disable command for these. They are disabled by selecting ok in the menu. Enabling in-game menus:
[no fix] EnableMagicMenu [no fix] EnableMapMenu
125
Also no disable commands here unfortunately. These would have been useful. The names of the functions should be self-explanatory. One use for these functions is as a cheat if you want to change your appearance or other things during a running game (although there might be problems associated with doing that). They can (and have been) used to create different ways of character generation. Be careful, sometimes these reset your level to 1. Sample Script: This is one of many CharGen scripts that guide the player through character generation. This one is basically a safety feature for a player who just runs out the door, without triggering any or all of the little tutorials.
Begin CharGenDoorExit ;this is the door that exits the first part of the census building ;safety check for all menus on short done if (done == 1) return endif if ( OnActivate == 1 ) enablestatsmenu enableinventorymenu enablemagicmenu enablemapmenu enableplayerfighting enableplayermagic set done to 1 Activate endif End
MenuMode returns one if the player has activated the menu (the inventory screen). It is common practice to put the following lines at the beginning of almost any script, to avoid that the script processes while the player is in the inventory. Dialogue, the sleep timer, the console and probably pretty much any menu will activate this too.
If ( MenuMode == 1 ) Return Endif
MenuTest doesnt return anything, however, when it is called, it closes certain types of inventory menus, including Player, NPC and containers. It doesnt work for dialogue, enchanting, alchemy, spell or armorer menus. (Forum Info / JOG, Jilin). 126
menutest or menutest 0 for closing menu menutest 3 open stats menu or focus on it menutest 4 open inventory menu or focus on it menutest 5 open spell menu or focus on it menutest 6 open map menu or focus on it for menutest 3,4,5,6, it's like clicking on the upper right button of the menu Example Script:
if ( OnPCEquip == 1 ) set OnPCEquip to 0 coc Balmora MenuTest endif
127
Return tells the game engine to finish processing the script for this frame. All code below this line will be ignored for this frame. In the next frame the script is executed again from the top.
If ( MenuMode == 1 ) Return Endif
Careful: Anything below a return function will not be processed, even if there are "true" if statements there! So use this with caution.
These function are used to control global scripts. Global scripts have to be started with the StartScript function (either from another local or global script or from a dialogue result field) and a running script can be terminated with the StopScript function. Note: If you use 'StopScript' from inside the global script you're terminating, it doesn't actually terminate the script immediately. Instead, the script continues executing to the 'End' statement, and then terminates. So you still need to use "Return" if you don't want the rest of the script to be processed. Tribunal "Start Scripts" in a plug-in start executing each time the game is loaded. If a Tribunal Start Script is terminated with a 'StopScript', it will start up again the next time the game is loaded - see the Tip and Tricks section on "Detecting when a player does a load from savegame". (Forum info / DinkumThinkum). To my knowledge these functions do not work with local scripts attached to objects, you can however start and stop "targeted scripts" by using an object "fix": ObjectID -> StartScript (for more info see the Tips and Tricks section on targeted scripts). The ScriptRunning function returns 1 if a script is running, 0 if it's not running:
if ( ScriptRunning, CharGen == 0 ) StartScript CharGen Endif
StopScript can also be used to construct do-once conditions for global scripts in a very clean way by self-terminating the script:
Begin do-once_script []; do stuff here StopScript do-once_script End
128
FadeIn and Fadeout fades the screen (not an object) to blackness in the time specified (in seconds). Time is > 0 and <= 10.0. FadeTo fades only to a certain percentage: 0 is full transparency. 100 is black.
This function will highlight the indicated cells. Cell ID can be full or partial, i.e. all cells that begin with the given string will be highlighted on the world map (e.g. ShowMap "Vivec" will highlight all the cantons). Sample Script: reading this book will indicate all these places on the world map:
Begin bookPilgrimsPath if ( GetJournalIndex TT_PilgrimsPath >= 100 ) Return endif if ( OnActivate == 1 ) Journal TT_PilgrimsPath 100 ShowMap "Gnisis" ShowMap "Vivec" ShowMap "Ghostgate" ShowMap "Koal Cave Entrance" ShowMap "Fields of Kummu" Activate endif End
Introducing some unpredictability into the effects of a script is a nice option, and it can be done with the Random function. Random returns values between 0 and the set value 1. So in the example above, my_variable will be set to a value in the range from 0 to 49. Note that the global short variable Random100 gets set each frame by the games Main script to a random value between 0 and 100, so you can make use of that one, too. Note: For any call to Random with a range over 100, the randomosity of the return value gets very poor indeed... right up to Random, 255 where you only get 0 or 1... and any multiple of 256 also gets you a CTD. (Morrowind and Tribunal). In Bloodmoon, they seem to have fixed the randomosity of the return value... you seem to get numbers that are more evenly distributed, even with a range above 100. But the CTD's at 256 and 512, etc, still happen (Info by Neko). It was furthermore discovered that sometimes the Random cap is set much higher 129
than the number given. Setting any variable to a Random with the cap value of one of the following numbers produces some strange result, setting the higher cap actually to something around 1100: 65, 66, 68, 70, 71, 76, 77, 79, 82, 83, 84
Playing videos
[no fix] PlayBink filename flag_enum
Pauses game and plays video. Set Flag to true if player can escape movie. The video needs to be in Bink format and placed into the Datafiles/Videos directory. MW defaults to loading videos from the CD, so I am not sure if this will actually work. It's possible (not tested) that setting "TryArchiveFirst=-1" in the Morrowind.ini file could have an influence on this (-1 Use raw data, 0 Use Newer, 1 use Archive Only). Otherwise you may have to resort to a no-CD crack to play your custom made videos.
These functions are used to manipulate Leveled Item and Leveled Creature lists at runtime. Leveled lists are comprised of object/level pairs where the level is the level the PC has to be to encounter the object. The AddTo functions will add the given object/level pair to the specified leveled list as long as the list does not already contain a matching pair. The RemoveFrom functions will remove all occurrences of the object/pair from the leveled list. Additionally, if a RemoveFrom function is given an object pair with a level of 1, all object pairs containing the specified object are removed. Note: The RemoveFrom functions will not remove existing objects from the world. If a Leveled Creature reference has already calculated to be a certain creature, removing that creature from the Leveled Creatures list will not get rid of the existing creature in the world. However it will prevent that Leveled Creature reference from calculating to be that creature again. Sample Script: When this script is placed on an object, activating it will toggle the existence of rats in the world by removing them from a Leveled Creature and removing rat meat from a Leveled Item.
Begin norats short norats if ( OnActivate == 1 ) if ( norats == 0 ) set norats to 1 RemoveFromLevCreature "rat_scamp_crab" "rat" 1 RemoveFromLevCreature "rat_scamp_crab" "rat-fast" 1 RemoveFromLevItem "lev_meat" "rat_meat" 1 MessageBox "No more rats." Else set norats to 0 AddToLevCreature "rat_scamp_crab" "rat" 1 AddToLevCreature "rat_scamp_crab" "rat-fast" 1
130
AddToLevItem "lev_meat" "rat_meat" 1 MessageBox "The rats return." Endif endif end
Square root
[no fix] GetSquareRoot, number (float)
set var_1 to GetSquareRoot var_2
The GetSquareRoot function returns the square root of the given number. This can be useful for vector or distance calculations (remember Pythagoras?).
A great opportunity for cruel traps These functions are used to determine and modify the Water Level of the current interior cell. When an Actor suddenly finds itself underwater, it will wait until it is halfway out of breath and then begin to make its way to the surface in a straight line up. Floating corpses are moved with the water without regard for collision. Sample scripts: This script goes on a crank to make it raise or lower the water level in the room.
Begin crank short float float short short float changelevel direction waterlift crankturn currcrank newwaterlevel
if ( MenuMode ) return endif if ( OnActivate == 1 ) if ( changelevel == 0 ) if ( direction == 1 ) set direction to 1 else set direction to 1 endif set changelevel to 1 endif endif if ( changelevel == 0 ) return endif set crankturn to 360 * GetSecondsPassed set crankturn to crankturn * direction set currcrank to GetAngle X set crankturn to currcrank + crankturn SetAngle X crankturn
131
set waterlift to 120 * GetSecondsPassed set waterlift to waterlift * direction ModWaterLevel waterlift set newwaterlevel to GetWaterLevel if ( direction == 1 ) if ( newwaterlevel >= 600 ) SetWaterLevel 600 set changelevel to 0 endif else if ( newwaterlevel <= 0 ) SetWaterLevel 0 set changelevel to 0 endif endif end crank
This modified Float script is placed on any object with a centered pivot point to make it float on the waters surface regardless of water level. It also will make the object stop bobbing if the PC is standing on it.
Begin NewFloat float float float float short float float float float float timer swingTime startAngle currangle reset xvalue zvalue zoffset tmpoffset weightoffset
set startAngle to GetStartingAngle, x if ( MenuMode == 0 ) if ( timer == 0 ) if ( reset == 0 ) set timer to Random 100 set timer to timer / 4 endif endif set swingTime to 1 set set set set timer to ( timer + GetSecondsPassed ) currangle to GetAngle X xvalue to 10 * GetSecondsPassed zvalue to 5 * GetSecondsPassed
if ( GetStandingPC ) set zoffset to 30 SetAngle X 0 else ;rotate up if ( timer < swingTime ) set currangle to currangle + xvalue SetAngle X currangle set zoffset to zoffset + zvalue ;rotate down elseif ( timer < (swingTime * 3) ) set currangle to currangle xvalue SetAngle X currangle set zoffset to zoffset zvalue ;up again elseif (timer < (swingTime * 4 ) )
132
set currangle to currangle + xvalue SetAngle X currangle set zoffset to zoffset + zvalue ;reset timer to zero else set timer to 0 set reset to 1 set zoffset to 0 SetAngle, x, startangle endif endif set tmpoffset to GetWaterLevel set tmpoffset to tmpoffset + zoffset SetPos Z tmpoffset endif end NewFloat
133
134
keyboard. This marks the feature as ignored. Loading and resaving the mod will remove these ignored features from the mod. An alternative, and much easier to use is the utility TESAME (TES advanced mod editor), available from various sites, e.g.: http://theseventhrealm.com/portal/tools.html A more recent tool that has become indispensable to me is the Morrowind Enchanted Editor, available at: http://tfo.rh.rit.edu/esforum/secretmasters/EnchantedSetup0.91c.exe. It's not very well documented, but offers a much nicer user interface than TESAME and is immensely powerful. For scripts, try to remove any unused global variables or whole scripts you may have made in the course of developing your script. It bloats your .esp filesize, it probably wastes memory, or at the very least it looks bad.
DIAL A new or changed topic
This is a list of the change indicators found in the details tab of TESAME:
INFO A dialogue response, or journal entry REFR a reference of an object that was put into the game world, while MISC, CONT etc. describe the actual Object (even if there is no instance of it placed in the world) SOUN A Sound NPC_ - A new type of NPC, or a changed NPC CREA A new creature or a change to a creature LIGH A new or changed Light LTEX An application of a landscape texture PGRD A change to the AI grid CELL obvious, signifies a changed cell either indoors or outdoors in case your mod had nothing to do with that cell you should get rid of it. This affects all changes in that cell automatically, I think automatically SCRPT A Script lots of people leave superfluous "test scripts" in their mods that's bad style, I think. MISC A new or changed miscellaneous object check names, delete if the change is unrelated to your plugin ACTI An activator see above CONT A container very critical: make sure you only change a new ID (copy of a container), not the original container or they will all be changed. STAT A static object see above
Be careful with cleaning up dialogue: When you enter new dialogue into a topic, that also changes the topics above and below the one you inserted that is because the responses in topics are a linked list, each contains the information about the next line, which allows quick processing of the topics to search for the correct response. Do not clean up topics that show up changed due to this it will create an error telling you that the next line is different for a specific response in a topic. You can recreate the link by moving the topic in question up and down, to re-register the order of topics with the TES CS.
136
On References Persist
The object windows in the TESCS have a checkbox named "References persist". Ticking this checkbox ensures that a reference (an instance of the object in the game world) is always available to be referenced by script, even if the player is in a different cell, or has not yet encountered the object. If a script uses a specific reference to an object such as Then "RefObject" should have References persist checked. Indirect referencing such as; do not usually require references persist. Some functions may be exceptional in this respect. For example;
GetDistance, RefObject PlaceAtMe my_object 1 1 1 Player->AddItem my_object 1 RefObject -> Enable
requires that RefObject has been placed in the world and references persist checked. Actors (NPC and Creatures) are always persistant. (Thanks to Nigedo for additional information)
137
This little piece of code, that should be at the very top of your script, will allow your script (or rather the main, CPU power eating part of it) to be executed only every 10th frame. You could do the same thing with a timer, and execute the script only every 3 seconds or once every minute. Execute script only if the player is suitably near. If you have scripted a fancy magic bouncing ball, or basically anything that is a visible effect, there is no reason to run the script if the player cannot see it. So put something like this on top of your script:
If ( GetDistance, player < 5000 ) Return Endif
Shortcut scripts that are no longer needed. If you have local scripts that you may not need from a certain point onwards, e.g. because of Actor death or because the object was disabled, reduce their CPU need by putting something like the following at the top of the script:
If ( GetDisabled == 1 ) Return Endif If ( GetHealth <= 0 ) Return Endif
Terminate global scripts. Remember, global scripts are running all the time until you stop them again with StopScript. You can do do-once global scripts by just putting a StopScript command at their end
Begin do_once_global_script [your code here] StopScript "do_once_global_script" End
Try to use local scripts instead of global scripts. With local scripts you are sure that they only run when you are in the vicinity. Think hard before making a script global if it can be done with a local script instead. Be careful with while-loops, GetDetected, GetLOS and other "slow" functions. Use methods as described above (e.g. a counter or a timer) to make sure they are not called too often. Stop script while in menu mode. Always, unless you have specific reason not to, put the following at the top, to avoid the mouse lagging in the menu and other unwanted effects.
If ( MenuMode == 1) Return Endif
138
It is possible to use the StartScript function to run global scripts that are tied to an object or Actor. These scripts resemble both local scripts (in that the functions called always default to the object or Actor the script targets) and global scripts (in that they are always running). This is from a post by FreshFish, who found this really amazing technique: "This is what the helpfile has to say on StartScript: This function starts a script running. This is a Global script. It is not attached to any object, so functions like moving, rotating, checking distances and such have no bearing in a global script. This is nonsense, ever tried starting a script from dialogue? Or from an NPC's default script? Well it works just fine, any AiTravel or PositionCell functions in the script are applied to the object they were started on. I'm going to call these 'targeted' scripts. Targeted scripts run all the time just like globals so you can get your NPC to do stuff when you are in other cells. And if you start another script from a targeted script then that script inherits the same target so you can fork 'em off or chain 'em up or whatever. So it looks like the limitation of only one small script per object is no more. I should point out that a targeted script still differs from a 'local' script in that variables defined in the targeted script are not considered local to the object from the point of view of dialogue and other scripts. If a script is stopped then restarted any variables are preserved, including doOnce type variables so if you are planning on using your script again you may need to reinitialize some stuff yourself. I dont know what happens if you try to start a targeted script on more than one target simultaneously but I doubt it would be pretty." >can you start one script on an object, then after it stops, start a second, >different script on the same object? You can start a second different script on the same object any time you like, no need to wait for the first to finish. Whether this causes a conflict or not is down to what you do in your scripts, can't walk in two directions at once, obviously. >what about objects that already have a "local" script attached? >are there any conflicts? No problems here either, I have an NPC with a local script which puts on a robe when it rains and also uses a 'targeted' script to make her follow another NPC sometimes. And some more info from a post by Riiak on the Morrowind Mods forum: a) Variables located in targeted scripts are NOT considered local and are basically unusable in dialogue. This is because the script is not a local script it is global. b) A targeted script can be started from generic dialogue on a generic NPC. Thus you could write a dialogue for say "Crusaders" and start the script from there regardless of character ID. (This can allow for some very interesting situations). In the same vein is a suggestion by Cortex: You can use generic voice bits (like the sounds Actors say 139
when you approach, when they are initiating combat, or when they are hit to start these scripts, since they, like all dialogue have a result field. This opens up a lot of possibilities! c) Targeted scripts can generically access an NPC's inventory (with the same limitations as regularly accessing the NPC's inventory, must know item ID, etc...) d) (As far as I can tell) Can not be used for Tribunal's companion sharing, but can be used to set up a simple follower script. e) (As far as I can tell) Can have multiple copies of same script targeting the same NPC. (could be helpful, but most likely will only cause problems) I would recommend that the script be self stopping as that would be the easiest way to have the script clean itself up and prevent multiple copies running. When using targeted scripts from dialogue, the script apparently always attaches to the NPC calling the dialogue response, not a referenced object: Object_ID -> StartScript "script_name" will not work, the script still attaches to the NPC saying the dialogue (Forum info / Argent). Careful with using targeted scripts with non-unique objects. This will work during runtime, however after loading a save, the script will attach to the first instance of the object in the database (similar to what was said regarding GetDistance), instead of the reference that originally called the script (forum info, MentalElf).
140
"Dummy" is any journal-topic that has no text for index 100. Setjournalindex will set the index to the new value, no matter if an entry exists for this value or not (useful for simple flags that don't need an own journal-entry) but when you reload, the index will be reset to the highest value of the existing entries that are already in the journal. MentalElf suggested that GetForceRun, GetForceSneak, GetScale can all be used to detect when the player has just loaded a save game. This is due to ForceRun and ForceSneak being cleared during a load from saved game, and scale is set to within the range 0.5 to 2.0. In my opinion ForceRun is best, as ForceSneak puts the NPC into a crouch posture.
; (NPC object) if ( GetForceRun == 0 ) ; Player just loaded a saved game ; Handle game load here. ForceRun Endif
A different option is to use start scripts ( available only with Tribunal and Bloodmoon): Here are two examples by Dinkum Thinkum:
begin DT_DoOnce_TribStartScript02 ;script to demonstrate a 'DoOnce' Tribunal Start Script that runs once ; each time a saved game is loaded with the mod enabled ;by DinkumThinkum ;script executes 'Do Once' code section once ; each time the mod is loaded as part of a game ;start of 'Do Once' code to be run each time a saved game is loaded with this mod enabled. MessageBox, "You will see this message everytime you load a saved game with this mod enabled.", "OK" ;end of 'Do Once' code. StopScript DT_DoOnce_TribStartScript02 end DT_DoOnce_TribStartScript02
141
;script executes 'Do Once' code section once, when the mod is loaded ; with a saved game that does not include the mod (or with a new game) ;script executes 'Reload' code section once, each time a save game ; made with the mod is reloaded with the mod enabled ;either code section can be omitted, but all the control structures will still be needed ;Note: BOTH 'StopScripts' are necessary. Trust me... ;DT_DoOnce_TSS01 - Global variable, won't be reset by StopScript (initialized to 0) if ( DT_DoOnce_TSS01 == 1 ) ;start of 'Reload' code, to be run once each time mod is reloaded MessageBox, "You have loaded this mod with a saved game made with the mod enabled.", "OK" ;end of 'Reload' code StopScript DT_DoOnce_TribStartScript01 Return endif ;start of 'Do Once' code, to be run only when the mod is first loaded. MessageBox, "You have loaded this mod with a saved game that was made without this mod enabled.", "OK" ;end of 'Do Once' code. set DT_DoOnce_TSS01 to 1 StopScript DT_DoOnce_TribStartScript01 end DT_DoOnce_TribStartScript01
142
set PCSkipEquip to 1 ; disable if used (a 1 use item) if ( gone == 1 ) if ( goneway == 1 ) ; activated as external item Disable else ; equipped from inventory startscript BankLetter10Remove endif set gone to 0 return endif if ( OnActivate == 1 ) Set messageOn to 2 set goneway to 1 endif If ( OnPCEquip == 1) Set messageOn to 2 Set OnPCEquip to 0 set goneway to 2 endif if ( messageOn == 0 ) return endif if ( messageOn == 2 ) MessageBox "Do you want to invoke the Letter of Credit?" "Yes" "No" Set messageOn to 1 return endif
if ( messageOn == 1 ) set button to GetButtonPressed if ( button == 0 ) Set invoke to 1 Set messageOn to 0 ; return endif if ( button == 1 ) Activate Set messageOn to 0 return endif endif if ( invoke == 1 ) PlaySound "Item Gold Up" Player->AddItem, Gold_001, 10000 set gone to 1 set invoke to 0 endif End
143
Erstam posted a script with even better features, that also revealed an interesting glitch with the scripting variables OnPCEquip / SkipEquip: "Inspired by the BankLetter script in MSFD 7, I have found a way to run custom script code on books and scrolls when either "equipped" from the player's inventory or activated from the game world, while the book/scroll is displayed as normally. Surprisingly, it's the PCSkipEquip variable that is set to 1 when the book is dropped on the player's portrait, rather than the OnPCEquip variable. This is the code I used:"
Begin activateBook short short short short OnPCEquip PCSkipEquip doOnce actionFlag
if ( actionFlag == 1 ) if ( doOnce == 0 ) ; insert your custom code here set doOnce to 1 endif set actionFlag to 0 endif ; PCSkipEquip is set to 1 every time the book is equipped from your inventory if ( PCSkipEquip == 1 ) set PCSkipEquip to 0 set actionFlag to 1 return endif ; these lines are important, otherwise the book can't be picked up from the ground if ( MenuMode == 1 ) return endif ; for activating the book when it is placed in the game world if ( OnActivate == 1 ) set actionFlag to 1 Activate endif End
It should work without the doOnce condition, in case you want the action to take place every time you equip the book, but I haven't tested it yet.
144
The next example is one by Bethesda, which does the same thing, using the skill change method (admittedly more elegant than mine ):
begin marksmanToggle short counter short myMarksman if ( MenuMode == 1 ) return endif if ( counter < 20 ) Set counter to counter + 1 Return endif if ( myMarksman == 0 ) set myMarksman to GetMarksman endif if ( GetMarksman > 0 ) if ( GetDistance Player < 400 ) SetMarksman 0 endif else if ( GetDistance Player > 600 ) SetMarksman myMarksman endif endif ;for level designers... forces AI to do what it ought to do ;when they are near, they use melee weapons ;when they are far, they use missile weapons ;checks every 20 frames for speed ;Note: does not affect spellcasting AI End
145
float killtimer if ( triggered == 1 ) if ( killtimer < 4 ) set killtimer to ( killtimer + GetSecondsPassed ) else SetDelete 1 endif return endif if ( MenuMode == 1 ) return endif if ( initialized == 0 ) set initialized to 1 set range to 150 set rate to 300 set targx to ( player->GetPos X ) set targy to ( player->GetPos Y ) set targz to ( player->GetPos Z ) set shiftx to ( targx GetPos X ) set shifty to ( targy GetPos Y ) set shiftz to ( targz GetPos Z ) set totaldist to ( ( shiftx * shiftx ) + ( shifty * shifty ) + ( shiftz * shiftz ) ) set totaldist to GetSquareRoot totaldist if ( totaldist != 0 ) set shiftx to ( shiftx / totaldist ) set shiftx to ( shiftx * rate ) set shifty to ( shifty / totaldist ) set shifty to ( shifty * rate ) set shiftz to ( shiftz / totaldist ) set shiftz to ( shiftz * rate ) else set triggered to 1 return endif endif
146
set distance to GetDistance "player" if ( distance < range ) set detonate to 1 else set currx to GetPos X set curry to GetPos Y set currz to GetPos Z set currshift to ( shiftx * GetSecondsPassed ) set currx to ( currx + currshift ) set currshift to ( shifty * GetSecondsPassed ) set curry to ( curry + currshift ) set currshift to ( shiftz * GetSecondsPassed ) set currz to ( currz + currshift ) if ( shiftx < 0 ) if ( currx set set else set endif else if ( currx set set else set endif endif if ( shifty < 0 ) if ( curry set set else set endif else if ( curry set set else set endif endif if ( shiftz < 0 ) if ( currz set set else set endif else if ( currz set set else set endif endif SetPos X currx SetPos Y curry SetPos Z currz endif if ( detonate == 1 ) ExplodeSpell "proj_trap_spell" set triggered to 1 disable endif end < targx ) detonate to 1 currx to targx detonate to 0 > targx ) detonate to 1 currx to targx detonate to 0
< targy ) detonate to 1 curry to targy detonate to 0 > targy ) detonate to 1 curry to targy detonate to 0
< targz ) detonate to 1 currz to targz detonate to 0 > targz ) detonate to 1 currz to targz detonate to 0
147
Scripted teleporting
Teleporting to variable positions in interior, and especially exterior locations is not trivial, there are issues with surrounding cells not loading properly (meaning part of the landscape may not be rendered) or crashes. One solution was suggested by Aftershock_81:
COE 0 0 Player->SetPos x xpos Player->SetPos x ypos Player->SetPos x zpos FixMe
where FixMe is meant to reload the destination cell to avoid the problem where SetPos does not force the cell to load correctly. Nigedo reported problems with this approach and suggests a solution: "Sometimes the destination cell failed to load correctly despite FixMe. On other occasions, it would throw up strange error reports or game freezes. With quite a lot of help from Grumpy and Mode_Locrian (thanks chaps), I have written a script that does work reliably as far as I can tell from testing it using various coordinates. It works by moving the Player by stages, which allows the destination cell to load correctly 'on approach'. For aesthetics, use FadeOut at the start (or in the trigger script) and FadeIn at the end of the script. There are two stages. The Player's starting exterior coordinates are recorded as three global variables when they are transported to the interior initially. This script then needs to be run by StartScript when the Player activates the trigger to transport them back to their original exterior coordinates. I have tried running a more optimized version of this script that used stacked SetPos jumps of magnitudes decreasing from 131072gu to reduce the number of cell loads. But this method failed sometimes. When the distance from 0,0 to the destination was closed by a jump larger than 8192gu it did not always force the cell to load and the purpose of this approach was lost. This method is a bit cumbersome, but it seems does seem to be reliable."
Begin script_placePC ;Global Long Start_PCX ;Global Long Start_PCY ;Global Long Start_PCZ Float xpos Float ypos Float zpos Long higher Long lower Short step If ( step == 0 ) Player->COE 0 0 Set step to 1 Return Endif Set xpos to ( Player->GetPos x ) Set ypos to ( Player->GetPos y ) If ( step == 1 ) Set higher to ( Start_PCX + 8192 ) Set lower to ( Start_PCX - 8192 ) If ( xpos > higher ) Set xpos to ( xpos - 8192 ) Player->SetPos x xpos Elseif ( xpos < lower ) Set xpos to ( xpos + 8192 ) Player->SetPos x xpos Else Set step to 2
148
Endif Return Elseif ( step == 2 ) Set higher to ( Start_PCY + 8192 ) Set lower to ( Start_PCY - 8192 ) If ( ypos > higher ) Set ypos to ( ypos - 8192 ) Player->SetPos y ypos Elseif ( ypos < lower ) Set ypos to ( ypos + 8192 ) Player->SetPos y ypos Else Set step to 3 Endif Return Elseif ( step == 3 ) Set xpos to Start_PCX Set ypos to Start_PCY Set zpos to Start_PCZ Player->SetPos x xpos Player->SetPos y ypos Player->SetPos z zpos Set step to 0 StopScript script_placePC Endif End
Notes: On a couple of occasions, my test PC has arrived at their destination and keeled over dead. Hehe.. I can only assume that some creature had a stab at them on the way through. So it's a good idea to nest the entire teleport section of the script within a pair of 'ToggleGodMode' statements. The aesthetics of the whole process are hugely improved by using FadeOut and FadeIn functions as I mentioned. It is also improved by calling ToggleMenus after the initial COE statement, which conceals the HUD and all of the ensuing cell loads. The menus/HUD can be reactivated at the end of the script by the combination of functions: ToggleMenus, MenuTest, MenuTest.
149
This method does not work, if the aforementioned Global has a pre-set value, as with this method, it will be overwritten. or the foreign plug-in has not yet changed the value to a number other than 0 by the time this check is performed Strong advice: Given this, never implement a global variable in your PlugIn with a pre-set value, but instead let it start with its default (Zero), and fill it with a script later (i.e. an autostart-script), as for if someone implements a Global of this name as well, your Plug-In might crash. I consider the fact that you can overwrite the Globals of another PlugIn without warning a serious bug! (Note by GBG: one more reason why people should try to use unique names wherever possible in their mods don't name your global "check" at least call it (your initials)_check, e.g. "YI_check" that avoids lots of problems and compatibility issues)
150
To make sure a global script is started in an already running game you can use a similar method, and place activators in commonly visited cells. If you have one in Balmora, Vivec, Sadrith Mora, Dagon Fel, and Caldera and maybe the PC strongholds, I am sure it won't take long until the script is running. You can also use an object that is required for your mod anyway to start it. E.g. for Indestructibles excellent Bank mod, I made myself a version that attaches the above script to the banner of the bank and starts the "interest" script. That makes sure that that script is running before the PC ever sets foot inside the bank.
151
look in the sounds menu in the TESCS to find which Sound ID corresponds to a specific action. For instance "illusion cast" corresponds to the player casting an illusion based spell. You'll probably have to experiment a little. Note: for some reason the Sound ID "drink" causes an error, so no checking if the PC is drinking a potion.
Large battles
(by Horatio) The easiest way to do a large battle between two groups of NPCs is to use the AI commands. Let's use an example of a bunch of imperial legionnaires, with whom the PC is aligned, versus a dark brotherhood gang. First set the 'fight' rating ( in the AI tab) of the DB NPCs to 100 so that they'll attack the PC on sight. Then, you'll need to set the AI of the legionnaires to: AIFollow, player, 0,0,0,0,0 you can do this either with scripts attached to the legion NPCs or with an external script. The default behavior of AIFollow is to attack whatever is attacking the person they are following. So when the DB guys attack the PC, all the legionnaires will freak out and starting attacking them back. Presto instant giant melee. I use a variation on this in the GIANTS mod to convince the guards to attack monsters that are actually NPCs ( vampires, shades, giants, gorgos, etc ).
152
Selecting objects
Practically all objects (statics/activators) can be used. However, selecting the right type of objects is paramount. It will make your scripting a lot easier later on. Now, what type of objects are suitable? Preference is given to small and minimum height ( thickness ). The other important factor is the center point which is also the point where your character will be standing on. This will also save you a lot of programming work later on. If the object center point is not what you want, you can fix this by importing the object to 3DS and move the axis to the point to where you plan your character to stand. I am not going to explain in details how to do it in 3DS, there should be quite a number of tutorials out there which teach you how to do it.
Creating/Deleting objects
I am sure a lot of modders know that you can only move an object through the exterior cells within certain distances. This is because the game will only update and process objects/codes within a certain distance. When your character gets out of that parameter, the object will actually be frozen or to the player, the object has warped/disappeared into thin air. But, if you trace back to the original cell, the object will re-appear. Now, to move objects throughout the entire exterior cells, the trick to use here is to create a new object. Everytime when you move to a new cell, the function "CellChanged" will become TRUE for one frame. This is the best time to replace the existing object with a new one. There is one BIG problem that I discovered here. NEVER create an object from an object script. It doesn't seems to work. So, what you need to do is to use a global script to create one instead. At the same time, do not forget to Delete the old object or you will have all these objects spreading in different cells which will cause you major problems later on. Always maintain one object at one time. Below is a simple example you can use:
;---------------; Object script ;---------------if ( player->CellChanged == 1 ) Startscript, "Create_obj_script" ; this is the global script set obj_count to ( obj_count - 1 ) ; global parameter to count how many object exist Disable SetDelete, 1 endif ;---------------; Global script ;---------------PlaceAtPC "objectname", 1, 0, 0 ; or you can use PlaceItem set obj_count to ( obj_count + 1 ) Stopscript "create_obj_script"
153
Ideally, the above script should work like a charm but in reality it is going to cause you major problems. Deleting an object immediately after changing cell may sometimes cause CTD. This is especially true when you have a heavy area loading. To fix this problem, delay the deletion. Introduce a time delay ( I personally find the 1.5seconds to be OK so far ). Here's how the object script will looks like now.
if ( player->CellChanged == 1 ) Startscript, "Create_obj_script" ; this is the global script Disable set timer_flag to 1 endif if ( timer_flag == 1 ) set timer to ( timer + GetSecondsPassed ) if ( timer > 1.5 ) set obj_count to ( obj_count - 1 ) SetDelete, 1 else return ; stop all other code processing endif endif
That is not all. If you plan to move your object at very high speed. There is a possibility that the object may encounter another cell change during the 1.5 seconds delay. You must make sure that the object gets deleted before it gets out of the processing parameter or it will come back and haunt you later. Now the script looks like this.
if ( player->CellChanged == 1 ) if ( timer_flag == 1 ) SetDelete, 1 return endif Startscript, "Create_obj_script" Disable set timer_flag to 1 endif if ( timer_flag == 1 ) set timer to ( timer + GetSecondsPassed ) if ( timer > 1.5 ) SetDelete, 1 else return endif endif
154
Collision detection
This is biggest headache of all. Objects will not collide with objects. Only character/NPC/creatures can collide with objects. In this term, objects means statics/activators and landmass. The only way to detect collision is when your character hit the object. That is why I mentioned earlier that if you select a big object to ride, you will see clipping until the moment your character hit something. If you can live with that, that's fine otherwise it looks pretty awkward. The simplest method to detect collision is to get your player coordinates and measure against the object coordinates ( the one you are riding on ). Although, this is not fully proven, using GetSquareRoot function in the object script can sometimes cause CTD. There are 2 planes that you need to take care of. For eg, the flying carpet uses detection for both vertical (z axis) and horizontal (x, y axis ) planes. You can refer to my script on how this is done. If somebody can come up with a better method, please do share it.
Savegame issue
If you have not realised already, when you save your game while in motion, the object coordinates updated in the your savegame are the ones during the cell changed. In order to position the object correctly, it is always best to keep a global parameters of the object coordinates. When you first load the game, do a detection on the object existing coordinates vs its global coordinates. If there is a big discrepancy, set the object to the global coordinates. In this way, when you first load the game, the object will be in precisely the same position when you save it.
155
You need to create all of the global vaiables before you can compile this script. The script is very fast, and the results very precise. The results will be available after one frame. (Extra thanks to JDGBOLT for sharing his script! By the way, this is the colored script output from MWEdit, see the tip on alternative editors.)
begin jdtrigscript ; by JDGBOLT ; edited and commented for MSFD by GhanBuriGhan ; simultaneous calculation of sine and cosine for three angles (e.g. three different axes) ; for intermediate results of sine and cosine float ax1 float ax2 float ay1 float ay2 ; main angle variable float angle ;temp storage for angle: float angle_source ;contains angle (loaded from global) float angle_temp float angle_temp2 short angleshort ; short variable to take up angle - for tab values float angledec ; for decimal portion of angle short anglequad ;quadrant float axfinal ; for final result sine float ayfinal ; for final result cosine float angconvx1 ; for calculating decimal portion of sine and cosine float angconvy1 float angconvx2 float angconvy2 short objnum ;counter to calculate all three angles ;-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ while ( objnum <= 3 ) ; this script calculates sine and cosine for all three axis in one frame ;exporting results: if ( objnum == 1 ) set Z_sin to axfinal ; assign to global var. Z_sin to free axfinal for next axis set Z_cos to ayfinal ; ditto endif if ( objnum == 2 )
156
endif if ( objnum == 3 ) set Y_sin to axfinal ;ditto set Y_cos to ayfinal ;ditto ;MessageBox "sine of Z: %.3f cosine of Z: %.3f", Z_sin, Z_cos ;MessageBox "sine of X: %.3f cosine of X: %.3f", X_sin, X_cos ;MessageBox "sine of Y: %.3f cosine of Y: %.3f", Y_sin, Y_cos Set objnum to 0 StopScript jdtrigscript Return endif ;-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ set objnum to ( objnum + 1 ) ;count up to do all three angles one by one ;-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ ; obtain the angles from global variables. if ( objnum == 1 ) set angle_source to Z_input_angle endif if ( objnum == 2 ) set angle_source to X_input_angle endif if ( objnum == 3 ) set angle_source to Y_input_angle endif ;GetAngle returns values from -180 to +180, so we need to compensate for calculation to get ;values from 0 to 360C: if ( angle_source < 0 ) set angle_source to ( 360 + angle_source ) endif set angle to angle_source ;-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ ;determine quadrant. This way we need to calculate sine and cosine only for 0-90 if ( angle <= 90 ) set angle_temp2 to angle set anglequad to 1 elseif ( angle <= 180 ) set angle_temp2 to ( 180 - angle ) set anglequad to 2 elseif ( angle <= 270 ) set angle_temp2 to ( angle - 180 ) set anglequad to 3 elseif ( angle <= 360 ) set angle_temp2 to ( 360 - angle ) set anglequad to 4 endif ; obtain the decimal part of the angle set angleshort to angle_temp2 set angledec to ( angle_temp2 - angleshort ) ; the difference between the float and the short is the decimal part set angle_temp to angleshort ;-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ ; These are pre-calcualted values for sine and cosine: if ( angle_temp <= 10 ) ; angles arranged in chunks of 10 for speed (and if block limits?) if ( angle_temp == 0 ) set ax1 to 0.000000 ; sine set ay1 to 1.000000 ;cosine set ax2 to 0.017452 ; sine of angletemp+1 set ay2 to 0.999847 ;cosine of angletemp+1 elseif ( angle_temp == 1 ) set ax1 to 0.017452 set ay1 to 0.999847 set ax2 to 0.034899 set ay2 to 0.999390 elseif ( angle_temp == 2 ) set ax1 to 0.034899 set ay1 to 0.999390 set ax2 to 0.052333 set ay2 to 0.998629 elseif ( angle_temp == 3 ) set ax1 to 0.052333 set ay1 to 0.998629 set ax2 to 0.069756
157
set ay2 to 0.997564 elseif ( angle_temp == 4 ) set ax1 to 0.069756 set ay1 to 0.997564 set ax2 to 0.087155 set ay2 to 0.996194 elseif ( angle_temp == 5 ) set ax1 to 0.087155 set ay1 to 0.996194 set ax2 to 0.104528 set ay2 to 0.994521 elseif ( angle_temp == 6 ) set ax1 to 0.104528 set ay1 to 0.994521 set ax2 to 0.121869 set ay2 to 0.992546 elseif ( angle_temp == 7 ) set ax1 to 0.121869 set ay1 to 0.992546 set ax2 to 0.139173 set ay2 to 0.990268 elseif ( angle_temp == 8 ) set ax1 to 0.139173 set ay1 to 0.990268 set ax2 to 0.156434 set ay2 to 0.987688 elseif ( angle_temp == 9 ) set ax1 to 0.156434 set ay1 to 0.987688 set ax2 to 0.173648 set ay2 to 0.984807 elseif ( angle_temp == 10 ) set ax1 to 0.173648 set ay1 to 0.984807 set ax2 to 0.190808 set ay2 to 0.981627 endif elseif ( angle_temp <= 20 ) ; and so on if ( angle == 11 ) set ax1 to 0.190808 set ay1 to 0.981627 set ax2 to 0.207911 set ay2 to 0.978147 elseif ( angle_temp == 12 ) set ax1 to 0.207911 set ay1 to 0.978147 set ax2 to 0.224951 set ay2 to 0.974370 elseif ( angle_temp == 13 ) set ax1 to 0.224951 set ay1 to 0.974370 set ax2 to 0.241921 set ay2 to 0.970295 elseif ( angle_temp == 14 ) set ax1 to 0.241921 set ay1 to 0.970295 set ax2 to 0.258819 set ay2 to 0.965925 elseif ( angle_temp == 15 ) set ax1 to 0.258819 set ay1 to 0.965925 set ax2 to 0.275637 set ay2 to 0.961261 elseif ( angle_temp == 16 ) set ax1 to 0.275637 set ay1 to 0.961261 set ax2 to 0.292371 set ay2 to 0.956304 elseif ( angle_temp == 17 ) set ax1 to 0.292371 set ay1 to 0.956304 set ax2 to 0.309016 set ay2 to 0.951056 elseif ( angle_temp == 18 ) set ax1 to 0.309016 set ay1 to 0.951056 set ax2 to 0.325568
158
set ay2 to 0.945518 elseif ( angle_temp == 19 ) set ax1 to 0.325568 set ay1 to 0.945518 set ax2 to 0.342020 set ay2 to 0.939692 elseif ( angle_temp == 20 ) set ax1 to 0.342020 set ay1 to 0.939692 set ax2 to 0.358367 set ay2 to 0.933580 endif elseif ( angle_temp <= 30 ) if ( angle_temp == 21 ) set ax1 to 0.358367 set ay1 to 0.933580 set ax2 to 0.374606 set ay2 to 0.927183 elseif ( angle_temp == 22 ) set ax1 to 0.374606 set ay1 to 0.927183 set ax2 to 0.390731 set ay2 to 0.920504 elseif ( angle_temp == 23 ) set ax1 to 0.390731 set ay1 to 0.920504 set ax2 to 0.406736 set ay2 to 0.913545 elseif ( angle_temp == 24 ) set ax1 to 0.406736 set ay1 to 0.913545 set ax2 to 0.422618 set ay2 to 0.906307 elseif ( angle_temp == 25 ) set ax1 to 0.422618 set ay1 to 0.906307 set ax2 to 0.438371 set ay2 to 0.898794 elseif ( angle_temp == 26 ) set ax1 to 0.438371 set ay1 to 0.898794 set ax2 to 0.453990 set ay2 to 0.891006 elseif ( angle_temp == 27 ) set ax1 to 0.453990 set ay1 to 0.891006 set ax2 to 0.469471 set ay2 to 0.882947 elseif ( angle_temp == 28 ) set ax1 to 0.469471 set ay1 to 0.882947 set ax2 to 0.484809 set ay2 to 0.874619 elseif ( angle_temp == 29 ) set ax1 to 0.484809 set ay1 to 0.874619 set ax2 to 0.500000 set ay2 to 0.866025 elseif ( angle_temp == 30 ) set ax1 to 0.500000 set ay1 to 0.866025 set ax2 to 0.515038 set ay2 to 0.857167 endif elseif ( angle_temp <= 40 ) if ( angle_temp == 31 ) set ax1 to 0.515038 set ay1 to 0.857167 set ax2 to 0.529919 set ay2 to 0.848048 elseif ( angle_temp == 32 ) set ax1 to 0.529919 set ay1 to 0.848048 set ax2 to 0.544639 set ay2 to 0.838670 elseif ( angle_temp == 33 ) set ax1 to 0.544639
159
set ay1 to 0.838670 set ax2 to 0.559192 set ay2 to 0.829037 elseif ( angle_temp == 34 ) set ax1 to 0.559192 set ay1 to 0.829037 set ax2 to 0.573576 set ay2 to 0.819152 elseif ( angle_temp == 35 ) set ax1 to 0.573576 set ay1 to 0.819152 set ax2 to 0.587785 set ay2 to 0.809016 elseif ( angle_temp == 36 ) set ax1 to 0.587785 set ay1 to 0.809016 set ax2 to 0.601815 set ay2 to 0.798635 elseif ( angle_temp == 37 ) set ax1 to 0.601815 set ay1 to 0.798635 set ax2 to 0.615661 set ay2 to 0.788010 elseif ( angle_temp == 38 ) set ax1 to 0.615661 set ay1 to 0.788010 set ax2 to 0.629320 set ay2 to 0.777145 elseif ( angle_temp == 39 ) set ax1 to 0.629320 set ay1 to 0.777145 set ax2 to 0.642787 set ay2 to 0.766044 elseif ( angle_temp == 40 ) set ax1 to 0.642787 set ay1 to 0.766044 set ax2 to 0.656059 set ay2 to 0.754709 endif elseif ( angle_temp <= 50 ) if ( angle_temp == 41 ) set ax1 to 0.656059 set ay1 to 0.754709 set ax2 to 0.669130 set ay2 to 0.743144 elseif ( angle_temp == 42 ) set ax1 to 0.669130 set ay1 to 0.743144 set ax2 to 0.681998 set ay2 to 0.731353 elseif ( angle_temp == 43 ) set ax1 to 0.681998 set ay1 to 0.731353 set ax2 to 0.694658 set ay2 to 0.719339 elseif ( angle_temp == 44 ) set ax1 to 0.694658 set ay1 to 0.719339 set ax2 to 0.707106 set ay2 to 0.707106 elseif ( angle_temp == 45 ) set ax1 to 0.707106 set ay1 to 0.707106 set ax2 to 0.719339 set ay2 to 0.694658 elseif ( angle_temp == 46 ) set ax1 to 0.719339 set ay1 to 0.694658 set ax2 to 0.731353 set ay2 to 0.681998 elseif ( angle_temp == 47 ) set ax1 to 0.731353 set ay1 to 0.681998 set ax2 to 0.743144 set ay2 to 0.669130 elseif ( angle_temp == 48 ) set ax1 to 0.743144
160
set ay1 to 0.669130 set ax2 to 0.754709 set ay2 to 0.656059 elseif ( angle_temp == 49 ) set ax1 to 0.754709 set ay1 to 0.656059 set ax2 to 0.766044 set ay2 to 0.642787 elseif ( angle_temp == 50 ) set ax1 to 0.766044 set ay1 to 0.642787 set ax2 to 0.777145 set ay2 to 0.629320 endif elseif ( angle_temp <= 60 ) if ( angle == 51 ) set ax1 to 0.777145 set ay1 to 0.629320 set ax2 to 0.788010 set ay2 to 0.615661 elseif ( angle_temp == 52 ) set ax1 to 0.788010 set ay1 to 0.615661 set ax2 to 0.798635 set ay2 to 0.601815 elseif ( angle_temp == 53 ) set ax1 to 0.798635 set ay1 to 0.601815 set ax2 to 0.809016 set ay2 to 0.587785 elseif ( angle_temp == 54 ) set ax1 to 0.809016 set ay1 to 0.587785 set ax2 to 0.819152 set ay2 to 0.573576 elseif ( angle_temp == 55 ) set ax1 to 0.819152 set ay1 to 0.573576 set ax2 to 0.829037 set ay2 to 0.559192 elseif ( angle_temp == 56 ) set ax1 to 0.829037 set ay1 to 0.559192 set ax2 to 0.838670 set ay2 to 0.544639 elseif ( angle_temp == 57 ) set ax1 to 0.838670 set ay1 to 0.544639 set ax2 to 0.848048 set ay2 to 0.529919 elseif ( angle_temp == 58 ) set ax1 to 0.848048 set ay1 to 0.529919 set ax2 to 0.857167 set ay2 to 0.515038 elseif ( angle_temp == 59 ) set ax1 to 0.857167 set ay1 to 0.515038 set ax2 to 0.866025 set ay2 to 0.500000 elseif ( angle_temp == 60 ) set ax1 to 0.866025 set ay1 to 0.500000 set ax2 to 0.874619 set ay2 to 0.484809 endif elseif ( angle_temp <= 70 ) if ( angle_temp == 61 ) set ax1 to 0.874619 set ay1 to 0.484809 set ax2 to 0.882947 set ay2 to 0.469471 elseif ( angle_temp == 62 ) set ax1 to 0.882947 set ay1 to 0.469471 set ax2 to 0.891006 set ay2 to 0.453990
161
elseif ( angle_temp == 63 ) set ax1 to 0.891006 set ay1 to 0.453990 set ax2 to 0.898794 set ay2 to 0.438371 elseif ( angle_temp == 64 ) set ax1 to 0.898794 set ay1 to 0.438371 set ax2 to 0.906307 set ay2 to 0.422618 elseif ( angle_temp == 65 ) set ax1 to 0.906307 set ay1 to 0.422618 set ax2 to 0.913545 set ay2 to 0.406736 elseif ( angle_temp == 66 ) set ax1 to 0.913545 set ay1 to 0.406736 set ax2 to 0.920504 set ay2 to 0.390731 elseif ( angle_temp == 67 ) set ax1 to 0.920504 set ay1 to 0.390731 set ax2 to 0.927183 set ay2 to 0.374606 elseif ( angle_temp == 68 ) set ax1 to 0.927183 set ay1 to 0.374606 set ax2 to 0.933580 set ay2 to 0.358367 elseif ( angle_temp == 69 ) set ax1 to 0.933580 set ay1 to 0.358367 set ax2 to 0.939692 set ay2 to 0.342020 elseif ( angle_temp == 70 ) set ax1 to 0.939692 set ay1 to 0.342020 set ax2 to 0.945518 set ay2 to 0.325568 endif elseif ( angle_temp <= 80 ) if ( angle_temp == 71 ) set ax1 to 0.945518 set ay1 to 0.325568 set ax2 to 0.951056 set ay2 to 0.309016 elseif ( angle_temp == 72 ) set ax1 to 0.951056 set ay1 to 0.309016 set ax2 to 0.956304 set ay2 to 0.292371 elseif ( angle_temp == 73 ) set ax1 to 0.956304 set ay1 to 0.292371 set ax2 to 0.961261 set ay2 to 0.275637 elseif ( angle_temp == 74 ) set ax1 to 0.961261 set ay1 to 0.275637 set ax2 to 0.965925 set ay2 to 0.258819 elseif ( angle_temp == 75 ) set ax1 to 0.965925 set ay1 to 0.258819 set ax2 to 0.970295 set ay2 to 0.241921 elseif ( angle_temp == 76 ) set ax1 to 0.970295 set ay1 to 0.241921 set ax2 to 0.974370 set ay2 to 0.224951 elseif ( angle_temp == 77 ) set ax1 to 0.974370 set ay1 to 0.224951 set ax2 to 0.978147 set ay2 to 0.207911
162
elseif ( angle_temp == 78 ) set ax1 to 0.978147 set ay1 to 0.207911 set ax2 to 0.981627 set ay2 to 0.190808 elseif ( angle_temp == 79 ) set ax1 to 0.981627 set ay1 to 0.190808 set ax2 to 0.984807 set ay2 to 0.173648 elseif ( angle_temp == 80 ) set ax1 to 0.984807 set ay1 to 0.173648 set ax2 to 0.987688 set ay2 to 0.156434 endif elseif ( angle_temp <= 90 ) if ( angle_temp == 81 ) set ax1 to 0.987688 set ay1 to 0.156434 set ax2 to 0.990268 set ay2 to 0.139173 elseif ( angle_temp == 82 ) set ax1 to 0.990268 set ay1 to 0.139173 set ax2 to 0.992546 set ay2 to 0.121869 elseif ( angle_temp == 83 ) set ax1 to 0.992546 set ay1 to 0.121869 set ax2 to 0.994521 set ay2 to 0.104528 elseif ( angle_temp == 84 ) set ax1 to 0.994521 set ay1 to 0.104528 set ax2 to 0.996194 set ay2 to 0.087155 elseif ( angle_temp == 85 ) set ax1 to 0.996194 set ay1 to 0.087155 set ax2 to 0.997564 set ay2 to 0.069756 elseif ( angle_temp == 86 ) set ax1 to 0.997564 set ay1 to 0.069756 set ax2 to 0.998629 set ay2 to 0.052335 elseif ( angle_temp == 87 ) set ax1 to 0.998629 set ay1 to 0.052335 set ax2 to 0.999390 set ay2 to 0.034899 elseif ( angle_temp == 88 ) set ax1 to 0.999390 set ay1 to 0.034899 set ax2 to 0.999847 set ay2 to 0.017452 elseif ( angle_temp == 89 ) set ax1 to 0.999847 set ay1 to 0.017452 set ax2 to 1.000000 set ay2 to 0.000000 elseif ( angle_temp == 90 ) set ax1 to 1.000000 set ay1 to 0.000000 set ax2 to 0.999847 set ay2 to 0.017452 endif endif ;Use simple linear extrapolation to approximate a decimal value for sine and cosine: set angconvx1 to ( ax2 - ax1 ) ; calculate distance sin(angle) and sin(angle+1) set angconvy1 to ( ay2 - ay1 ) ; same for cos set angconvx2 to ( angconvx1 * angledec ) ;calculate a fraction by the decimal residue set angconvy2 to ( angconvy1 * angledec ) ; same for cos set axfinal to ( ax1 + angconvx2 ) ; set final result to result + fraction set ayfinal to ( ay1 + angconvy2 ) ; set final result to result + fraction
163
;correct for quadrant: if ( anglequad == 1 ) set axfinal to ( axfinal * 1 ) ; holds final sine set ayfinal to ( ayfinal * 1 ) ; holds final cosine elseif ( anglequad == 2 ) set axfinal to ( axfinal * 1 ) ; holds final sine set ayfinal to ( ayfinal * -1 ) ; holds final cosine elseif ( anglequad == 3 ) set axfinal to ( axfinal * -1 ) ; holds final sine set ayfinal to ( ayfinal * -1 ) ; holds final cosine elseif ( anglequad == 4 ) set axfinal to ( axfinal * -1 ) ; holds final sine set ayfinal to ( ayfinal * 1 ) ; holds final cosine endif endwhile ; loop for all three axis ;-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ end jdtrigscript
164
Mannequins
These are popular with many people as they are a nice way to show off your collected armor you find them in many house mods this shows how it is done (many thanks to Stephen Kent aka Riiak Shi Nal for sharing the script). This example is a "next generation" one that uses Tribunal functions for checking weapon/armor to prevent PC from moving mannequin while weapons (Riiak has not yet figured out how to get mannequins to wield weapons) and/or armor are present on mannequin. Also split into two separate scripts to support both male and female versions of the mannequin. These changes do not prevent PC from picking up the mannequin while there are still misc items on it, those items will be lost. I have added some extra comments in addition to Riiak's. The Mannequin is in reality a normal NPC with 0 health or corpse (health set to 0 in TES CS). For this version you simply activate it to give it items, and it will equip armor you give it.
Begin rsn_mannequin_f_script short short short short float button questionState nEquipType nStillEquipped fDeleteTimer
SkipAnim ;GBG: This is essential, it makes the Mannequin, which is an NPC, stand still if ( menumode == 1 ) return endif if ( GetDisabled == 1 ) ; if mannequin has been disabled then we need to wait some time then delete this reference Set fDeleteTimer to ( fDeleteTimer + GetSecondsPassed ) if ( fDeleteTimer > 5 ) SetDelete 1 endif return endif if ( OnActivate == 0 ) if ( questionState == 0 ) return endif endif if ( questionState == 0 ) MessageBox, "Armor Mannequin", "Move Mannequin", "Add/Remove Armor" set questionState to 1 endif if ( questionState == 1 ) set button to GetButtonPressed if ( button == 0 ) set questionState to 10 elseif ( button == 1 ) set questionState to 0 Activate endif endif if ( questionState == 10 ) ; This section is split into two groups of nested ifs because of nested if limits of ; the scripting language. Set nStillEquipped to 0 ; Here we check to see if a weapon is equipped (put in mainly for if anyone can figure ; out how to get a mannequin to show a weapon) Set nEquipType to ( GetWeaponType ) if ( nEquipType == -1 ) ; Here we check to see if any armor is equipped (NOTE: there are 10 different possible ; pieces of armor so we need to check each individually) Set nEquipType to ( GetArmorType 0 )
165
if ( nEquipType == -1 ) Set nEquipType to ( GetArmorType 1 ) if ( nEquipType == -1 ) Set nEquipType to ( GetArmorType 2 ) if ( nEquipType == -1 ) Set nEquipType to ( GetArmorType 3 ) if ( nEquipType == -1 ) Set nEquipType to ( GetArmorType 4 ) if ( nEquipType == -1 ) Set nEquipType to ( GetArmorType 5 ) if ( nEquipType != -1 ) Set nStillEquipped to 1 ;GBG: Set to 1 if there is still some armor equipped endif else Set nStillEquipped to 1 endif else Set nStillEquipped to 1 endif else Set nStillEquipped to 1 endif else Set nStillEquipped to 1 endif else Set nStillEquipped to 1 endif else Set nStillEquipped to 1 endif if ( nStillEquipped != 1 ) ;We only want to process if we haven't found any equipment. Set nEquipType to ( GetArmorType 6 ) if ( nEquipType == -1 ) Set nEquipType to ( GetArmorType 7 ) if ( nEquipType == -1 ) Set nEquipType to ( GetArmorType 8 ) if ( nEquipType == -1 ) Set nEquipType to ( GetArmorType 9 ) if ( nEquipType == -1 ) Set nEquipType to ( GetArmorType 10 ) If ( nEquipType == -1 ) ;Only show this question if the mannequin doesn't have weapons or armor equipped. MessageBox "Did you remove all items from the mannequin?", "Yes", "No" else Set nStillEquipped to 1 endif else Set nStillEquipped to 1 endif else Set nStillEquipped to 1 endif else Set nStillEquipped to 1 endif else Set nStillEquipped to 1 endif endif ; Now we need to go to the next stage of processing (either wait for user choice or immediately activate) set questionState to 20 endif if ( questionState == 20 ) if ( nStillEquipped != 1 ) set button to GetButtonPressed else ; Mannequin still has weapons or armor equipped so we want activate it and warn ; the user instead of allowing pick-up. MessageBox "You haven't removed your equipment." Set button to 1 ;says that there are still items on the Mannequin endif if ( button == 0 )
166
set questionState to 0 Disable the current mannequin and create a new one we wouldn't have to worry about losing items) GBG: if Mannequins are transported a lot a SetDelete function might be a good idea Disable ; This is the item that contains the script ; to generate a new mannequin when dropped. ; GBG: for a "female" mannequin this would be a different item player->addItem, "_rsn_man_f_holder", 1 playSound "Item Misc Up" elseif ( button == 1 ) ; There are still items on the mannequin (either from checks or user response) set questionState to 0 Activate endif endif ; ; ; ; end
The following script goes on the item thats added to our inventory when we move the mannequin. When you drop it, a new mannequin is created at your feet, hence the necessary removal of armor. You will lose it all otherwise:
; Script split into two scripts to handle the two different mannequin genders. Begin rsn_man_f_holder_script short OnPCDrop float fDeleteTimer if ( GetDisabled == 1 ) ; if holder has been disabled then we need to wait some time then delete this reference Set fDeleteTimer to ( fDeleteTimer + GetSecondsPassed ) if ( fDeleteTimer > 5 ) SetDelete 1 endif return endif if ( OnPCDrop == 1 ) Disable ; This is the NPC with 0 health that is really just a standing corpse. PlaceAtPC, "_rsn_mannequin_female", 1, 0, 0 Set OnPCDrop to 0 endif end
167
short sPCLookAtMe set sPCLookAtMe to 1 ;you could probably also add a GetLOS check in here ; however i could never get GetLOS to work properly...although i didn't try very hard ;is PC really far away if ( GetDistance, Player > 8000 ) set sPCLookAtMe to 0 else ;yay trigonometry ;this basically does a rough calculation of the PCs direction relative ;to the Actor, it only uses 45 degree chunks, though set fPCX to ( player->GetPos, X ) set fPCY to ( player->GetPos, Y ) set fPCAngle to ( player->GetAngle, Z ) set fdx to GetPos, X set fdy to GetPos, Y set fdx to ( fdx - fPCX ) set fdy to ( fdy - fPCY ) set fRatio to ( fdx / fdy ) if ( fdx > 0 ) if ( fdy > 0 ) if ( fRatio > 1 ) if ( fPCAngle < -45 ) set sPCLookAtMe to 0 endif else if ( fPCAngle < -90 ) set sPCLookAtMe to 0 endif if ( fPCAngle > 135 ) set sPCLookAtMe to 0 endif endif else if ( fRatio < -1 ) if ( fPCAngle < 0 ) if ( fPCAngle > -135 ) set sPCLookAtMe to 0 endif endif else if ( fPCAngle < 45 ) if ( fPCAngle > -90 ) set sPCLookAtMe to 0 endif endif endif endif else
168
if ( fdy > 0 ) if ( fRatio < -1 ) if ( fPCAngle > 45 ) set sPCLookAtMe to 0 endif else if ( fPCAngle > 90 ) set sPCLookAtMe to 0 endif if ( fPCAngle < -135 ) set sPCLookAtMe to 0 endif endif else if ( fRatio > 1 ) if ( fPCAngle > 0 ) if ( fPCAngle < 135 ) set sPCLookAtMe to 0 endif endif else if ( fPCAngle > -35 ) if ( fPCAngle < 90 ) set sPCLookAtMe to 0 endif endif endif endif endif endif if ( sPCLookAtMe == 0 ) ;do something while the PC is not looking endif End
169
Cinematic sequence
The following is a very smart approach to do a cinematic sequence by gianluca (Morrowind Summit forums). It removes player control, places the player on an invisible "CollisionWall" object and then moves him (and thus the camera) around. You can't have cinematic sequences involving the PC, but it's still great.
If menumode==1 return endif if doOnce==0 "Collision wall2"->disable "Collision wall3"->disable "Collision wall4"->disable set doOnce to 1 endif if doOnce==1 "Collision wall1"->moveworld X 800 messagebox "moving" if ( "Player"->getPos Z < 570 ) set doOnce to 2 set playxx to "Player"->getPos X set playyy to "Player"->getPos Y set playzz to "Player"->getPos Z "Collision wall2"->enable "Player"->position 114679 4119 590 90 endif endif if doOnce==2 "Collision wall2"->moveworld X 800 messagebox "moving" if ( "Player"->getPos Z < 570 ) set playxx to "Player"->getPos X set playyy to "Player"->getPos Y set playzz to "Player"->getPos Z "Collision wall3"->enable Player->position 112634 4119 590 90 set doOnce to 3 endif endif if doOnce==3 "Collision wall3"->moveworld X 200 "Collision wall3"->moveworld Y 800 if ( "Player"->getPos Z < 570 ) set doOnce to 4 set playxx to "Player"->getPos X set playyy to "Player"->getPos Y set playzz to "Player"->getPos Z "Collision Wall4"->enable Player"->position 112126 6150 590 90 endif endif if doOnce==4 "Collision wall4"->moveworld X 600 "Collision wall4"->moveworld Y 450 if ( "Player"->getPos Z < 570 ) set doOnce to 5 set playxx to "Player"->getPos X set playyy to "Player"->getPos Y set playzz to "Player"->getPos Z endif endif if doOnce==5 stopscript ELDQ_visualforbattle endif end ELDQ_visualforbattle
170
Troubleshooting
General hints
A good way to debug is to insert MessageBox commands at key points in your script. If you produce error messages and can't find the cause, try to remove suspect lines of codes one by one (using ; to mark them as comments) to pinpoint the error causing line. Pay attention to the error codes that the editor and the game give you, they usually let you pinpoint the source of the problem to some degree
The Console
Using the Console to check variables:
In the game you can use the console to check on the state of variables. Bring up the console window (standard key is ~ or whatever key is left of the "1" key if you are using a non-US keyboard layout) and type "sv" this lists all the global variables with their values. Now find an object that has a script running on it. Bring up the console again, left click on the object the console window title will change. Type "sv" again now the local variables for the script running on this object will be listed. To check global variables not displayed by "sv", use "show var_name"
This will drop the item into your inventory To go to a specific location use
coc "cell_name" coe 1,-7
for exterior cells (write down the cell coordinates in the editor) coc works for exterior cells too but since most exterior cells have non-unique names you may not land quite where you want. It can still be useful though, for example coc balmora will take you somewhere in Balmora.
tcl
Toggles collision float through walls, visit difficult to reach places easily.
Tgm
Toggle God mode test without worrying about some monster killing you. Also, the invaluable console commands to run the game in "debug" mode allow one to view hard numbers about spell effects, chances to hit, etc (thanks to Wakim). Some of these are: 1) press the "~" key to call up the console. 2) type "tcs" into the console and hit return. 3) click (right or left click, can't recall) anywhere on the screen outside of the console box to continue game time while leaving the box displayed and active. That's it. There are other variants on the "tcs" command, such as (but not limited to) "tks" and "tms" which all stand for "toggle xxxxxx statistics" where xxxxx is: c = combat, m = magic, k = kill, or what have you. 171
Does not exist. When you write a script and then create a new object to be thus referenced you will also get this error. Close the editor window and reopen it to register the object with the compiler. Another syntax error, indicating you have used an undefined variable, function or a nonexistent object.
"Script command "foofunc" not found on line 3" "Could not find variable or function "Foobject""
A command / function was not recognized by the compiler. Usually results from typos. Indicates that the compiler did not find the End command. This error can also appear when a previous error disrupts the compilation process.
"Syntax error Line 20. Miss matched paranthesis" "You need to end a script with script End scriptname"
Indicates that you do not close all parantheses you opened or vice versa.
"You need to enter a value on line 20"
You have not supplied all the arguments needed by a specific function.
Followed by
This error indicates that Variables are not declared. Most often this happens with game variables that are almost used like functions, e.g. PCEquip. EXPRESSION in general appears mostly when variables have not been declared in the script. this error seems to come up when you have accidentally declared a Function as a variable. The following lines e.g. would produce this error:
short ScriptRunning if (ScriptRunning "MyScript" == 1 )
"RightEval ..."
"LeftEval"
172
Both of the above can also be caused by not having spaces at the proper places. Always leave a space between parantheses and function calls, variables etc. If ( OnActivate == 1 ), not if (OnActivate==1). This only causes errors very rarely, but it sometimes does, trust me.
"Infix to Postfix" error
Usually indicates bad syntax. Can be caused by bad set commands using the "fix" arrow:
set somevar to ActorID->GetHealth
an alternative is again a forgotten variable declaration of variable type functions, e.g. of OnPCEquip, etc. (Thanks Horatio and Ragnar_GD) AITravel command does not work A common cause is coordinates erroneously set too far away (e.g. by omitting a "-" or having a digit too much in there). I once had a very nasty one of having typed two "-" which looked like one just slightly longer than usual "-" in the editor.
Doubled NPCs Doubling of NPCs and other objects seems to happen occasionally when a new version of a plugin overwrites an old one, and the savegame info is also kept, leading to a clone of the NPC, even if you only changed his script. Try to load the plugin in a cell away from the NPC. Seems to be avoided by keeping the mod filename identical, apparently savegames save filename information with NPCs in savegames (thanks Raptormeat). For much more information on doubling and what to do to avoid it go to Shadowsongs excellent webpage on this issue: http://www.angelfire.com/clone2/shadowsong/index.html Crash to desktop when executing the script There are unfortunately a great number of possible causes. Many are connected with not having "do once" conditions (e.g. calling certain functions every frame). Other known problems: Removing objects with running scripts from within their own script. Using Equip on anything but potions (fixed with Tribunal). Casting targeted spells from an activator (fixed with Tribunal). Using AIActivate on teleport doors that lead outside of the active cell. Trying to use PlaceItem with the same Object ID the script is running on. Using SetDelete on a nondisabled object. Crash to Desktop (CTD) upon loading the plugin One reported reason is overlong calculations: there appears to be an issue with very long additions (e.g. adding up more than 20 variables in one line of code) that causes a mod to CTD upon loading. If this happens, split the calculations to several lines.
173
Appendix
New functions that come with TRIBUNAL
The Tribunal expansion for Morrowind introduced a number of new functions and fixes and extends several of the old ones. Note that both you and the user of the mod must have Tribunal (or Bloodmoon, or GOTY edition) installed to make use of these, so make sure you mark your mod accordingly. The functions are now sorted into the main document, but this list may serve as an easy reference to see which functions are Tribunal functions. (many thanks to Bethsofts Mike Lipari for sharing the information on these functions with the community)
175
Also be aware that most console commands can be compiled as functions by the Construction Set (see list below). These are also to a large part not listed by the helpfile.
176
Variable-type functions:
For easy reference, the following list shows all those variable/function type hybrids that you need to declare as variables if you use them in a script.
(Tribunal)
Special Globals
Some globals hold special significance that you can take advantage of for your own scripting. Since they are globals, you do not need to declare them.
Short NPCVoiceDistance (750) Float GameHour Short Day Short Month Short Year (427) Float TimeScale (30) Short Random100 Short PCRace
Short PCWerewolf Float WerewolfClawMult (25.00) Short PCHasGoldDiscount Short PCHAsTurnIn Short PCHasCrimeGold Short CrimeGoldTurnIn CrimeGoldDiscount
Used as a distance when Following NPCs call after you to wait for them (e.g. see DandsaScript) Holds the current hour of the day (0-23) Holds the current day of the month (1-30) Holds the current Month of the year (0-11) Holds the current year Sets the ratio of real-time/game-time Is randomly set between 0-100 (set by main script) Contains the players Race (1=Agonian, 2=Breton, 3=Dark Elf, 4=High Elf, 5=Imperial, 6= Khajiit, 7=Nord, 8=Orc, 9=Redguard, 10=Woodelf) Vampire status: 0=Normal, 1=Vampire, -1= cured If the PC becomes a vampire, this indicates his clan. 1=Aundae, 2=Berne, 3=Quarra Tribunal: Contains the number of days since the game started. Reportedly Broken in Bloodmoon (JOG) (Forum info / JOG). Werewolf status: 0=Normal, 1=Werewolf, -1=Cured Increased during the Werewolf quests to make your claw attack more powerful. Used in dialogue. Gets set to 1 if player has enough gold to pay thieves guild discount on the "price on your head". Used in dialogue. Gets set to 1 if player has enough gold to pay the reduced fee for turning yourself in. Used in dialogue. Gets set to 1 if player has enough gold to pay the crime fee. Gold needed for reduced crime fee Gold needed for thieves guild discount crime fee
177
Game units:
1 game unit = 0.56 inches 50 =28 inches 500 = 23.3 feet 5000 = 233.3 feet 8192 = 385 feet = 1 game cell 1 game unit = 1.42 cm 100 game units = 142 cm = 1.42 meters 1000 game units = 14.2 meters 8192 game units = 116.33 meters = 1 exterior cell The island of Morrowind itself is 5.00 km north to south and 4.65 km east to west. (thanks to Iudas for this information)
178
179
Description
Places the PC in the named cell. Very useful for testing mods. Places the PC in the exterior cell grid.
CenterOnExterior, X, Y
CreateMaps "Filename.esp"
Creates map image file depending on the Create Maps Enable value in the Morrowind.INI file. If it is 1 (XBox), the file FILENAME.ESP.MAP is created in the DataFiles path with the map data (unknown format). If the value is 2 (Exterior Cell Maps) and you have created a directory /Maps/ in the main Morrowind game directory, this command will create a 256x256 high color bitmap of each exterior cell in the game. This command takes a long while even on fast computers as each cell in the game is loaded.
BC
FillJournal
* *
Beta Comment: Edit the morrowind.ini file to give a filename in the beta comment line: Beta Comment File=BetaComment.txt Then you can use the BC Command to make a note about an object in the game. You open the console and click something, then type your comment, like this: BC "Root not attached well." And in BetaComment.txt you get: 6/20/2004 (21:02) Morrowind.esm 5/8/2003 (21:07) Paul ex_t_root_03 Tel Vos (10,14) 85078 118468 4111 "Root not attached well." The time I made the comment, the file the object is from, the modification time of that file, my name (windows log-in I think), the cell, the X, Y and Z Position of the object, and of course, the comment (forum info / ManaUser). add all entries to journal, takes a long time show all the towns / uniquely named cells on the full map. Takes a few seconds. Not recommended for scripts. Jump 128 units away from where I am now. Good to get "unstuck" The faction ID's are not optional, works in Console window only. Not sure about the actual meaning of the output.
FillMap FixMe
MOTO ORI
This command changes the speed at which the PC actor (and presumably other actors) RUN. With MOTO active your walking and running speeds are the same, and the same animation will play for either walking or running.(IndigoRage) Lists info about the selected object, such as the cell it's in and the esm/esp file it originates from. Handy when identifying which mod added a certain item. Counts all objects in various categories. Output is written to the console window Counts all references in various categories. Output is written to the console window. "Purge textures" makes the engine reload all textures. If you play in windows mode you can use this to test textures in-game, while editing them in another application. Writes the value of the specified global variable to the console Lists global variables and variables in global scripts, or local variables if you click on an object with a local script first. Output to console. Stops the cell test, player remains in currently loaded cell Loads all cells in alphabetical order (On testing it seemed to be only interiors Not sure about difference to TestInteriorCells) Loads all interior cells in alphabetical order Loads all exterior cells in (random ?) order
PT Show global_var ShowVars StopCellTest TestCells TestInteriorCells TestThreadCells TestModels 180 SV SCT
T3D
ToggleAI
TA TB TCS
ToggleBorders ToggleCombatStats
Stops AI, including combat. Useful in testing a cell without being attacked by nasties Shows borders of exterior cells Allows you to monitor combat statistics in realtime. Enable this, the rightclik outside the console window to continue playing with the console window open. Note: When I tested, the output was also written to log.txt - not sure if this is by default. Turns collision on and off. Lets you float through walls. Can make Actors drop through floors,or float Shows the collision boxes of all models Outputs a matrix to the screen that probably indicates the current collision situation - I couldn't interpret it. Slows the game to a crawl Displays some debugging info on the screen: Players animation groups, speed, heading, position, FPS, delta movement per frame, and some I could not identify Outputs result of persuasion attempts (and maybe other dialogue results?) to the console Lets you see all of the local map Shows you ownership and script on mouseover while in console mode or in the info box during normal play. Also displays info on how the game fills leveled lists (upon entering a cell or opening a container) in the console. Makes you invulnerable. Displays the current cell's coordinates, and a grid of the currently loaded cells on screen, indicating the activities of morrowinds "thread loading" (caching of cells) When an actor is killed the name of the kill, the total number of kills, and (with Bloodmoon) werewolf kills, is displayed in the console Unknown, I did not get any effect or output from this. Unknown. From the name it would seem to refer to the screen fading in and out on loading of a game or teleporting, but I could not detect a differenc. Displays info on active spell effects in the console. Gives effect #, spell name, and statistical info Disables all menus (including the main save/load/options menu!). Menus stay invisible until console is brought up again (press console key twice). Not recommended for use in scripts - If the player uses the console, your script may end up disabling the menus completely! Presumably stops script processing Unknown, I did not get any effect or output from this. Activates all stat debugging modes (ToggleCombatStats, ToggleMagicStats, ToggleDialogueStats, ToggleKillStats) Switches the sky off. Also affects lighting, basically with switched off sky it's also "night". Unknown, I did not get any effect or output from this. Unknown, I did not get any effect or output from this. Stops the "world" and all objects from being rendered, just leaves the sky and water. Does not affect anything else, meaning collision, AI, etc. all remain active, just invisible Shows grid instead of full render Toggle AI path grid display Switches to vanity mode, player can not switch again until toggle is off. May be useful for cutscenes. "Show Animation" Shows status and animation info for the selected actor: Spell readied, weapon drawn, attacked, animation group Writes the selected Actors goup actual ID + reference number to the console window. For the player this is PlayerSaveGame "Show target group" Writes the ID + reference number of the selected actors "target" group (combat opponent) to the console window. Opens a new window that displays a hierarchical view of (I assume) the data structure of the currently rendered scene. Use TAB to get to the window. MW will remain unresponsive while the scene graph window is open.
ToggleCollision
ToggleFogOfWar
ToggleFullHelp
*
ToggleGodMode
TMS TM
ToggleMenus
ToggleSky
181
Game Settings
The following long table is a list of game settings. Listed here are all settings that have a numerical value. Not listed are string entries which are used to set many standard message texts, menu-texts, spell effect names, etc. But since they are fairly descriptive, they should be easy to figure out. Not so the numerical settings. Thanks to four forum members (maxpublic, Ldones, Wakim and Iudas), the meaning of many of the settings is now known and compiled into the list below. The list may still be a bit rough. I have not edited it thoroughly, but I am sure it will be interesting information for many modders. In many cases where you see Base and Mult game settings, the formula they're involved in is a standard linear equation in the form y = mx + b, where m is the mult, b is the base, and x is some attribute, skill, or other value. Note that the entry names begin with f or i (for floats and integers). The string entries begin with s (string). To my knowledge they can not be changed in-game, only in the TES-CS. Nr.
"465" "466" "467" "468" "469" "470" "471" "472" "947"
Name
Value
1.0000 3.0000 10.0000 7.0000 1000.0000 4000.0000 16000.000 0 10.0000 15.0000
Sets the general effectiveness of the repair skill of the character, via the armorer's hammer used Tells the game how many points of health are returned to the item when repaired Determines cost for repairing items (Whether calculated from Max Item Health or Item Cost, Im not sure) is the setting for the price you pay at an enchanter to enchant an item. Linear. Sets the cost of Silt Strider and boat travel (I think) Multiplies cost of Travel Unsure why the number is so high, but raising it raises the cost of Fast Travel Tells the game how much time elapses during this sort of travel Sets the cost of Guild Guide travel Iudas: Used to calculate whether a plant has any ingredients inside. Wakim: is compared to your alchemy skill to determine which of the effects of an ingredient you can see.
"949" "950"
"fMinWalkSpeed" "fMaxWalkSpeed"
100.0000 200.0000
"951" "952" "953" "954" "955" "956" "957" "958" "959" "960" "961" "962" "963"
"fMinWalkSpeedCreature" "fMaxWalkSpeedCreature" "fEncumberedMoveEffect" "fBaseRunMultiplier" "fAthleticsRunBonus" "fJumpAcrobaticsBase" "fJumpAcroMultiplier" "fJumpEncumbranceBase" "fJumpEncumbranceMultiplier" "fJumpRunMultiplier" "fJumpMoveBase" "fJumpMoveMult" "fSwimWalkBase"
5.0000 300.0000 0.3000 1.7500 1.0000 128.0000 4.0000 0.5000 1.0000 1.0000 0.5000 0.5000 0.5000
This is the minimum walking speed of the PC, regardless of stats, skills or encumbrance This is the maximum walking speed of the PC, regardless of stats, skills, or encumbrance The actual walking speed of NPCs (and the PC) is set by checking various fActors (Speed, Athletics, etc.) and assigning a value between fMinWalkSpeed and fMaxWalkSpeed based on that The two settings dictate the spectrum of Walk Speeds The same as for the PC, but if you badly encumber a creature it'll move veeerrry slowly. I've done this by accident. Same as above, they get faster, so they cover the speed spectrum more rapidly This sets how encumbrance affects walking and running speed, within the min/max limits set by other values. Exactly as it says. Changing the value will increase/decrease base running speed. Dictates how much faster Running is than the current Walk Speed Sets how Athletics affects running speed. Sets the base jumping distance for the PC. Sets the multiplier for Acrobatics, which is why you can leap over tall buildings when your Acro is high enough. Effects how greatly jumping ability is effected by Encumbrance, but Im unsure how Effects how greatly jumping ability is effected by Encumbrance, but Im unsure how UNSURE Presumably effects Jump Distance while running (it doesnt seem to effect height, but I could be wrong) Multiplies your walking speed to achieve the swimming speed at a 'walk' Base swim speed while walking
182
"964" "965" "966" "967" "968" "969" "970" "971" "972" "973"
"fSwimRunBase" "fSwimWalkAthleticsMult" "fSwimRunAthleticsMult" "fSwimHeightScale" "fHoldBreathTime" "fHoldBreathEndMult" "fSuffocationDamage" "fMinFlySpeed" "fMaxFlySpeed" "fStromWindSpeed"
0.5000 0.0200 0.1000 0.9000 20.0000 0.5000 3.0000 5.0000 300.0000 0.7000
"974" "975" "976" "977" "978" "979" "980" "981" "982" "983"
"fStromWalkMult" "fFallDamageDistanceMin" "fFallDistanceBase" "fFallDistanceMult" "fFallAcroBase" "fFallAcroMult" "iMaxActivateDist" "iMaxInfoDist" "fVanityDelay" "fMaxHeadTrackDistance"
0.2500 400.0000 0.0000 0.0700 0.2500 0.0100 192 192 30.0000 400.0000
"984" "985" "986" "987" "988" "989" "990" "991" "992" "993" "994" "995"
"fInteriorHeadTrackMult" "iHelmWeight" "iPauldronWeight" "iCuirassWeight" "iGauntletWeight" "iGreavesWeight" "iBootsWeight" "iShieldWeight" "fLightMaxMod" "fMedMaxMod" "fUnarmoredBase1" "fUnarmoredBase2"
Multiplies your running speed to achieve the swimming speed at a 'run'. Tells the game how Athletics affects 'walking' swimming speed. These low values keep you from flying through the water like you do on land when your Athletics is high. Same as above. Determines how close to the surface you have to be before the breathe indicator goes away The number of seconds your PC can hold her breath. base time that a character can remain underwater before incurring suffocation damage How Endurance affects the time you can hold your breath. I believe this is a flat-out multiplier to End, added as seconds to HoldBreathTime.<Doesn't seem to work.> The amount of health damage you take each second you suffocate Exactly as it says minimum flying speed. See above UNSURE - Determines altered walk speed during an ash or blight storm, but Im unsure how Might be a separate value from that entirely might determine speed of storm particles /sprites(Dust, etc.) Interesting (possibally related) note, while treading water in an ash storm, I noticed I was moving slightly. Determines altered walk speed during an ash or blight storm, but Im unsure how uses the getwindspeed to lower the PC movement speed during storms... The minimum distance you have to fall before you take damage. (Presumably in units) In game units each unit - .0.56 inches This will increase/decrease the distance needed to fall before you take damage. Higher you are the more damage you take when you hit Acrobatics skill increases the distance you can fall before you take damage. Has to do w/ how the Acrobatics skill effects Fall Distance and Damage, but unsure how Maximum distance for the player to be able to Activate an object - approx 9 feet Maximum distance for an Info message (object/NPC/creature name, etc.) to pop up in the Players view Seconds until VanityMode begins the camera starts circling the player if there is no input via mouse or keyboard. IIRC, this is the maximum distance an NPC or creature can be away from another NPC or creature and still trigger the 'head follow' routine you sometimes see. Put your PC in Balmora, let it go to Vanity View and you'll see your PC watch passing NPCs and 'follow' their movements for a certain amount of time. UNSURE something to do w/ the modifier for this in Interiors Do they track at half-distance in Interiors? These values are used to set what weights are used to determine whether a piece of armor is light, medium, or heavy. Altering a value alters these categories for *all* armor of that type *everywhere* in the game. Rather nice, actually; I used it in redux to set weight categories for all of my armor types across the board.
"996"
"iBaseArmorSkill"
30
These values are used in conjunction with armor weights to set the weight classes (Light, Medium, Heavy). These two values dictate the range of AR for characters going Unarmored, based on the Unarmored skill As they are, the settings produce a Maximum Unarmored AR of 65 (at 100 Unarmored skill), which you can see is some for of multiplication between the two settings Reversing the values produces the same effect , so it seems the values are interchangeable (unless I missed something could be wrong) - Changing one to 1.000 and the other to 0.0650 results in a max Unarmored AR of 650 The game multiplies the numbers and then multiplies the resulting number by 1000 to obtain the actual in-game Max Unarmored AR Doesnt seem to effect Min AR independently, only max - Progression of AR (from low skill to high skill) appears to be hard-coded. It has also been found that the Unarmored skill doesnt work at all UNLESS atleast one item of armor is worn. ( Forum Info / The other Felix ) The Skill Level where in-game armors reach their base (i.e. In-Editor) AR value Example: Glass Armor has a Base AR of 50 At Light Armor skill level 30 (as indicated above), it will read as having AR 50 in-game Before Skill Level 30, armors have diminished ARs from their Base Value, and after Skill Level 30, armors have higher ARs than their base until Skill Level reaches 100 I havent figured out the games scheme for determining the mult value yet UNSURE Presumably the amount that standing still increases the chance to block Your STR adds to the damage you do with weapons. This determines how much damage is added. Effects amount that Strength effects damage dealt in combat (Unsure of how this value relates to in-game effect) How much fatigue you lose while walking. However, this appears to let you jump very high without getting hurt (Bug? Forum Info / DinkumThinkum).
183
"1003" "1004" "1005" "1006" "1007" "1008" "1009" "1010" "1011" "1012" "1013" "1014" "1015" "1016" "1017" "1018" "1019" "1020" "1021" "1022" "1023" "1024" "1025" "1026" "1027" "1028" "1029" "1030" "1031" "1032" "1033"
"fFatigueMult" "fFatigueReturnBase" "fFatigueReturnMult" "fEndFatigueMult" "fFatigueAttackBase" "fFatigueAttackMult" "fWeaponFatigueMult" "fFatigueBlockBase" "fFatigueBlockMult" "fWeaponFatigueBlockMult" "fFatigueRunBase" "fFatigueRunMult" "fFatigueJumpBase" "fFatigueJumpMult" "fFatigueSwimWalkBase" "fFatigueSwimRunBase" "fFatigueSwimWalkMult" "fFatigueSwimRunMult" "fFatigueSneakBase" "fFatigueSneakMult" "fMinHandToHandMult" "fMaxHandToHandMult" "fHandtoHandHealthPer" "fCombatInvisoMult" "fCombatKODamageMult" "fCombatCriticalStrikeMult" "iBlockMinChance" "iBlockMaxChance" "fLevelUpHealthEndMult" "fSoulGemMult" "fEffectCostMult"
0.5000 2.5000 0.0200 0.0400 2.0000 0.0000 0.2500 4.0000 0.0000 1.0000 5.0000 2.0000 5.0000 0.0000 2.5000 7.0000 0.0000 0.0000 1.5000 1.5000 0.1000 0.5000 0.1000 0.2000 1.5000 4.0000 10 50 0.1000 3.0000 0.5000
1002 1022 All effect Fatigue in-game, obviously For separate actions, although not all of them actually have an effect in-game (Ive never been able to get spells to reduce fatigue) They seem pretty self-explanatory, but I havent tested them thoroughly Used to determine successful chance of casting if you are fatigued How much fatigue you regain per second. This is why you don't actually fatigue while walking. How much fatigue returns per second while walking How much fatigue you lose with every melee attack you make How much fatigue you lose blocking with a shield. This will increase the amount of fatigue lost when blocking with a shield. How much fatigue you lose running. This one appears to work with encumbrance,the more encumbered the more fatigue you lose/second How much fatigue you lose jumping. Modifier for fatigue loss How much fatigue you lose swimming at a 'walk' How much fatigue you lose swimming at a 'run'. Modifier for fatigue loss Modifier for fatigue loss The base level of fatigue loss while sneaking Multiplier to that base level
Reduce the chance to hit the PC when he is chameleoned or invisible This one appears to only work if you hit someone unawares while sneaking. I never got it to do anything else. 4x damage from a successful sneak attack works when chameleoned or invisible Minimum chance of blocking with a shield Maximum chance of blocking with a shield Multiplies current END to get hit points added at level-up. A soul gem's monetary value is multiplied by this value to determine the soul capacity of a soul gem. Creatures with a soul value less than or equal to that capacity can "fit" in the gem. The setting for all magicka costs for all spell effects. Changing this will change what all spells and enchantments cost. Everything. Linear change. Doubling this makes all spells cost twice as much magicka, all enchanted items cost twice as many charges.
"1034" "1035" "1036" "1037" "1038" "1039" "1040" "1041" "1042" "1043" "1044" "1045" "1046" "1047" "1048" "1049" "1050" "1051"
"fSpellPriceMult" "fFatigueSpellBase" "fFatigueSpellMult" "fFatigueSpellCostMult" "fPotionStrengthMult" "fPotionT1MagMult" "fPotionT1DurMult" "fPotionMinUsefulDuration" "fPotionT4BaseStrengthMult" "fPotionT4EquipStrengthMult" "fIngredientMult" "fMagicItemCostMult" "fMagicItemPriceMult" "fMagicItemOnceMult" "fMagicItemUsedMult" "fMagicItemStrikeMult" "fMagicItemConstantMult" "fEnchantmentMult"
2.0000 0.0000 0.0000 0.0000 0.5000 1.5000 0.5000 20.0000 20.0000 12.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 0.1000
is the setting for how much enchantment an item can hold based upon the value set in each individual item's property file. Linear, if an item in TESCS shows an enchantment value of 1200 (i.e. an exquisite ring) multiply it by fEnchantmentMult to get the actual enchantment you'll see in the make an enchanted item window. These affect the PC's chance of making an enchantment This sets the spell point multiplier for the PC with respect to INT (e.g., 1 x INT with this setting) This does the same thing for NPCs.
184
"1059" "1060" "1061" "1062" "1063" "1064" "1065" "1066" "1067" "1068" "1069" "1070" "1071"
"iAutoSpellAlterationMax" "iAutoSpellConjurationMax" "iAutoSpellDestructionMax" "iAutoSpellIllusionMax" "iAutoSpellMysticismMax" "iAutoSpellRestorationMax" "iAutoPCSpellMax" "iAutoRepFacMod" "iAutoRepLevMod" "iMagicItemChargeOnce" "iMagicItemChargeConst" "iMagicItemChargeUse" "iMagicItemChargeStrike"
5 2 5 5 5 5 100 2 0 1 10 5 10
A positive modification to relations you get with people who belong to the same faction You can apparently add rep points with each level-up. I've never tried it. 1068-1071 effect the amount of charges auto-calculated on magic items based on their function This value is the number of uses that the game will account for when calculating the max charges of a magic item (works universally, across the board with all ingame items 1068 is the setting for the number of charges an automatically calculated cast once effect enchanted item will have. Formula is BaseSpellEffectCost x iMagicItemChargeOnce. Linear. This way an item with a cast once effect will have exactly the number of charges needed to cast the effect upon it 1069 for const effect items 1070 is the setting for the multiplier for charges for automatically calculated cast when used effect enchanted items. See above for explanation. 1071 for "Cast on Strike" items (charges are calculated to account for X uses with this value as is) The time to respawn things like the Fighters Guild/Mages Guild chests, etc. How many months before a picked plant respawns ingredients. Chests in guilds respawn contents the same as any other chests. How many hours it takes before a non-persistent corpse disappears. How many hours it takes before a respawnable creature actually respawns (note that this doesn't seem to work properly). How many hours it takes before a trader resets it barter gold to its default value. A straight multiplier to STR to see how much a PC/NPC/creature can carry. Dictates amount that Lock pick difficulty raises according to Lock Level Lower the value here, the harder it gets Positive values make locks get easier with higher lock Levels Dictates difficulty of traps based on the spell cost of the spell assigned as trap Lower the value here, the harder it gets to disarm (again, based on spell cost of assigned trap) The values is multiplied by the spell cost of a trap and then added to your chance of disarming it. Since it's set to zero, the trap spell's cost is not incorporated into the chance. So basically it's also unused. This is the setting for the amount of charges restored to a charged magic item per second of game play. Linear. 0.05 x 20 seconds = 1 charge restored. If you barter with a merchant successfully, your disposition with that merchant increases by one and falls by 1 if you fail a barter attempt. How many skill points you need before you level up. How much each major skill is worth in points. E.g., if you set this to 2 then each point earned in a major skill counts as 2 skill points for leveling up. Same as above, but for minor skills. I *think* - not sure if I remember this correctly - but I think this works like the above, but for skills governed by your two primary attributes. So if your primary attributes are STR and AGI, and you set 1087 to 2, then any major skill governed by one of these attributes which goes up by a point counts as 2 points for purposes of leveling. The game keeps track of how many skill points you've gained since the last level up. If you gained 8 skill points in skills governed by AGI, then when you get to distribute attribute points whatever number is in place for iLevelUp08Mult will be used for AGI. So if this value is 4, you'll see a x 4 next to AGI when you level up (you'll get 4 points in AGI if you pick this during the leveling process).
"1079" "1080" "1081" "1082" "1083" "1084" "1085" "1086" "1087" "1088" "1089" "1090" "1091" "1092" "1093" "1094" "1095" "1096" "1097" "1098" "1099" "1100" "1101" "1102" "1103" "1104" "1105" "1106"
"fMessageTimePerChar" "fMagicItemRechargePerSecond" "i1stPersonSneakDelta" "iBarterSuccessDisposition" "iBarterFailDisposition" "iLevelupTotal" "iLevelupMajorMult" "iLevelupMinorMult" "iLevelupMajorMultAttribute" "iLevelupMinorMultAttribute" "iLevelupMiscMultAttriubte" "iLevelupSpecialization" "iLevelUp01Mult" "iLevelUp02Mult" "iLevelUp03Mult" "iLevelUp04Mult" "iLevelUp05Mult" "iLevelUp06Mult" "iLevelUp07Mult" "iLevelUp08Mult" "iLevelUp09Mult" "iLevelUp10Mult" "iSoulAmountForConstantEffect"
"fConstantEffectMult" 15.0000 "fEnchantmentConstantDurationMult 100.0000 " "fEnchantmentConstantChanceMult" "fWeaponDamageMult" "fSeriousWoundMult" 0.5000 0.1000 0.0000
This is the setting for the minimum soul value to toggle the constant effect button in the enchantment creation window. UNUSED This setting is the multiplier for constant effect cast cost as compared to a 0 duration spell. so restore health 2-2 for 0 secs, which costs 0.50 to cast as a spell, costs 0.5 x 100 = 50 as a constant effect. weapon damage during combat. depreciation as it were. UNUSED
185
"1107" "1108" "1109" "1110" "1111" "1112" "1113" "1114" "1115" "1116" "1117" "1118" "1119" "1120" "1121" "1122" "1123" "1124" "1125" "1126" "1127" "1128" "1129" "1130" "1131" "1132" "1133" "1134" "1135" "1136" "1137" "1138" "1139" "1140" "1141" "1142" "1143"
"fKnockDownMult" "iKnockDownOddsBase" "iKnockDownOddsMult" "fCombatArmorMinMult" "fHandToHandReach" "fVoiceIdleOdds" "iVoiceAttackOdds" "iVoiceHitOdds" "fProjectileMinSpeed" "fProjectileMaxSpeed" "fThrownWeaponMinSpeed" "fThrownWeaponMaxSpeed" "fTargetSpellMaxSpeed" "fProjectileThrownStoreChance" "iPickMinChance" "iPickMaxChance" "fDispRaceMod" "fDispPersonalityMult" "fDispPersonalityBase" "fDispFactionMod" "fDispFactionRankBase" "fDispFactionRankMult" "fDispCrimeMod" "fDispDiseaseMod" "iDispAttackMod" "fDispWeaponDrawn" "fDispBargainSuccessMod" "fDispBargainFailMod" "fDispPickPocketMod" "iDaysinPrisonMod" "fDispAttacking" "fDispStealing" "iDispTresspass" "iDispKilling" "iTrainingMod" "iAlchemyMod" "fBargainOfferBase"
0.5000 50 50 0.2500 1.0000 10.0000 10 30 400.0000 3000.0000 300.0000 1000.0000 1000.0000 25.0000 5 75 5.0000 0.5000 50.0000 3.0000 1.0000 0.5000 0.0000 -10.0000 -50 -5.0000 1.0000 -1.0000 -25.0000 100 -10.0000 -0.5000 -20 -50 10 2 50.0000
This sets the chance for a knock-down fActored on how much damage you do in a single blow. Sets the base odds for a knockdown when the condition for it is met Sets the reach of HTH weapons. Values of less than 1.0 have no meaning. Controls likelihood of an NPC speaking a voice clip when Idle (Unsure of specifics) Controls likelihood of an NPC speaking a voice clip when attacking (Unsure of specifics) Controls likelihood of an NPC speaking a voice clip when being hit (Unsure of specifics Sets the minimum speed of projectile weapons Dictates maximum speed of projectiles from bows and crossbows Sets the minimum speed of thrown weapons Dictates Max speed of thrown weapons Sets the speed of spells. Double this and your spells will *zip* across the screen! Min speed is apparently hard-coded The odds of getting arrows back when you loot a corpse. Thrown weapons also UNSURE Dont know if this is with pick pocketing or lock picking UNSURE Dont know if this is with pick pocketing or lock picking You have better relations with your own race than with others. These determine how personality affect NPC disposition These determine how your rank in a faction will alter your relations with people that belong to that faction. This is why when you reach high ranks in a faction everyone in that faction suddenly becomes very friendly. This is multiplied by the player's crime level (bounty) to determine how that information affects an NPC's disposition towards the player. How much disposition is lowered when you're suffering from a disease. Not completely sure NPC disposition modifier if PC attacks said NPC How much disposition is lowered when you have a weapon drawn. I don't remember if these work the same as the previous barter disposition values, or if these are multipliers. These effect the long term disposition of the merchant NPC disposition modifier for catching the PC attempting to pickpocket them determines prison time based on your crime level. Unsure I believe its an NPC Disposition modifier if the PC is attacking something other than the NPC it effects non-combatants dispostion. Unsure - I believe its an NPC Disposition modifier if the PC is stealing from someone other than the NPC it effects NPC Disposition modifier for catching the PC trespassing Not sure what that exactly means in-game Unsure NPC Disposition modifier for witnessing the PC kill an innocent NPC (I think) determines training costs. The higher the value, the more training costs. unsure of method of calculation This is multiplied by the item's value to determine what the merchant will offer when selling. Base value is also modified by PC level. Base amount that merchants will buy items from you for, in percentage points Believe it goes both ways, but Im unsure how it would work the other way Effects how much the merchant lowers his offers during a bargaining session IIRC, this is multiplied by your Luck as a percentage to get a base increase to all skills. Dictates amount that NPC Disposition will raise on a successful 10 Gold Bribe Dont believe its in straight disposition points Could be percentages - (Other fActors like race, sex, opposing faction etc. reduce this amount significantly) Dictates amount that NPC Disposition will raise on a successful 100 Gold Bribe. See above. Dictates amount that NPC Disposition will raise on a successful 1000 Gold Bribe. See above. is used in just about every disposition modifying calculation. These all determine how fast you gain skill points in each skill. The lower the value, the faster you'll gain skill points. The values are multiplied by whatever rate you set for each individual skill.
"1144" "1145" "1146" "1147" "1148" "1149" "1150" "1151" "1152" "1153" "1154" "1155" "1156" "1157" "1158" "1159" "1160" "1161"
"fBargainOfferMulti" "fDispositionMod" "fPersonalityMod" "fLuckMod" "fReputationMod" "fLevelMod" "fBribe10Mod" "fBribe100Mod" "fBribe1000Mod" "fPerDieRollMult" "fPerTempMult" "iPerMinChance" "iPerMinChange" "fSpecialSkillBonus" "fMajorSkillBonus" "fMinorSkillBonus" "fMiscSkillBonus" "iAlarmKilling"
-4.0000 1.0000 5.0000 10.0000 1.0000 5.0000 35.0000 75.0000 150.0000 0.3000 1.0000 5 10 0.8000 0.7500 1.0000 1.2500 90
186
"1162" "1163" "1164" "1165" "1166" "1167" "1168" "1169" "1170" "1171" "1172" "1173" "1174" "1175" "1176" "1177" "1178" "1179" "1180" "1181" "1182" "1183" "1184" "1185" "1186" "1187" "1188" "1189" "1190" "1191" "1192" "1193" "1194" "1195" "1196" "1197" "1198" "1199" "1200" "1201" "1202" "1203" "1204" "1205" "1206" "1207" "1208" "1209" "1210" "1212" "1213" "1214" "1215" "1216" "1217" "1218" "1219" "1220" "1221" "1222" "1223" "1224" "1225" "1226" "1227" "1228"
"iAlarmAttack" "iAlarmStealing" "iAlarmPickPocket" "iAlarmTresspass" "fAlarmRadius" "iCrimeKilling" "iCrimeAttack" "fCrimeStealing" "iCrimePickPocket" "iCrimeTresspass" "iCrimeThreshold" "iCrimeThresholdMultiplier" "fCrimeGoldDiscountMult" "fCrimeGoldTurnInMult" "iFightAttack" "iFightAttacking" "iFightDistanceBase" "fFightDistanceMultiplier" "iFightAlarmMult" "fFightDispMult" "fFightStealing" "iFightPickpocket" "iFightTrespass" "iFightKilling" "iFlee" "iGreetDistanceMultiplier" "iGreetDuration" "fGreetDistanceReset" "fIdleChanceMultiplier" "fSneakUseDist" "fSneakUseDelay" "fSneakDistanceBase" "fSneakDistanceMultiplier" "fSneakSpeedMultiplier" "fSneakViewMult" "fSneakNoViewMult" "fSneakSkillMult" "fSneakBootMult" "fCombatDistance" "fCombatAngleXY" "fCombatAngleZ" "fCombatForceSideAngle" "fCombatTorsoSideAngle" "fCombatTorsoStartPercent" "fCombatTorsoStopPercent" "fCombatBlockLeftAngle" "fCombatBlockRightAngle" "fCombatDelayCreature" "fCombatDelayNPC" "fAIMeleeWeaponMult" "fAIRangeMeleeWeaponMult" "fAIMagicSpellMult" "fAIRangeMagicSpellMult" "fAIMeleeArmorMult" "fAIMeleeSummWeaponMult" "fAIFleeHealthMult" "fAIFleeFleeMult" "fPickPocketMod" "fSleepRandMod" "fSleepRestMod" "iNumberCreatures" "fAudioDefaultMinDistance" "fAudioDefaultMaxDistance" "fAudioVoiceDefaultMinDistance" "fAudioVoiceDefaultMaxDistance" "fAudioMinDistanceMult"
50 1 20 5 2000.0000 1000 40 1.0000 25 5 1000 10 0.5000 0.9000 100 50 20 0.0050 1 0.2000 50.0000 25 25 50 0 6 4 512.0000 0.7500 500.0000 1.0000 0.5000 0.0020 0.7500 1.5000 0.5000 1.0000 -1.0000 128.0000 60.0000 60.0000 30.0000 45.0000 0.3000 0.8000 -90.0000 30.0000 0.1000 0.1000 2.0000 5.0000 3.0000 5.0000 1.0000 1.0000 7.0000 0.3000 0.3000 0.2500 0.3000 1 5.0000 40.0000 10.0000 60.0000 20.0000
When an NPC raises the alarm, this is the base radius for response by other affiliated NPCs. These set the gold value for crimes. I believe that fCrimeStealing is multiplied by the price of the item stolen.
When NPC's start to react negatively to the PC Thieves guild discount when you have a price on your head. Discount on the fine if you turn yourself in.
UNUSED Used for those annoying voice greetings NPCs use when you get too close Specifically (if the contrustion set help is to be believed) this is multiplied by their hello rating to get the distance before they talk. How far away from an NPC you have to get before they check for a voice greeting again. Probability multiplier that an NPC will mumble something while standing idly near the PC Helps determine if you can sneak Helps determine how long before the Sneak Icon come on see above see above Multiplied by base walking speed to see how fast you move while sneaking. Makes it more difficult to sneak when in view of an NPC. Makes it easier to sneak when you aren't in view. Multiplied by the boot value (weight?) to determine the reduction to Sneak skill. Combined with weapon reach, determines the effective distance that hits can be obtained
Shields are worn on the left and partially block attacks from 90 degrees left to 30 degrees right of the PCs facing. Used in the determination of how far away an NPC will flee if they flee combat and the PC has a melee weapon in hand as above but the PC has a crossbow or Bow in hand As above but the PC has a spell readied Alters the opponents flee rating when health declines Used to alter base flee ratings. Affects the chance of a mob waking the PC up while asleep in the wilderness. Unused (Thanks to Damar Stiehl for these two)
187
"1229" "1230" "1231" "1232" "1399" "1400" "1401" "1431" "1432" "1435"
"fAudioMaxDistanceMult" "fNPCHealthBarTime" "fNPCHealthBarFade" "fDifficultyMult" "fMagicDetectRefreshRate" "fMagicStartIconBlink" "fMagicCreatureCastDelay" "fDiseaseXferChance" "fElementalShieldMult" "fMagicSunBlockedMult" fWereWolfRunMult fWereWolfSilverWeaponDamageM ult iWereWolfBounty fWereWolfStrength fWereWolfAgility fWereWolfEndurance fWereWolfSpeed fWereWolfHandtoHand fWereWolfUnarmored fWereWolfAthletics fWereWolfAcrobatics fWereWolfInteligence fWereWolfWillPower fWereWolfPersonality fWereWolfLuck fWereWolfBlock fWereWolfArmorer fWereWolfMediumArmor fWereWolfHeavyARmor fWereWolfBluntWeapon fWereWolfLongBlade fWereWolfAxe fWereWolfSpear fWereWolfDestruction fWereWolfAlteration fWereWolfIllusion fWereWolfConjuration fWereWolfMysticism fWereWolfRestoration fWereWolfEnchant fWereWolfAlchemy fWereWolfSecurity fWereWolfSneak fWereWolfLightArmor fWereWolfShortBlade fWereWolfMarksman fWereWolfSpeechcraft iWereWolfLevelToAttack iWereWolfFightMod iWereWolfFleeMod fWereWolfHealth fWereWolfFatigue fWereWolfMagica fCombatDistaceWereWolfMod fFleeDistance
50.0000 3.0000 0.5000 5.0000 0.0167 3.0000 1.5000 2.5000 0.1000 0.5000 1.3000 2.0000 1000 150.0000 150.0000 150.0000 90.0000 100.0000 100.0000 50.0000 80.0000 0.0000 0.0000 0.0000 25.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 95.0000 0.0000 0.0000 0.0000 0.0000 20 100 100 2.0000 400.0000 100.0000 0.3000 3000.0000
Controls delay before the Opponents health bar disappears Controls how many seconds the bar "fades" for (rather than abruptly vanishing) The number of seconds a spell icon will fade before the spell runs out, on the lower right-hand corner of the screen. The chance of catching a disease if hit by a creature, or looting a diseased creature's corpse. Vampire weakness Werewolf run speed multiplier. The damage multiplier for silver weapon damage against all werewolves. These are the skills and attributes for Werewolf form.
Determines the attack range of a Werewolf. Determines how far away someone will flee.
188
Index
"
"Equal to", 28 "Greater than or equal to", 28 "Greater than", 28 "Smaller than or equal to", 28 "Smaller than", 28 "Unequal to", 28 character creation, 125 Choice, 90 Cleaning, 135 ClearForceJump, 72 ClearForceMoveJump, 72 ClearForceRun, 72 ClearForceSneak, 71 ClearInfoActor, 91 coc, 180 coe, 180 Commands, 14 Comments, 24 companion, 75 Console, 171 console commands, 180 cosine, 156 CreateMaps, 180 CrimeGoldDiscount, 104 CrimeGoldTurnIn, 104 ctrl-c, 13 ctrl-v, 13 ctrl-x, 13
[
[no fix], 31
^
^Cell, 87 ^Class, 88 ^Faction, 88 ^Gamehour, 87 ^Global, 87 ^Name, 87 ^NextPCRank, 87 ^PCClass, 87 ^PCName, 87 ^PCRace, 87 ^PCRank, 87 ^Race, 88 ^Rank, 88
D
Day, 119 DaysPassed, 119 Disable, 62 DisableLevitation, 107 DisablePlayerControls, 124 DisablePlayerFighting, 124 DisablePlayerJumping, 124 DisablePlayerLooking, 124 DisablePlayerMagic, 124 DisablePlayerViewSwitch, 124 DisableTeleporting, 106 DisableVanityMode, 124 Division, 27 DontSaveObject, 64 Drop, 33 DropSoulgem, 109
A
Activate, 57 AddItem, 32 Addition, 27 AddSoulGem, 109 AddSpell, 109 AddToLevCreature, 130 AddToLevItem, 130 AddTopic, 88 AiActivate, 68 AIEscort, 70 AIEscortCell, 70 AiFollow, 70 AiFollowCell, 70 AiTravel, 65 AiWander, 67 AllowWereWolfForceGreeting, 89, 175 AND, 30
E
Else, 28 Elseif, 28 Enable, 62 EnableBirthMenu, 125 EnableClassMenu, 125 EnableInventoryMenu, 126 EnableLevelUpMenu, 125 EnableLevitation, 107 EnableMagicMenu, 125 EnableMapMenu, 125 EnableNameMenu, 125 EnablePlayerControls, 125 EnablePlayerFighting, 125 EnablePlayerJumping, 125 EnablePlayerLooking, 125 EnablePlayerMagic, 125 EnablePlayerViewSwitch, 125 EnableRaceMenu, 125 EnableRest, 125 EnableStatsMenu, 126 EnableTeleporting, 106
B
BecomeWerewolf, 80 Bloodmoon Script Functions, 175 Boolean operators, 30
C
Cast, 109 CellChanged, 54 CellUpdate, 42 CenterOnCell, 180 CenterOnExterior, 180 ChangeWeather, 121
189
EnableVanityMode, 125 Endif, 28 EndWhile, 30 Equip, 35 Error messages, 172 ExplodeSpell, 112 EXPRESSION, 172
F
Face, 67 FadeIn, 128 FadeOut, 129 FadeTo, 129 FixMe, 180 Float, 25 ForceGreeting, 89 ForceJump, 72 ForceMoveJump, 72 ForceRun, 72 ForceSneak, 71 Friend Hit (dialogue), 92 Functions, 14
G
game settings, 182 GameHour, 119 Get/Mod/SetAcrobatics, 96 Get/Mod/SetAgility, 95 Get/Mod/SetAlarm, 100 Get/Mod/SetAlchemy, 96 Get/Mod/SetAlteration, 96 Get/Mod/SetArmorBonus, 113 Get/Mod/SetArmorer, 96 Get/Mod/SetAthletics, 96 Get/Mod/SetAttackBonus, 114 Get/Mod/SetAxe, 96 Get/Mod/SetBlindness, 113 Get/Mod/SetBlock, 96 Get/Mod/SetBluntWeapon, 96 Get/Mod/SetCastPenalty, 113 Get/Mod/SetChameleon, 113 Get/Mod/SetConjuration, 96 Get/Mod/SetDefendBonus, 114 Get/Mod/SetDestruction, 96 Get/Mod/SetDisposition, 79 Get/Mod/SetEnchant, 96 Get/Mod/SetEndurance, 95 Get/Mod/SetFatigue, 95 Get/Mod/SetFight, 99 Get/Mod/SetFlee, 99 Get/Mod/SetFlying, 113 Get/Mod/SetHandToHand, 96 Get/Mod/SetHealth, 95 Get/Mod/SetHeavyArmor, 96 Get/Mod/SetHello, 92 Get/Mod/SetIllusion, 96 Get/Mod/SetIntelligence, 95 Get/Mod/SetInvisibile, 113 Get/Mod/SetInvisible, 113 Get/Mod/SetLevel, 96 Get/Mod/SetLightArmor, 96 Get/Mod/SetLongBlade, 96 Get/Mod/SetLuck, 95 Get/Mod/SetMagicka, 95 Get/Mod/SetMarksman, 96 Get/Mod/SetMediumArmor, 96
Get/Mod/SetMercantile, 96 Get/Mod/SetMysticism, 96 Get/Mod/SetPCCrimeLevel, 103 Get/Mod/SetPersonality, 95 Get/Mod/SetReputation, 79 Get/Mod/SetResistBlight, 113 Get/Mod/SetResistCorprus, 113 Get/Mod/SetResistDisease, 113 Get/Mod/SetResistFire, 113 Get/Mod/SetResistFrost, 113 Get/Mod/SetResistMagicka, 113 Get/Mod/SetResistNormalWeapons, 113 Get/Mod/SetResistParalysis, 113 Get/Mod/SetResistPoison, 113 Get/Mod/SetResistShock, 113 Get/Mod/SetRestoration, 96 Get/Mod/SetSecurity, 96 Get/Mod/SetShortBlade, 96 Get/Mod/SetSilence, 113 Get/Mod/SetSneak, 96 Get/Mod/SetSpear, 96 Get/Mod/SetSpeechcraft, 96 Get/Mod/SetSpeed, 95 Get/Mod/SetStrength, 95 Get/Mod/SetSuperJump, 113 Get/Mod/SetSwimSpeed, 113 Get/Mod/SetUnarmored, 96 Get/Mod/SetWaterBreathing, 113 Get/Mod/SetWaterWalking, 113 Get/Mod/SetWillpower, 95 GetAIPackageDone, 65 GetAngle, 52 GetArmorType, 38 GetAttacked, 98 GetBlightDisease, 112 GetButtonPressed, 86 GetCollidingActor, 57 GetCollidingPC, 57 GetCommonDisease, 112 GetCurrentAIPackage, 71 GetCurrentWeather, 121 GetDeadCount, 101 GetDetected, 54 GetDisabled, 62 GetDistance, 51 GetEffect, 111 GetFactionReaction, 180 GetForceJump, 72 GetForceMoveJump, 72 GetForceRun, 72 GetForceSneak, 71 GetHealthGetRatio, 95 GetInterior, 50 GetItemCount, 37 GetJournalIndex, 91 GetLineOfSight, 53 GetLocked, 60 GetLOS, 53 GetMasserPhase, 119 GetPCCell, 51 GetPCCrimeLevel, 103 GetPCFacRep, 77 GetPCInJail, 104 GetPCJumping, 73 GetPCRank, 76 GetPCRunning, 73 GetPCSleep, 123 GetPCSneaking, 73 GetPCTraveling, 55
190
GetPlayerControlsDisabled, 125 GetPlayerFightingDisabled, 125 GetPlayerJumpingDisabled, 125 GetPlayerLookingDisabled, 125 GetPlayerMagicDisabled, 125 GetPlayerViewSwitch, 125 GetPos, 52 GetRace, 76 GetScale, 49 GetSecondsPassed, 118 GetSecundaPhase, 119 GetSpell, 111 GetSpellEffects, 111 GetSpellReadied, 74 GetSquareRoot, 131 GetStandingActor, 55 GetStandingPC, 55 GetStat, 94 GetTarget, 98 GetVanityModeDisabled, 125 GetWaterLevel, 131 GetWeaponDrawn, 74 GetWeaponType, 38 GetWerewolfKills, 80 GetWindSpeed, 122 Global scripts, 22 global variables, 25 Goodbye, 89 GotoJail, 103
minimumprofit, 75 ModCurrentFatigue, 95 ModCurrentHealth, 95 ModCurrentMagicka, 95 ModFactionReaction, 78 ModHealth, 94 ModPCFacRep, 78 ModRegion, 121 ModScale, 49 ModStat, 94 ModWaterLevel, 131 moto, 180 Move, 41 MoveOneToOne, 180 MoveWorld, 42 Multiplication, 27
O
Objects, 14 OnActivate, 57 OnDeath, 100 OnKnockout, 101 OnMurder, 100 OnPCAdd, 34 OnPCDrop, 34 OnPCEquip, 35 OnPCHitMe, 97, 104 OnPCRepair, 38 OnPCSoulGemUse, 34, 109 OnRepair, 38 operators, 27 OR, 30
H
HasItemEquipped, 40 HasSoulgem, 108 Help, 180 HitAttemptOnMe, 98 HitOnMe, 98 HurtCollidingActor, 57 HurtStandingActor, 56
P
PayFine, 103 PayFineThief, 103 PC Clothing Modifier (dialogue), 92 PC Sex (dialogue), 91 PCClearExpelled, 78 PCExpell, 78 PCExpelled, 77 PCForce1stPerson, 125 PCForce3rdPerson, 125 PCGet3rdPerson, 125 PCHasGoldDiscount, 105 PCJoinFaction, 77 PCLowerRank, 77 PCRaiseRank, 77 PCSkipEquip, 36 PlaceAtMe, 46 PlaceAtPC, 46 PlaceItem, 47 PlaceItemCell, 47 PlayBink, 130 Player Controls, 123 PlayGroup, 61 PlaySound, 116 PlaySound3D, 116 PlaySound3DVP, 116 PlaySoundVP, 116 Position, 45 PositionCell, 45 PT, 180 Purge textures, 180
I
If, 28 indentation, 24 INFIX to POSTFIX, 173 IsWerewolf, 80
J
Journal, 90
L
LeftEval, 172 Local scripts, 22 local variables, 25 Lock, 60 Long, 25 LoopGroup, 61 LowerRank, 77
M
Mathematical calculations, 27 maximum health, 95 MenuMode, 74, 126 MenuTest, 126 MessageBox, 86
191
R
RaiseRank, 77 Random, 129 Rank Requirement (dialogue), 92 References persist, 137 RemoveEffects, 111 RemoveFromLevCreature, 130 RemoveFromLevItem, 130 RemoveItem, 32 RemoveSoulgem, 108 RemoveSpell, 109 RepairedOnMe, 38 Resurrect, 101 Return, 128 RightEval, 172 Rotate, 48 RotateWorld, 48
T
T3D, 180 TA, 181 Talked to PC (dialogue), 92 TB, 181 TCB, 181 TCG, 181 TCL, 181 TCS, 181 TDS, 181 TDT, 181 TESAME, 136 TestCells, 180 TestInteriorCells, 180 TestModels, 180 Text defines, 87 TFH, 181 TFOW, 181 TG, 181 TGM, 181 TKS, 181 TM, 181 TMS, 181 ToggleAI, 181 ToggleBorders, 181 ToggleCollision, 181 ToggleCollisionBoxes, 181 ToggleCollisionGrid, 181 ToggleCombatStats, 181 ToggleDebugText, 181 ToggleDialogueStats, 181 ToggleFogOfWar, 181 ToggleFullHelp, 181 ToggleGodMode, 181 ToggleGrid, 181 ToggleKillStats, 181 ToggleLights, 181 ToggleLoadFade, 181 ToggleMagicStats, 181 ToggleMenus, 181 TogglePathGrid, 181 ToggleScriptOutput, 181 ToggleScripts, 181 ToggleSky, 181 ToggleStats, 181 ToggleTextureString, 181 ToggleVanityMode, 181 ToggleWater, 181 ToggleWireframe, 181 ToggleWorld, 181 TPG, 181 Tribunal Script Functions, 174 Troubleshooting, 171 TS, 181 TSO, 181 TST, 181 TTS, 181 TurnMoonRed, 79 TurnMoonWhite, 79 tutorial, 12 TVM, 181 TW, 181 TWF, 181
S
SA, 181 SameFaction, 77 Say, 115 SayDone, 115 scripting window, 12 ScriptRunning, 128 SCT, 180 Set to, 25 SetAngle, 48 SetAtStart, 46 SetDelete, 63 SetFactionReaction, 78 SetJournalIndex, 90 SetPCFacRep, 78 SetPos, 43 SetScale, 49 SetStat, 94 SetWaterLevel, 131 SetWerewolfAcrobatics, 79 SetWillpower, 94 SG, 181 Short, 25 Show, 180 Show Animation, 181 Show target group, 181 ShowGroup, 181 ShowMap, 129 ShowRestMenu, 123 ShowScenegraph, 181 ShowVars, 180 sine, 156 SkipAnim, 61 SSG, 181 ST, 181 StartCombat, 97 StartScript, 128 StayOutside, 75 StopCellTest, 180 StopCombat, 97 StopScript, 128 StopSound, 116 StreamMusic, 115 string variables, 25 Subtraction, 27 sv, 180 Syntax, 23
U
UndoWerewolf, 80
192
Unlock, 60 UsedOnMe, 41
W
WakeUpPC, 123 While, 29
193