HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

KaTTaNa's Conversation System

02-02-2004, 06:27 PM#1
KaTTaNa
This is a couple of functions along with some globals, that will allow you to create conversations like those in real RPG games like Morrowind and Neverwinter Nights.
It uses texttags (Floating texts) to display the NPC's speech, and the player can then choose his response using the arrow keys. The possible response are also shown using texttags, where the selected response gets highlighted. You speak the chosen line by pressing the arrow key right.
When writing the conversation, you can use commands enclosed by #'es. For example, #pc# would get replaced by the name of the player, and #npc# replaced with the name of the NPC (Object name).

I made a Demo Map (click to download) to show it off, and I urge you to try it, it demonstrates just a fraction of what's possible with this system.

You can get the functions themselves here: http://kattana.users.whitehat.dk/viewfunc.php?id=229

Here I'll write a guide of usage.

Setting it up
Step 1: Implementation
First, create all the global variables below:
Conv_CanIHelp: String array
Conv_Choice: Integer array
Conv_Conversations: String array
Conv_Hello: String array
Conv_Id: Integer array
Conv_Msg: Floating Text array
Conv_TalkTriggers: Trigger array
Conv_Triggers: Trigger array
Conv_NPC: Unit array
Conv_Count: Integer
Conv_EventNPC: Unit
Conv_EventPC: Unit
Conv_EventId: Integer
Conv_NoDisturb: Boolean array
PlayerHeroes: Unit array

Then copy all the function into the map root.
If you already have EvaluateBoolexpr, StringFind, StringReplace, Boolexpr2Integer or Integer2Boolexpr there, be sure there won't be two of them.

Step 2: Map initialization
During map initalization, run the function InitConversationSystem.
Also lock the camera to the player's hero and make sure that PlayerHeroes[N] = Player N's hero.

Writing a conversation
In this system, a "conversation" means an NPC line, and a set of PC responses to that. Each PC response either end conversation, or sends it to another "conversation".
You create new conversations using NewConversation. That function takes the parameters:
string NPCOpening, string Responses, trigger trg
NPCOpening is the text that the NPC speaks when dialogue reaches that conversation.
Responses should in most cases be set to "" (NOT null).
trg is the trigger that gets runned every time an NPC speaks this line (can be null).
NewConversation returns an integer, which you must save in order to access later.
You can add responses to that conversation using ConversationAddResponse.
That takes: integer ConversationID, string Response, integer To
ConversationID is the ID for the conversation. Use the integer returned by NewConversation.
Response is the text that the player can choose to speak.
To is the conversation ID that it leads to. Use -1 to terminate conversation.

Let's have a small example:
Code:
local integer array p

set p[1] = NewConversation("Hello, my name is Joe. Can I help you?", "", null)
set p[2] = NewConversation("He lives just down the street to the left", "", null)

call ConversationAddResponse(p[1], "Where does Bob live?", p[2])
call ConversationAddResponse(p[1], "Goodbye Joe", -1)

call ConversationAddResponse(p[2], "Okay thanks.. see you later", -1)
This demonstrates the downside of this system.. all NPC replies must be created before responses are added.
The example given will create a small conversation, where the NPC says "Hello, my name is Joe", and then the player can either say "Where does Bob live?" or "Goodbye Joe".
If the player sais "Where does Bob live?", the NPC will say "He lives just down the street to the left", and the player can only say "Okay thanks.. see you later".

Now, here is an easy way to add some spice to conversations:
Certain words gets replaced by other strings, when the text is shown.
Here is the list:
#pc# -> Player name
#npc# -> NPC name (units object name)
#type# -> Player unit type (units object name)
#gold# -> Gold player has
#lumber# -> Lumber player has
#lvl# -> Level of the player
#hello# -> Random string from udg_Conv_Hello
#help# -> Random string from udg_Conv_CanIHelp

I call those 'Speech controls'.
Note: udg_Conv_Hello and udg_Conv_CanIHelp gets initialized in InitConversationSystem. You can change them as you like.
If we use these in the example, we could make the first NPC line look like this:
Code:
set p[1] = NewConversation("#hello# #pc#, my name is Joe. #help#", "", null)
That would make the NPC say something like this: "Well met KaTTaNa, my name is Joe. What can I do for you?", but the first and the last part would differ with each time, and "KaTTaNa" would be the name of the player.

Soon you will need to make certain PC responses appear only under the right circumstances. Like if he is carrying a certain item, for example.
Luckily, this is very easy to acomplish:
Code:
[color=red]function PlayerHasBobsRing takes nothing returns boolean
    return UnitHasItemOfTypeBJ(udg_Conv_EventPC, 'I000')
endfunction[/color]
local integer array p

set p[1] = NewConversation("#hello# #pc#, my name is Joe. #help#", "", null)
set p[2] = NewConversation("He lives just down the street to the left", "", null)

call ConversationAddResponse(p[1], "Where does Bob live?", p[2])
call ConversationAddResponse(p[1], "Goodbye Joe", -1)
[color=red]call ConversationAddConditionalResponse(p[1], "Here, take this ring. Bob told me to give it to you", p[3], Condition(function PlayerHasBobsRing))[/color]

call ConversationAddResponse(p[2], "Okay thanks.. see you later", -1)
As you can see, the function PlayerHasBobsRing now decides wether the response option is available or not.
Notice the way I use udg_Conv_EventPC. The udg_Conv_EventXXX variables works just as event responses. In this case it is the unit talking to the NPC.

The fake event responses also work in triggers called by NPCOpenings:
Code:
set p[3] = NewConversation("Thank you #pc#! You're the kindest #type# I've ever met. Take this 100 gold in return.", "", gg_trg_Bobs_Ring_Delivered)
.....
call ConversationAddResponse(p[3], "I appreciate that. Good day to you", -1)
gg_trg_Bobs_Ring_Delivered should remove the item from the player's inventory and add 100 gold to his resources.


I suggest that you look at the demo map to understand it better.
From there it's just up to you.

Comments, suggestions and bugs are welcomed
02-02-2004, 08:11 PM#2
Vidstige
Nice! (I didn't manage to boost the self-confidence though...)
02-03-2004, 12:57 AM#3
weaaddar
Very nice. Glad to see someone else is working on the less fun part of the RPG system (the actual roleplaying part).
02-04-2004, 01:02 PM#4
jmoritz
This looks really good :D
02-06-2004, 02:33 PM#5
Sucker
Very Nice!
But Ive a lil problem.
Ive created a new map, exported the Trigger from yours, imported them into mine an created some new Conversations. Then the Textes appears but if i would select the Text, nothing is going on :(
can u help me plz?
02-15-2004, 05:41 PM#6
KaTTaNa
Try posting the code initializing the conversation here, so I might pin out any errors.
Also check these..
  • Run InitConversationSystem() at map initialization
  • The conversation responses have valid targets (last parameter)
  • Start the correct conversation in the first place
02-17-2004, 10:51 AM#7
Sucker
Yes, it was the InitConversationSystem()

but ive solved it alone ;)

the map is in Betatest status...
02-20-2004, 11:56 AM#8
KillaFish
I dont understand how to make it work properply

Ive got the system to start a conversation with a villager and branch out properly, but I dont know how to make it choose the right conversation for when I click on a certain villager, how does this work?
02-20-2004, 09:18 PM#9
KaTTaNa
How to start the right conversation is not a part of the Conversation System, it's up to the user to find a way he likes.
In my Demo Map, I set the Custom Value of units to the conversation ID they should start, and I made a trigger initiate conversation when the order "smart" was issued on them while you were nearby.
If you want to do the same, open the Demo Map (it's not protected) and see the triggers I use to start the conversation.
02-21-2004, 08:18 AM#10
Sucker
and dont forgett to call the init Trigger with

"InitConversationSystem() "


at your first Conversation :D