ID:154317
 
This is a tutorial book I've written for the Ensya Archives, but since I'm not the most advanced DM programmer out there, I thought I'd stick it up for review and corrections.

Making Interactive NPCs
~~~~~~~~~~~~~~~~~~~~~~~

Page 2: Telling Them What They're Told
Page 3: Deciding Who "Them" Is
Page 4: Is That All You Have To Say?

~~~~~~~~~~~~~~~~~~~~~~~
<FONT SIZE=4>Is That All You Have To Say?</FONT>
~~~~~~~~~~~~~~~~~~~~~~~

Likely, if you're going through the trouble to make your NPCs able to talk, you don't want them to be the quiet types who only say hello back and never speak another word. The following is an example of how to easily extend your list.
<FONT COLOR=silver>
mob/npc/Storeowner
   icon = 'storeowner.dmi'
   name = "Store Owner"
   var/list/dialogue = list(\
"hello"="Hello, stranger.",\
"hey"="Hey.",\
"name"="I don't have a name, I'm just a stop owner.",\
"job"="I run the shop and sell stuff to people.",\
"help"="Help with what?",\
"dantom"="I wouldn't be alive without 'em!",\
"cookies"="Mmm...",\
"french fries"="Mmm...again!",\
)
</FONT>Now you don't have to put up with a ridiculously long list of messages, you can line them up in organized rows. Keep in mind that the lower down the row the word is, the higher the chance that the message you Told() the NPC will find another word before it finds that one. Make sure you put the things you really want said towards the top, while other less important things can be at the bottom.

Also, you may want your NPCs to do things when you talk to them besides just talk back. For example, maybe you have a guard that you want to step out of the way when you tell him "step aside". Here's how you do that.

In the Told() proc, before you search the message for things to respond to, put in a line that goes like this:
<FONT COLOR=silver>
   Told(msg)
      if(findtext(msg,"step aside"))
</FONT>Now the NPC will recognize it when you tell him to "step aside". But he doesn't know what to do when you tell him that. So lets give him something to do!
<FONT COLOR=silver>
   Told(msg)
      if(findtext(msg,"step aside"))
         step(src,WEST)
         sleep(50)
         step(src,EAST)
</FONT>Now when you tell them to "step aside", they will immediately step to the west, wait there for roughly five seconds, then step back. And, if you don't want them to continue responding to other things in your say message, you may want to <FONT COLOR=blue>return</FONT> the proc so that it doesn't continue.
<FONT COLOR=silver>
         return
</FONT>
And that's it!

~~~~~~~~~~~~~~~~~~~~~~~
<FONT SIZE=4>Deciding Who "Them" Is</FONT>
~~~~~~~~~~~~~~~~~~~~~~~

Making it possible to tell an NPC something doesn't do any good unless there is an NPC to tell, so here we'll start with a pretty basic one.
<FONT COLOR=silver>
mob/npc/Storeowner
   icon = 'storeowner.dmi'
   name = "Store Owner"
</FONT>Now, right below where we declare the NPC's icon_state, we're going to modify his version of the Told() proc.
<FONT COLOR=silver>
mob/npc/Storeowner
   icon = 'storeowner.dmi'
   name = "Store Owner"
   Told(msg)
</FONT>Now we have an NPC to talk to. But we need to modify their Told() proc so that we get something out of it. So here, we're going to go step-by-step and make that proc do something.

<FONT COLOR=silver>
// NPC code...
   Told(msg)
      for(var/t in src.dialogue)
         if(findtext(msg,t))
            sleep(rand(5,25)) // responce time
            src.say("[speech[t]]")
            break
</FONT>If you try to compile that, it will give you an error because we haven't defined the dialogue list for the NPC. So we need to do that.
<FONT COLOR=silver>
mob/npc/Storeowner
   icon = 'storeowner.dmi'
   name = "Store Owner"
   var/list/dialogue = list("hello"="Hello, stranger.")
   Told(msg)
</FONT>Here we give them one word to respond to on the left side of the equal sign, and something to say in response on the right. We'll get into how this works in just a bit.

Now back to the Told() proc.
<FONT COLOR=silver>
   Told(msg)
</FONT>Now, what this is doing is first, it searches the NPC's dialogue list to see if there is anything there. If there is, it will take whatever you told this poor NPC and scan it to see if any of the words in your message match up to the words in the NPC's dialogue list.
<FONT COLOR=silver>
      for(var/t in src.dialogue)
         if(findtext(msg,t))
</FONT>If it finds any matching words in the NPC's dialogue list, it'll pause for a moment, giving you time to breathe before the NPC responds. Then, the NPC will respond with whatever is on the other side of the equal sign of the word is found to match with. That is, if it found "hello" in list("hello"="Hello, stranger."), it will tell the NPC to use say() to say, "Hello, stranger."
<FONT COLOR=silver>
            sleep(rand(5,25)) // responce time
            src.say("[speech[t]]")
</FONT>After that, we don't want them to respond to every little thing he matches with his dialogue list, so we want to break the loop here so that he wil only respond to that one word.
<FONT COLOR=silver>
            break
</FONT>After that, you'll want to fill in the NPC's dialogue list with something more meaningful. We'll get into that on the next page!

~~~~~~~~~~~~~~~~~~~~~~~
<FONT SIZE=4>Telling Them What They're Told</FONT>
~~~~~~~~~~~~~~~~~~~~~~~

This tutorial is a step by step guide and example to creating your own interactive NPCs. First of all, what do I mean by Interactive NPCs? I'm referring to the type of NPCs you will find in Ensya, that is, the kind you can talk to. Interactive NPCs will talk back when you talk to them, and this tutorial will explain how it's done.

To start off, you need to setup a proper dialog command that will inform the NPCs that they are being talked to. For this purpose, I'm going to use the verb "Tell".
<FONT COLOR=silver>
mob/verb/Tell(mob/M as mob in view(), msg as text)
   usr << "You tell [M], \"[msg]\""
   M << "[usr] tells you, \"[msg]\""
   oview() - M << "[usr] tells [M], \"[msg]\""
</FONT>Now, this Tell verb has the same effect as most "Say" verbs do, so we're going to add a little proc to make it different from "Say", that is, we're going to tell the mob you're talking to that you Told() them something.
<FONT COLOR=silver>
mob/proc/Told()
mob/verb/Tell(mob/M as mob in view(), msg as text)
   usr << "You tell [M], \"[msg]\""
   M << "[usr] tells you, \"[msg]\""
   oview() - M << "[usr] tells [M], \"[msg]\""
   M.Told(msg) // Tell them whatever "msg" says.
</FONT>Now when you create a new NPC mob, you only need to specify what happens within their Told() proc. We'll discuss this on the next page.

~~~~~~~~~~~~~~~~~~~~~~~
You might want to check out the BYOND Home library, I believe it's already set up for NPCs to listen and talk. "Residents" they're called.