Welcome to the MMOtop - Arcemu, Mangos, Trinity.
+ Reply to Thread
Results 1 to 4 of 4
  1. #1
    Status : MattH is offline
    Join Date : Aug 2011
    Location : Google Chrome
    Posts : 3
    Thanks: 2
    Thanked 3 Times in 1 Post
    Rep Power : 0
    Reputation:10MattH is on a distinguished road

    Default [TrinityCore] C++ Guide

    When going about modifying something on TrinityCore, it's remarkably different from ArcEmu. Since a lot of it is based inside the DB, and it's nearly all C++, no LUA whatsoever. I'm going to write a few small linked-together guides on scripting and implementing the SQL, lay back, relax, and prepare to read.




    The Shell of C++

    Code:
    #include "ScriptPCH.h"
    
    enum eNums
    {
    };
    
    class example : public CreatureScript
    {
        public:
    		example() : CreatureScript("example"){}
    		
    		CreatureAI* GetAI_example(Creature* pCreature) const
    		{
    			return new exampleAI(pCreature);
    		}
    
    		struct exampleAI : public ScriptedAI
    		{
    			exampleAI(Creature *c) : ScriptedAI(c) {}
    			
    			void Reset()
    			{
    			}
    
    			void KilledUnit(Unit * /*victim*/)
    			{
    			}
    			
    			void JustDied(Unit * /*victim*/)
    			{
    			}
    
    			void EnterCombat(Unit * /*who*/)
    			{
    			}
    
    			void UpdateAI(const uint32 uiDiff)
    			{
    				if (!me->getVictim())
    				{
    				}
    				
    				if (!UpdateVictim())
    					return;
    
    			DoMeleeAttackIfReady();
    			}
    		};
    };
    
    void AddSC_example()
    {
        new example();
    }
    The C++ example above is a basic skeleton of a C++ code for a basic NPC. I'm going to show you how to:

    1. Cast Spells

    - On Self
    - On Target
    - On Random Target(s)


    2. Phases

    - Health % Phases
    - Timed Phases

    3. Speaking

    - Saying
    - Yelling





    Part I


    [Casting Spells]


    In {Part I} of the guide we'll work on all the magic of the scripting, literally. I'll show you how to make an NPC - buff themselves with Ice Armor, then cast Frostbolt on the attacking target AND Fireball on random target(s).

    In your C++ shell, go back to the following:


    Code:
    enum eNums
    {
    };
    Here we'll basically keep track of spells, and NPC's and such to be used in a script. Kind of like using the local function in a LUA script to define random stuff. So we are going to have Ice Armor, Frostbolt, and Fireball. So lets define them, shall we? Simply do this:

    Code:
    enum eNums
    {
    	SPELL_ICEARMOR = 36881,
    	SPELL_FROSTBOLT = 59251,
    	SPELL_FIREBALL = 57628
    };

    See how we just registered the spells right there? Simple, eh? Now, notice after each one, a comma follows. All of them will have to have a comma after them, except for the last one. This also means if they're only going to cast one spell, then they won't have to have a comma at the end.

    Now, lets go down to this section:

    Code:
    exampleAI(Creature *c) : ScriptedAI(c) {}
    Under there we'll add some more ”locals.” These will count as timers and variables, the script will call back on from time to time, when we tell it too.

    We're simply going to follow this formula: uint32 SpellName_Timer;.

    Code:
    exampleAI(Craeture *c) : ScriptedAI(c) {}
    
    	uint32 Icearmor_Timer;
    	uint32 Frostbolt_Timer;
    	uint32 Fireball_Timer;
    After this, we'll need to set times for the boss to use the spells, so go down to here:

    Code:
    void Reset()
    	{
    	}
    Now, we add the times for them to first call upon it. I want the Ice Armor spell to be used the second they're spawned. Frostbolt, as soon as we enter combat. Fireball after being in combat for five seconds. So simply do this:

    Code:
    void Reset()
    	{
    		Icearmor_Timer = 0;
    		Frostbolt_Timer = 0;
    		Fireball_Timer = 5000;
    	}
    See what I did there? Those numbers in there, specify how long (in milliseconds) this monster will first call upon the spell, where it is in the script. Now, we'll put these in the appropriate locations, to make him cast these spells at the appropriate time. So, first go to here:

    Code:
    void UpdateAI(const uint32 uiDiff)
    	{
    		if (!me->getVictim())
           		{
    		}
    		
    		if (!UpdateVictim())
    			return;
    
    	DoMeleeAttackIfReady();
    	}
    To make them cast a spell outside of combat, what we'll put here is under:

    Code:
    if (!me->getVictim())
    {
    }
    We'll simply follow this format for making the NPC cast the spell:

    Code:
    if (SpellName_Timer <= uiDiff)
    {
    	<Targeting Info Goes Here>;
    	SpellName = <Time Till Want to Recast>;
    }
    else
    	SpellName -= uiDiff;
    So, for out of combat, we will have this work under the if (!me->getVictim())

    We will make him cast Ice Armor on Himself!

    Code:
    if (!me->getVictim())
    {
    	if (Icearmor_Timer <= uiDiff)
    	{
    		DoCast(me, SPELL_ICEARMOR);
    		Icearmor_Timer = 18000000;
    	}
    	else
    		Icearmor_Timer -= uiDiff;
    This will make them cast Ice Armor, then after thirty minutes, re-cast it. Since it is under the “if (!me->getVictim())” it'll be cast outside of combat. Now, to make him cast something inside of combat. We'll go down to the next area, and add the “If (SpellName_Timer <= uiDiff)” Go down to here:

    Code:
    if (!UpdateVictim())
    			return;
    Underneath of that is where we'll add everything. We will make Frostbolt cast on the MT (Main Tank). Fireball is to be cast on random targets.

    Code:
    if (!UpdateVictim())
    	return;
    
    	if (Frostbolt_Timer <= uiDiff)
    	{
    		DoCast(me->getVictim(), SPELL_FROSTBOLT);
    		Frostbolt_Timer = 3000;
    	}
    	else
    		Frostbolt_Timer -= uiDiff;
    
    	if (Fireball_Timer <= uiDiff)
    	{
    		if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0))
                    			DoCast(pTarget, SPELL_FIREBALL);
    
    		Fireball_Timer = 10000;
    	}
    	else
    		Fireball_Timer -= uiDiff;
    See how I used each of those targeting for all three spells? Those are the different targeting types.

    Main Tank = DoCast(me->getVictim(), SPELL_SPELLNAME);

    On Self = DoCast(me, SPELL_SPELLNAME);

    On Random = if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0))

    DoCast(pTarget, SPELL_SPELLNAME);

    The 0 in the Random Targeting, can be changed for which you want to target (Mana, Close Range, or Far Range) I believe it is the same as it is on LUA. But, I've only really used those three.










    Part II



    [Health Percentage Phasing]

    Making phases in C++ is not terribly difficult. It does require making a new variable, and then a few more if's, but over all, it is more to type in, but it's straightforward, and it's obvious what it does.

    First, go back up to the section you made all the “uint32 Spell_Timer;” Here you will make another one “uint32 Phase;”


    Code:
    exampleAI(Craeture *c) : ScriptedAI(c) {}
    
    	uint32 Icearmor_Timer;
    	uint32 Frostbolt_Timer;
    	uint32 Fireball_Timer;
    
    	uint32 Phase;
    Now, go down to the “void Reset()” and we'll set Phase to equal one.

    Code:
    void Reset()
    {
    	Icearmor_Timer = 0;
    	Frostbolt_Timer = 0;
    	Fireball_Timer = 5000;
    
    	Phase = 1;
    }
    This'll set the Phase to one. This is really useful for setting any variable, because you can set after a certain spell, or something else to change it to a different value. After a certain value, you can trigger something else. But for now, lets set up what's needed to Switch Phases, and how to set it up, to make spells only cast in certain phases. First, lets set up the mechanism we need to Switch spells with a Health % loss. We will need to add this after “if (!UpdateVictim()) return;”

    Code:
    if (!UpdateVictim())
    	return;
    	
    	if (((me->GetHealth()*100 / me->GetMaxHealth()) < 55) && (Phase == 1))
    	{
    		Phase = 2;
    	}
    Here is the thing needed to change phases, it'll make the phase set too 2, and what I will show in the following CODE box, will show you what to do to make the spells cast in the correct phases!

    Code:
    if (!UpdateVictim())
    	return;
    	
    	if (((me->GetHealth()*100 / me->GetMaxHealth()) < 55) && (Phase == 1))
    	{
    		Phase = 2;
    	}
    
    	if (Phase == 1)
    	{
    	}
    	
    	if (Phase == 2)
    	{
    	}
    See the “If Phase = 1” and “if Phase = 2” thing? It does simply this: “If the phase equals one, it'll do what's in the brackets below it.” Here lets have Phase 1, be what we scripted earlier, and lets make phase two, only cast Fireball.

    Code:
    if (!UpdateVictim())
    	return;
    	
    	if (((me->GetHealth()*100 / me->GetMaxHealth()) < 55) && (Phase == 1))
    	{
    		Phase = 2;
    	}
    
    	if (Phase == 1)
    	{
    		if (Frostbolt_Timer <= uiDiff)
    		{
    			DoCast(me->getVictim(), SPELL_FROSTBOLT);
    			Frostbolt_Timer = 3000;
    		}
    		else
    			Frostbolt_Timer -= uiDiff;
    
    		if (Fireball_Timer <= uiDiff)
    		{
    			if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0))
                    			DoCast(pTarget, SPELL_FIREBALL);
    
    			Fireball_Timer = 10000;
    		}
    		else
    			Fireball_Timer -= uiDiff;
    	}
    	
    	if (Phase == 2)
    	{
    		if (Fireball_Timer <= uiDiff)
    		{
    			DoCast(me->getVictim(), SPELL_FIREBALL);
    			Fireball_Timer = 3000;
    		}
    		else
    			Fireball_Timer -= uiDiff;
    	}





    [Time Phasing]

    Now, for Timed Phases it's a bit different. But, at the same time its 100% the same as making a new spell. Lets just register another spell in “enum Enums” and call it “SPELL_ENRAGE”

    Code:
    enum eNums
    {
    	SPELL_ENRAGE = 54287
    };
    Also, make a “uint32 Enrage_Timer;”

    Code:
    exampleAI(Craeture *c) : ScriptedAI(c) {}
    
    uint32 Enrage_Timer;
    Now, we'll set it up too work after ten minute(s).

    Code:
    void Reset()
    {
    	Enrage_Timer = 600000;
    }
    Now, lets go down and make it work in combat. Do this:

    Code:
    if (!UpdateVictim())
    	return;
    
    	if (Enrage_Timer <= uiDiff)
    	{
    		DoCast(me, SPELL_ENRAGE);
    	}
    That's all you need to do, no extra timers, no nothing else. (Hopefully, by now your script is an unstoppable killing machine.) - (Also, it should be able to be queried over and over.)









    Part III



    [Creature Speaking]

    Let us go back up to the middle area that we didn't use. This is the area that we'll add ways to talk and / or yell.

    Code:
    void KilledUnit(Unit * /*victim*/)
    {
    }
    	
    void JustDied(Unit * /*victim*/)
    {
    }
    
    void EnterCombat(Unit * /*who*/)
    {
    }
    I believe it's quite obvious what does what here. If by chance you can't figure it out... [KilledUnit: Is what the NPC will do or say when they kill something]. [JustDied: Is what they do or say when they die]. [EnterCombat: Is what they do or say upon entering combat]. Now, lets get to talking part...

    Say!

    Code:
    me->MonsterSay(“TEXT”, LANG_UNIVERSAL, NULL);
    Just replace “TEXT” with what you want to say, and “LANG_UNIVERSAL” with whatever language you want, make “UNIVERSAL” into which language you want. “LANG_COMMON”, or “LANG_ORCISH”, etc.


    Yell!

    Code:
    me->MonsterYell(“TEXT”, LANG_UNIVERSAL, NULL);
    Just replace “TEXT” with what you want to say, and “LANG_UNIVERSAL” with whatever language you want, make “UNIVERSAL” into which language you want. “LANG_COMMON”, or “LANG_ORCISH”, etc.









    Thanks To



    Ikizami: For the original post.

    MattH: For revising the grammar and updating the whole post to work with the latest revision of TrinityCore.




    Special Thanks To



    [Only registered and activated users can see links. ] for allowing this post to be shared! :)

  2. The Following 3 Users Say Thank You to MattH For This Useful Post:

    Bezo (10-27-2011), LadySynystra (09-26-2011), SephiZe (10-01-2011)

  3. #2
    LadySynystra's Avatar
    Status : LadySynystra is offline
    Join Date : Sep 2011
    Location : Adobe Photoshop CS5
    Posts : 53
    Thanks: 8
    Thanked 2 Times in 1 Post
    Rep Power : 1
    Reputation:20LadySynystra is on a distinguished road

    Default

    Thanks for sharing this Matt! This is actually quite helpful. +REP

  4. #3
    SephiZe's Avatar
    Status : SephiZe is offline
    Join Date : Feb 2010
    Location : Sweden
    Posts : 796
    Thanks: 51
    Thanked 25 Times in 19 Posts
    Rep Power : 3
    Reputation:85SephiZe will become famous soon enough

    Default

    Thank you for the share! Could be usefull for somebody who wants to learn C++ :)
    MMotop.org Moderator

  5. #4
    Status : Bezo is offline
    Join Date : Jul 2009
    Posts : 1
    Thanks: 1
    Thanked 0 Times in 0 Posts
    Rep Power : 0
    Reputation:10Bezo is on a distinguished road

    Default

    Thanks help me on some script i start work on it . :)


 

Visitors found this page by searching for:

Trinity Core C

trinity core script hook

TrinityCore guide

C Trinity core

phasing scripting trinitycore

trinity script cast on self

trinity core c tutorial

wow trinity c guide

trinity core tutorial

trinitycore c tutorial

trinity c guide

TrinityCore C

trinity scripting guide

trinity core c script

trinity core guide c

c trinitycore

custom script trinitycore

trinitycore creaturescript

example() : creaturescript(example){}

trinity core scripts

trinity core guide

trinity core c scripting

trinity core scripting

Trinity c tutorial

trinity c

SEO Blog

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