[ArcEmu] Basic C++ Boss Scripting menu

User Tag List

Results 1 to 8 of 8
  1. #1
    Hardball's Avatar Member
    Reputation
    147
    Join Date
    May 2008
    Posts
    61
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [ArcEmu] Basic C++ Boss Scripting

    Yes I am Halestorm, or HalestormXV if you prefer. I am both and both are me. If you would like proof that I am me then send me a PM if you wish

    So I see a small amount of C++ ones. Now I am going to give this warning once. This is not easy to understand. I recommend this ONLY if you really want to spend a lot of time becoming frustrated and many attempts at Trial and Error, and many more attempts and recompiling your brains out because unlike Lua you can't just reload the .dll

    PART I - What You Need
    If you do not have the following then do not even continue reading this guide. It will be a waste of your time. Here is your check list:
    - The ability to compile your own server
    - The ability to understand C++ code or the mental capacity to learn it. (This is Fact, not to be mean)
    - Microsoft Visual Studio C++ Express 2010 (Arc no longer has a 2008 solution)
    - Knowledge on how to compile your own scripts either by creating a new project or using a copy of the existing solution.
    - The ability to understand that text within () is extra information that someone can validate me on if they see that I have made an error. Otherwise you can ignore it.



    PART II - The Background Info
    When you create a C++ Script and compile it you are not creating an actual script. You are creating an extension or external library or a .dll file. This file gets loaded with your server on startup. Yes you are creating a script but once you compile it, it becomes an extension to the application. It is loaded once during server load up and the core takes care of it from there.

    The ArcScript Team has created an ArcScript library (or at least it was called that at the time of creating this example boss). The ArcScript Library is a preset compilation of function and command that you can use to set up your AI. There are two libraries. One for Bosses and one for Basic Trash. You can use either or for whatever you want but the Boss library obviously has more functionality. (I know it was based off of MoonScript and I believe you can still use the Moon Script Class as well. For those who have no idea what I am talking about relating to this just ignore it.)


    PART III - Let's Begin - Create the Blueprints
    C++ Scripts always need a general same header for this tutorial's purpose. The header is as follows:
    Code:
    #include "StdAfx.h"  //This uses the existing functions in Arc's Core
    #include "Setup.h"  //So does this
    #include "Base.h"  // This is used to include the ArcAI engine commands
    
    #ifdef WIN32 //This is our structure
    #pragma warning(disable:4305)  //This disables an annoying error that may pop up while compiling
    #endif
    Now we are creating a boss named Captain Randle. He is a mean person who likes to beat you up. Now what I am going to show you below is good coding practice however you do not actually need to define your constants/enumerations but I like to define everything at the top of my scripts so this is the way I teach others how to do it.
    Code:
    //Captain Randal
    #define COT_CAPTAIN_RANDAL   48264  //This is the entry number of the good captain
    
    //Everything below this is his ability ID numbers.
    #define RANDAL_THUNDER       43583  
    #define RANDAL_DECAY         56359   
    #define RANDAL_BLADE         63784
    #define RANDAL_BLOOD         59130
    #define RANDAL_ICY           60952
    #define RANDAL_CLEAVE        31345
    #define RANDAL_FEAR          22686
    We have defined the entry of the good captain and given him a nice list of spells to use. He looks really mean. Scripting him will be even meaner

    PART IIIII - Let's Begin - Create the Structure
    Now we have to tell the scripting engine what we will be pulling from and we have to create our structure by telling the extension what we will be doing.
    Code:
    class RandalBossAI : public MoonScriptBossAI
    {
    public:
        MOONSCRIPT_FACTORY_FUNCTION(RandalBossAI, MoonScriptBossAI);
    	RandalBossAI(Creature* pCreature) : MoonScriptBossAI(pCreature)
    	{
    		randalThunder = AddSpell(RANDAL_THUNDER, Target_Current, 13, 0, 10);
    		randalDecay = AddSpell(RANDAL_DECAY, Target_Destination, 9, 3, 12);
    		randalBlood = AddSpell(RANDAL_BLOOD, Target_Current, 15, 0, 8);
    
    		AddPhaseSpell(2, AddSpell(RANDAL_ICY, Target_Current, 14, 0, 8));
    		AddPhaseSpell(2, AddSpell(RANDAL_BLADE, Target_Current, 8, 0, 12));
    
    		AddPhaseSpell(3, AddSpell(RANDAL_CLEAVE, Target_Current, 11, 0, 12));
    		AddPhaseSpell(3, AddSpell(RANDAL_FEAR, Target_Current, 9, 1.5f, 15));
    
    		AddEmote(Event_OnCombatStart, "You have faced many challenges, pity they were all in vain. Soon your people will kneel to my lord!", Text_Yell, 10292);
    		AddEmote(Event_OnTargetDied, "It is over! Finished!", Text_Yell, 10297);
    	}
    HOLY SHIT WHAT JUST HAPPENED!! Oh Noez! A Big Wall of Text in C++ No Wai!! If you are saying this to yourself right now you may want to turn away as this is just the beginning. Now lets take it apart piece by piece for those brave adventurers still reading on.
    Code:
    class RandalBossAI : public MoonScriptBossAI
    All we did here was tell the script that we will be using the ArcBossAI/MoonBossAI "Library" it is public because it can be pulled from.
    Code:
    {
    All this did was open up our function.
    Code:
    public:
        MOONSCRIPT_FACTORY_FUNCTION(RandalBossAI, MoonScriptBossAI);
    	RandalBossAI(Creature* pCreature) : MoonScriptBossAI(pCreature)
    This assigns the name of our AI, for this our AI is named RandalBossAI. The MoonScriptBossAI is basically assigning our RandalBossAI to this. The RandalBossAI(Creature* pCreature) : MoonScriptBossAI(pCreature) is setting up our pointer. We are saying that RandalBossAI is a creature and we are declaring it as pCreature. The MoonScriptBossAI(pCreature) is telling the MoonScriptBossAI library to use creature arguments so to speak.
    Code:
    {
    This digs deeper into our function making it nested so that C++ knows to run this as all part of the same code block
    Code:
    randalThunder = AddSpell(RANDAL_THUNDER, Target_Current, 13, 0, 10);

    This line of code and all of those that look like it simply add the spell to the AI of the boss. AddSpell is a function in the library that takes 5 arguments. The are as follows as shown in the line above respectively.
    - Spell ID (Remember we declared this at the top)
    - The target of the spell Target_Current means who he is currently attacking
    - The percent chance that it will occur. We have a 13 percent chance here.
    - The cast time. 0 means instant cast
    - The cooldown, which is self explanatory

    Code:
    AddPhaseSpell(2, AddSpell(RANDAL_ICY, Target_Current, 14, 0, 8));
    This is a neat little feature that does the same as above however adds it to a phase of the boss. So the boss will only use this ability if he is in phase 2 of the encounter which is what the first argument is.
    Code:
    AddEmote(Event_OnTargetDied, "It is over! Finished!", Text_Yell, 10297);
    This adds an emote to the boss. What it translates to is simply - When his target dies yell It is over! Finished! in the yell text and play soundID 10297. That's it. Pretty neat huh?
    Code:
    }
    All this did was close the block of code that we entered above.

    PART V - Let's Continue - The Heart
    While dealing with C++ we need multiple functions and multiple things to occur within each function just as we would with Lua. However in C++ we call this void.
    Code:
    void OnCombatStart(Unit *pTarget)
    Looks easy right Well that part is very east. This is the function that will occur once combat starts. Now have your eyes look at this

    Code:
    	
    {
          // Phase 1
          if (randalThunder != NULL)
          {
             randalThunder->mChance = 13.0f;
             randalThunder->mEnabled = true;
          }
          if (randalDecay != NULL)
          {
             randalDecay->mChance = 9.0f;
             randalDecay->mEnabled = true;
          }
          if (randalBlood != NULL)
          {
             randalBlood->mChance = 15.0f;
             randalBlood->mCooldown = 8;
             randalBlood->mEnabled = true;
          }
    		ParentClass::OnCombatStart(pTarget);
    }
    OMG HALESTORM I HATE YOU I HATE YOU I HATE YOU!! WHAT IS ALL OF THIS SHIT YOU ARE THROWING IN MY FACE! I AM GOING TO ASSPLOAD!!

    Easy now young grasshopper. Every boss automatically when combat begins starts in phase 1. All this is doing is as follows. During phase 1 all of this will occur.
    Code:
          if (randalThunder != NULL)
          {
             randalThunder->mChance = 13.0f;
             randalThunder->mEnabled = true;
          }
    Let's break this down. if (randalThunder != NULL) means that if it is not non-existent and is infact there and has a value then proceed.
    Code:
    randalThunder->mChance = 13.0f;
    This adjusts the chance this will occur to 13%.
    Code:
    randalThunder->mEnabled = true;
    This means that the spell will be enabled during phase 1. The two { open and close our if statement. Now lets move to the next line of code shall we?

    Code:
    void OnCombatStop(Unit* pTarget)
    Well this function will run when CombatStops. And now for the meat of the function itself.
    Code:
    {
       if(GetHealthPercent() >= 1)
       {
       sEventMgr.AddEvent(TO_UNIT(GetUnit()), &Unit::SendChatMessage (uint8)CHAT_MSG_MONSTER_YELL, (uint32)LANG_UNIVERSAL, "Is there no one left to test me?", EVENT_UNIT_CHAT_MSG, 2000, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
       sEventMgr.AddEvent(TO_OBJECT(GetUnit()), &Object::PlaySoundToSet, (uint32)10293, EVENT_UNK, 2000, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
        GetUnit()->SetHealthPct(100);
    	}
    		ParentClass::OnCombatStop(pTarget);
    	}
    So who wants to kill me right now? Well I know I would. So here is what we are doing here. When combat ends we are checking the bosses HP. If it is above 1% that means that the group wiped right? So what we do is we take control of the event manager. Which is one of the most power features the C++ library has.
    Code:
    sEventMgr.AddEvent(TO_UNIT(GetUnit()), &Unit::SendChatMessage (uint8)CHAT_MSG_MONSTER_YELL, (uint32)LANG_UNIVERSAL, "Is there no one left to test me?", EVENT_UNIT_CHAT_MSG, 2000, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
    
    sEventMgr.AddEvent(TO_OBJECT(GetUnit()), &Object::PlaySoundToSet, (uint32)10293, EVENT_UNK, 2000, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
    What we are doing is adding an event to the handler. Here is what it does in english terms. We are getting the unit (Randal) and he is sending a chat message in the yell format with a universal language with the message "Is there no one left to test me?". The 2000 means that we execute this 2 seconds after the CombatStop function is called and only once and we execute this outside of world context.

    The second event we have basically assigns object from the Unit (Randal) and that object we are assigning is going to Play a sound which is an unsigned integer 32 bytes long, which is really useless to you if you do not care to know background information. But the ID of said Int is 10293. We do EVENT_UNK because there are no specific flags for the sound event. We also have a delay of 2 seconds after the CombatStop function is called so that it lines up with our send chat message event and once again we execute this only once and not within world context so it is destroyed afterward.


    Code:
     GetUnit()->SetHealthPct(100);
    What this simply does is get the unit (Randal) and set his health percentage back to 100. Yes we have to tell C++ to do this because it won't always do it automatically.

    Code:
    }
      ParentClass::OnCombatStop(pTarget);
    }
    The first bracket closes our if statement then the ParentClass is called which is basically calling the combatstop function from the library. Then the second bracket closes our entire function.

    Code:
    void OnDied(Unit* pKiller)
    	{
    		Emote("My lord will be the end of you...all..", Text_Yell, 10299);
    		ParentClass::OnDied(pKiller);
    	}
    This is our OnDied function. All this does is say. Hey when the boss dies play that emote that we declared up top and then make sure to call the OnDied function from our Library.

    PART VI - Let's Continue - The Meat
    Code:
    void AIUpdate()
    This is one of the most essential commands to any AI. This function is automatically called every second and this is where all of your phases, and anything else you want to happen will happen. Here is what we will use for this tutorial. Hold on to your hat as this is a biggie.

    Code:
    	
    {
          // Phase 2
    		if(GetHealthPercent() <= 95 && GetPhase() == 1)
    		{
    			SetPhase(2);
             if (randalThunder != NULL)
             {
                randalThunder->mEnabled = false;
                randalThunder->mChance = 15.0f;
             }
             if (randalDecay != NULL)
             {
                randalDecay->mChance = 11.0f;
             }
             if (randalBlood != NULL)
             {
                randalBlood->mChance = 12.0f;
                randalBlood->mCooldown = 10;
             }
    		}
    
          // Phase 3
    		if(GetHealthPercent() <= 65 && GetPhase() == 2)
    		{
    			Emote("Your days are done!", Text_Yell, 10298);
    			SetPhase(3);
             if (randalDecay != NULL)
                randalDecay->mEnabled = false;
    
             if (randalBlood != NULL)
                randalBlood->mEnabled = false;
    
             if (randalThunder != NULL)
                randalThunder->mEnabled = true;
    		}
    
          // Phase 4
    		if(GetHealthPercent() <= 40 && GetPhase() == 3)
    		{
    			Emote("You are nothing! I answer a higher call!", Text_Yell, 10295);
    			SetPhase(4);
    		}
    
    		ParentClass::AIUpdate();
    }
    HALESTORM I AM GOING TO KILL YOU! WHY DOES THIS SHIT SPEW OUT SO MUCH!! WHEN WILL IT END!!!!

    Well little one. You are almost done actually. Once this part is complete you are pretty much done. But lets break this done shall we.
    Code:
    if(GetHealthPercent() <= 95 && GetPhase() == 1)
    This basically returns the NPCs Health Pct and if it is less then or equal to 95 AND his current phase is equal to 1 then do the following.
    - Set his phase to number 2
    - Disable his thunderclap
    - change the percentage of his Death and Decay
    - etc. etc. etc.

    Now remember this is all being done within the AiUpdate function and remember that his runs every second so you can pretty much follow the code now to see what we do in phase 3.

    We then at the end do our standard parent class.


    PART VII - The End Game - Your Done
    Code:
       protected:
          SpellDesc * randalBlood;
          SpellDesc * randalThunder;
          SpellDesc * randalDecay;
    };
    This is our segment of code that protects our declarations so that cannot be called from other functions.

    Code:
    void SetupStratInstance(ScriptMgr * mgr)
    {
    	mgr->register_creature_script(COT_CAPTAIN_RANDAL, &RandalBossAI::Create);
    }
    This is an entirely new function that creates our AI. It is run once the creature is loaded and it becomes unique to that creature.


    DISCALIMER: ArcScripts had undergone some changes since I last created this guide. This guide should still be a valid resource for you to learn some basic C++ scripting. One big change may be the name of the actual library. I know one time it was once called.

    Code:
    ARCSCRIPT_FACTORY_FUNCTION(<Name Your AI>, ArcScriptBossAI);
    However upon inspection of the existing scripts it looks they have all been renamed to what I have above. So keep your eyes on the SVN log. This is not an easy guide to follow nor is it easy to learn C++. I will not make any promises to you by following this guide. I do not go over syntax in this guide or methods, arrays, tables, enumeration, etc. It is unnecessary for a basic guide. Follow this an learn from it.[/COLOR]

    Here is the full completed code. However in this code it is not renamed to MOONSCRIPT it remains as ARCSCRIPT
    http://halestorm.pastebin.com/wWTzxFpp
    Last edited by Hardball; 07-25-2010 at 05:29 PM.

    [ArcEmu] Basic C++ Boss Scripting
  2. #2
    2dgreengiant's Avatar ★ Elder ★


    Reputation
    1190
    Join Date
    Feb 2007
    Posts
    7,129
    Thanks G/R
    1/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Very nice and very detailed
    If you need me you have my skype, if you don't have my skype then you don't need me.

  3. #3
    daycro's Avatar Sergeant
    Reputation
    1
    Join Date
    Jul 2010
    Posts
    47
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This scripts can be usable for Trinity or only for Arcemu?

  4. #4
    Namor's Avatar Active Member
    Reputation
    27
    Join Date
    Jul 2008
    Posts
    311
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I love it.
    Huge help. One question though. Where can I get all of the functions/hooks to use throughout ArcEmu? In stdafx.h, right? I don't feel like checking.
    +Rep

    Editable signature, at last!

  5. #5
    Willzy's Avatar Banned
    Reputation
    22
    Join Date
    Jul 2010
    Posts
    389
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Can someone make a video of this?
    I'm not a big fan of reading.

  6. #6
    mager1794's Avatar Member
    Reputation
    356
    Join Date
    Feb 2008
    Posts
    703
    Thanks G/R
    0/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Can someone make a video of this?
    I'm not a big fan of reading.
    Then you probably shouldn't be coding? Not being offensive - but video tutorials are pointless IMO unless your trying to show how to use a piece of software. Programming is best in text.


    On topic:
    Very nice tutorial :P I like how detailed it is compared to most other tutorials. For once someone shows how to probably use ArcScripts base classes. Thanks for the guide. +rep
    Lunar Gaming - Reaching For The Stars

  7. #7
    Zibenatum's Avatar Corporal
    Reputation
    1
    Join Date
    Mar 2010
    Posts
    19
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Very nice and detailed... too bad i didn't understand a single word of it...

  8. #8
    Daimyo2704's Avatar Member
    Reputation
    37
    Join Date
    Jan 2009
    Posts
    39
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Zibenatum View Post
    Very nice and detailed... too bad i didn't understand a single word of it...
    Your English for christ' sake.

    On topic;

    Thank you for this guide but isn't #ifdef (if defined) for header files?
    Last edited by Daimyo2704; 06-30-2011 at 09:38 AM.

    thanks to P1raten

Similar Threads

  1. [HELP] Lua boss script not working-solutions?
    By WinKIller0 in forum World of Warcraft Emulator Servers
    Replies: 15
    Last Post: 03-21-2008, 08:19 AM
  2. LUA Boss Script
    By Lindoz12 in forum World of Warcraft Emulator Servers
    Replies: 4
    Last Post: 03-04-2008, 02:45 PM
  3. LUA Boss Script Help
    By neurothymia in forum World of Warcraft Emulator Servers
    Replies: 4
    Last Post: 02-05-2008, 02:57 PM
  4. Lua Boss Script Problems!!
    By blah7 in forum World of Warcraft Emulator Servers
    Replies: 14
    Last Post: 01-22-2008, 08:59 PM
  5. [Ascent] Boss Scripts help
    By n0t5ew in forum World of Warcraft Emulator Servers
    Replies: 1
    Last Post: 12-24-2007, 03:04 PM
All times are GMT -5. The time now is 11:26 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search