Welcome to the MMOtop - Arcemu, Mangos, Trinity.
+ Reply to Thread
Results 1 to 7 of 7
  1. #1
    Jerry's Avatar
    Status : Jerry is offline
    Join Date : Mar 2009
    Location : Serbia
    Posts : 2,321
    Thanks: 223
    Thanked 501 Times in 286 Posts
    Rep Power : 10
    Reputation:2077Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute

    Default [C++ Tutorial] How to Make a Creature AI (Creature Combat)

    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:

    #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 :

    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:

    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:

    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:

    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.

    _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

    #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:

    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:

    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.

    [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:

    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

    #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)
    {

    }
    (Repeated in next post!)

  2. #2
    Jerry's Avatar
    Status : Jerry is offline
    Join Date : Mar 2009
    Location : Serbia
    Posts : 2,321
    Thanks: 223
    Thanked 501 Times in 286 Posts
    Rep Power : 10
    Reputation:2077Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute Jerry has a reputation beyond repute

    Default

    Creature Spell Casting

    Firstly, we need to define our spells up the top of our script. In this case, I'll use 2 spells. You can add more if you want.

    We go to the top of our script, and a few lines below our "#include"s I'm going to put this:

    #define REND 47465
    #define PUMMEL 59344
    In the above code, #define means to, well, define the following text and relate it to the text a space after it.

    REND and PUMMEL are the names of my "#define"s. Make yours whatever name you want, as long as the name doesn't appear as blue in your C++ program.

    The 47465 and 59344 are the IDs of my defined spells.

    Now once the defining of the spells is done, we can proceed with our spell casting phase for our creature AI.

    Go down to this section in the script:

    class CreatureAI : CreatureAIScript
    {
    public:
    ADD_CREATURE_FACTORY_FUNCTION(CreatureAI);
    CreatureAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
    }

    protected:

    };
    In between the brackets ({ and }) put this:

    rend = pummel = true;
    inforend = dbcSpell.LookupEntry(REND);
    infopummel = dbcSpell.LookupEntry(PUMMEL);
    Below where it says "protected". Place:

    bool rend;
    bool pummel;
    SpellEntry *inforend, *infopummel;
    Note: We still haven't put anything in between the curly brackets in "SpellCast".

    Now to add everything in the "SpellCast".

    Firstly we need to see if the player has a target selected and is not currently casting a spell. One way of doing this (the way I'm going to do it) is:

    if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget())
    {
    This basically says that if the NPC has no current spell and has a next target then it will do what comes after this "if" statement.

    We'll add this under the bracket...

    if(rend)
    {
    _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), inforend, false);
    rend = false;
    return;
    }

    if(pummel)
    {
    _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), infopummel, false);
    pummel = false;
    return;

    }
    What this means (I'll try to explain it so you all understand):

    rend and pummel are our bools from the top of the script. If they are set to true they will cast the spell that we.... linked.. them to at the top of our program.

    inforend and infopummel are the actual spells.

    rend = false; and pummel = false; is just setting the bools to false. We will add the resetting of the spells next.

    if(rend) and if(pummel) are pretty much saying "if(rend == true)" and "if(pummel == true)".

    Let's now put this below that code, this:

    if(val >= 100 && val <= 250)
    {
    _unit->setAttackTimer(2250, false);
    rend = true;
    }
    if(val >= 650 && val <= 850)
    {
    _unit->setAttackTimer(3500, false);
    pummel = true;
    }
    if(val >= 100 && val <= 225) and if(val >= 790 && val <= 900) are "if" statements that say that if the random UInt value is between 100 and 250 then the NPC casts the spell rend. If the value is between 650 and 850 it casts pummel. We are just about to set up the random value section of our code...

    It then sets the unit's attack timer to the time above. (2250 and 3500)

    Here we go. Almost done.



    Your script should look something like this so far

    #include "StdAfx.h"
    #include "Setup.h"

    #define REND 47465
    #define PUMMEL 59344

    class CreatureAI : CreatureAIScript
    {
    public:
    ADD_CREATURE_FACTORY_FUNCTION(CreatureAI);
    CreatureAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
    rend = pummel = true;
    inforend = dbcSpell.LookupEntry(REND);
    infopummel = dbcSpell.LookupEntry(PUMMEL);
    }

    protected:

    bool rend;
    bool pummel;
    SpellEntry *inforend, *infopummel;

    };


    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)
    {
    if(rend)
    {
    _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), inforend, false);
    rend = false;
    return;
    }

    if(pummel)
    {
    _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), infopummel, false);
    pummel = false;
    return;

    }
    if(val >= 100 && val <= 250)
    {
    _unit->setAttackTimer(2250, false);
    rend = true;
    }
    if(val >= 650 && val <= 850)
    {
    _unit->setAttackTimer(3500, false);
    pummel = true;
    }
    }
    Creature AI Update

    In between the brackets below "AIUpdate()", place the following:

    void AIUpdate()
    {
    uint32 val = RandomUInt(1000);
    SpellCast(val);
    }
    uint32 val = RandomUInt(1000); gives us our value of "val" from the "SpellCast" part of the script.


    Setting up your Creature AI

    A few spaces below all your code enter this:

    void SetupCreatureAI(ScriptMgr * mgr)
    {
    mgr->register_creature_script(NPCID, &CreatureAI::Create);
    }
    This sets up our creature AI script.

    Put your NPC's entry ID where I have: NPCID.

    Make sure that CreatureAI is the name of your "class" at the top of the script! (class CreatureAI : CreatureAIScript)

    Well done! You've created a creature AI program!!!



    The end script should look something like this!

    Note: You can comment C++ scripts with // for line comments and /* */ for block comments.

    I have commented this example script to basically show what everything does:

    #include "StdAfx.h"
    #include "Setup.h"

    #define REND 47465 // Here is the spell ID of Rend defined
    #define PUMMEL 59344 // Here is the spell ID of Pummel is defined

    class CreatureAI : CreatureAIScript
    {
    public:
    ADD_CREATURE_FACTORY_FUNCTION(CreatureAI);
    CreatureAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
    rend = pummel = true; // The rend and pummel bools are set to "true"
    inforend = dbcSpell.LookupEntry(REND); // We look up the entry ID for the spells...
    infopummel = dbcSpell.LookupEntry(PUMMEL);
    }

    protected:

    bool rend;
    bool pummel;
    SpellEntry *inforend, *infopummel;

    };


    void OnCombatStart(Unit * mTarget) // OnCombatStart function. Occurs when the creature enters combat.
    {
    int RandomChance;
    RandomChance = rand()%4;
    switch(RandomChance)
    {
    case 0:
    _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am saying a chat message! Hoorahh!"); // Makes the unit send a chat message. Type: Yell, Language: Universal, Text: 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: // Nothing happens in this case
    break;
    case 3: // " "
    break;
    }
    }
    void OnCombatStop(Unit * mTarget) // OnCombatStop. Occurs when the creature leaves combat. (Not when it dies).
    {
    _unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
    _unit->GetAIInterface()->SetAIState(STATE_IDLE);
    RemoveAIUpdateEvent();
    }

    void OnDied(Unit * mKiller) // OnDied. Occurs when the creature dies.
    {
    RemoveAIUpdateEvent(); // Removes our AI update event
    }

    void AIUpdate() // This is our AI update event
    {
    uint32 val = RandomUInt(1000); // Random value. Will be used for spellcasting
    SpellCast(val);
    }

    void SpellCast(uint32 val) // This is where the majority of the creature's spell casting is handled.
    {
    if(rend) // if(rend == true)
    {
    _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), inforend, false);
    rend = false; // This sets the bool "rend" to false.
    return;
    }

    if(pummel) // if(pummel == true)
    {
    _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), infopummel, false);
    pummel = false; // This sets the bool "pummel" to false.
    return;

    }
    if(val >= 100 && val <= 250) // if our random value ("val") is higher than 100 and lower than 250 then execute the following code...
    {
    _unit->setAttackTimer(2250, false); // Sets the creature's attack timer to 2250
    rend = true; // This sets the bool "rend" to true.
    }
    if(val >= 650 && val <= 850) // if our random value ("val") is higher than 650 and lower than 850 then execute the following code...
    {
    _unit->setAttackTimer(3500, false); // Sets the creature's attack timer to 3500
    pummel = true; // This sets the bool "pummel" to true.
    }
    }

    void SetupCreatureAI(ScriptMgr * mgr)
    {
    mgr->register_creature_script(NPCID, &CreatureAI::Create);
    }

  3. #3
    Status : coder_gate is offline
    Join Date : Mar 2010
    Posts : 1
    Thanks: 0
    Thanked 0 Times in 0 Posts
    Rep Power : 0
    Reputation:10coder_gate is on a distinguished road

    Default

    where does setup.h

  4. #4
    Status : bfrings is offline
    Join Date : Feb 2010
    Location : England!!
    Posts : 136
    Thanks: 8
    Thanked 8 Times in 5 Posts
    Rep Power : 3
    Reputation:71bfrings will become famous soon enough

    Default

    Awesome :)

  5. #5
    AnTo's Avatar
    Status : AnTo is offline
    Join Date : Oct 2009
    Location : not saying
    Posts : 701
    Thanks: 21
    Thanked 63 Times in 23 Posts
    Rep Power : 3
    Reputation:97AnTo will become famous soon enough

    Default

    Nice!

  6. #6
    Status : bfrings is offline
    Join Date : Feb 2010
    Location : England!!
    Posts : 136
    Thanks: 8
    Thanked 8 Times in 5 Posts
    Rep Power : 3
    Reputation:71bfrings will become famous soon enough

    Default


  7. #7
    Truster's Avatar
    Status : Truster is offline
    Join Date : Apr 2010
    Location : Norway
    Posts : 3,341
    Thanks: 46
    Thanked 87 Times in 83 Posts
    Rep Power : 10
    Reputation:2014Truster has a reputation beyond repute Truster has a reputation beyond repute Truster has a reputation beyond repute Truster has a reputation beyond repute Truster has a reputation beyond repute Truster has a reputation beyond repute Truster has a reputation beyond repute Truster has a reputation beyond repute Truster has a reputation beyond repute Truster has a reputation beyond repute Truster has a reputation beyond repute

    Default

    nice share :)


 

Similar Threads

  1. [Tutorial] How to setup an Account Creation page for your server
    By Jerry in forum Emulator Server Guides
    Replies: 6
    Last Post: 03-17-2012, 09:52 AM
  2. Replies: 39
    Last Post: 03-07-2012, 09:18 PM
  3. Anyone want to make an private server and make it public together?
    By zakakid1 in forum Recruitment & Gamemasters
    Replies: 4
    Last Post: 05-31-2010, 02:08 AM
  4. Make ArcEmu public + Make 2 realm in ArcEmu
    By Jerry in forum ArcEmu Guides
    Replies: 15
    Last Post: 05-23-2010, 04:32 AM
  5. Replies: 1
    Last Post: 02-21-2010, 12:19 AM

Visitors found this page by searching for:

how to make ai in c

how to make an ai in c

how to create an ai program

c AI tutorial

how to create AI in c

how to make ai with c

how to make a ai program

ai tutorial c

how to make AI c

c creature classnpc ai c creature ai trinityHOW TO MAKE AN AI USING C c ki tutorialmonster ai c fCHAT_MSG_MONSTER_YELLmaking ai in c creature combathow to create AI using c how to create AI c how to make an npc ai in c how to create an ai in c how to create a creature TRINITYmake a c ai
SEO Blog

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts