Game Development Community

dev|Pro Game Development Curriculum

RPGDialog - NPC interaction system

by Nelson A. K. Gonsalves · 11/29/2002 (12:27 pm) · 186 comments

RPGDialog is a Torque Game Engine modification that adds standard RPG Dialogs support, including multiple choice questions and question linking(underlined words on a question that perform actions when clicked on). Also included is an editor for creating and editing dialogs easily.

Instructions on installing are included on the zip file.

New download location since geocities is dead

Have fun using it! :)
And let me know of any problems you might find.

Contact me at dk_uo@yahoo.com or leave a comment here.

Features

- Multiple choice questions, present a question and a list of answers and do something depending on which answer the player picks, the choices are numbered and can be picked either by the mouse or by pressing the 1,2,...,9,0 keys on the keyboard, choices after 10 must be selected via mouse.

- Question Links, Ex: "Hello, I'm Mary, how are you?" clicking on the word Mary would trigger an action as if it was a choice in the Multiple choice window.

- Portraits, pictures that represent the NPC, change it depending on the choices of the player or even use them to show the mood of the NPC.

- Sounds, add voice overs or any sound effects that are triggered when the question is displayed.

- Fully functional in multiplayer games, only allowing one player to talk to each NPC at a time, sending a message telling the others that the NPC is busy if they try to talk to it.

- Moving the player too far away from the NPC closes the Dialog automatically.

- Each option triggers a function, allowing complete customization of the actions caused by the dialog, either by using the included functions, altering them or creating your own.

June 8th 2005.
I finnaly got around to giving this a much deserved update!

Firstly I updated the instructions and made a few changes to make it fully compatible with TGE 1.3.

Also I've added buttons to move the answers up and down in the editor, so its now easier to organize the available options.

And finnaly, multiple actions can now be triggered by one response, thanks goes to BrokeAss Games for the idea. To execute multiple actions just add them one after the other without anything separating them, there is one example of this in the test scripts. Ohh, and now clicking on the actions list will add them to the actions edit and not replace them.

I have one warning though, version 1.0 .dla files are incompatible with version 1.3, there is an easy workaround I've used on my files, just open them directly in a text editor and do a quick replace all from "<" to "<END><", add <END> to the end of each line and remove the <END> from the beginning of the line, that should make them 100% compatible.

Let me know if you find any problems.

-Nelson

About the author

Recent Blogs

#41
04/23/2005 (7:01 am)
I have been unable to get this to function as well - I've managed to get it to spawnt the NPC, but alas, it will not activate TalkTo, niether via keyboard nor via console window. Any ideas?

Also - it states it cant even FIND the TalkTo function when attempting to use the console, so maybe thatll do it?
#42
04/23/2005 (2:42 pm)
Well there are two issues there.... if it can't find the TalkTo() function you're either not exec'ing it or you have an error in the code. Look in the console for red error spew from some script file not compiling.

Second i found that the InitContainerRadiusSearch() method in serverCmdRPGDialogRay() for finding NPCs was inconsistent. It seemed not to work in many cases where it should. So i replaced it with ContainerRayCast(). Now it's works 100% of the time that i aim at the NPC i want to look at and he's in range. I'm also adding an NPC chat in range cursor now as it helps visualize the results of serverCmdRPGDialogRay() better for both me as the designer and the player.
#43
05/10/2005 (10:27 am)
Wow, what a great resource. Just applied it to my custom 1.3 starter.fps (with AdvancedCamera, Factions, NPCs and improved crosshairs) and I've got a strong basis for an RPG already.

A couple of points:

1. The search radius used for the InitContainerRadiusSearch calls is way too small. 0.5 means that the crossbow in starter.fps has to penetrate the NPC to be close enough for dialog. Could lead to some interesting conversations... :)

At a minimum, the initial test in serverCmdRPGDialogRay needs the radius changed from 0.5 to 2.5, in IsRPGDialogBusy change it to 5, and in CheckRPGDialogStatus change it to 5.

function serverCmdRPGDialogRay(%client)
{
   %StartPos=%client.player.gettransform();
   %Eye = %client.player.getEyeVector();
   %EndPos = vectorScale(%Eye, -1);
   %EndPos = vectorsub(%StartPos,%EndPos);

   InitContainerRadiusSearch(%EndPos, 2.5, $TypeMasks::PlayerObjectType);

   %rayCast=ContainerSearchNext();
   while(%rayCast != 0 )
   {
      if(%rayCast.aiPlayer && %rayCast.RPGDialogScript!$="")
      {
         if(!%rayCast.RPGDialogBusy)
         {
            RPGDialogMessageClient(%client, %rayCast, %rayCast.RPGDialogScript,%rayCast.RPGDialogStartQuestion); //start dialog.
            return;
         }
         else
         {
            if(IsRPGDialogBusy(%rayCast))
            {
               if(%client!=%raycast.RPGDialogTalkingTo)
               {
                  messageClient(%client, '', %rayCast.RPGDialogBusyText, %raycast.RPGDialogTalkingTo.player.getShapeName());
                  return;
               }
               else
                  return;
            }
            else
            {
               RPGDialogMessageClient(%client, %rayCast, %rayCast.RPGDialogScript,%rayCast.RPGDialogStartQuestion); //start dialog.
               return;
            }
         }
      }
      %rayCast=ContainerSearchNext();
   }
}

function IsRPGDialogBusy(%AiPlayerID)
{
   InitContainerRadiusSearch(%AiPlayerID.getTransform(), 5, $TypeMasks::PlayerObjectType);
   %rayCastBusyCheck=ContainerSearchNext();
   while(%rayCastBusyCheck != 0 )
   {
      if(%rayCastBusyCheck==(%AiPlayerID.RPGDialogTalkingTo).player)
      {
         return(true);
      }
      %rayCastBusyCheck=ContainerSearchNext();
   }
   return(false);
}

function CheckRPGDialogStatus(%Client,%Sender) //Checks if the player has moved since he started the dialog, moving too far from the sender will cancel the dialog
{
   InitContainerRadiusSearch(%Sender.getTransform(), 5, $TypeMasks::PlayerObjectType);
   %rayCast=ContainerSearchNext();
   while(%rayCast != 0 )
   {
      if(%rayCast==%Client.player)
      {
         schedule(1000,0,"CheckRPGDialogStatus",%Client,%Sender);
         return;
      }
      %rayCast=ContainerSearchNext();
   }
   CommandToClient(%client,'CloseRPGDialog');
   %Sender.RPGDialogBusy=false;
   %Sender.RPGDialogTalkingTo=0;
   %Sender.clearAim();
}


2. Also in starter.fps/server/scripts/RPGDialog.cs, LightMaleHumanArmor can be changed to DemoPlayer for the starter.fps game.

function SpawnTestNPC()
{
   %player = new AIPlayer() {
      dataBlock = DemoPlayer; // was LightMaleHumanArmor
      aiPlayer = true;
      RPGDialogScript = "Test";
      RPGDialogPortrait = "Test.png";
      RPGDialogStartQuestion = 1;
      RPGDialogBusy = false;
      RPGDialogBusyText = 'Sorry but I\'m busy talking to %1 right now.';
      RPGDialogTalkingTo = 0;
   };
   MissionCleanup.add(%player);

   // Player setup

   %player.setMoveSpeed(8);
   %player.setTransform(pickSpawnPoint(2));
   %player.setEnergyLevel(60);
   %player.setShapeName(%player);
   return %player;
}

function SpawnNPC(%Name,%Script,%Portrait,%startQuestion,%location)
{
   %player = new AIPlayer() {
      dataBlock = DemoPlayer; // was LightMaleHumanArmor
      aiPlayer = true;
      RPGDialogScript = %Script;
      RPGDialogPortrait = %Portrait;
      RPGDialogStartQuestion = %startQuestion;
      RPGDialogBusy = false;
      RPGDialogBusyText = 'Sorry but I\'m busy talking to %1 right now.';
      RPGDialogTalkingTo = 0;
   };
   MissionCleanup.add(%player);

   // Player setup
   %player.setMoveSpeed(8);
   %player.setTransform(%location);
   %player.setEnergyLevel(60);
   %player.setShapeName(%Name);
   return %player;
}

@ari - your snippets for multiple actions per response are great, just what I needed.
#44
05/10/2005 (1:09 pm)
@sebastion.. thanks for the update the little things help alot.

@ari or seb or anyone..

i dont understand how exactly the rewards or sell items work.

where does the go:

RewardItem(FlameThrower_01,1)RewardItem(FlameThrowerAmmo_01,500)RewardItem(Pistol_01,
1)RewardItem(PistolAmmo_01,34)SayChat("Thank you for completing that for me.")-

when i sell a item is this just a predetermined everything listed? or can you specify "what you want to sale?

confused on this stuff
#45
05/10/2005 (2:06 pm)
hmm getting a error

getSubStr(...): error, starting position and desired length must be >= 0: (0, -1)
getSubStr(...): error, starting position and desired length must be >= 0: (0, -1)
Syntax error in input.
getSubStr(...): error, starting position and desired length must be >= 0: (0, -1)
getSubStr(...): error, starting position and desired length must be >= 0: (0, -1)
Syntax error in input.

seems to be either right after i close the question window in game or after i click a question like rename the sender. anyone else get this?

ok narrowed it down to close dialog i // all the closedialog in the rest of the file like Ari had. but everytime i choose a question window drops and get the errors not sure where else closes the window that causes the problem
#46
05/29/2005 (5:53 pm)
@DejaBlue
That goes in the command area of the answer edit dialog.
I made a screen shot to demonstrate.
http://www.imagedump.com/index.cgi?pick=setandget&tp=256628&poll_id=0&category_id=20&warned=y
The errors you are getting used to happen in my code as well.

I have fixed it, and I'll try and update my snippit as soon as possible.
Currently I'm taking a small break from coding so as not to get burned out.

Ari
#47
06/29/2005 (5:18 am)
With the multiple commands snippit in, I have to use notepad to edit my dialogs.
It renders the dialog editor almost useless.
I had to roll back a bit and lost my fix and now I'm wrapped up in other code.
Sorry.

Ari
#48
06/29/2005 (5:26 am)
I am going to be implimenting this tonight or tomorrow. Seems like you guys have done a lot on it.
#49
06/29/2005 (9:01 am)
Just implemented this in tutorial.base, make sure to include chathud.cs, messagehud.cs, chathud.gui and graphics needed for those and all should be fine.
#50
06/29/2005 (9:08 am)
Thanks for the tips
#51
06/30/2005 (12:31 am)
I have a question, is there somewhere that explains the color code system for the font colors? I see that Question color is C1 and Answer color is C5, but I've done a search and don't see these referenced anywhere. I'd like my questions to be a light gray and my answers to be green.
#52
07/01/2005 (3:43 pm)
This is even better then I thought... Thanks.
#53
07/01/2005 (3:47 pm)
Matt - Check out : starter.fps\client\ui\RPGDialog.gui
#54
07/06/2005 (7:41 am)
Hi...
i execute all tasks...

F5 works....

but i go to console and type:

SpawnTestNPC();

then... nothing happens.....

am i doiing something wrong???


thks
#55
07/06/2005 (9:21 am)
Does it give you errors in teh console ? Open server/scripts/RPGDialog.cs and change the spawn position. It is probably spawning somewhere that you can't see.

I placed an item in the world... then wrote down it's coordinates (F11->F3) ... and used that for my spawn point.
#56
07/10/2005 (6:25 am)
BUT.. OK here is ONE small newbie question...
the testing function where you can type:
Execute SpawnTestNPC(); to bring up an NPC at the center of the world.....
It works great.

So how can I add this TestNPC INTO my game at a particular location?
(and another at a different location?)
(with a different skin?)

OH!! And another question... Is there a programming reason as to WHY there HAS to be a reply IF the NPC is questioned by another player (when in multiplayer??) It seems to me that it would be better if its was possible just for all players to speak to NPC's at the same time! (Thats how it works in Anarchy Online and World of Warcraft anyhow...)

m
#57
07/10/2005 (7:19 am)
WELL ...I typed SpawnTestNPC() into server/scripts/game.cs for a giggle
(just after...
function GameConnection::spawnPlayer(%this)
{
)and I got the SpawnTestNPC to turn up in game!!! HURRAH!!

But Now Im thinking.. Im defining my character in RPGDialog.cs, and calling it in game.cs ... is this wise... can I move ALL the code pertaining to SpawnTestNPC to... um... somewhere else (where would YOU put it?) somewhere that I define ALL my characters... its OWN BRAND NEW FILE perhaps.. of straight in game.cs perhaps??? whats the USUAL thing here???

AND ONE MORE THING... I also managed to put the RPGDialog on another NPC, the one that started out as Kork... Now hes unning in circles like a mad thing.. can RPGDialog Stop him running? (in the same way as they look your way) as soon as the Dialog starts? Right now, the RPGDialog convo box opens up when I hit Q, and then the NPC runs off, taking him out of the minimum distance...and the Dialog closes...
Silly


M

m
#58
07/19/2005 (6:38 am)
Mark I created a seperate script. In it I declared a funciton spawnNPCs() ... Which basically calls SpawnNPC for every locastion and PlayerData datablock I need.

I call spawnNPCs in startgame() in game.cs
#59
07/20/2005 (6:30 am)
If you are saying that you made a new xxx.cs that handles all the parameters for ALL your NPC's.. I was thinking along these lines too... but do you HAVE to then call them in game.cs? I was trying to make a character.cs file where simply all people in the game get created... everything... parameters for different meshes..RPGDiologs... position... everything...

If afraid I CANNOT write ANY code from scratch, Im no programmer... but a helluver code stealer... I need a For instance really.

BTW: Is there a document that simply lays out which files DO what... it seems to me that theres bits and pieces all over the place... and VERY irritating that there are multiple files with the same name.. I bought Kens Book,to try and figure this out... which is low level on all the tools (the in game tools-- - Quark - - Milkshape etc... ) but jumps right in and confusing with the scripting... for me anyhow... I dont need a "type this in" and something will happen.. I need a " Use THIS code to do THIS... and stick it HERE..."because... kind of tut... ANyway getting off topic for this forum...
#60
07/20/2005 (9:41 am)
Mark - server/scripts/RPGDialog has everything you need really.

Go into the game hit F5 and build yourself some scripts, make sure you write down the names of them.

Then go into RPGDialog and check out the SpawnNPC() functoin. That will tell you and show you what you need to send into the spawnNPC function when you create your npc's.

Ok... so you have a basis. Since there is no way to set a spawnpoint or anything... I went in and created a healthpack where ever I wanted an NPC. I named them the same as what script they were to use.

Then I went into my .mis file, cut out the item declerations for my npcs. Saved the mis file. Created a new text file in server/scripts. Called it NPCCharacters.cs and pasted the item declerations into it.

Now... Knowing that I needed to spawn NPC's with those locations I created a spawnNPC() funciton that would create an NPC with the right script at the right location. I knew the name of the script because I wrote it down, and I knew the location because I named the item the same as the name of the script I wanted to use.

Now, I made a spawnNPC call for each of the locations... Which was a lot. I also had to create new PlayerData datablocks for each NPC that needed a different shapefile used. Which means I had to change the spawnNPC() function. I added %datablock to the end of its decleration, and changed the spawnTestNPC() function to tack DemoPlayer onto its call to spawnNPC().

Now to get my NPC's to have the right shape, I went into server/scripts/player.cs, searched for PlayerData... That is the datablock that tells TGE what DemoPlayer (PlayerBody) what it does and how to act and look. To extend it you add something like this: (could be wrong, I have NO code here)
PlayerData (NEWBody : PlayerBody)
{
   //new shapefile
   ShapeFile = "I am a shape directory";
}

All that did was tell TGE: "Hey, I need a Player datablock... Gimme everything the same as the Orc, but make it into 'enter new character' instead"


Now. You have everything set up and ready to rock.

Make sure that the only thing in you NPCCharacters script is the spawnNPC() function calls. You have to add just a little more to it.

You want to place all of those in a function... So change it like this:

function spawnEveryone()
{
   // Place all the SpawnNPC(...); calls here
}

and execute your script by placing the following in game.cs:

[code]
exec(