Jump to content

[HOW-TO] FO4: Papyrus: Sharing Code Between Scripts and Fragments


fireundubh

Recommended Posts

I've been reworking Auto Loot to dynamically support DLC while not actually requiring DLC.
 
I've learned some things that might be useful to you if you want to share code between your scripts. I'll use examples from my scripts.


Create a quest
 
In order to share code between scripts, you need to:

  • Create a quest that starts enabled.
  • Attach a library script that will contain all of your shareable code to that quest.
  • Make note of the Form ID of the quest record. The load order (first two digits) does not matter.

 

Your library script
 
In your library script, add a GetScript() function like this:

dubhAutoLootLibraryQuestScript Function GetScript() Global
	Return Game.GetFormFromFile(0x00019FB7, "Auto Loot.esp") as dubhAutoLootLibraryQuestScript
EndFunction

The GetFormFromFile() function uses the name of a plugin to retrieve the load order to be used with the Form ID, so make sure you do not include the load order in the Form ID.


 
Update your scripts
 
In the scripts with which you want to share code from your library, create a locally scoped variable. For example:

dubhAutoLootLibraryQuestScript AutoLoot = None

The data type should be the name of your library quest script, and the reason why we set the value of the variable to None is simply to instantiate the variable.
 
We want the variable to be scoped outside of any events or functions because we don't want to declare the variable in every function or event where we want to use code from the library.
 
In the entry point to your script, such as OnEffectStart() in an ActiveMagicEffect script, assign the library script to that variable using the GetScript() function.

Event OnEffectStart(Actor akTarget, Actor akCaster)
	AutoLoot = AutoLoot:dubhAutoLootLibraryQuestScript.GetScript()
	If AutoLoot
		StartTimer(dubhAutoLootDelay.Value, dubhAutoLootTimer)
	Else
		Debug.Trace(Self + " Could not find 0x00019FB7 in file: Auto Loot.esp")
	EndIf
EndEvent

Using library code

Now, you can use functions, properties, etc., from the library script wherever you want in your ActiveMagicEffect script.

Event OnTimer(Int aiTimerID)
;...snip...
	If LootArray.Length > 0
		LootArray = FilterArray(LootArray)
		AutoLoot.LootContainerArray("Container", LootArray, dubhAutoLootPerk)
	EndIf
;...snip...

	If AutoLoot
		StartTimer(dubhAutoLootDelay.Value, dubhAutoLootTimer)
	Else
		Debug.Trace(Self + " Could not find 0x00019FB7 in file: Auto Loot.esp")
	EndIf
EndEvent

Ta-da! You'll need to do this for every script in which you want to share code from your library.


 
Sharing code with fragment scripts
 
You can also do something similar with fragment scripts. Here's a straightforward example:

ScriptName AutoLoot:Fragments:Terminals:TERM_dubhAutoLootMenuContain_010026F4 Extends Terminal Hidden Const

;...snip...;

;BEGIN FRAGMENT Fragment_Terminal_06
Function Fragment_Terminal_06(ObjectReference akTerminalRef)
;BEGIN CODE
AutoLoot:dubhAutoLootLibraryQuestScript AutoLoot = Game.GetFormFromFile(0x00019FB7, "Auto Loot.esp") as AutoLoot:dubhAutoLootLibraryQuestScript
AutoLoot.ConfigureSupportForDLC()
;END CODE
EndFunction
;END FRAGMENT

;...snip...;

If you're new to Papyrus in Fallout 4, this probably doesn't look that straightforward, right?
 
You'll note from the ScriptName that I'm using project folders (Scripts\User\AutoLoot\Fragments\Terminals).
 
In order to declare the library script variable in a script contained in a different folder, you need to declare the variable's data type using the path to the library script.
 
In Papyrus, colons are backslashes. These are equivalent:

  • System path: AutoLoot\dubhAutoLootLibraryQuestScript[.psc|.pex]
  • Papyrus path: AutoLoot:dubhAutoLootLibraryQuestScript

So, remember that the data type is also the path to the script.
 
In fact, this is true for every data type, excluding perhaps the standard data types like Bool, Int, Float, and String.
 
You just don't notice this at first because Bethesda placed scripts like Actor.psc, Formlist.psc, etc. in the root Scripts folder to make things easier on everyone.
 
I hope that helps.

  • Like 1
Link to comment
Share on other sites

A slight improvement:

 

In the library script itself, make a GetScript() function, like so:

dubhAutoLootLibraryQuestScript Function GetScript() Global
	return Game.GetFormFromFile(0x00019FB7, "Auto Loot.esp") As dubhAutoLootLibraryQuestScript	
EndFunction

In whichever script you want to use that library, you can get it as follows now:

dubhAutoLootLibraryQuestScript LQS = dubhAutoLootLibraryQuestScript.GetScript()

Advantages are that you don't have to look up the formID every time you want to make use of it, and that you won't have to modify all scripts relying on it when you modify it in Auto Loot.esp (or when you change the name of the esp).

 

In Fallout4, the Attraction Object scripts make plenty of use of this.

Link to comment
Share on other sites

That wouldn't compile the first time I tried it. I'll try again.

 

edit: Yeah, that doesn't work.

variable dubhAutoLootLibraryQuestScript is undefined
edit: When you have a project folder, you have to do this:

dubhAutoLootLibraryQuestScript AutoLoot = AutoLoot:dubhAutoLootLibraryQuestScript.GetScript()
Gets a bit redundant in fragments:

AutoLoot:dubhAutoLootLibraryQuestScript AutoLoot = AutoLoot:dubhAutoLootLibraryQuestScript.GetScript()
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...