New documentation for the extension framework is located on GitHub. Some info in this article is outdated.
INTRODUCTION
Skyrim Unbound Reborn includes an extension framework that allows users to extend the available starting options by creating addons. In most cases creating an addon requires using xEdit or Creation Kit (xEdit is enough for most things) and some basic mod editing/creation skills.
PapyrusUtil is required for addons support.
Addons are only read once, when you start a new game from the main menu. Therefore, if you added, removed, updated or edited an addon, you need to start a new game to see the changes.
What options can be added by addons:
A SUR addon consists of the following files:
Feel free to ask me for help or suggest new features (i don't promise to add everything people ask, though)
GENERAL INFO ABOUT ADDON JSONS
If you don't know what JSON is
.json is a file format widely used for storing and transmitting data. It can be edited using any text editor, even the Windows Notepad, though something like VS Code, Sublime Text or Notepad++ would be better. It's designed to be human-readable and the syntax is very simple. You can google it but it may be enough to just look at some addon examples.
Referencing forms (records) in JSON
Game forms (records) are referenced using a string in a special format. For example:
"0x801|Dawnguard.esm"
Alternatively you can specify FormID as a decimal number without the "0x" prefix. To convert FormIDs to this format you can use an online converter (hexadecimal number to decimal), which there are plenty of. For example the example above in the decimal format will look like:
"2049|Dawnguard.esm"
This is the only format supported on LE, since the LE version of PapyrusUtil is outdated and doesn't support the hexadecimal format.
Structure
Addon JSONs can contain the following blocks (objects and arrays of objects):
All of them are optional, you don't have to use the ones you don't need for your addon. Below they are described in groups. The order of these blocks and elements inside them doesn't matter.
SECTIONS
Addon Requirements (for all addons)
Even though it's not required, it's recommended to specify requirements of your JSON, since they prevent a bug that old versions of PapyrusUtil (for LE or SE v1.5.97 i.e. pre-AE) have - if the plugin that a record (form) is from is missing or disabled, it will try to pick the record with the same FormID from Skyrim.esm. So specifying requirements prevents this bug if the user disabled your addon .esp or the .esp of the mod that the addon is for, or doesn't even have that mod installed.
It's also useful if you want to distribute multiple addons that don't have their own plugins in a single archive, so that the user installs one package and only the addons for the mods user has installed will be loaded.
You don't need to specify vanilla plugins or Skyrim Unbound.esp there. You don't need to specify all of the required plugins, just the ones that are enough to check if they're loaded in the game or not. For example if your addon comes with a .esp Skyrim Unbound Addon - Cool Sexy Armor.esp that has Cool Sexy Armor.esp and Skyrim.esm as masters, it's enough to only specify Skyrim Unbound Addon - Cool Sexy Armor.esp in requirements, since if any of its masters aren't loaded it won't be loaded too.
Examples
{
"requirements" :
{
"required" : [ "MysticismMagic.esp" ]
},
...
}
2:
{
"requirements" :
{
"required" : [ "Apocalypse - Magic of Skyrim.esp" ],
"requiredAny" : [ "Apocalypse Adjustments - Vanilla.esp", "Apocalypse Adjustments - Ordinator.esp", "Apocalypse Adjustments - Adamant.esp" ]
},
...
}
("required" is actually redundant here, since the plugins in "requiredAny" have it as a master and won't be loaded if it's disabled or missing)
Structure
"requirements" : object (optional)
Contains arrays:
An array of plugin names (with extensions). If any of the listed plugins is not found, the JSON won't be loaded.
"requiredAny" : string array (optional)
An array of plugin names (with extensions). If none of the listed plugins is found, the JSON won't be loaded.
"incompatible" : string array (optional)
An array of plugin names (with extensions). If any of the listed plugins is found, the JSON won't be loaded.
Armors
Examples
1. Whiterun Guard Armor. Not added to randomization, doesn't have any flags.
2. Forsworn Armor. Not added to randomization. Has flags to disable hoods and shields because forsworn don't use them.
3. Chef Clothes. Added to randomization.
{
"armors" :
[
{
"fArmorSet" : "0xD33C6|Skyrim.esm",
"sName" : "Whiterun Guard Armor",
"sType" : "Light"
},
{
"fArmorSet" : "0x43BD9|Skyrim.esm",
"sName" : "Forsworn Armor",
"sType" : "Light",
"sFlags" : [ "NoRandomHood", "NoRandomShield" ]
},
{
"fArmorSet" : "0x1BC5E|Skyrim.esm",
"sName" : "Chef Clothes",
"sType" : "Clothes",
"sFlags" : [ "AddToRandom" ]
}
]
}
Structure
"armors" : array of objects (optional)
New armor set options. One element of this array is one armor option. Properties:
LeveledItem (leveled list) or Outfit record that contains the armor set. If a leveled list or outfit containing all the armor parts you need already exists, you can just use it. If it doesn't, you can create a new one in xEdit or CK. Yes, you can't just list armor parts in JSON.
There are no limitations on the structure and contents of the armor set list. The only rules:
In fact you can add any additional items that need to be given with this armor set into it.
"sName" : string (required)
The name of your armor set that will be displayed in the MCM.
"sType" : string (required)
The armor type of this armor. Valid values: "Clothes", "Light", "Heavy".
"fAutoWeaponSet" : form (optional)
Using this property you can specify a weapon set that will be always given with your armor set if Weapon Set is Random in the MCM. Usually this is a weapon set from your addon. The form is the same FormList that you specify in fWeaponSet when adding new weapon sets.
"sFlags" : string array (optional)
Flags here are strings in the array. To add a flag, add it to the array (at any position). Flags:
Weapons (except staffs)
Examples
{
"weapons" :
[
{
"fWeapon" : "0x801|Dawnguard.esm",
"sType" : "Crossbow",
"sWeaponSet" : "Steel"
},
{
"fWeapon" : "0xBB3|Dawnguard.esm",
"sType" : "Bolt",
"sWeaponSet" : "Steel"
}
]
}
2. The CC Fishing addon:
{
"weapons" :
[
{
"fWeapon" : "0xE44|ccBGSSSE001-Fish.esm",
"sType" : "Dagger",
"sWeaponSet" : "Ancient Nord"
},
{
"fWeapon" : "0xE46|ccBGSSSE001-Fish.esm",
"sType" : "Mace",
"sWeaponSet" : "Ancient Nord"
},
{
"fWeapon" : "0xE47|ccBGSSSE001-Fish.esm",
"sType" : "Warhammer",
"sWeaponSet" : "Ancient Nord"
}
]
}
3. See the Beyond Skyrim Morrowind - Bonemold Weapon Pack addon for an example with a new weapon set (material)
4. Weapon type flags look like this (see Armors examples if you want to see how it looks in a JSON):
"sFlags" : [ "AddToRandom" ]
Structure
"weaponTypes" : array of objects (optional)
New weapon type options. One element of this array is one weapon type option. Properties:
You need to create a FormList record for your weapon type and reference it here. You can either pre-fill this formlist with all the new weapons that belong to this type, or keep the formlist empty and make SUR fill it by setting this formlist in the "fWeaponTypeList" property on each of the new weapons that belong to this type (not needed if you fill the formlist yourself).
"sName" : string (required)
The name of your weapon type option.
"sCategory" : string (required)
The category of your weapon type. Valid values: "1H", "2H", "Ranged".
"sFlags" : string array (optional)
Flags here are strings in the array. To add a flag, add it to the array (at any position). Flags:
"weaponSets" : array of objects (optional)
New weapon set options. One element of this array is one weapon set option. Properties:
You need to create a FormList record for your weapon set and reference it here. You can either pre-fill this formlist with all the new weapons that belong to this set, or keep the formlist empty and make SUR fill it by setting this formlist in the "fWeaponSet" property on each of the new weapons that belong to this set (not needed if you fill the formlist yourself).
"sName" : string (required)
The name of your weapon set option.
"fAutoWeaponSetOn" : array of forms (optional)
Array of armor sets (fArmorSet) that this weapon set will be set as auto weapon set on. Has the same effect as fAutoWeaponSet property on armors, no need to use both.
"weapons" : array of objects (optional)
New weapons (arrows and bolts are considered weapons here). Specific weapons can't be selected from the MCM directly: the player or the randomization selects a weapon type and a weapon set, and SUR chooses a random weapon that belongs to both the type and the set. By default there is only one weapon for each weapon type+set combination, however more weapons can be added by addons. Properties:
The weapon, usually Weapon, Ammo or LeveledItem (leveled list) record.
"sType" : string (optional)
If your weapon belongs to one of the default weapon types, this must be the name of that type. Crossbows and Bolts are default types too, they're just hidden if no addons extend them. Valid values: "Dagger", "Sword", "Axe", "Mace", "Scimitar", "Greatsword", "Battleaxe", "Warhammer", "Bow", "Crossbow", "Arrow", "Bolt".
"fWeaponTypeList" : form (optional)
If your weapon belongs to an addon-added weapon type, this is its formlist record (the one specified in the "fWeaponTypeList" property of that weapon type). This can be used to add weapons to weapon types added by other addons, as well as to the ones from your addon if you don't want to pre-fill the formlist (if you pre-fill it, you don't need to use this property).
"sWeaponSet" : string (optional)
If your weapon belongs to one of the default weapon sets, this must be the name of that weapon set. Valid values: "Iron", "Steel", "Imperial", "Orcish", "Elven", "Ancient Nord".
"fWeaponSet" : form (optional)
If your weapon belongs to an addon-added weapon set, this is its the formlist record (the one specified in the "fWeaponSet" property of that weapon set). This can be used to add weapons to weapon sets added by other addons, as well as to the ones from your addon if you don't want to pre-fill the formlist (if you pre-fill it, you don't need to use this property).
In fact a weapon doesn't have to belong to a weapon set: if there are no weapons of the selected type that belong to the selected weapon set, the iron and steel sets, a random weapon belonging to this weapon type will be picked.
Spells and Staffs
Examples
{
"spells" :
{
"remove" :
[
"0x211EB|Skyrim.esm"
],
"alteration" :
[
"0x3C2436|MysticismMagic.esp",
"0x5D175|Skyrim.esm"
],
"conjuration" :
[
"0x1CE06|Dragonborn.esm",
"0x413541|MysticismMagic.esp",
"0x4DBA4|Skyrim.esm"
],
"illusion" :
[
"0x4DEE9|Skyrim.esm"
],
"restoration" :
[
"0x8C886D|MysticismMagic.esp",
"0x7388D3|MysticismMagic.esp",
"0x4D3F8|Skyrim.esm"
]
},
"staffs" :
{
"conjuration" :
[
"0xE1FB5B|MysticismMagic.esp",
"0xBE122|Skyrim.esm"
],
"illusion" :
[
"0xC62046|MysticismMagic.esp"
],
"restoration" :
[
"0xD2C9FB|MysticismMagic.esp",
"0xD4B03C|MysticismMagic.esp",
"0x29B94|Skyrim.esm"
]
}
}
Structure
"spells" : object (optional)
"staffs" : object (optional)
Both objects have the same arrays inside. In "spells" they contains spells, in "staffs" they contain staffs:
Array of spells/staffs to remove from SUR. This can only remove the default ones and the ones added by JSONs loaded before yours (they're loaded in the alphabetical order). This can be used for magic overhauls that change the level of spells that are novice in vanilla, as well as for "patch addons" such as the default ApocalypseBalanceAdjustments.json that applies Balance Adjustments for Apocalypse changes to the default Apocalypse addon.
"alteration" : form array (optional)
"conjuration" : form array (optional)
"destruction" : form array (optional)
"illusion" : form array (optional)
"restoration" : form array (optional)
Arrays of spells/staffs of the corresponding schools to add to SUR (the names are extracted automatically).
Items
Examples
1. Broom. Count = 1, named automatically.
2. Flute. Count = 1, named automatically.
3. Three blood potions. A name is assigned.
All options are of Disabled-Enabled-Random type.
{
"items" :
[
{
"fItem" : "0x6717F|Skyrim.esm"
},
{
"fItem" : "0xDABA7|Skyrim.esm"
},
{
"fItem" : "0x18EF3|Dawnguard.esm",
"iCount" : 3,
"sName" : "Blood Potions"
}
]
}
Musical Instruments - for Skyrim's Got Talent. Both options are of menu type.
{
"items" :
[
{
"fItem" : "0xBC1567|Skyrim Unbound.esp",
"sName" : "$SU_MusicalInstrument"
},
{
"fItem" : "0x80A|Skyrim Unbound Addon - Skyrim's Got Talent.esp",
"sName" : "$SU_MusicalInstrumentPlayingLevel",
"options" : [
{
"fItem" : "0x805|Skyrim Unbound Addon - Skyrim's Got Talent.esp",
"sName" : "$SU_SkyrimsGotTalentRank1"
},
{
"fItem" : "0x806|Skyrim Unbound Addon - Skyrim's Got Talent.esp",
"sName" : "$SU_SkyrimsGotTalentRank2"
},
{
"fItem" : "0x807|Skyrim Unbound Addon - Skyrim's Got Talent.esp",
"sName" : "$SU_SkyrimsGotTalentRank3"
},
{
"fItem" : "0x808|Skyrim Unbound Addon - Skyrim's Got Talent.esp",
"sName" : "$SU_SkyrimsGotTalentRank4"
},
{
"fItem" : "0x809|Skyrim Unbound Addon - Skyrim's Got Talent.esp",
"sName" : "$SU_SkyrimsGotTalentRank5"
}
]
}
]
}
Structure
"items" : array of objects (optional)
New item options. One element of this array is one MCM option. There are two types of options that you can create:
1. Disabled-Enabled-Random-type options. These options represent one item (or set of items given at once) that the player can set to Disabled, Enabled or Random (50% chance).
2. Menu-type options: Disabled + Random + any number of menu options. These options represent a type of items (or sets of items given at once) from which the player can select a certain one, or set it to Disabled or Random (a random option from the available ones with 100% chance).
Both types of options are set to Disabled by default.
Properties:
For Disabled-Enabled-Random-type options - the item that this option gives to the player. It can be any type of item, including armor and weapons, as well as a LeveledItem (leveled list). If you want to add some randomization (i don't mean a "Random" option in the MCM, it's always there) or give multiple different items from one MCM option, you need to use a leveled list (create a new one or use an existing one).
For menu-type options - you need to create a FormList record and reference it here. You can either keep the formlist empty and specify all items in the options property, or pre-fill this formlist with items, or mix these two ways. Specifying an item in options allows you to set name and count for this item. For items not specified in options but present in the formlist the name will be automatically extracted (but that doesn't work for leveled lists, since they don't have names).
"iCount" : integer (optional)
The count of items to add to the player. If this property is not set, the count is 1.
"sName" : string (optional)
The name of your MCM option. If this property is not set, the name will be extracted from the item set in "fItem". Leveled lists don't have names, so if you use one then you have to specify a name. For menu-type option this property must always be set.
"fItemByWealth" : array of forms (optional)
For Disabled-Enabled-Random-type options. Allows to give different items depending on the player's Wealth. This is an array of 4 forms (same types as in "fItem") matching the 4 Wealth sets: Beggar, Poor, Medium and Wealthy. The one matching the player's Wealth is given to the player instead the one specified in "fItem" (you can use that one in this array for one or more Wealth sets too, and i recommend doing so). One form can be in the list multiple times. Syntax: "fItemByWealth" : [ beggarForm, poorForm, mediumForm, wealthyForm ]
"options" : array of objects (optional)
For menu-type options. One element of this array is one option inside the menu. Properties:
The item that this menu option gives to the player. It can be any type of item, including armor and weapons, as well as a LeveledItem (leveled list). If you want to add some randomization (i don't mean a "Random" option in the MCM, it's always there) or give multiple different items from one MCM option, you need to use a leveled list (create a new one or use an existing one).
"iCount" : integer (optional)
The count of items to add to the player. If this property is not set, the count is 1. If iCount is set both on the item level and the option level, the resulting count will be the multiplication of the two counts.
"sName" : string (optional)
The name of this menu option. If this property is not set, the name will be extracted from the item set in "fItem". Leveled lists don't have names, so if you use one then you have to specify a name.
"fItemByWealth" : array of forms (optional)
Allows to give different items depending on the player's Wealth. This is an array of 4 forms (same types as in "fItem") matching the 4 Wealth sets: Beggar, Poor, Medium and Wealthy. The one matching the player's Wealth is given to the player instead the one specified in "fItem" (you can use that one in this array for one or more Wealth sets too, and i recommend you do so). One form can be in the list multiple times. Syntax: "fItemByWealth" : [ beggarForm, poorForm, mediumForm, wealthyForm ]
Locations
Examples
See the Orc Strongholds and Bruma addons from the installer. The Orc Strongholds addon adds a new location type and uses a script. The Bruma addon adds a new hold and simple locations (without scripts) that belong to this hold and default location types.
Structure
"locationTypes" : array of objects (optional)
New location types. One element of this array is one location type (such as City or Inn). Properties:
You need to create a FormList record for your location type and reference it here. You can either pre-fill this formlist with all the new locations that belong to this type, or keep the formlist empty and make SUR fill it by setting this formlist in the "fLocationTypeList" property on each of the new locations that belong to this type (not needed if you fill the formlist yourself).
"sName" : string (required)
The name of your location type.
"sDescription" : string (optional)
The description of your location type that is displayed at the bottom of the MCM.
"fQuest" : form (optional)
(see Running Scripts section) The quest hosting the custom script.
"sParam" : string (optional)
(see Running Scripts section) A custom string parameter passed as locationTypeParam to custom scripts.
"sAutoLocalInhabitant" : string (optional)
Sets how Local Inhabitant = Auto works for locations of this type. This property can also be set for a specific location, the location value overrides the location type one. Valid values: "Region", "Settlement". If not set, Local Inhabitant will be set to Disabled.
"iAutoBounty" : array of integers (optional)
Enables the Auto Bounty feature for this location type. Contains 3 elements: the minimum bounty, the maximum bounty and the chance of bounty in percents. You can set -1 as the minimum and/or maximum bounty to use default bounty (the one used for bandit camps). Example: 60% chance of bounty between 250 and 2500 septims - "iAutoBounty" : [ 250, 2500, 60 ]
"conditions" : object (optional)
Adds conditions that restrict when this location type is included into the randomization. All conditions have logical AND between them. All conditions are optional. If there are no locations of the location types selected by the player with matching conditions in the holds selected by the player, it ignores all conditions. Conditions currently supported:
"raceIs" : array of strings. Valid values: "Argonian", "Breton", "Dark Elf", "Imperial", "High Elf", "Khajiit", "Nord", "Orc", "Redguard", "Wood Elf".
"raceIsNot" : array of strings.
"hasSpells" : 0/1
"hasWeapon" : 0/1. Doesn't count items from the Inventory MCM tab as weapons.
"hasWeaponOrSpells" : 0/1. Doesn't count items from the Inventory MCM tab as weapons.
"isInArmor" : 0/1. 0 = True if the player is in clothes. 1 = True if the player is in light or heavy armor.
"isInRags" : 0/1. Check is the player is in the "Rags" armor set.
"isVampire" : 0/1.
"isWerewolf" : 0/1.
"wealthIsOrLowerThan" : 1-4. 1 = Beggar, 2 = Poor, 3 = Medium, 4 = Wealthy.
"wealthIsOrHigherThan" : 1-4.
an example for a location that is by some reason only fits noble breton or high elf spell warriors:conditions: {
"raceIs" : [ "Breton", "High Elf" ],
"hasSpells": 1,
"hasWeapon" : 1,
"isInArmor" : 1,
"wealthIsOrHigherThan" : 3
}
but actually only use conditions when they are really needed.
"sFlags" : string array (optional)
Flags here are strings in the array. To add a flag, add it to the array (at any position). Flags:
"holds" : array of objects (optional)
New holds. One element of this array is one hold. Properties:
You need to create a FormList record for your hold and reference it here. You can either pre-fill this formlist with all the new locations that belong to this hold, or keep the formlist empty and make SUR fill it by setting this formlist in the "fHoldList" property on each of the new locations that belong to this hold (not needed if you fill the formlist yourself).
"sName" : string (required)
The name of your hold.
"fCrimeFaction" : form (optional)
A Faction record, the so called "crime faction" of your hold (the faction that is reponsible for tracking crimes in this hold). Specifying this property enables the Bounty option for your hold and automatically generates a Jail location for it.
"locations" : array of objects (optional)
New locations. One element of this array is one location option (such as City > Solitude or Inn > The Winking Skeever). Properties:
This can be either an object reference that the player will be teleported to (a world object, usually an invisible marker like XMarkerHeading) or a FormList with such references, one of which will be picked randomly (it allows you to have multiple positions for one location, like in the default City and Town locations). You can use an existing marker (which of course you can only see in Creation Kit), but usually you want to place a new marker, this can be done using Creation Kit or Marker Placer. All references (markers) must be persistent (have Persistent flag in their record header or/and be located in a plugin that is not .esm/.esm-flagged. i recommend to add Persistent flag anyway), whether it's one specified in fLocation, or ones included in a formlist specified in fLocation.
"sName" : string (optional)
The name of your starting location. If the name is not set, SUR will try to automatically retrieve it in the following priority: parent cell > parent location > parent worldspace.
"sType" : string (optional)
If your location belongs to one of the default types, this must be the name of that type. Jail locations can't be added this way, they get created automatically for addon-added holds. There are also default types Player Home and Other that are hidden if no addons extend them. "Other" can be used if your location doesn't belong to any of the default types and you don't want to create a new one. Valid values: "City", "Town", "Inn", "Wilderness", "Border", "Docks", "Temple", "Player Home", "Homeless Shelter", "Faction Headquarters", "Bandit Camp", "Warlock Lair", "Vampire Lair", "Other". See notes about default location types below.
"fLocationTypeList" : form (optional)
If your location belongs to an addon-added location type, this is its formlist record (the one specified in the "fLocationTypeList" property of that location type). This can be used to add locations to location types added by other addons, as well as to the ones from your addon if you don't want to pre-fill the formlist (if you pre-fill it, you don't need to use this property).
"sHold" : string (optional)
If your location belongs to one of the default holds, this must be the name of that hold. Valid values: "Eastmarch", "Falkreath", "Haafingar", "Hjaalmarch", "The Pale", "The Reach", "The Rift", "Whiterun", "Winterhold", "Solstheim", "Other". "Other" can be used if your location doesn't belong to any of the default holds and you don't want to create a new one. Each location must have a hold assigned, whether it's through "sHold", "fHoldList" or by prefilling your hold formlist.
"fHoldList" : form (optional)
If your location belong to an addon-added hold, this is its formlist record (the one specified in the "fHoldList" property of that hold). This can be used to add locations to holds added by other addons, as well as to the ones from your addon if you don't want to pre-fill the formlist (if you pre-fill it, you don't need to use this property). Each location must have a hold assigned, whether it's through "sHold", "fHoldList" or by prefilling your hold formlist.
"fQuest" : form (optional)
(see Running Scripts section) The quest hosting the custom script.
"sParam" : string (optional)
(see Running Scripts section) A custom string parameter passed as locationParam to custom scripts.
"sAutoLocalInhabitant" : string (optional)
Sets how Local Inhabitant = Auto works for this location. This property can also be set for a location type, the location value overrides the location type one. Valid values: "Disabled", "Region", "Settlement". If not set, the location type value will be used (for vanilla location types: Player Home, Homeless Shelter, Faction Headquarters = "Settlement"; Bandit, Warlock, Vampire Lair = "Region").
"sForceLocation" : string (optional)
When Local Inhabitant is enabled, to identify to which settlement your location belongs SUR checks in which location your marker is. By location i mean the technical location, the Location record set in the properties of the cell (or the worldspace if the cell doesn't have any location set). However if you place a marker in a mod-added interior that is not properly set or on the edge of a settlement, it's possible that your marker won't technically be in this settlement location. In such cases if you want the Local Inhabitant option to work with your location, you need to set sForceLocation. Valid values: "Dawnstar", "Falkreath", "Markarth", "Morthal", "Riften", "Solitude", "Whiterun", "Windhelm", "Winterhold", "Raven Rock", "Dragon Bridge", "Ivarstead", "Karthwasten", "Riverwood", "Rorikstead", "Shor's Stone".
"iAutoBounty" : array of integers (optional)
Enables the Auto Bounty feature for this location type. Contains 3 elements: the minimum bounty, the maximum bounty and the chance of bounty in percents. You can set -1 as the minimum and/or maximum bounty to use default bounty (the one used for bandit camps). Overrides the same setting set on the location type. Example: 60% chance of bounty between 250 and 2500 septims - "iAutoBounty" : [ 250, 2500, 60 ]
"fAdditionalFriendFactions" : array of forms (optional)
Only for location types "Bandit Camp", "Warlock Lair" and "Vampire Lair". Allows to specify a list of additional enemy factions that must be made friends with the player when starting in this location, in addition to the vanilla factions that are already used by default. (see "Notes about default location types")
"fAdditionalFriendFactionsInteriorOnly" : array of forms (optional)
Same as fAdditionalFriendFactions, but NPCs in these factions will only be made friends if they're in an interior cell (useful for tamed animals).
"conditions" : object (optional)
Adds conditions that restrict when this location is included into the randomization. See the same property in "locationTypes" for detals.
"sFlags" : string array (optional)
Flags here are strings in the array. To add a flag, add it to the array (at any position). Flags:
Notes about default location types
Wilderness
Bandit Camp, Warlock Lair, Vampire Lair
To better understand these limitations, you need to know how it works. The corresponding NPCs in the starting location need to be detected. If the player starts in an interior, it follows the player through any number of interior cells detecting NPCs in these cells. Once the player reaches an exterior or if the player started in an exterior, it detects NPCs around and stops. Therefore, there are the following limitations:
1) If the location has a single interior cell, the player must start in that interior.
2) If the location has multiple interior cells, all the interior cells must be connected in chain that looks like Exterior > Interior > Interior, where you can get from one end to the other one by only one way, and the player must start in the final/farthest interior cell, so that the player always goes from that cell through all the other interior cells and all of them are loaded before exiting to the exterior.
3) If the location has interior cell(s) and multiple entrances to the interior, these entrances must not be too far from each other in the exterior.
(Locations that only have an exterior are fine)
This limits where the starting marker can be placed and doesn't allow to use complex cell structures such as most forts.
Only NPCs that have at least one faction from the corresponding SUR formlist (BanditCamp/WalorkLair/VampireLairFactions(InteriorOnly)) are made friends with the player. If enemies in your location use unique factions, specify them via the fAdditionalFriendFactions/fAdditionalFriendFactionsInteriorOnly property.
The following factions are included in the aforementioned formlists and are therefore working by default:
How to check where the player started in conditions? How to implement conditions when implementing Local Inhabitant in non-vanilla settlements?
GetInCurrentLoc()
GetInCurrentLocFormList()
GetInCell()
GetInSameCell()
IsInSameCurrentLocAsRef()
GetDistance()
Alternatively you can create a custom quest for your location and set a custom global variable, which you can then check via GetGlobalValue().
To check if Local Inhabitant is enabled at all you can check global variable PlayerIsLocalInhabitantOfSettlement/PlayerIsLocalInhabitantOfRegion ("Disabled" = 0/0, "Region" = 0/1, "Settlement" = 1/1).
If you need to check if the player started as a Local Inhabitant in a specific settlement, you need to combine checks for StartingLocationMarker and PlayerIsLocalInhabitantOfSettlement/PlayerIsLocalInhabitantOfRegion.
Example for dialogues that shouldn't play if the player is a local inhabitant in a specific settlement:
Any.GetGlobalValue(PlayerIsLocalInhabitantOfSettlement) = 0 OR
StartingLocationMarker.GetInCurrentLoc(the settlement location) = 0
Example for the ones that should play only if the player is a local inhabitant in a specific settlement:
Any.GetGlobalValue(PlayerIsLocalInhabitantOfSettlement) = 1 AND
StartingLocationMarker.GetInCurrentLoc(the settlement location) = 1
Locations - Running Scripts
Examples
See the Orc Strongholds addon.
Steps
1. Create a new quest that will host your script
Create a new quest (in CK or xEdit). You don't need to create a real quest with objectives and stuff, just an empty invisible quest to attach your script to it.
2. Create a new script that extends SkyrimUnboundLocationAddonScript on the created quest
Attach a new script to the created quest. The script must extend SkyrimUnboundLocationAddonScript: you can replace "Quest" to "SkyrimUnboundLocationAddonScript" when adding a new script in CK or in the first line of an already created script so the first line looks like this:Scriptname YourCustomScriptName extends SkyrimUnboundLocationAddonScript
3. Add PrepareStart function to your script
Add the following function to your script. This is the main function of your script. It will be called by SUR before teleporting the player to the starting location.function PrepareStart(ObjectReference teleportMarker, string locationTypeParam, string locationParam)
endFunction
4. Add the created quest to your JSON
To make SUR know that it should run your quest and for which locations it should do that, you need to specify your quest in the fQuest property. You can set it either on a specific location or a location type. A single quest can be used for multiple locations or/and location types (but you can use as many quests (with their own scripts) as you want). If for some location fQuest is set both on this location and its location type, only the quest on the location will be used.
5. Write your script
Now you can write any code you want but first you need to know two things.
5.1. How to identify the current location and location type if you used your quest for multiple locations or/and location types AND what are the paramaters of the PrepareStart function
To identify the current location (the one selected by the player or randomly this time), you can use the parameters of the PrepareStart() function:ObjectReference teleportMarker
One of the ways to identify current location is to add all your markers as ObjectReference properties and compare teleportMarker to them to indentify which one it is:ObjectReference Property MyMarker1 Auto
ObjectReference Property MyMarker2 Auto
function PrepareStart(ObjectReference teleportMarker, string locationTypeParam, string locationParam)
if teleportMarker == MyMarker1
;do stuff needed for location 1
elseif teleportMarker == MyMarker2
;do stuff needed for location 2
endif
;do stuff needed for both locations
endFunctionstring locationTypeParam, string locationParam
One of possible uses of these custom parameters is to identify the current location (as an alternative to teleportMarker):function PrepareStart(ObjectReference teleportMarker, string locationTypeParam, string locationParam)
if locationTypeParam == "MyType1" ;as set on the location type in the .json
if locationParam == "1" ;as set on the location in the .json
;do stuff for location 1 of type 1
elseif locationParam == "2"
;do stuff for location 2 of type 1
endif
elseif locationTypeParam == "MyType2"
;do stuff needed for all locations of type 2
endif
endFunction
You may find other uses of these parameters.
5.2. When your code runs and how to control that
The PrepareStart function is run before teleporting the player to the strarting location. The player doesn't get teleported unless one of two things happen:
1) Your PrepareStart function returned (ended)
2) Your script called TeleportPlayer() function
TeleportPlayer() allows teleportation and waits until the player is teleported, and can be used if you need to run some code after teleportation. If you don't need that, you don't need to use this function.
I.e. there are two options:function PrepareStart(ObjectReference teleportMarker, string locationTypeParam, string locationParam)
; code that runs before teleportation
endFunction
function PrepareStart(ObjectReference teleportMarker, string locationTypeParam, string locationParam)
; code that runs before teleportation
TeleportPlayer()
; code that runs after teleportation
endFunction
If you have some code that runs after teleportation, SUR doesn't wait for the PrepareStart() function to return - both scripts run in in parallel and SUR enables controls and advances the SkryimUnbound quest stage regardless of whether your function already returned or not. This is the desired behavior in most cases, but not if you want to show some messagebox or other menu to the player in your location addon script, because then if the player has other mods that add menus that pop up after the game start (like class selection), these menus will interfere with yours. For such cases there's AfterTeleportationSync() function.
AfterTeleportationSync() is another function that you can use in addition to PrepareStart(). It's called after the player is teleported to the starting location and (which is the difference from code after you call TeleportPlayer() in PrepareStart()) SUR waits for this function to return before enabling player controls and advancing the SkyrimUnbound quest stage. It means that mod-added menus that pop-up after the game start and check these things to determine when to pop up will be delayed until this function returns.function AfterTeleportationSync(ObjectReference teleportMarker, string locationTypeParam, string locationParam)
endFunction
Notes
Starting and stopping your quest
When creating a new quest in CK the "Start Game Enabled" flag is set. It's recommended to uncheck it, SUR will start your quest if it isn't started yet. It's also recommended to stop your quest once everything is done, unless you need it to be running. To do this, call Stop() in the last line of the PrepareStart function. This way your quest and script will only work when they're needed.
Creating Addons for Skyrim Unbound Reborn
-
Total views10.9k