Ok guys i found this phenomanal tut on creature AI, greatest thing ever.
Please please please give credits to Alvanaar. GL!
PART1
Hi there, everyone! This is my tutorial on Creature AIs.
In this tutorial I'll teach you a way to program a creature AI using C++.
I will be keeping this tutorial updated. If you have any requests, questions, or need more explaining. Please say so!
Please note: I have only just finished making this tutorial and I know it may have some mistakes in it. Please alert me of any.
What you need:
- Microsoft Visual C++
- Skillz
Introduction
AI stands for Artificial Intelligence. Creature combat scripts are known in C++ as Creature AIs.
This is what I'll be teaching you about in this tutorial.
Scripting Your C++ Creature AI
Create a .cpp file (C++ Source File) in Microsoft Visual C++.
We'll start our creature AI with the following code:
Code:
Code:
#include "StdAfx.h"
#include "Setup.h"
As I've stated in my gossip NPC tutorial, this tells the C++ compiler to include the two external files, StdAfx.h and Setup.h in this script.
(A "#" is a preprocessor symbol and tells the C++ compiler to do whatever comes after it before compiling).
Next comes this :
Code:
Code:
class CreatureAI : CreatureAIScript
{
public:
ADD_CREATURE_FACTORY_FUNCTION(CreatureAI);
CreatureAI(Creature* pCreature) : CreatureAIScript(pCreature)
{
}
protected:
};
We'll fill this in a bit more later. But, basically, what this "class" means is that it is naming the script "CreatureAI" (you can change it but it will be used later, so I recommend keeping it as it is) and in between the brackets later we will include some other functions. Don't worry about the spells yet.
We'll then put this below that in our script:
Code:
Code:
Code:
void OnCombatStart(Unit* mTarget)
{
}
void OnCombatStop(Unit *mTarget)
{
}
void OnDied(Unit * mKiller)
{
}
void AIUpdate()
{
}
void SpellCast(uint32 val)
{
}
These are our basic "functions" or "voids". Pretty friggin' self explanatory .
We're going to tackle this one void at a time...
Creature On Combat
We're going to start scripting our creature AI with the OnCombatStart void:
Code:
Code:
void OnCombatStart(Unit* mTarget)
{
}
We're going to make this NPC start its combat phase with a chat message. But we don't want it to be boring, so we'll change things up a little.
We'll randomise it. And, in this case, I'm going to give the NPC a 50% chance to say a message, 50% chance to not. So we put this:
Code:
Code:
void OnCombatStart(Unit* mTarget)
{
int RandomChance;
RandomChance = rand()%4;
switch(RandomChance)
{
case 0:
_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!");
break;
case 1:
_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!");
break;
case 2:
break;
case 3:
break;
}
}
What the hell does this all mean? I'll break it down for you all. From top to bottom...
The "int" in "int RandomChance;" means that whatever follows that "int" is an integer. An "int" integer can only be a certain amount of bytes. But don't worry about that.
The "RandomChance" after "int" is just the name of my integer. On the next line of the script, we define what this integer is.
RandomChance = rand()%4; is saying that there is a 1 in 4 chance for this script to perform a certain function. As you can see, there is our "RandomChance" integer at the start of it.
This part of the script: switch(RandomChance) tells the C++ engine to show all the "cases" (or "intids" in Lua) for our "RandomChance" integer.
case 0: is just the first case or "intid". What comes below it is what happens on the 25% chance.
[code]_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!"); is pretty self explanatory.
It makes the NPC send a chat message (which is "Yell" in this case, for say, change CHAT_MSG_MONSTER_YELL to "CHAT_MSG_MONSTER_YELL"). The language is "LANG_UNIVERSAL" (which is universal). The chat message in this case is "I am saying a chat message! Hoorahh!"
The code break; used in this part of the script just tells the C++ engine that the case is over. No more actions will be performed in that case.
Your script should look something like this so far
Code:
Code:
#include "StdAfx.h"
#include "Setup.h"
class CreatureAI : CreatureAIScript
{
public:
ADD_CREATURE_FACTORY_FUNCTION(CreatureAI);
CreatureAI(Creature* pCreature) : CreatureAIScript(pCreature)
{
}
protected:
};
void OnCombatStart(Unit * mTarget)
{
int RandomChance;
RandomChance = rand()%4;
switch(RandomChance)
{
case 0:
_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!");
break;
case 1:
_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!");
break;
case 2:
break;
case 3:
break;
}
}
void OnCombatStop(Unit * mTarget)
{
}
void OnDied(Unit * mKiller)
{
}
void AIUpdate()
{
}
void SpellCast(uint32 val)
{
}
Next we need to register our AI event update. This will be used throughout the script to update the current AI status. To do this we add to our
OnCombatStart section of the script the text in red:
Code:
void OnCombatStart(Unit * mTarget)
{
RegisterAIUpdateEvent(_unit->GetUInt32value(UNIT_FIELD_BASEATTACKTIME));
int RandomChance;
RandomChance = rand()%4;
switch(RandomChance)
{
case 0:
_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!");
break;
case 1:
_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!");
break;
case 2:
break;
case 3:
break;
}
}
We've registered the AI event update as the unit's base attack time.
That's our OnCombatStart... for now.
On to our "OnCombatStop".
Creature On Combat Stop
The OnCombatStop section of our script looks like this:
Code:
Code:
void OnCombatStop(Unit * mTarget)
{
_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
_unit->GetAIInterface()->SetAIState(STATE_IDLE);
RemoveAIUpdateEvent();
}
_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL); sets the unit's AI agent to NULL (nothing).
_unit->GetAIInterface()->SetAIState(STATE_IDLE); makes the unit stand idle and stop attacking.
RemoveAIUpdateEvent();[/GREEN] removes the AI update event we had.
That was fairly simple and easy, now for the OnDied.
Creature On Died
This part of the script is simple, unless you want to make it more advanced. However we'll keep this easy.
Simply make our "OnDied" section of the script this:
Code:
void OnDied(Unit * mKiller)
{
RemoveAIUpdateEvent();
}
RemoveAIUpdateEvent(); is simply removing the AI update event. There is no need for it now.
Now, we'll set up our spell casting. But first, let's see how our script looks so far:
Your script should look something like this so far
Code:
#include "StdAfx.h"
#include "Setup.h"
class CreatureAI : CreatureAIScript
{
public:
ADD_CREATURE_FACTORY_FUNCTION(CreatureAI);
CreatureAI(Creature* pCreature) : CreatureAIScript(pCreature)
{
}
protected:
};
void OnCombatStart(Unit * mTarget)
{
int RandomChance;
RandomChance = rand()%4;
switch(RandomChance)
{
case 0:
_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!");
break;
case 1:
_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!");
break;
case 2:
break;
case 3:
break;
}
}
void OnCombatStop(Unit * mTarget)
{
_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
_unit->GetAIInterface()->SetAIState(STATE_IDLE);
RemoveAIUpdateEvent();
}
void OnDied(Unit * mKiller)
{
RemoveAIUpdateEvent();
}
void AIUpdate()
{
}
void SpellCast(uint32 val)
{
}