Differences from Skyrim to Fallout 4
- 1 Overview
- 2 What's Different?
- 2.1 Changes
- 2.1.1 Compiler
- 2.1.2 Events
- 2.1.3 Event Registration
- 2.1.4 OnUpdate Replaced
- 2.1.5 OnHit and OnMagicEffectApply require registration
- 2.1.6 OnItemAdded and OnItemRemoved no longer sent without filter
- 2.1.7 Fragments
- 2.1.8 Array Casting
- 2.1.9 Array Sizes
- 2.1.10 Smarter Import
- 2.2 New Features
- 2.2.1 ScriptObject script
- 2.2.2 Conditionally-Compiled Script Functions
- 2.2.3 Remote Event Registration
- 2.2.4 Custom Events
- 2.2.5 Const Auto Properties
- 2.2.6 Mandatory Properties
- 2.2.7 Const Variables
- 2.2.8 Const Scripts
- 2.2.9 Native Scripts
- 2.2.10 Property Dropdown Menu
- 2.2.11 Property Edit Window
- 2.2.12 Script Use Info
- 2.2.13 Project Files
- 2.2.14 Grouping Properties
- 2.2.15 Is Operator
- 2.2.16 Var Type
- 2.2.17 Namespaces
- 2.2.18 Structs
- 2.2.19 CK Compile Settings
- 2.2.20 Inter-mod Communication
- 2.1 Changes
For the most part, Papyrus remains the same between Skyrim and Fallout 4. A script written in Skyrim will be able to be brought over to Fallout 4 with a minimum of changes, sometimes just needed to be recompiled with the new compiler. Also note that Skyrim .pex files are not compatible with Fallout 4, and vice-versa. Both games will throw a "Game ID number doesn't match" error if you try to load a pex file from the other game. Just re-compile the file with the right compiler to fix the issue.
The compiler for Fallout 4 is different than the one for Skyrim. You shouldn't have to do anything special to use the new one, it's plugged into the editor and Sublime just like the old one (and Sublime should be set up to use the correct compiler based on the script source folder, if you've got the latest package). You can tell which compiler you are using by the output it gives. If you see "Papyrus Compiler 2.X.X.X for Fallout 4" then you're running the Fallout 4 compiler, and if you don't see that, it's the Skyrim compiler.
You may no longer make your own events in your script. Events may only be created in native scripts, and the compiler will enforce this. This means the compiler will now catch misspelling of event names, rather than thinking it's a new event entirely.
All event registration, from LOS events, to animation events, is now done on a per-script basis. So each script, even if attached to the same form, can be registered for it's own set of events. See the new ScriptObject Script for a list of events you can register for.
OnUpdate and its various versions have been completely replaced with a new timer system in Institute. A timer operates like the old RegisterForSingleUpdate except that you can register for multiple timers at once using different ID numbers and different durations, and the registrations are per-script. Other scripts on the same form won't get your timer events, and vice-versa.
- CancelTimer - ScriptObject
- CancelTimerGameTime - ScriptObject
- StartTimer - ScriptObject
- StartTimerGameTime - ScriptObject
- OnTimer - ScriptObject
- OnTimerGameTime - ScriptObject
OnHit and OnMagicEffectApply require registration
The OnHit and OnMagicEffectApply events now require registration before you can receive them, and the registration only sticks for the first event that matches the filter you give the registration method.
- RegisterForHitEvent - ScriptObject
- RegisterForMagicEffectApplyEvent - ScriptObject
- UnregisterForAllHitEvents - ScriptObject
- UnregisterForAllMagicEffectApplyEvents - ScriptObject
- UnregisterForHitEvent - ScriptObject
- UnregisterForMagicEffectApplyEvent - ScriptObject
OnItemAdded and OnItemRemoved no longer sent without filter
The OnItemAdded and OnItemRemoved events no longer are sent to any scripts that do not have any filters in place. You can give it a None filter to get all events, but you are then expected to be able to handle the player dumping hundreds of items into your container.
- AddInventoryEventFilter - ScriptObject
- RemoveAllInventoryEventFilters - ScriptObject
- RemoveInventoryEventFilter - ScriptObject
Fragment scripts are now stored in subfolders in the main script folder, grouped by type. They are also flagged as "const" which means you cannot change any property value they contain (see below for more information). To access a fragment script's properties, use the properties button on the fragment edit window, as the fragment script no longer shows up in the script list window.
Fragment functions are now sorted by name (rather then being in random order) and the function names will now match what they are associated with in the editor (like Stage_0010) which should help make looking at them in a text editor much easier.
Fragment scripts can be easily opened for edit in your favorite text editor using the new "Edit" button on the fragment's "Advanced" tab.
If you're missing a fragment script (or it is out of date) the editor will no longer make any changes to it if you don't edit it directly. This lets you edit non-fragment-related items in the form without having to have the latest script. If you do make a fragment-related change, the editor will now give you a better error dialog telling you every fragment that failed to load, and give you a few options to recover.
The fragment area in most edit dialogs now gives you the option to directly set a quest stage on the parent quest with a dropdown, instead of running a fragment. If all you want to have happen is a quest stage being set, please use this option rather then a SetStage in the fragment, as it is more memory-efficient. (And easier to use!)
Quest fragment scripts no longer automatically create Alias_* properties. You may create them yourself using the new dropdown menu next to the properties button in the stage fragment edit window. Just pick the property from the list that you want to create.
Topic Info Fragments
Topic info fragments will now include their parent quest name in the name of the script, to help associate them with a quest when you see them in errors or warnings.
Topic info fragments now have a "kMyQuest" dropdown that lets you pick a type for the topic info's parent quest. This will help in cases where you would normally write "GetOwningQuest() as MyQuestScript" in the fragment.
Scene fragments now have a "kMyQuest" dropdown that lets you pick a type for the scene's parent quest. This will help in cases where you would normally write "GetOwningQuest() as MyQuestScript" in the fragment.
Arrays can now be cast to other types of arrays. Doing so makes a copy of the array being cast, with any elements that failed to cast being set to None, 0, or the equivalent.
Array sizes can now be defined via a variable or expression, rather then being restricted to raw numbers. They may also be dynamically resized using add and remove functions. (The size restriction is still enforced, however)
The "import" command now works with namespaces so you don't have to prefix script names with their whole namespace (or even part of the namespace), as well as letting you use structs without prefixing them with their script name.
Institute now has a new ScriptObject script that is the base for all scripts in the game. It refers to an individual instance of a running script, rather then an in-game form or alias. As a result, all the functions on it run even if it isn't attached to a valid in-game object (or the object is unavailable, like when it's in a container). As another side effect, this allows all event registrations to be on a per-script basis, rather then per-form (see above). No more changing another script's OnAnimationEvent registration on accident!
Conditionally-Compiled Script Functions
There are two new flags that can be applied to functions and scripts - "DebugOnly" and "BetaOnly". These control whether these functions are left in or trimmed out from your script, based on the options given to the compiler.
Script functions in the Debug Script, as well as a few other functions, have been marked as "DebugOnly", which means that the compiler will now remove them from any script when building the release or beta script archive. This means that all your trace statements will not be visible on a machine running the either script archive. Scripts you build yourself will not strip these functions, if you're using the default compile options in your editor or the CK. If you need to get trace statements from someone else's machine who doesn't normally run with loose scripts, you may rename the "Fallout4 - Misc - Debug.bsa" file to simply "Fallout4 - Misc.bsa" to have the game use the debug scripts. (You'll probably want to rename the existing misc archive as well so you can restore it when you're done)
BetaOnly script functions operate in the same way as DebugOnly, but are only removed from release final archives. Both the debug and beta archives contain these functions, so if you want to see their output, you'll want to rename one of those so the game loads them. Again, by default, BetaOnly functions are included in scripts you compile.
If you want to compile your scripts for release, you can use one of the other compile batch files, add the options to the command line yourself, or change the CK into release mode in the script preferences tab.
Remote Event Registration
Another new feature in Institute is the ability to register for any event sent to another form. For example, your quest could register for OnDeath from an alias, without having to script the alias to tell the quest when it dies. More information is available on this page.
Institute also supports script-defined events that a single script can send, and multiple other scripts can register to receive. For example, you could have some kind of an earthquake marker that actors entering a location can register with and which periodically sends out an earthquake event, which the actors could use to stagger themselves. This way the actors just have to register when they enter the region, unregister when they leave, and the little script on the earthquake marker just has to focus on sending out the event without worrying about keeping track of every actor in the area. More information is available on this page.
- RegisterForCustomEvent - ScriptObject
- SendCustomEvent - ScriptObject
- UnregisterForCustomEvent - ScriptObject
Const Auto Properties
By adding the word "Const" at the end of a property definition, you are telling the game that the value will not change once it has been set by the editor. The compiler will make sure you cannot change the property's value, and the game will ignore any value in the save game recorded for the property. This allows you to change the value of a property in the editor, and have the change be reflected in the game, even if you load a save game. Properties made via the editor will be const by default.
By adding the word "Mandatory" at the end of a property definition you are telling the editor that the property should contain a value in the plugin. As such, unfilled mandatory properties will cause warnings when the plugin is loaded in the editor, will display as red in the property edit window, and the editor will complain when closing a property edit window with unfilled mandatory properties.
By adding the word "Const" at the end of a variable definition, you are telling the game that the value will not change from the value given on the line the variable is defined on. Const variables must have their initial value set on the same line as the definition. The compiler will make sure you cannot change the variable's value, and the game will ignore any value in the save game recorded for the variable.
Const scripts can be made by adding "Const" to the end of the Scriptname line. This tells the game that the script does not store any actual data, and the game may choose to unload the script at any time to save memory. You may not have non-const variables or non-const auto properties in a const script, nor can you have states, and the compiler will print out an error if you try. Fragment scripts are all flagged as const.
Scripts can now be flagged as "Native" by adding it to the end of the Scriptname line. Scripts flagged as such are expected to be a script the game itself knows about and are the only scripts allowed to have new events defined in them. They also are not allowed to have states, variables, or auto properties. Modders should not need to make any native scripts and the flag is added mostly to improve error reporting from the compiler and prevent mistakes.
Property Dropdown Menu
In the editor, a little down-arrow button is next to the properties button on fragments, and the "Add Property" button inside the property edit window. Clicking on this arrow shows you a list of properties that can automatically be created for whatever you're editing, as well as a new "Create from form" option. Picking this option will allow you to type in the editor ID of a form, and have the editor automatically create and fill a property with that form on the script. You can change the name and type if you want it to be something different, as well.
Property Edit Window
Auto properties with a default value in script will now show their default value in the property edit window, if they are not given a value there.
Script Use Info
The Papyrus Use Info dialog (access via "Use Info" in the right-click menu of a script in the Papyrus script manager) now lists all Papyrus scripts that use a particular script, as well as any forms.
The Papyrus compiler now supports project files (XML files with a .ppj extension). This allows you to easily build a set of files at once without having to run the compiler multiple times, and also speeds up the editor build process when using the "Compile Papyrus Scripts" option, or building scripts after retrieving them from Perforce. A longer description is available here.
Properties may now be grouped together and their order preserved using groups. Just surround the properties you want grouped in a "Group <name> ... EndGroup" block.
The new "Is" operator has been added, allowing you to query the type of a variable without actually casting it. If used on a basic type (like int or string) the operator is strict and returns true only if the type exactly matches (even if a cast would succeed). If used on an object type (like Alias or ObjectReference) the operator is less strict and returns true if the type matches or if a cast would succeed. Note that if you're going to do the cast anyway it may be faster to just do it rather then using "is" and then "as" later on.
The new "Var" type has been added. Variables of this type can have any value assigned to them and will remember the value and type that they were given. The only thing you can do with a var variable is to ask it for its type (via "is") or to cast it (via "as"). This is most often used for passing parameters to custom events (via an array of var values). The only exception is that Var variables cannot accept arrays.
A script can now be put into a "namespace" which lets you organize scripts into subfolders. Namespaces are designated by separating a series of identifiers with ':' characters. The namespace must match the path to the script file, relative to the root script folder. For example, the script "Scripts/Traps/Triggers/Tripwire.psc" would be named "Traps:Triggers:Tripwire".
Structs can be defined inside scripts which let you group related variables together into something that can be passed-around by reference or stored in an array or var.
CK Compile Settings
The Creation Kit now supports setting what mode the compiler should run in, being debug (the default), release (optimizations turned on, debugOnly functions removed), and release final (release + betaOnly functions removed).
Several new functions have been added to allow one mod to communicate to scripts on another mod without depending on those scripts directly. This allows you to call functions, access properties and get events from other mods which the user may or may not have installed, in cause you want to "light up" special features of your mod in response, or if you want to add custom items you created to a target mod if it exists.