Conversation Script Variables
Aikurou
Member Posts: 5
Hello everyone,
I'm not sure if this is the correct place to ask for new features. If it isn't, please let me know where I should post this.
One thing that I've come to hate about NWN conversations is the scripting side of it. There's a lot of potential, but the way it is currently implemented requires you to create multiple copies of the same script.
For example: if you have a generic conversation with 3 options, you'll need a different script for every option, so you know if the user clicked on option 1, 2 or 3. Often all the scripts are the same and the only difference is the option number.
This creates a bloat of conversation scripts and prevents some system designs from being realized.
I found this problem particularly limiting when I decided to create a conversation driven quest system. I wanted a simple way to start an arbitrary quest, like say quest #158, from a conversation. Or perform other operations, like completing a quest, checking if a player meets the necessary requirements to start a quest, etc.
This system would require one new script per action per quest. However, thanks to NWNX, I was able to create a workaround.
By hooking the function that runs a script on the server, I could modify the script name. So I created a system that would detect a # in the script name, take the value after if and make it available through a local variable set on the module that the script could use. The system detected multiple # and set the appropriate variables.
This meant that instead of creating a script "start_quest_158" to start one quest, I could have a generic script "start_quest", and the builders of my module could use it to start a quest by placing the script name "start_quest#158".
This feature was a blessing, it not only allowed my quest system to exist, but also allowed me to significantly clean up my module's scripts by condensing most conversation scripts.
So I would like to propose this becomes a feature in NWN:EE. It could be extended to any script, but to keep things simple I will keep it to conversations.
The idea is to have a variable input field, like the we have for local variables on creatures, for each dialog option. The game would check for these values before running a script, and store them in a place accessible by the script virtual machine.
A new set of functions would be needed to access these, like the ones we have for local variables:
int GetConversationInt(string sVarName);
string GetConversationString(string sVarName);
float GetConversationFloat(string sVarName);
This would allow for much more powerful conversation-driven systems to be define and would help a lot when creating generic conversations.
I'm not sure if this is the correct place to ask for new features. If it isn't, please let me know where I should post this.
One thing that I've come to hate about NWN conversations is the scripting side of it. There's a lot of potential, but the way it is currently implemented requires you to create multiple copies of the same script.
For example: if you have a generic conversation with 3 options, you'll need a different script for every option, so you know if the user clicked on option 1, 2 or 3. Often all the scripts are the same and the only difference is the option number.
This creates a bloat of conversation scripts and prevents some system designs from being realized.
I found this problem particularly limiting when I decided to create a conversation driven quest system. I wanted a simple way to start an arbitrary quest, like say quest #158, from a conversation. Or perform other operations, like completing a quest, checking if a player meets the necessary requirements to start a quest, etc.
This system would require one new script per action per quest. However, thanks to NWNX, I was able to create a workaround.
By hooking the function that runs a script on the server, I could modify the script name. So I created a system that would detect a # in the script name, take the value after if and make it available through a local variable set on the module that the script could use. The system detected multiple # and set the appropriate variables.
This meant that instead of creating a script "start_quest_158" to start one quest, I could have a generic script "start_quest", and the builders of my module could use it to start a quest by placing the script name "start_quest#158".
This feature was a blessing, it not only allowed my quest system to exist, but also allowed me to significantly clean up my module's scripts by condensing most conversation scripts.
So I would like to propose this becomes a feature in NWN:EE. It could be extended to any script, but to keep things simple I will keep it to conversations.
The idea is to have a variable input field, like the we have for local variables on creatures, for each dialog option. The game would check for these values before running a script, and store them in a place accessible by the script virtual machine.
A new set of functions would be needed to access these, like the ones we have for local variables:
int GetConversationInt(string sVarName);
string GetConversationString(string sVarName);
float GetConversationFloat(string sVarName);
This would allow for much more powerful conversation-driven systems to be define and would help a lot when creating generic conversations.
3
Comments
Those are some nice ideas, however they would require significant changes to both the game and the editor. Sometimes it's better to take a step back and propose a simpler feature than to take a step forward. The bigger it is, the harder it is for beamdog to accept the idea!
Arguments for scripts have plenty of other uses too beyond just conversations.
That's is exactly what I'm proposing: A variable input field like the one we have for local variables (allows you to pick the name, type and value), that can then be accessed inside the conversation script.
While yes, I agree that this kind of functionality is useful beyond conversations, most other script-holding objects can also store local variables. So for the most part, you can use that as a replacement in order to customize the script. My quest system also uses local variables on creatures, placeables, trigger, etc, to do exactly what I have to use this system for conversations.
For that reason, I think pursuing a more widespread implementation of a system like this would be unnecessary.
For conversations, you would only need one set of variables per conversation node (per conditional/action script pair). I don't think it would make it possible to put the entire conversation in a single script, as the entry point for a conditional script is different. It would allow you to place your entire conversation on two scripts, however, one for actions and one for conditions.
I had no idea that NWN2 had this already. It would make explaining the idea way easier...
Since I don't have the game installed here, I can not check how it works exactly. From a tutorial I found (https://neverwintervault.org/rolovault/projects/nwn2/nwn2tutorials/31/NWN2_BetaTest_Toolset.pdf), it seems that NWN2 allows you to pass arbitrary values as key/value pairs. That is exactly what I want.
I do not know, however, how those values are passed to the script. From a screenshot I found, they seem to be passed as an argument to the script's entry point (main function). This approach requires more significant changes to the scripting engine than what I initially proposed. As far as I know, NWN1's script engine does not deal with entry function arguments.
If the idea is already to upgrade to NWN2's script virtual machine, that would be the best way to do it. If that is not the case, my approach may be simpler to implement in the current engine.
In the meantime, I'll see if there's interest in putting my current solution in one of the NWNX default plugins. It has it's limits (only integer values, total script name plus values length must fit in 16 bytes), but it has served me very well so far.
Other than that, the script would have to check for the specific variable name, so it would be pretty much the same.
Having the UI automatically identify the parameters names and types would lead to a less error-prone system overall.
TR
TR
I have 8 options in a dialog, I want to code a SINGLE action taken script which can get which dialog line number triggered it.
My custom crafting system uses a Z-Dialog like system, it sucks because of the bloat. tokens are nice, but the overall module code is a mess because whatever you do you need multiple action taken scripts and you can get many very fast...
Cheers.
1."A Token displaying a choice" //call your function to set your quest choice based on the variable
2.Forward. //increments the local variable and sets the token
3.Back. //decrements the local variable and sets the token
Its not exactly what you want, but will allow you to use one script to set quest states.
This change as first suggested has a great general impact, reducing the number of scripts and the cost of maintenance for a PW. In my opinion this should be top priority to implement, since is low effort and high impact.
Here is a simple mockup of how this could work:
As you can see, each line of the conversation will have the same old boring variable screen that other objects do have. On a conversation, script, be it on test or action taken callbacks, a new function needs to be disponible:
object GetConversationLine();
This simply returns an "empty" object with the set local variables for that conversation line, which can be get by using the traditional GetLocal methods.
There is a workaround using the journal. It so happens that the journal is updated before the Action Taken script executes, so if every action sets a different journal entry, a single script can be used. Since it's not always convenient to have a bespoke journal for every conversation, a dummy journal with a null title and null entries can be used, as long as the script clears the journal entry once it's read the journal value. The downside is that players see the message "Your Journal has been updated" even though it hasn't.
For N=0,1,2,... write scripts
and in the include file
In your 'action script' you write
Set the action script in the previous conditional script with
You can make it even more simple if you drop the 'action script' and move the case statement into the next conditional script (that what I'm doing in https://neverwintervault.org/project/nwn1/hakpak/original-hakpak/customize-character-override-hak-ccoh ).
"For N=0,1,2,... write scripts" where put this code?
Please if you can be more clear why this thing you say would be fantastic.
Thanks in advance
You have to write N action scripts (e.g. call them action_01.nss, action_02.nss, ...
action_01.nss:
action_02.nss:
action_03.nss:
all using this include file:
Now your dialog has to look like
(cond_script)node
|- line 1 (action_01)
|- line 2 (action_02)
|- line 3 (action_03)
using the action scripts from above and the conditional script cond_script.nss has to look like:
and in 'myactionscript' you have write
The advantage is that you write the script action_01, action_02, ... once and you can use them throughout all your dialogs. This will reduce the number of scripts and especially the number of script you have to maintain.
You can improve this system even more by also writing contitional scripts condition_01, condition_02, ...: ...
and make your dialog look like:
(cond_script)node
|- (condition_01) line 1 (action_01)
|- (condition_02) line 2 (action_02)
|- (condition_03) line 3 (action_03)
...
and set the conditions "CONDITION_01", "CONDITION_02"... inside the 'cond_script':
This is just a rough write down. The https://neverwintervault.org/project/nwn1/hakpak/original-hakpak/customize-character-override-hak-ccoh uses this and the source code is included in the download (inside the erf file - mk_inc_generic.nss - documentation lacks a little bit however).
Great job ccoh
TsiZ
It might seem super complex, but it's really not, you just use Switch/Case statements for two variables...
Conversation Section & Conversation Line is fed by the actual Starting Conditional & Action Taken Scripts.
e..g DoLineAction(oPC, nLine); / GetStartingConditional(oPC, nLine);
Those are just custom functions you can create to quickly swim through MILES of code!
Objectively, the draw back is, it's a bit tedious to create, but it can VERY SIMPLE TOO!
With just 3 tokens you can create A LOT of various conversations on the fly from ONE Conversation...
You'd just check the tag of the NPC / OBJECT_SELF to determine which conversation you are running.