If you have been studying artificial intelligence for a while, you may have heard of the Turing Test. A layman's explanation: A human being types a series of questions into a machine. He gets a series of answers. If he cannot tell whether he is talking to another human or a computer, it's f#%king great AI.
Well, something like that.
In any case, this lesson won't merely be another one of those silly bot talking tutorials. After this, you will be able to "ask" your bots a few preset questions (or bring up a subject), and they will offer a relevant answer. Moreover, the bots will ask each other these questions.
You may not have a use for this lesson; you may be more interested in hardcore AI or mod applications. Then again, you may be looking for just such a thing. In fact, the following code could be developed into a sophisticated algorithm in which your bot would discuss the story, characters, or themes of your mod.
The concept behind this tutorial is very simple. Each question (or subject) is given a number value, and the bots respond to that value randomly. When a bot asks a question, he comes up with a random number that will correspond to one of the questions. Sounds boring, but it turns out pretty cool.
We need to create three new values for our conversation code. Open up defs.qc and paste at the very bottom:
float group_question; float group_talk_time; entity group_asker; void() ask_question;The first is the number value of the question or topic. The second is the delay between when the question is asked and when it is answered. The third is the player or bot who asks the question. The fourth is a new subroutine that we will call before it actually appears.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void() bot_answer_question = // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { local float re; if (time < group_talk_time) return; if (group_question == 0) { group_question = floor(random() * 4) + 1; ask_question(); group_talk_time = time + 4; group_asker = self; return; } if (group_asker == self) return; bprint(self.netname); re = floor(random() * 7); // how is everyone? if (group_question == 1) { if (re == 0) bprint(": i'm feeling anxious\n"); if (re == 1) bprint(": feeling the killer instinct\n"); if (re == 2) bprint(": doing well thanks\n"); if (re == 3) bprint(": i'm ready to get it on!\n"); if (re == 4) bprint(": i'm feeling good, looking good\n"); if (re == 5) bprint(": doing better than you, loser\n"); if (re == 6) bprint(": i've seen better days\n"); } // do you like this map? if (group_question == 2) { if (re == 0) bprint(": no, it blows rats\n"); if (re == 1) bprint(": doesn't have enough ammo\n"); if (re == 2) bprint(": it needs more weapons\n"); if (re == 3) bprint(": i prefer ztndm3\n"); if (re == 4) bprint(": the textures are cool\n"); if (re == 5) bprint(": yeah, this level rox!\n"); if (re == 6) bprint(": i've played better maps\n"); } // you all suck if (group_question == 3) { if (re == 0) bprint(": just like your mama\n"); if (re == 1) bprint(": no way, i rule\n"); if (re == 2) bprint(": same to you pal\n"); if (re == 3) bprint(": well, you suck harder\n"); if (re == 4) bprint(": shut up, llama\n"); if (re == 5) bprint(": i can kick your ass\n"); if (re == 6) bprint(": you'll regret saying that\n"); } // what's your favorite weapon? if (group_question == 4) { if (re == 0) bprint(": the RL rox d00d!\n"); if (re == 1) bprint(": the perforator suits my needs\n"); if (re == 2) bprint(": i'd enjoy a railgun\n"); if (re == 3) bprint(": super shotgun all the way\n"); if (re == 4) bprint(": all the Q1 weapons suck\n"); if (re == 5) bprint(": come here i'll show ya\n"); if (re == 6) bprint(": uh, i like the BFG\n"); } group_question = 0; group_talk_time = time + 300; group_asker = world; sound (self, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NONE); };This may be long, but it is very simple. Let's take it step by step. If the group_talk_time has not expired, we leave the routine. If no one has posed a question, the current bot will call a new routine to ask one, initialize the new variables, then leave the routine.
// group_question = 0; group_talk_time = time + floor(random * 3) + 3; group_asker = self; };Here we rem out the first line, thus the group_question will stay the same. We reset the group_talk_time, and then set the group_asker to the current bot. Now, a diferent bot will respond to the same question in the next three to six seconds. (Of course, this would work best with a bunch of bots and a lot of potential replies.) Remember that this is an optional change.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void() ask_question = // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { local float re; group_talk_time = time + 4; group_asker = self; bprint(self.netname); re = floor(random() * 3); if (group_question == 1) { if (re == 0) bprint(": how is everyone?\n"); if (re == 1) bprint(": how are you all doing?\n"); if (re == 2) bprint(": how's everybody feeling?\n"); } if (group_question == 2) { if (re == 0) bprint(": do you like this map?\n"); if (re == 1) bprint(": anybody like this level?\n"); if (re == 2) bprint(": this map is cool, huh?\n"); } if (group_question == 3) { if (re == 0) bprint(": you all suck the big one\n"); if (re == 1) bprint(": you guys all suck\n"); if (re == 2) bprint(": all of you suck bigtime\n"); } if (group_question == 4) { if (re == 0) bprint(": what's your favorite weapon?\n"); if (re == 1) bprint(": what weapon do you prefer?\n"); if (re == 2) bprint(": which gun do you guys like?\n"); } sound (self, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NONE); };Again, this is straight-forward code. We initialize two variables. We print the guy's name. We generate a random number. The bot asks the new question, with some randomly chosen wording. The next bot will respond to that question after four seconds expire.
bot_answer_question();So now your bots will talk to each other.
if (self.impulse == 200) { group_question = 1; ask_question(); } if (self.impulse == 201) { group_question = 2; ask_question(); } if (self.impulse == 202) { group_question = 3; ask_question(); } if (self.impulse == 203) { group_question = 4; ask_question(); }Swell. If the player types impulse 200, he will ask the first question, impulse 201 the second question, and so on. Yes, he will call the same routine that the bot does, because it does not include any bot-specific code. After four seconds, a bot will reply to the query.
bind F1 "impulse 200" bind F2 "impulse 201" bind F3 "impulse 202" bind F4 "impulse 203"Now the player can press F1 through F4 to ask one of the four questions. Much more fun this way. Remember that the wording of the question will be different every time too.