Jump to content

How to add scripts to FO4?


Recommended Posts

 

You can do this on Actor or ReferenceAlias.

 

You have these events that are available:

; Event received when this actor starts a new package
Event OnPackageStart(Package akNewPackage)
EndEvent
 
; Event received when this actor's package changes
Event OnPackageChange(Package akOldPackage)
EndEvent
 
; Event received when this actor's package ends
Event OnPackageEnd(Package akOldPackage)
EndEvent

 

 

 

Yes, but that has to be attached to each and every actor...

 

What I hope exists is a place where I can attach the script and then have a event that would look like:

 

Event OnPackageStart(Package akNewPackage, actor NPCref) or similar

 

 

 

 

--------------------------------

 

 

OK, so it is not possible to do this as a general functionality.

What are the possibilities?

1. To add scripts to 40+ packages

2. To create a quest (oli3d suggested earlier on the chat creating a quest that scans for beds on cell load, checking if the beds are occupied and assigning triggers to them)

3. ?

Link to comment

1. editing 40 vanilla packages is long and risky. But probably the quickest solution.

2. scanning for beds will be a pain. And, do you have an easy way to track cell changes? Or a safe function to find furniture in F4SE? Not yet.

3. adding a single script to a refalias, and then duplicating it is quick. But then you have to fill all actors inside. So at the end is long.

Link to comment

From what I understood I add the PC as alias in the Quest and use it to detect cell changes. 

Then put the results of FindAllReferencesOfType() search for beds in another alias and add triggers.

However this is too complicated for me at my current level of CK understanding. Also it seems a lot less performance-friendly.

So editing packages it is. 

 

Link to comment

From what I understood I add the PC as alias in the Quest and use it to detect cell changes. 

Then put the results of FindAllReferencesOfType() search for beds in another alias and add triggers.

However this is too complicated for me at my current level of CK understanding. Also it seems a lot less performance-friendly.

So editing packages it is. 

 

If you ever plan on publishing this mod, please make sure you give proper warning about the fact that it uses poor methods and alters all Sleep packages found in the game. People need to be made aware.

Link to comment

 

From what I understood I add the PC as alias in the Quest and use it to detect cell changes. 

Then put the results of FindAllReferencesOfType() search for beds in another alias and add triggers.

However this is too complicated for me at my current level of CK understanding. Also it seems a lot less performance-friendly.

So editing packages it is. 

 

If you ever plan on publishing this mod, please make sure you give proper warning about the fact that it uses poor methods and alters all Sleep packages found in the game. People need to be made aware.

 

 

What is the better method?

This is the best method possible. 

The fastest, the most "organic" and "native", no scans, no chain of references, no memory impact, no complicated scripting that can cause problems. 

People who install mods should be aware that mods by definition "alter stuff in the game". 

And it is not exactly "altering". I'm adding a script to the packages and not changing anything that is already there.  

I'm going to attach the script to 5-10 packages. The ones with "default" in the name and leave custom ones like "InstituteMadisonSleep" that are used for a single NPC untouched. 

Also it is one and the same script. It is not a fragment that is copy/pasted around making it hard to maintain, debug and update.

I really don't see a better way to do it.

 

 

This is the current situation:

 

post-925979-0-02960000-1462731600_thumb.jpg

 

 

On the top left are the packages that use the Sleep template. Most of them a custom and I have decided to not touch them.

On the right is the package edit that in FO4 has also an option to attach a full script. 

Currently I'm running a debug there as seen in the script window.

Link to comment

So as far as I can tell, it's not as clean as you describe it.

Although adding a fragment that references a Quest script to run a single function to 5-10 packages sounds a lot better than adding something to 40 packages or even to all actors in the game, I still think there may be a lot of debris left.

And I don't really think this can be described as non-complicated scripting. It's a script that stores something, then does something and at a later point in time retrieves the data and does something again. Which leaves a lot of stuff in memory, and that stuff is going to be left in the save game even after you uninstall the mod.

 

Also, fiddling with master behavior packages isn't a great idea - I'm just saying.

Experience tells me things can go wrong with this. I may be wrong.

 

Don't forget to include a "Uninstall mod" function - to re-equip all currently naked actors with their gear and shut the functions down - because once we get the CellScan framework, that's going to be used instead.

 

 

EDIT: I just saw your picture.

Don't do that. Cleaner way is to add a new Quest, add a new Script to the Quest and then write the code in there like function Undress(actor akActor) etc etc.

Then just reference the functions in that Quest script from the packages. That way you don't duplicate your code and paste it all over the packages, instead the code is kept in one single place.

Link to comment

I may propose a smaller improvement on the scripts, to avoid to write tons of code for each of them.

 

Create a Quest, create a script that extends Quest.

Have an array of Actors

have an array of Armors

 

Add a function: setSleepOutfit(Actor a), and restoreNormalOutfit(Actor a)

 

In the first function check if the actor is in the array, if not, then add it, grab the armor, and save it, and then add the sleep outfit you want (that should be in a Property)

In the other function get the index of the actor, and restore the saved armor.

 

You may want to create a struct, in case you like to use a single array. This is a little bit more advanced.

 

And then on the "sleep package scripts", just add the property referring your quest script (<scriptname> Property <Quest name> Auto), and then call the first function in the OnStart, and the other function in the OnEnd.

 

If you will do a second version of your mod, you will need to change only the script on the quest to add new features.

 

Link to comment

I'm a bit confused.

It is already the same script. 

Open the package, select the script from the scripts list, add, done.

It is one and the same script. 

 

 

I'm not trying to do this in the easiest way, I'm trying to do it in the best way possible. That's why I made this thread :-)

So if is a bad way I'll just try another.

Link to comment

You can re-use the same code for multiple packages. But you have to re-fill the properties every time.

And if you day you want to add different sleep outfits based on some conditions, then it can be a pain to re-edit all the scripts in the packages to re-set the properties.

 

If you do it only once in a quest script, then you can do future upgrades way more easy.

Link to comment

Yeah, I had issues with that as well in F4SS. Wanted to implement a simple "Is Actor Naked" check - turns out no functions are available.

Right now you can easily do the undress part by .SetOutfit(outfitProperty) with outfitProperty pointing to an empty outfit, but well, actor is going to stay naked for the rest of the game unless you call Reset(), which also moves the actor back to editor position, thus is completely useless.

Link to comment

So for all intents and purposes the idea for such a mod is doomed at the moment. 

I need to find another idea to experiment with. 

 

 

 

There was a concern that adding scripts directly to the packages can lead to conflicts with other mods that add such scripts.

I made a test. I made 2 different esp files and attached 2 different scripts with similar content to the same packages in them.

 

The first script (PSS_SleepPackScript):

 

Scriptname PSS_SleepPackScript extends Package

Event OnStart(Actor akActor)
  Debug.Notification("This package started on " + akActor)
endEvent

Event OnEnd(Actor akActor)
  Debug.Notification("This package finished on " + akActor)
endEvent

 

The second script (PPPTest1) , added to the same packages in the second esp file is the same but the notification says "Haha".

 

They coexisted perfectly in the game:

 

post-925979-0-44972900-1462736093_thumb.jpg

 

 

They were also handled correctly by FO4Edit:

 

post-925979-0-36883000-1462736128_thumb.jpg

 

 

 

 

Link to comment

Of course they co-exist and both run. It's just a really messy way of handling the scripts. 

You have unnecessary copies of the same script, since you should be referencing them in a Quest script instead.

 

It's not about whether it works or not - it's about whether it's done properly or done hastily. Plastering scripts onto multiple objects when you can just have one script and reference that over and over again is an example of done hastily.

 

I think you should read through this page and all sub-pages. There are some good tutorials on there, including one that goes into referencing.

Link to comment

Of course they co-exist and both run. It's just a really messy way of handling the scripts. 

You have unnecessary copies of the same script, since you should be referencing them in a Quest script instead.

 

It's not about whether it works or not - it's about whether it's done properly or done hastily. Plastering scripts onto multiple objects when you can just have one script and reference that over and over again is an example of done hastily.

 

I think you should read through this page and all sub-pages. There are some good tutorials on there, including one that goes into referencing.

 

 

Again - it is the same script.

 

There are no "unnecessary copies" and there is no "them".

"when you can just have one script and reference that over and over again" is exactly what I'm doing. Except for referencing it - I don't need to. There is a way now to avoid all the unnecessary complications.

I really dion't understand why a solution that seems better on any account is considered worse.

Link to comment

Look, if you put that same script on each of the packages, the game creates a script instance for each .. instance.. of the script.

You know, if you ask here and one half-decent scripter (me) and an extremely decent scripter (CPU) tell you that you should be running the script on a Quest and referencing it, how big is the chance that we're just making this shit up to annoy you?

 

Please, if you ask for the best way like you did, then do follow up on that if you're being told what the best way is. Thank you and if you need any help with the whole referencing, let me know, happy to help.

 

Link to comment

Just a couple of considerations on performance, and instances.

 

OPTION 1 - It is the same script.

You create the source script once, and compile it once.

Then you go in all packages and attach it to the package.

Then you add the properties for the armors to be replaced, and some variables to keep the old armors.

 

OPTION 2 - use a quest script

You create the source script once, with all the functions, the properties, and the variables. in a quest.

You do an empty script for the package, with just one property (the quest script), that calls a function at begin, and one at end.

 

 

=== (as example I will consider 30 packages to be updated)

 

MEMORY OPT 1: (more memory)

1 instance for each actor that is running the package. a set of variables to store the armors, a set of properties to get the night outfit

 

MEMORY OPT 2: (less memory)

1 instance for the quest with only once the properties and the variables
1 instance for each actor that is running the package with only the referral property
 
Link to comment

Me today - the several times I almost "got it" :-)

 

post-925979-0-43878900-1462742096_thumb.gif

 

I guess the reason I'm confused in all of this is because I don't understand the quest approach and I'm missing something in the bigger picture. And the reason I keep asking Why is because I want to understand the logic behind all this so I can use it in the future.

The reason I want to make this mod is not because I want naked people sleeping in the game, but because I want to learn and understand how it works. 

So in the next few days I'm going to experiment with this and see where it gets me. Thanks for your help!

Link to comment

The thing you should focus on is Quests. Once you get the concept of how Quests work and what they do for the modder, you'll have unlimited possibilities. Except for doing what you want to do, because Bethesda will not have implemented the functions you need to do it. Count on it!  :D

Link to comment

Example code (super simplified)

 

 

Scriptname myNakedSleep extends Quest
 
function iAmGoingToSleep(Actor a)
  a.unequipAll()
endFunction

 

 

and then in your package

 

 

 
myNakedSleep Property myNakedSleepQuest Auto
 
Event OnStart(Actor akActor)
  myNakedSleep.iAmGoingToSleep(akActor)
EndEvent

 

Link to comment

 

Thanks for the example code. I think it helped me finally understand what are we talking about.

Translated into my web-developers mindset the quest script is a "library class" that contains the actual code the package scripts call. And the Quest thingy is a workaround in order to get it included into the system.

 

Basically, if I want to translate this into PHP it looks like:

 

 include ("myNakedSleep.php");

$myNakedSleep = new MyNakedSleep();

--> we use the Quest functionality in CK in order to achieve this - inject and initialize the library object

 

and then

$mynakedSleep->goToSleep($actor);

--> the package object calls the function from the library

 

I can completely agree that this is way better programming style than simply assigning the same script everywhere. It is more modular, more expandable and simply more beautiful solution. 

But I want to point out that the other solution (with assigning the script to the packages) while not so elegant is still technically correct.

 

And I still believe it is more memory efficient. 

It is been noticed before that Papyrus uses the term "Reference" not in the same sense as all the other languages and all the "references" are actually passed by value. So for each and every function or event call the parameters are duplicated in the memory.

This means that in the example when a NPC goes to sleep the package script that already has received it's own copy of the actor object will call the Quest script and will give it yet another copy of the actor object. And now instead of one we have two of them each within the scope of their script. And since each NPC that goes to sleep will create two instances - one of the each script, all the properties will also be created within the script.

 

Meaning - if John and Samantha are sleeping you have now 2 instances of the Quest script, each of them with it's own set of variables and properties (sleep outfit or whatever you assign via the properties window in CK). And with duplicated John and Samantha objects within the package script.

 

It's 3AM here now so I'm not sure if I'm explaining it correctly. And it is quite possible that I;m wrong. 

But I completely agree that using the library object is a better way to do it. 

Link to comment

Your statement is correct.

But you have only two options to create a reference:

1) Using a property

2) Getting a form from file

 

And "instances" are not "references" they are actual threads in the VM.

Link to comment

Your statement is correct.

But you have only two options to create a reference:

1) Using a property

2) Getting a form from file

 

And "instances" are not "references" they are actual threads in the VM.

 

 

I edited my post while you were posting this one. Since LL doesn't allow two consecutive posts I had to edit it :-)

Link to comment

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use