Thursday, June 19, 2008

The LUA brain of a quest giver

I thought this might interest some people so here's the AI of one of the quest givers in the game.

Initialization section


LOOPTIME: Loop speed in miliseconds
GODMODE: I'd like to keep (most) of my quest givers alive please
HP - MAXHP: Pretty much useless here but heh

Looping code

inmessage = getheard();
name = inmessage.sender;

if (name ~= '') then
if (inmessage.message ~= '') then
if (gotbadge(name, 14) == 1) then
saymessage = 'Thanks for helping me. Oh and I hope you didn\'t touch anything...';
sayto(saymessage, name, 2);
if (inmessage.message == '/talk') then
-- 1=quest active, 0=quest not active
questactive = badgegetvalue(name, 14, 1);

if (questactive == 1) then
-- Check if killed 5 zombies
queststatus = badgeexpectedkillsstatus(name, 14);

if (queststatus[0] == 1) then
addbadge(name, 14);
badgeresetexpectedkills(name, 14);
addprestigepoints(name, 10);
givemoney(name, 1);

saymessage = 'Thanks a lot. Look, my pockets are quite empty right now so all I can afford to give you is 1 gold coin.

You didn\'t touch anything in there, did you?

You received a new badge';
sayto(saymessage, name, 2);
if (queststatus[2] == 0) then
saymessage = 'So, you found the zombies in the basement?';
sayto(saymessage, name, 2);
saymessage = 'You only killed ' .. queststatus[2] .. '? Think you can kill at least ' .. (queststatus[1] - queststatus[2]) .. ' more?';
sayto(saymessage, name, 2);
saymessage = 'When I woke up this morning, I heard some strange noises coming from the basement. I went to take a look and there was zombies everywhere!

I have no idea how they got there. I think they must have digged they\'re way to my house but I haven\'t found where exactly.

I fought some of them but there is too many. Think you can help me a bit?';
askyesno(name, saymessage, 'I\'ll see what I can do', 'Maybe later', '/ok', '');
if (inmessage.message == '/ok') then
-- Set quest active
badgesetvalue(name, 14, 1, 1);
-- Wait for 5 zombies killed from Stanford basement
badgeaddexpectedkills(name, 14, 24, 0, 5);

saymessage = 'Thanks. Go in there and look in the basement. They shouldn\'t be hard to find.

Defeat 5 zombies from Stanford\'s basement';
sayto(saymessage, name, 2);


You'll notice that some functions here are not from LUA (getheard, sayto, gotbadge, ...). These functions are .NET functions allowing LUA to access and update the game data. So far, there's 59 of those functions allowing NPCs to walk, talk, attack, follow, give rewards, take items from players and other traditional actions we expect from an NPC.

Check first message received by the NPC. When a player "talks" to an NPC, he is in fact adding a command to an array (first in, first out). getheard retuns an object containing the name of the sender (which could also be an NPC) and the command we expect the NPC to react to.

Just checking if the current character has already done the quest associated with the quest giver.

This command can either send a private message or show a dialog box. This command is also used to get two NPCs to "talk" to each others (like go attack my current target).

Used to keep track of the progress of the quest like how many items of a type were given to the NPC so far and other useful stuff to change how the NPC interact with the player.

This command tells the server that from this moment, we want to count the kills done by a character (and by his golems). In this quest, the NPC ask the player to destroy 5 zombies. So this command starts the counter.

Just returning the data compiled after using badgeaddexpectedkills.

addprestigepoints, givemoney:
Rewards! Some NPCs also use the command "giveto" to give players specific items.

Much like sayto, used to ask a yes/no question type, allowing deeper interactions with NPCs. Eventually, I'd like to add a window that would allow players to type text to NPCs and/or a window allowing to chose an answer among more than 2 choices.

This quest is a very basic one. I'll keep the more complex ones for later!