Aller au contenu

Photo

Scripting NPC Conversations.


  • Veuillez vous connecter pour répondre
12 réponses à ce sujet

#1
JamieaaWroe11

JamieaaWroe11
  • Members
  • 5 messages
Hi everyone. So I've just started learning how to use the toolset and I've got a slight problem. I want to be able to see other characters having a conversation, like you can in the OC sometimes.

I figured using scripts on heartbeat would be a way of doing it, and have been able to knock a scrip together that does technically work but it's not perfect. If anyone could show me another way to do it, or a way to make the intervals between each statement more uniform, I would appreciate it! The way I've done it, because the characters heartbeats aren't synced up, they speak in the correct order but the timings are all wrong. 

Btw I've only started learning today so please don't be too complex!!! :unsure:

and thanks for any help!!

Edit: Okay so the code I copied and pasted is all messed up! using BBCode button seems to have fixed it, but now it's lost all indentation!! 


#include "hench_i0_monsho"
#include "ginc_behavior"

void main()
{
object self = OBJECT_SELF;
object guard1 = GetObjectByTag("npc_castleguardspk1");
object guard2 = GetObjectByTag("npc_castleguardspk2");
object guard3 = GetObjectByTag("npc_castleguardspk3");
// already assigned counts
int g1count = GetLocalInt(guard1, "count");// this is 1, as he speaks first
int g2count = GetLocalInt(guard2, "count");// 0
int g3count = GetLocalInt(guard3, "count");// 0


if (self == guard1) { // if guard 1 is running the script
switch (g1count){
case 1:
SpeakString("I say the first line"); // say line 1 if count = 1
g2count = 1; // set guard2's count = 1, so he will say his first line
break;
case 2:
SpeakString("I respond to guard 3"); //say line 2
g3count = 2; // set guard3's count = 2, so he will say his next line
break;
case 3:
SpeakString("I respond to guard 2. This is the last line."); // say line 3, last line
break;
}

} else if (self == guard2) { // if guard 2 is running the script
switch (g2count){
case 1:
SpeakString("I respond to guard 1"); // say line 1 if count = 1
g3count = 1; // set guard3's count = 1, so he will say his first line
break;
case 2:
SpeakString("I respond to guard 3. This is my last line."); //say line 2
g1count = 3; // set guard1's count = 3, so he will say his next line
break;
default:
return;
}

}

else if (self == guard3) { // if guard 3 is running the script
switch (g3count){
case 1:
SpeakString("I respond to guard 2"); // say line 1 if count = 1
g1count = 2; // set guard1's count = 2, so he will say his second line
break;
case 2:
SpeakString("I respond to guard 1. This is my last line."); //say line 2
g2count = 2; // set guard2's count = 2, so he will say his next line
break;
default:
return;
}
}
SetLocalInt(guard1, "count", g1count); //updates the local variable for guard 1
SetLocalInt(guard2, "count", g2count); //updates the local variable for guard 2
SetLocalInt(guard3, "count", g3count); //updates the local variable for guard 3
SetLocalInt(self, "count", -1); //Sets own count to unusable value.
}

Modifié par JamieaaWroe11, 29 juillet 2010 - 10:46 .


#2
_Knightmare_

_Knightmare_
  • Members
  • 643 messages
Are these guards just standing around talking? If so there can be a simpler way of doing it by just using a DelayCommand and AssignCommand to the other guards to seperate the nodes. Can be fired from anything, trigger, cliententer, etc.



Give some more details of the guards' situation and I can suggest something.

#3
Morbane

Morbane
  • Members
  • 1 883 messages
gtrSpeakNode is a nice function - it is short by itself but the scripts it links to have some options for NPC conversations - I think you may have to look at the #includes...

#4
JamieaaWroe11

JamieaaWroe11
  • Members
  • 5 messages
 Knightmare: Yes the guards are stood still in a circle. I don't really want them to do anything more complex than speak their lines right now, in order and with a timing that looks like a real convo. I've looked at the AssignCommand function on the nwn2 wiki (not got access to the toolset right now) and I see it uses a parameter of type action, I've not used that type before so I'm not sure what I would be putting in there . I've also looked at DelayCommand and I'm not sure I see how they fit together. Is:

DelayCommand(5.0, Object, Action);

the same as:

ActionWait(5.0); 
AssignCommand(Object, Action); 
?
Cheers for the help. 

Morbane :
I can't find any information online on gtrSpeakNode, but I'm presuming the toolset has notes on it?. As for the #includes, how do I find out which ones I need? Cheers for the help. 

Modifié par JamieaaWroe11, 30 juillet 2010 - 08:08 .


#5
Morbane

Morbane
  • Members
  • 1 883 messages
gtrspeaknode is a conversation trigger script used in the OC - you should be able to access it in the toolset by going File>Open Script/Conversation>gtrspeaknode.nss -

I used it to make my own custom script to make two creatures have a conversation as the PC listened then attack after they finished. the includes that will help you will be called at the top of gtrspeaknode.

Thing is the convo will be staged by each node and the player will click through the nodes - i dont think gtrspeaknode will allow a convo that goes all on its own.

Modifié par Morbane, 30 juillet 2010 - 12:03 .


#6
_Knightmare_

_Knightmare_
  • Members
  • 643 messages

JamieaaWroe11 wrote...

 Knightmare: Yes the guards are stood still in a circle. I don't really want them to do anything more complex than speak their lines right now, in order and with a timing that looks like a real convo. I've looked at the AssignCommand function on the nwn2 wiki (not got access to the toolset right now) and I see it uses a parameter of type action, I've not used that type before so I'm not sure what I would be putting in there . I've also looked at DelayCommand and I'm not sure I see how they fit together. Is:

DelayCommand(5.0, Object, Action);

the same as:

ActionWait(5.0); 
AssignCommand(Object, Action); 
?
Cheers for the help. 


ActionWait() makes the NPC wait a specified time before taking their next action. DelayCommand makes the script wait a certain amount of time before it executes the script command. So, while similar, they work on different things (the NPC vs. the script itself).

Here's a quick example of what I meant. Not exactly sure of the convo order you wanted, but I think I have it right. This is untested in game, but does compile in the toolset:

void main()
{
// Declare Objects
object oPC = GetFirstPC(FALSE);
object oGuard1 = GetNearestObjectByTag("npc_castleguardspk1", oPC);
object oGuard2 = GetNearestObjectByTag("npc_castleguardspk2", oPC);
object oGuard3 = GetNearestObjectByTag("npc_castleguardspk3", oPC);
// Do not run rest of script if any guards are in combat
if(GetIsInCombat(oGuard1)) return;
if(GetIsInCombat(oGuard2)) return;
if(GetIsInCombat(oGuard3)) return;
// Speak the guards' convo
AssignCommand(oGuard1, SpeakString("I say the first line."));
DelayCommand(3.0, AssignCommand(oGuard2, SpeakString("I respond to guard 1.")));
DelayCommand(6.0, AssignCommand(oGuard3, SpeakString("I respond to guard 2.")));
DelayCommand(9.0, AssignCommand(oGuard1, SpeakString("I respond to guard 3.")));
DelayCommand(12.0, AssignCommand(oGuard3, SpeakString("I respond to guard 1. This is my last line.")));
DelayCommand(15.0, AssignCommand(oGuard2, SpeakString("respond to guard 3. This is my last line.")));
DelayCommand(18.0, AssignCommand(oGuard3, SpeakString("I respond to guard 2. This is the last line.")));
}


#7
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages
In my Silverwand Sample Campaign available in the vault I have a sample conversation in an inn in which a group of NPCs stand around and have a conversation which the PC can overhear. This was done with no custom scripting required - as I recall only a trigger and a standard conversation.



Regards

#8
JamieaaWroe11

JamieaaWroe11
  • Members
  • 5 messages
Thanks everyone! Seems there are a few ways of doing it then. I'll have a look at gtrspeaknode and your silverwind campaign Kaldor then. The code you supplied Knightmare looks like it will work, the only thing I don't understand is what does the

GetFirstPC(FALSE); line do? I've looked at the toolset notes but I don't really get it,

Also why wouldn't OBJECT_SELF work instead of oPC?



Cheers.


#9
Morbane

Morbane
  • Members
  • 1 883 messages

JamieaaWroe11 wrote...


GetFirstPC(FALSE); line do? I've looked at the toolset notes but I don't really get it,
Also why wouldn't OBJECT_SELF work instead of oPC?

Cheers.


GetFirstPC() is a sort of "global" way of finding the main PC or the Main controlled character. OBJECT_SELF might be anything that script is attached to.

#10
_Knightmare_

_Knightmare_
  • Members
  • 643 messages
Yup, Morbane has it there. GetFirstPC(False) returns the player's currently controled character. OBJECT_SELF would be the trigger that fired the script (for example).

In my script above, it is just used as a basis to compare nearby objects, in this case the closest NPCs to the currently controlled PC that have the specified tags of XXXX.

Modifié par _Knightmare_, 30 juillet 2010 - 09:59 .


#11
JamieaaWroe11

JamieaaWroe11
  • Members
  • 5 messages
 Ok, I can imagine that's something important to know then! One final thing (hopefully :lol:)
The DelayCommand function. I understand what is does, however shouldn't the first parameter always be (for example) 6.0 to give a 6 second gap between each spoken line. I know your way is right because I have tested the script, I just can't understand why. Are all the lines evaluated simultaneously,  rather than sequentially? 

Thanks again! I've learnt so much just from trying to get this simple script working! :D

#12
_Knightmare_

_Knightmare_
  • Members
  • 643 messages

JamieaaWroe11 wrote...

 Ok, I can imagine that's something important to know then! One final thing (hopefully :lol:)
The DelayCommand function. I understand what is does, however shouldn't the first parameter always be (for example) 6.0 to give a 6 second gap between each spoken line. I know your way is right because I have tested the script, I just can't understand why. Are all the lines evaluated simultaneously,  rather than sequentially? 

Thanks again! I've learnt so much just from trying to get this simple script working! :D


As currently written, there is a 3 second gap between each spoken line. Since a SpeakString defaults to "floating there" for 5 seconds (and we did not change this in the script), the lines will "overlap" by 2 seconds. Change the delay settings to whatever you need for it to look good. I just chose 3.0 seconds as an example.

And yes, essentially the script has evaluated all the lines at the same time (within a couple miliseconds of the script being fired). We have just told the script to Delay the execution of our script Commands until a specific amount of time has gone by. This is different from ActionWait() - which is where I'm guessing your "always 6.0 seconds" question comes from - in that it is measured from the initial firing of the script, not since the last script command was executed.

So:
Fire the Action (first node) immediately upon script execution
Delay the next Action (spoken node) until 3.0 seconds after initial script execution
Delay the next Action (spoken node) until 6.0 seconds after initial script execution
...
Delay the last Action (spoken node) until 18.0 seconds after initial script execution

You can insert other actions in there if you want (like performing animations, moving to a location, etc.) by delaying those actions too and sticking it in the appropriate spot of the script. DelayCommand() will not work right if two or more things have the exact same delay time within the same script. To solve this, just use tenths of a second, ie. 3.0, 3.1, 3.2, ... Nobody is going to notice a tenth of a second delay between this action and that!

And finally, my usual self-serving plug: You may find my tutorial has some useful info for you in there. Linked in sig below.

Modifié par _Knightmare_, 30 juillet 2010 - 11:16 .


#13
M. Rieder

M. Rieder
  • Members
  • 2 530 messages
I second what Kaldor Silverwand noted. It is possible to have a purely NPC conversation with no special scripting. It was done in the OC when you first enter Neverwinter.

All you have to do is make a new conversation, and assign each node to each NPC and put a "continue" between each NPC node. This will cycle through each NPC node without showing the PC.

I know this will work for a cutscene (NWN2 style conversation), but I am not sure what happens if you do this for an NWN1 style conversation.

If you do not want a cutscene and just want text to appear over the heads of the NPCs, then the custom scripting route may be easier and more effective.

For instructions on writing a basic conversation, download the NWN2 toolset manual.  I beleive it has a basic tutorial on creating coversations.

Modifié par M. Rieder, 04 août 2010 - 10:41 .