Jump to content

[LE] Is it possible to give every NPC a custom stat/attribute? The player?


Sigillimus

Recommended Posts

Disclaimer: I'm still learning the Creation Kit, so this could be an obvious or simple question.

 

I'm curious about whether it's possible to create a new stat/attribute for the player/NPCs that I would then have the ability to reference in a conditional Papyrus script or dialogue topic. Something like (just as an example) creating a 'Bravery' attribute that ranges from 1 to 100, that I'd be able to create logic or dialogue for people to react to. I hope that's descriptive enough. And thanks in advance for any help.

Link to comment
Share on other sites

Disclaimer: I'm still learning the Creation Kit, so this could be an obvious or simple question.

 

I'm curious about whether it's possible to create a new stat/attribute for the player/NPCs that I would then have the ability to reference in a conditional Papyrus script or dialogue topic. Something like (just as an example) creating a 'Bravery' attribute that ranges from 1 to 100, that I'd be able to create logic or dialogue for people to react to. I hope that's descriptive enough. And thanks in advance for any help.

The answer is "kind of but not really", basically.

 

You cannot create new arbitrary actor values proper, only repurpose existing ones, which leads to lots of conflict potential.

 

As alternatives, you can add script variables to the player that you can expose to the condition system, and as long as it's just the player you intend to do this to you can make everything work fine. You can also do some really hacky workarounds with factions and quests to do something with NPCs generally, but it's a kludge.

Edited by foamyesque
Link to comment
Share on other sites

Are these script variables persistent across the player's dialogues/NPCs, something that would stick to the player and could be adjusted dynamically? If so, could you tell me how they can be created/exposed? Since what I've got in mind only really has to do with how the player interacts with NPCs, and not how they interact with each other, then I could create a single variable for just the player that could be raised/lowered and weighted positively/negatively based on their choices, actions, etc.

Link to comment
Share on other sites

Are these script variables persistent across the player's dialogues/NPCs, something that would stick to the player and could be adjusted dynamically? If so, could you tell me how they can be created/exposed? Since what I've got in mind only really has to do with how the player interacts with NPCs, and not how they interact with each other, then I could create a single variable for just the player that could be raised/lowered and weighted positively/negatively based on their choices, actions, etc.

 

There's a few ways. The most straightforward, if you're interested in just tracking one specific thing for the player, and don't need high speeds, is a global variable. Globals can be checked by the condition system quite simply and worked with in scripts. If it's something you need to manipulate a lot, you might look into a local script variable: you'd create a script attached to a quest alias that contains the player, flag the script as conditional, and declare the variable as a conditional property. Then you can use the condition GetVMScriptVariable to pull out and test it.

Link to comment
Share on other sites

The most straightforward, if you're interested in just tracking one specific thing for the player, and don't need high speeds, is a global variable.

 

TBH I'd actually expect access to a global to be marginally faster than access to a script variable, but probably only on the order of milliseconds either way.

 

 

 

I'm still learning the Creation Kit

I don't know how easy this will be for you to follow since we'll be talking about scripts, but fortunately, you don't need to know absolutely everything I'm about to tell you; I'm just gonna try to give you some idea of how far you can go.

 

Globals are the simple approach, for if you need to track values on the player only. For example, if you want NPCs to comment on the player's bravery, a single global for bravery will get the job done. Every NPC will always have a perfect, real-time awareness of the player's bravery.

 

If you want a more detailed approach, then you can use a script. Bethesda did that for Serana: her DLC1_NPCMentalModelScript has tons of boolean variables to track specific dialogue choices that the player has made, along with several script properties for managing her short-term and long-term mental state. These properties wrap private variables in getters and setters: this means that you can interact with these properties by just passing in a value, but when you do, the game automatically runs script code, which can validate, change, or even reject the value before it's stored.

 

In this case, getters and setters are used to do all of those things. The short-term "axis" properties represent Serana's emotions as opposing values (e.g. seriousness versus playfulness) and their setters call a function (to change her animations) when the values cross from positive to negative or vice versa. The long-term properties represent Serana's view of the player-character (e.g. does she trust the player), and their setters clamp incoming values to a minimum and maximum.

 

(Where this gets really clever is this: the script allows for much more advanced behaviors. Bethesda never used any of it, but they track how often Serana crosses an axis (e.g. switching from guarded to open). Bethesda also planned to add "anchors" -- values that her emotional state would drift toward whenever nothing happened for a while -- and these anchors would move as her relationship with the player changed. Bethesda may have left these things incomplete on purpose: they'd be great if Serana had meaningful interactions throughout an entire playthrough, but due to limits on what Bethesda could do (and had time to do) in DLC, she only has content for her own storyline.)

 

Even if you don't want to get that detailed, using a script still works well if you want to be able to manipulate your mental model properties "blindly." For example, if you want a dialogue fragment to "increase the player's bravery by 3" without worrying that it'll exceed some maximum bravery level, then you can write a script that has "increase" and "decrease" functions on it, and these can check and restrict the incoming value.

Edited by DavidJCobb
Link to comment
Share on other sites

 

The most straightforward, if you're interested in just tracking one specific thing for the player, and don't need high speeds, is a global variable.

 

TBH I'd actually expect access to a global to be marginally faster than access to a script variable, but probably only on the order of milliseconds either way.

 

Setting or getting a global variable requires an external function call from whatever script is doing so, which means other tasks can jump in and delay getting the result back. For the operations the OP's appears to be planning the difference is irrelevant, but for heavy-duty processes the distinction is very dramatic.

Link to comment
Share on other sites

For tracking things with a reasonably small number of values for arbitrary NPCs as well as the player one of the best options is to use a custom faction and treat its rank value as the number. Skyrim mostly uses faction membership tests but SetFactionRank and GetFactionRank are extremely useful if you need to associate small integer numbers with every NPC. If you want NPCs to be able to react to the player's current Bravery level you would just write conditions to check the player's rank in your Bravery faction. You will be limited to values in the range 0 to 127 because faction ranks are stored as signed bytes with negative values having special pre-defined meanings (although you can get away with using -1 if you really need it).

 

If you're only interested in the player's Bravery then a global variable will work just as well or better.

 

 

 

The most straightforward, if you're interested in just tracking one specific thing for the player, and don't need high speeds, is a global variable.

 

TBH I'd actually expect access to a global to be marginally faster than access to a script variable, but probably only on the order of milliseconds either way.

 

Setting or getting a global variable requires an external function call from whatever script is doing so, which means other tasks can jump in and delay getting the result back. For the operations the OP's appears to be planning the difference is irrelevant, but for heavy-duty processes the distinction is very dramatic.

Global variables are highly optimized, the only time a script variable would be faster is when it is accessed from that same script. When accessed from anywhere else including conditions on dialogue, spells, etc. the script property (and it has to be a property for remote access) will be slower than a simple global.

Link to comment
Share on other sites

 

 

The most straightforward, if you're interested in just tracking one specific thing for the player, and don't need high speeds, is a global variable.

 

TBH I'd actually expect access to a global to be marginally faster than access to a script variable, but probably only on the order of milliseconds either way.

 

Setting or getting a global variable requires an external function call from whatever script is doing so, which means other tasks can jump in and delay getting the result back. For the operations the OP's appears to be planning the difference is irrelevant, but for heavy-duty processes the distinction is very dramatic.

Global variables are highly optimized, the only time a script variable would be faster is when it is accessed from that same script. When accessed from anywhere else including conditions on dialogue, spells, etc. the script property (and it has to be a property for remote access) will be slower than a simple global.

 

How dramatic is *that* difference, anyway? Between a global's GetValue/SetValue calls and a ExternalScript.Property = x call? Or as used in the condition system? I'm curious, though it's not really important here AFAICT.

Link to comment
Share on other sites

The real difference would be that to use the variable you need a lock on the object. The lock on the global variable is only locking that one value. The lock to access a script variable has to lock the object holding that script which can have far more potential conflicts with other scripts and events. SmkViper (one of the Papyrus developers) said that the locks and access features for global variables are unique and highly optimized compared to those for other objects.

Link to comment
Share on other sites

For tracking things with a reasonably small number of values for arbitrary NPCs as well as the player one of the best options is to use a custom faction and treat its rank value as the number. Skyrim mostly uses faction membership tests but SetFactionRank and GetFactionRank are extremely useful if you need to associate small integer numbers with every NPC. If you want NPCs to be able to react to the player's current Bravery level you would just write conditions to check the player's rank in your Bravery faction. You will be limited to values in the range 0 to 127 because faction ranks are stored as signed bytes with negative values having special pre-defined meanings (although you can get away with using -1 if you really need it).

 

If you're only interested in the player's Bravery then a global variable will work just as well or better.

 

 

 

The most straightforward, if you're interested in just tracking one specific thing for the player, and don't need high speeds, is a global variable.

 

TBH I'd actually expect access to a global to be marginally faster than access to a script variable, but probably only on the order of milliseconds either way.

 

Setting or getting a global variable requires an external function call from whatever script is doing so, which means other tasks can jump in and delay getting the result back. For the operations the OP's appears to be planning the difference is irrelevant, but for heavy-duty processes the distinction is very dramatic.

Global variables are highly optimized, the only time a script variable would be faster is when it is accessed from that same script. When accessed from anywhere else including conditions on dialogue, spells, etc. the script property (and it has to be a property for remote access) will be slower than a simple global.

 

If you only want to access the variable as a condition, it doesn't have to be a property. If you want to be able to set it from other scripts then it has to be a property.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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