Jump to content

Curiosity: How does it work? Things, I need to learn in the CK


worik

1,474 views

TLDR: how do I do certain things in the CK?

 

Now that I learn a bit about modding in the CK, https://www.loverslab.com/blogs/entry/7679-window-peeking-or-how-do-i-learn-to-love-the-creation-kit/

I come upon some good practises that I noticed in mods from other authors,... and I try to figure out how to achieve those.

 

 

Maintainability: Good quest structures

I took a first idea of that  from here https://www.loverslab.com/topic/50094-radiant-prostitution-322-29-oct-2015/?page=14&tab=comments#comment-1278057 (Stage handling and failsafe quest cleanup)

I think his is a good idea to make them understandable and hopefully reduce mistakes, logical errors, ...etc.

Based on that, I learned the hard way, that all quests are prone to trigger scipt heavy activities at the same time. Worst moment is the game start.

Next thing is, that all too often the game runs into an unforseen situation. If all is well designed, the player should be able to recover the situation, skip the story a bit and continue at the next safe stage.

My principle §1: avoid quest with "start game enabled" and prefer delayed actions, triggered by willing actions of the player. Make sure quests are clean and with proper stages. Allow for player intervention with console commands.

 

 

Controlled start/stop: How do I enable certain parts of my mod AFTER the player performed an enabling trigger

I see it as a good practice to enable / disable parts or all of mods based on someplayer action.

They can be in the MCM "swicth mod on/off" or by an action in game, like reading a book.

I took a bit of the last weekend and tried to learn from @Blackbird Wanderer's SBC how this can be done.

But I think, I still have to learn a lot more about this and would be very happy to find more examples. Especially for the stopping/shutdown/disable part, I am still lost. :classic_shy:

If anyone could point me to some more reading stuff or examples in mods with script sources?

Anyway, I will be experimenting a bit with what I have learned already.

My principle §2: allow the player to start, stop, reset, and selftest a mod in game at his own command.

 

 

Handling dependencies: How to check if other mods are present and how do I do soft dependencies?

I think the question says it all, and again it was Blackbird Wanderer's SBC and @Teutonic's SLAdv, where I could learn quite a bit how to do that.

My principle §3: avoid hard mod dependencies, employ selftests and feedback messages if a mod is found/not found

My principle §4: allow the player to override the names and ID's e.g. if the player merged a required mod, or if it was updated

(side note RP/RPG has such a feature in an plain txt file)

Update, 20200125:

@Lupine00 wrote a very helpful post about it: https://www.loverslab.com/blogs/entry/10593-soft-dependencies-without-pain/

 

 

Updating: How do I know if an update would need a clean save and when not?

I am totally lost on this question and still have no idea, which changes in my mod(s) could be considered "safe" and why? :classic_blink:

But if I release a mod, it will certainly receive updates. So this question will be important.

Any comments, hints or links would be very helpful for me.

 

 

Internal maintenance: How do I do internal updating routines?

I have seen this feature with @Inte's POP @Teutonic's SLAdv and in some other mods as well. This is veeery player-friendly in my eyes and something that I decided for my self as a must.

But it stretches beyond my abilities yet, what I have to watch out for and how I can do these. :classic_blink:

Of course this question is secondary and to be answered after the "safe/not safe" question above. A dedicated internal maintenence/update routine would only be needed for "unsafe" updates, right?

I feel pretty sure, that I have to follow certain principles in the design of my quests and scripts. Yet, I have no clue what they could be.

Again, any comments, hints or links would be very helpful for me.

 

 

... more questions will come... curiosity is still rising

..

 

 

Thanks and credits

The code and the mods of these authors below have already been very helpful for me to learn and understand. Thank you very much :classic_smile:???!

 

 

15 Comments


Recommended Comments

Quote

Updating: How do I know if an update would need a clean save and when not?

I am totally lost on this question and still have no idea, which changes in my mod(s) could be considered "safe" and why? :classic_blink:

But if I release a mod, it will certainly receive updates. So this question will be important.

Any comments, hints or links would be very helpful for me.

The most common reason for needing a clean save has to do with script properties.  The values in script properties are stored with each savegame, and the values you give them in the CK are just the default values they get when the script is first loaded.  If you change a property value when making a new version of your mod, the value of that property won't be updated in older saves.

 

A simple example:

  1. You have a scripted event that equips an Iron Helmet to the player.  In order to access the Iron Helmet item from your script, you need to add an Armor property and set its value to Iron Helmet.  Then you release your mod (version 1).
  2. You're making some changes to your mod, and decide you'd rather equip a Steel Helmet instead.  So you change the Armor property to Steel Helmet and release version 2 of your mod.

For a player who started their game under version 1, the script property would have been initialized to Iron Helmet and stored in their savegame.  If they upgrade to version 2, the new Steel Helmet value won't be used because the property already has a value set in their savegame.  So they'll always get the Iron Helmet on that save.  If they clean the save, by removing your mod and saving and then reloading with your mod, then the script will be reloaded from scratch with the new default value.

 

There is a way to work around this, but it's not always feasible: if your script has some startup code that runs on game load (or if you can add some), you can use GetFormFromFile to set the property directly and ensure it has the correct value, effectively bypassing what's been set in the CK altogether.

Link to comment
10 hours ago, Holzfrau said:

The most common reason for needing a clean save has to do with script properties. 

Thank you very much ! :classic_cool: ?

I think this is the first time that I understood a bit about the background :classic_lightbulb:

 

Link to comment

To add on the comment about script properties, it is really an issue if your script is attached to a Quest Alias. 

Once the quest is started, the script is 'baked' into your saved game.

If you change properties on that script, the game will detect the change and keep running the previous version of the script baked into the saved game.

 

Two solutions to that:

 

1- Make quests repeatable and force a stop/start when you load the game after a big version change. That will reset the aliases and load a new version of the scripts.

2- Move heavily modified functions into scripts that are not attached to quest aliases and have them behave like mini libraries. I found you can make changes to scripts without having to reload the main quests that way. 

 

For an example of this, look at the player alias script in SD+

 

https://github.com/SkyrimLL/SDPlus/blob/master/SanguineDebauchery/Data/scripts/source/_sdras_player.psc

 

The definitions of script functions like fctSlavery at the top of the script make it possible to access functions inside each scripts by creating an alias of that script file name as a property.

 

_SDQS_fcts_slavery Property fctSlavery  Auto

 

Where '_SDQS_fcts_slavery' is the file name of the script (without extension) and 'fctSlavery' is a local property defined for that script.

 

That way I can call internal functions defined in that script through 'fctSlavery.StartSlavery()' or 'fctSlavery.GetMaster()'. These two functions 'StartSlavery()' and 'GetMaster()' are defined inside the _SDQS_fcts_slavery.psc script, but I can call them inside the quest alias script using that property.

 

This saved me from hours of headaches testing things only to realize that the quest never updated what I changed in the first place.

Link to comment
On 12/24/2018 at 3:50 PM, DeepBlueFrog said:

Two solutions to that:

Again two very helpful hints :classic_cool: Thank you very much and merry christmas ???

Link to comment

Try GetModByName. The checks to see if the mod is loaded. If not, you don't need to try and load anything from it, and you don't clutter up t he papyrus log with loads of errors where it couldn't find things that were never going to be there.

 

For enabling things based on quest events, a good trick is to set an enable parent. For instance, if you had fifty bandit captives that weren't supposed to exist until the player reads a certain note, you can set them all with an enable parent. I usually set up a test cell somewhere and I'll leave the enable parent as an object on a table there. When something happens (like reading the note) A script can enable the object in the test cell and all the "enable children" will be enabled as well.

 

There's an option to use the opposite state to the parent as well. In S.L.U.T.S, I put a cow skull on a rock by t-junction where the path up to Whiterun joins the main road. If you activate the skull, it turns into a human skull, and also enables a bunch of bandits down the road a little way. That was just so I could test to see what happen when you were attacked while pulling the cart, but it's also a nifty use of enable parents. The cow skull is the enable parent for the human one (which uses the opposite state) and the bandits have same-state enable parent links to the human skull.

 

For larger scale control, I tend to have a master quest end test for quest stage. Ideally you'd keep that one just to keep track or progress and put functionality in sub-quests launched from the MQ stages ... but I never seem to do that in practice. Another possibility would be to use a player faction rank. It's always there, can be tested in conditions as well as scripts, and unlike quests, it's easy to roll back if you want to reset something.

Link to comment
On 3/7/2019 at 1:03 PM, DocClox said:

For enabling things based on quest events, a good trick is to set an enable parent.

That's a cool trick. I didn't know that one yet. Thank you ?

Link to comment
On 12/25/2018 at 1:50 AM, DeepBlueFrog said:

To add on the comment about script properties, it is really an issue if your script is attached to a Quest Alias. 

Once the quest is started, the script is 'baked' into your saved game.

If you change properties on that script, the game will detect the change and keep running the previous version of the script baked into the saved game.

If you look at Monoman's favored pattern, he uses GetFormFromFile to get almost every form he wants, even within his own quests and quest fragments.

 

This means he doesn't have (m)any properties that end up baked into his files, because he uses hex IDs for everything instead.

It's probably not the best in terms of performance, but it does avoid a pain-point in creating a mod that is easy to update.

 

Defeat had a more disciplined approach to this, with code to reset all its properties using GetFormFromFile if it needed to.

SLD has something similar, but its more case-by-base, but it should be able to rebuild on demand any group of data that plausibly needs update, and if it can't, then I add that capability as I need it. Reliance on properties is rare, but does occur.

 

Monoman still runs into the dialog problems, as there's no way to code around them with GetFormFromFile :) 

I brought this up on the SLS forum just today, as it's been a thorn in my side in DFC.

 

What data within a dialog, or a topic are baked in, and what data is re-loaded. I can clearly see deleted dialogs will show up, but it does seem to be possible to add condition records beyond those existing, and in that case the new records are loaded and applied.

 

This leads to a wasteful pattern, where old dialogs are killed by adding perma-false conditions on the end of their conditions lists, and then they are replaced with replica dialogs that perhaps modify some nuance of a pre-existing condition. As its a new dialog, it has to be loaded fresh. It's the only way to make the dialog update with an edited ESP that I'm aware of - without forcing a new game. However, I seek further information on the topic. With all these things, usually, engine experts have written about it, but not on popular forums, or in places where their information is easy to find.

Link to comment
On 12/25/2018 at 1:50 AM, DeepBlueFrog said:

Two solutions to that:

 

1- Make quests repeatable and force a stop/start when you load the game after a big version change. That will reset the aliases and load a new version of the scripts.

2- Move heavily modified functions into scripts that are not attached to quest aliases and have them behave like mini libraries. I found you can make changes to scripts without having to reload the main quests that way.

I have a slightly different perspective on (2).

 

Write all scripts bound to aliases as empty wrappers.

Each function does nothing but call the function in the 'real' script. It's technically similar to (2), but the emphasis is different. You know that there is essentially nothing in those alias holders except the calls out, one per event.

 

SLD has (1) and that variant of (2). The sex scene threads and their manager are restartable on demand, while the main OnLoad handler is nothing but an empty wrapper.

Link to comment

On quest stages, I would urge caution. Maria Eden's newest incarnation does everything with quest starts, and to a lesser extent stages.

The idea that story manager could spin up quests instantly, and could handle limitless quests and trigger conditions led to the overloading the story manager, so it couldn't traverse properly, breaking quests pervasively, not just in ME itself.

 

Don't make excessive use of the story manager, and bear in mind that starting a quest is a very slow operation, and quite costly.

If you want some internal state, quest stages can be checked quickly, but changing one is complex, because there are so many things that can be triggered by it.

 

If you want to build a state-machine, don't use quest stages to do it, use an Int value in StorageManager to store the state; it's thread-safe and fast.

 

If all you want to do is track a number, use a GlobalValue. You can use it just the same in dialog conditions, and also in dialog texts, which you can't do with a quest stage.

If you don't need those capabilities, use a StorageUtil value.

 

If you genuinely want to track quest progress, then don't use stages unless you are going to do it properly, with journal messages that advance and clear properly.

I see many quests full of stages that are implementing an internal state-machine in the quest. This leads to a mass of fragments where a single script file would have sufficed.

Large numbers of fragments are a terrible pain to look after, release and maintain - also it's hard to associate fragments back to their points of use.

 

The number of quests I've seen that create objectives that are NEVER, EVER removed from the journal, cluttering it up with rubbish, are endless.

I tend to lose faith in a mod that can't keep its quest objectives clean. If the attention to detail on something so visible is so poor, what hope do the hard-to-spot issues have?

Link to comment
6 hours ago, worik said:

I thought, that's what the papyrus states were made for

Not really. They are intended for thread safety, but not for developing real state machines in the sense I'm describing them.

You can make state machines with them, but not good ones. They only allow function overloads. In practice a state machine may not even want to do that.

 

I had in mind the typical mis-use of quest stages, where a mod has maybe 25 stages in  a 'quest' which is really just a dialog container, none of which are sequential, and none of which have journal entries of goals in the quest sense; they're just used in dialog conditions. 

 

Imagine a practical use of a state machine in a quest: prostitution.

 

What states would we have:

 

Advertising for client (wait for client to come to you)

Hunting client (asking clients)

Negotiate act

Negotiate price

Lead to sex location

Follow to sex location

Invite sex

Customer demands sex

Customer tries to change the deal

Customer binds PC

Customer unbinds PC

Sex

Post sex

Negotiate follow-up act

Negotiate follow-up act price

Collect payment

Customer runs

Customer goes to pay innkeeper

etc.

 

There are tons of states, and you would probably add more and more as you developed the mod.

For the state machine to be well implemented, we want all transitions to work the same way, but using Papyrus states requires us to hardcode branching logic for each state instead of data-driving the whole thing. Appalling.

 

In the data driven version each state is just an integer value, and the transition tests are just a list of integer indices per state used to determine the entry conditions.

You can load the definitions from a file, and even modify your state machine without stopping Skyrim.

I haven't written such a machine yet (for Skyrim), but it's likely I will add one to SLD to drive the sex-threads.

I have used such machines in the past though.

 

I'm not saying the Papyrus states are useless for this, but they are very static, and you have to bind a lot of code to them. It's not flexible.

I use the for managing very simple state sets like "mod enabled" / "mod disabled" / "mod starting" / "mod stopping" but beyond those sorts of scenarios they are too clunky.

Link to comment
20 minutes ago, Lupine00 said:

I'm not saying the Papyrus states are useless for this, but they are very static, and you have to bind a lot of code to them. It's not flexible.

I use the for managing very simple state sets like "mod enabled" / "mod disabled" / "mod starting" / "mod stopping" but beyond those sorts of scenarios they are too clunky.

? Your post is just in time. ... to stop me from trying to shoot myself an arrow in my knee :classic_blush:

 

:classic_laugh:

I had indeed tried to write a bunch of my storytelling in mini-stages with states ... :wacko: overly complicated and in reflection most likely to contains errors.

Link to comment

×
×
  • 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