CREDITS: Alvanaar
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:
- [Only registered and activated users can see links. ]
- 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:
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.#include "StdAfx.h"
#include "Setup.h"
(A "#" is a preprocessor symbol and tells the C++ compiler to do whatever comes after it before compiling).
Next comes this :
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.class CreatureAI : CreatureAIScript
{
public:
ADD_CREATURE_FACTORY_FUNCTION(CreatureAI);
CreatureAI(Creature* pCreature) : CreatureAIScript(pCreature)
{
}
protected:
};
We'll then put this below that in our script:
These are our basic "functions" or "voids". Pretty friggin' self explanatoryvoid OnCombatStart(Unit* mTarget)
{
}
void OnCombatStop(Unit *mTarget)
{
}
void OnDied(Unit * mKiller)
{
}
void AIUpdate()
{
}
void SpellCast(uint32 val)
{
}.
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:
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.void OnCombatStart(Unit* mTarget)
{
}
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:
What the hell does this all mean? I'll break it down for you all.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;
}
}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.
_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
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:#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)
{
}
We've registered the AI event update as the unit's base attack time.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;
}
}
That's our OnCombatStart... for now.
On to our "OnCombatStop".
Creature On Combat Stop
The OnCombatStop section of our script looks like this:
_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL); sets the unit's AI agent to NULL (nothing).void OnCombatStop(Unit * mTarget)
{
_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
_unit->GetAIInterface()->SetAIState(STATE_IDLE);
RemoveAIUpdateEvent();
}
_unit->GetAIInterface()->SetAIState(STATE_IDLE); makes the unit stand idle and stop attacking.
[COLOR="Green"]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:
RemoveAIUpdateEvent(); is simply removing the AI update event. There is no need for it now.void OnDied(Unit * mKiller)
{
RemoveAIUpdateEvent();
}
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
(Repeated in next post!)#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)
{
}



LinkBack URL
About LinkBacks





Reply With Quote


Bookmarks