TES 3 MODDING CONVENTIONS v1.0
by Moredan Kantose




    INTRODUCTION
    **********************************************************************************

    
CONTENTS

    
INTRODUCCION
    Contents
    Mission Statement
    Sources
    Boasting
    Recognitions
    Community
    Formats and Patterns
    Tone
    Version History

    THE RULES
    Modders Identification
    Mods
    Objects of Objects Window
    Other Objects
    Script Code
    Delivery
    Readme

    TIPS
    Avoiding Global Scripts
    Save FPS Using menuMode
    Save FPS Using a Counter
    Save FPS Using Proximity
    Save FPS Using Priorities.
    Save FPS Using 'activation'.
    Making Time Pass


    MISSION STATEMENT

    The target of any software convention is to unifiy the criteria about writing code around some set of good practices. It does not pretend to reach an optimum, but to ensure a regularity which helps developers to understand, enhance and correct the work of other developers.

    

    
SOURCES

    * Desciptions of the ESM, ESP and ESS format:
First One, Second One
    * Morrowind Mod Makers Manual.
    * Scripting for Dummies.

    BOASTING (author's qualifications)

    I would describe my own experience as "middle". I have never published a mod, but I have merged more than 400 esp + 5 esm in 10 esp (the "Moredan Collection"), and I have accumulated a lot of experience bringin all that to work.
    I have read about 10 documents, between them "Scripting for Dummies" and "The Mod Makers Bible". I have downloaded and used about 10 tools, between them the Enchanted Editor, TESAME, TESTools, TESFaith, TESPDK, TESPCD and Levelled Lists Merger.
    And I love conventions.
    If you dislike boasting as much as I do, I humbly apologize. But I wanted to state who am I, as I am new in ths forum, for you to judge my experience and decide for yourself.


    
RECOGNITIONS

    Thanks to Mr/Ms. Abot, Mr. Björn, Mr. CdCooley (the author of the Script Extender!), Mr. Onerail78, Ms. Galsiah and Mr./Ms. Raveren of the Morrowind Official Forums for their useful feedback.
    Thanks to Marina Viktorovna Rakhmanina, loving wife and patient gamer's "widow". Ia tibia liublu, ptichka maia...


    
COMMUNITY

    Mr. Moredan and Mr. Raveren of the Official Forum support these conventions.
    If you are following them and you want to be named here, please contact MoredanKantose (at) hotmail (dot) com.


    
FORMAT AND PATTERNS

    An "R" is a rule, an "A" is an advise. Rules have some technical reason IMHO. Advices are more a question of taste.
    Something between "{" and"}" must be interpreted.
    For example, the ISO 8601 date format YYYYMMDD would be written here as {Year}{Month}{MonthDay} with a further explanation about Year being a 4 digit number, Month a 2 digits number starting with 01 for January, and so on.
    Plain text describes the rules: Aqua for the examples, Lime for the explanations and red for the patterns.


    
TONE

    The tone used in this convention is the imperative tone used in professional conventions. This allow the conventions to be used without rephrasing by a coordinated team of modders who do have a central authority. This does not mean I am trying to put a gun over your head and force you to write the mod as I like it. You have my explicit permission (if you need it) to print these conventions and use them as toilette paper if you like.


    
VERSION HISTORY

    1.0: 2006-01-31: Minor changed, ready for hosting.
    0.7: Local variables pattern changed ("L" reintroduced) and postfixes of objects shortened even a bit more.
    0.6: Names of objects made shorter. Prefix for global and local variables deleted. Type for local variables made mandatory, to give a difference between local variables and built-in variables or methods.
    0.5: Corrections and enchancements, mostly on the rules, because of abundant feedback. Reference to check for ==1 deleted. Tip about activator in interior cell modified.
    0.4: New "Delivery" and "Readme" sections. Some feeedback used to correct or enhance the document.
    0.3: Some formal improvements. Ready for review?
    0.2: Version History. All naming conventions included.
    0.1: Published while editing.


    
DA RULES, MAN!
    **********************************************************************************

    
1. Modders Identification

    R1.1: A modder chooses an identificator, also called Modders ID. This identification remains equal for all mods.
    R1.2: The Modders ID has a minumum of 3 letters.2 are too few to avoid other modder's ID's being the same.
    R1.3: The Modders ID has a maxiumum of 6 letters.
    A1.1: The Modders ID combines the characters {0 to 9}, {a to z}, {A to Z} and '_'.
    A1.2: The Modders ID does not begin with '_'. This casuses problems sometimes in the names.
    A1.3: The Modders ID have few or no vowels. They are too common.
    Good Modders IDs: Mrd (mine), 1IcCnd (for Ice Canadian), MaxNbd (Max, AKA Nobody). The last has a vowel, and it is ok so.
    R1.4 Modders ID's of different modders accumulate, being the first one, the one set at last. This is a way to acknowledge the work of others. If I change an object made by 1IcCnd, I will write "Mrd1IcCnd".
    R1.5 The whole series of modder's id corresponding to a situation is called in this convention "Authors".


    
2. Mods

    A2.1: Every mod has also a name.
    A2.2: The mod name uses the same characters a modder's ID can use.
    A2.3: The mod name can be as short as the modder considers adequate to identificate this mod between his mods.
    A2.4: Mod names do not accumulate like the modder's name.
    A2.5: The part of a name containg the mod's name is caled "ModId" in this document.


    
3. Objects of Object Window

    R3.1: The objects are named {Authors}{ModId}{Proper Name}{ObjectTag}
    * Whether Authors or ModId can be consistently ommited in a mod, if the length of the whole ID runs in danger to provoke problems, but at least one of them must be kept.
    * Proper Name is a free name, describing the object as good as possible.
    * ObjectTag is inspired on the short name of the object type in the ESM / ESP / ESS files:

    Act  for Activators
    Alc  for Alchemy
    App  for Apparatus
    Arm  for Armor items
    Bk   for Books
    Bd   for Body Parts
    Clt  for Clothing items
    Cnt  for Containers
    Cr   for Creatures
    Dr   for Doors
    Enc  for Enchantings
    Ing  for Ingredients
    LC   for Leveled creatures
    LI   for Leveled items
    Lt   for Lights
    Msc  for Misc items
    Npc  for Non Player Characters
    Prb  for Probes
    Rep  for Repair items
    Sp   for Spells
    St   for Statics
    Wp   for Weapon

    For example: This is an activator made by me (Mrd) for the mod Administrate Factions (Af), which checks if the player has led the faction to ruin: MrdAf_RuinDetection_Act


    
4. Other Objects

    R4.1 Global Variables are named {Authors}{ModId}{Proper Name}{Data Type}.
    * Data Type is:

    S for shorts
    L for longs
    F for floats

    MrdAfLastCheckedHourF could be the last time (in float hours) the Administrate Factions mod checked the situation of the PC.

    R4.2 Local Variables are named l{Proper Name}{Data Type}. lFrameCountS.
    * The DataType can be omited.

    A4.1 Local Variables Proper Name does not repeat the Authors or ModId.

    R4.3 Races are named {Authors}{ModId}{Proper Name}Race. This postfix is the Object Tag in the ESx file.
    * ModId here can be ommited, specially if your mods do not use different concepts for the same race. That is, if one mod of you can overwrite a race of the other without provoking problems (including PCRace code).
    MrdDwarfRace.

    R4.4 Factions are named {Authors}{ModId}{Proper Name}Fct.
    * ModId can be ommited, specially if your mods do not use different concepts for the same faction. That is, if one mod of you can overwrite a faction of the other without provoking problems.
    MrdHouseDresFct.

    R4.5 Birthsigns are named {Authors}{ModId}{Proper Name}Bsgn. This postfix is the Object Tag in the ESx file.
    * ModId can be ommited, specially if your mods do not use different concepts for the same birthsign. That is, if one mod of you can overwrite a birthsign of the other without provoking problems.
    MrdAquariusBsgn.


    
5. Scripts

    R5.1 Scripts are named {Authors}{ModId}{Proper Name}{Global Indicator}.
    * The Global Indicator is ommited for normal local scripts and for scipts which stop after running a deteminated number of times (once, twice...).
    * The Global Indicator is "_G" for global StartUp scripts and scripts started with startScript, which do run an indeterminate period of time (forever, or until a quest is completed, etc.).
    * The Global Indicator is "_T" for global scrpts which are started "targeted", that is, ObjectId->startScript, and which run an indeterminate period of time (until the user unequip something, etc).
    It is not obvious, which scripts do that, these are the scripts which can run "continuously", at least for a while, and deserve special mention and caution.
    MrdAfStartUp_G can be the StartUp script of the Administrate Factions mod.

    A5.1 After the begin line, a comment explains if the script is global or not, and where it is attached, and what it does.

    A5.2 The end of a script repeats the name of the script.
    End MrdAfUpdateTreasury_G

    A5.3 All method calls shall begin with lower case, but with a capital letter at the beginning of every other lexeme: getStrength, messageBox, placeAtPC. The exception to this advise are the methods beginning with "PC".

    R5.2 A space must exist before and after every parenthesis.
    If ( menuMode )

    R5.3 The content of a block must be indented.
    Begin MrdFaUpdateTreasury
        startScript MrdFaCalculateProfitGlobal
    End MrdFaUpdateTreasury

    A5.4 There nothing but a comma between the name of a method and its first parameter, not between the parameters.
    placeAtPc "Bee" 1 1 0

    R5.4 There is no space around the targetting operator "->"
    player->addItem "Gold_001" 100000


    
6. Delivery

    A6.1 Deliver one or more ESP files and its content. Do not deliver master files. If you want an esp to have low priority, change the date of it using a tool like Enchanted Editor to a "past" date. There are very few good reasons not to follow this advise, and some heavy ones to follow it. But it is still an advice, not a rule for all cases.
    A6.2 When possible, deliver different versions of the ESP for different configurations or different tastes. Keep this in mind while modding. It is very pleasant to have the chance to choose. Typical cases are with / without official expansions, with / without widespread used mods, and with / without explicit sex.


    
7. Readme

    R7.1 Deliver a file with the name "{Main Esp Name Part} readme.txt" with the mod. "MrdTribAttack readme.txt" for a mod which includes MrdTribAttack.esp, and MrdTribAttack (Bloodmoon).esp.
    A7.1 Deliver a well formated rtf or doc readme file with the mod, with the same information as the txt file.

    A7.2 These are the sections of the readme file:
    * Header
    * Contents
    * Resume
    * Packaging
    * Disclaimer
    * Installation
    * Features
    * Architecture
    * Tweaks
    * Compatibility
    * Saved Games
    * Troubleshooting
    * Version History
    * Credits
    * Permissions
    * Other Mods by {Modder Alias}

    A7.3 The Header of the readme file consist on:
    * The constant string: "Modification of The Elder Scrolls III: Morrowind by Bethesda Softworks"
    * The full name of the mod.
    * The string "by {Modder Alias}"
    * A contact address. Avoid putting the e-mail with a functional format, because spy programs can detect your uploaded readme file and send you spam. Use a format like "MoredanKantose (at) hotmail (a point) com" if you present your e-mail address.

    A7.4 The Contents is a simple table with the list of secions and subsections of the file.

    A7.5 The Resume must contain a brief description of the mods feature, a reference to the instalation way (specially if it is pretty standard) and the fact that all readme files have the same content and do not need to be read one after the other. The target is to allow the normal player to play the mod without reading further if he/she is not interested on the details.

    A7.6 The Packaging section describes the files which should be present in the public file, to allow the user to know if he/she has really downloaded all that is necessary.

    A7.7 The Disclaimer section can be funny but should include enough seriousness to avoid problems if some user is so (CENSORED) to sue you: "I shall not be held responsible if this mod causes damage of any kind on you or you computer".

    A7.8 The Installation section describes the installation process, even for people who have never installed a mod.

    A7.9 The Features section describes all changes made by the mod, which are visible to a player, in so much detail as reasonable. For example, if you use complex formulas to calculate the change of something happening, put the formulas here.

    A7.10 If any section contains information which a normal player should not know to enjoy the mod, write this information between the strings: "* SPOILER WARNING: BEGIN *" and "* SPOILER WARNING: END *.

    A7.11 The Architecture section is necessary only in few mods. It describes the way the mod was implemented: Which global scripts run and where, which Journal adventures are provided, naming conventions...

    A7.12 The Tweaks section is necessary only in mods which provide a way to tweak them. For example, a mod which makes Dagoth Ur "harder" can contain a global variable which can be set in the console, to make him "just a bit harder" up to "practically invincible". In this section you could describe which variable is this one, and how to set it, for people who have never used the console.

    A7.13 The Compatibility section describes extensions and mods this mod need, is compatible with, or is incompatible with, as far as you can tell. This is a good place to tell which cells where heavily changed or new, something which cannot be differenciated from "slightly changed" with normal mod editors. Adding an activator in the Magues Guild of Balmora as a way to implement you mod, is very respectful and probably causes no problems. But substituting the Magues Guild of Balmora by another building of your own, just to implement a mod about another subject should be advertised in this section with CAPITAL LETTERS as a warning. If the mod's name was "New Magues Guild in Balmora", you have described this already in the Resume and in Features, so it is not necessary to describe it here. But if the mod is "The Wizards Gulid of Cyrodill" you'd better tell at least here what you mod is doing in Balmora (the Balmora Subsidiary, probably).

    A7.14 The Saved Games section describes what happens with saved games as the user activates the mod and load them, and what happens with games saved while using your mod when the user deselects it and load the game.

    A7.15 The Troubleshooting section describes what to do when usual problems come. It is optional if there are no usual problems known.

    A7.16 The Version History section shows, in descending order, all the versions of the mod and the main changes between them. You do not need to go into details, just the subjects handled.

    A7.17 The Credits section is optional if all objects, meshes, algorithms and ideas are your own. If not, give credit to the people who deserve it, as long as they have not renounced to it.

    A7.18 The Permissions section describes in which conditions other people can use the text you wrote, the ideas you had, the objects, meshes and textures you created, as well as the ones coming from people mentioned in the Credits section.

    A7.19 I, Mr. Moredan Kantose of the Official Morrowind Forums, give the explicit permission to everybody to use this conventions without giving me any credit or mention me in any way. This does not mean I am not grateful if you do it and / or drop me a line. This means do not worry about it if you feel you have better things to do.

    A7.20 The Other Mods section is optional. It describes other mods related to you, divided into ideas (which everybody can use), planned mods, and implemented mods.


    
SOME TIPS
    **********************************************************************************

    
Avoiding Global Scripts

    Global Scripts are eaters of CPU time. They run always, even when the player is doing nothing which requires their attention. They eat CPU time, decreasing the number of Frames Per Second (FPS) the computer can process.
    There are many techiques, but the best I know are:
    * Don't use many if you can use one: Don't use many scripts to watch over simple things, each of them watching one of them. Use one script watching all them. Of course the conditions and priorities must be looked over carefully if the scripts to merge are complex.
    * If it's done, it's done: The last state of a global script is not like "state = -1" but stopped with stopScript.
    * If everything happens in an interior cell, use an activator in it, run the script from it, and check if the PC is in the cell.
    * If they are many cell affected, make a script for the activator, in order to start again the script if it is not running. Then, make the script run some frames (like 20, for example) and then stop itself. It will be indeed a global script, then (every script started with startScript is global) but it will not run forever, just some frames after the "interesting place" was left.


    
Save FPS Using menuMode.

    A script which does not need to be active while the player is using a menu (rest, bargain, etc.) should terminate ASAP for this frame.
    If ( menuMode == 1 )
        return
    EndIf


    Save FPS Using a Counter.

    Many scripts do not need really to check every frame if things are changing. For example, a script like "Suspitious Behaviour", which makes the guards follow the PC if they discover him/her sneaking, can run only every 20 frames or so.
    Other scripts need to run every frame for specific conditions (OnActivate or so) but not in other states (like "already activated").
    For both cases, you can insert a clause to avoid the script to run every frame. This is an example I implemented for Supicious Behaviour:
    Short lFrameCountS
    If ( lFrameCountS < 20 )
        set lFrameCountS to ( lFrameCountS + 1 )
        return
    EndIf
    set lFrameCountS to 0

    Now imagine that there are 10 guards in a cell. That means, as the cell is loaded in a single frame, that all 10 guards run their script every 20 frames. That is, exactly at the same frame, suddenly all 10 scripts run fully. This can lead to undesired time gaps. To avoid this, randomize the number of frames to be jumped.
    Short lFrameCountS
    Short lFrameCountMaxS
    If ( lFrameCountS < lFrameCountMaxS )
        set lFrameCountS to ( lFrameCountS + 1 )
        return
    EndIf
    set lFrameCountS to 0
    set lFrameCountMaxS to ( random 40 )


    
Save FPS Using Proximity .

    Don't run a script on something if the PC is too far away from it to be affected. Do not use getDistance to check the distance, because it is reported to be really slow. Use a simple check of the player's position, OR the difference between the x and y of the object and the position, OR Pitagoras, but using not sware root method, which is also slow, but instead |x| + |y| < 40000 (for a distance of 200).


    
Save FPS Using Priorities.

    If a script has many situations, where nothing needs to be done, try to check the most common first.

    WRONG:
    If ( getJournalIndex MrdLotr_Jrnl >= 60 )
        If ( getJournalIndex MrdLotr_Jrnl <= 80)
            ...
            return
        EndIf
    EndIf
    If ( player->getLevel <= 10 )
        return
    EndIf
    If ( menuMode == 1 )
        return
    EndIf

    RIGHT:
    If ( menuMode == 1 )
        return
    EndIf
    If ( player->getLevel <= 10 )
        return
    EndIf
    If ( getJournalIndex MrdLotr_Jrnl >= 60 )
        If ( getJournalIndex MrdLotr_Jrnl <= 80 )
            ...
            return
        EndIf
    EndIf


    
Save FPS Using 'activation'.

    Something I used in my own version of the Tribunal Attack's script. I wanted the attacks to occur only under certain conditions, like being chief of some factions. So I wrote the script with two 'modi': In the first, if checked only per DAY, to see if the conditions were accomplished. If they were, it activated the second modi, which checked quite more often to see if the player was sleeping.
    After the player killed the Dark Brotherhood chief, the script went to the third modi... stopped.


    
Making Time Pass.

    I like this so much I have altered the mod "Complete Morrowind" so that every time I chop a tree, cook, make a cloth or everything else, some game time passes. I have changed also "Herboristery" that way. It is a realistic way to represent the fact that some things need TIME to be done.
    This is the "long" version, made for complex scripts where there are many places to put this "time passes", but we want to write the calculation only once.

    Short lFinalDayS
    Float lFinalHourF
    set lFinalHourF to ( GameHour + MrdMaxWoodcutTimeF )
    If ( lFinalHourF > 24 )
        set lFinalDayS to ( DaysPassed + 1 )
        set lFinalHourF to ( lFinalHourF - 24.0)
    Else
        set lFinalDayS to DaysPassed
    EndIf
    ...Repeat this in the correct place, where time passes:
    fadeOut 1.0
    set GameHour to lFinalHourF
    set DaysPassed to lFinalDayS
    ...Some message?
    fadeIn 1.0

    You can observe that the time passed depends on a global variable named "gMrdMaxWoodcutTimeF" which I have set to 0.5 (so, 1/2 hours cutting a tree, in Complete Morrowind you need 4 successes to completely chop the tree). I could of course have written simply "0.5" instead. But I like to have my "magic numbers" (numbers which are my invention, and not a logical consequence of the script, as the 1 of "+1" or the 24 of "-24") in global "variables" (which I never change, so they are actually "constants".
    This is the short version:

    fadeOut 1.0
    Float lFinalHourF
    set lFinalHourF to ( GameHour + MrdMaxWoodcutTimeF )
    If ( lFinalHourF > 24 )
        set DaysPassed to ( DaysPassed + 1 )
        set GameHour to ( lFinalHourF - 24.0 )
    Else
        set GameHour to lFinalHourF
    EndIf
    fadeIn 1.0

    Now I have a beutiful selection of gMrdMax...F variables which I will adapt to make the mod more and more realistic. Maybe I even put this in making potions, if I find a good way to implement this.
    WARNING: Note that, as all this happens in one single frame, this method can cause conflicts with mods which must check long periods of "rest", like for example a method which implement the necessity to eat. For this reason, I guess that this method is good only for relative short periods of time, up to one day.
    For longer periods, it can be better to "split" the operation between many frames and allow interruptions. I have not done this so I will not write here how. For short amounts of time, you will probably not need this.