ArcEmu: [c++] Scripting A Basic Boss - ArcEmu

Jump to content

Toggle shoutbox Lastest Announcements

dfighter  : (07 December 2014 - 12:06 PM) Arcemu is in hibernation mode, please read http://arcemu.org/fo...showtopic=26903
dfighter  : (01 January 2013 - 05:56 PM) Arcemu wishes you all a happy new year!
Hasbro  : (12 September 2012 - 10:01 AM) Please excuse our outage from the web! Our web host had a major malfunction!
dfighter  : (01 September 2012 - 04:05 PM) Since the spam bots just don't want to stop, I've enabled admin verification when registering.
dfighter  : (23 January 2012 - 09:56 PM) Please note that from now on you will need to confirm your email on the wiki in order to edit it!
Hasbro  : (31 December 2011 - 12:50 PM) Happy New Years all!
Navid  : (26 December 2011 - 04:09 AM) Merry Christmas !!!!!! Happy holidays all :)
WAmadeus  : (24 December 2011 - 03:54 PM) Merry Christmas to all!
dfighter  : (24 December 2011 - 11:05 AM) The Arcemu team wishes y'all a Merry Christmukkah!
Hasbro  : (05 October 2011 - 12:53 PM) Looking for web designers for upcoming web related project. If you're interested in designing user interfaces contact me
dfighter  : (02 September 2011 - 03:47 PM) So who here wants vehicles in Arcemu? :P http://arcemu.org/fo...showtopic=25440
Hasbro  : (14 August 2011 - 03:25 PM) Join us on irc, grab an irc client and connect to irc.freenode.net join channel #arcemu /server irc.freenode.net:6667 /join #arcemu
jackpoz  : (03 August 2011 - 05:33 AM) to all Lua Engine (old one) users: please check http://arcemu.org/fo...showtopic=25274
Hasbro  : (20 May 2011 - 05:27 PM) Looking for people experienced with CMake configuration and setup! Contact me asap
Hasbro  : (15 May 2011 - 05:03 PM) ArcEmu is recruiting C++ programmers, contact Hasbro if interested.
paroxysm  : (03 May 2011 - 06:26 PM) Updated luabridge gossip example to describe the whole gossip creation process rather than just how to create menu. Gossip tutorial
paroxysm  : (23 April 2011 - 11:35 AM) Lua writers can refer to the Luabridge Tutorials section in the Wiki to learn how to write gossip code correctly.
Hasbro  : (20 April 2011 - 05:22 PM) Thank you for your continuous contribution of bug reports, we are working on them.
Hasbro  : (17 April 2011 - 03:20 AM) Please consider donating to support our bills. Donations can be sent using PayPal to donations@arcemu.org - Thank you for your support.
paroxysm  : (10 April 2011 - 12:43 AM) Refer to the Luabridge Tutorials section in the Wiki to learn the new syntax of luabridge.
Resize Shouts Area

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

[c++] Scripting A Basic Boss

#1 User is offline   HalestormXV 

  • The Ultimatum
  • PipPipPipPipPipPip
  • Group: Members
  • Posts: 1,031
  • Joined: 07-June 08
  • Gender:Male

Posted 25 July 2010 - 10:03 PM

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:
#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.
//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 :D

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.
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.
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.
{

All this did was open up our function.
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.
{

This digs deeper into our function making it nested so that C++ knows to run this as all part of the same code block
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

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.
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?
}

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.
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 :)

	
{
      // 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.
      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.
randalThunder->mChance = 13.0f;

This adjusts the chance this will occur to 13%.
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?

void OnCombatStop(Unit* pTarget)

Well this function will run when CombatStops. And now for the meat of the function itself.
{
   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.
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.


 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.

}
  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.

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
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.

	
{
      // 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.
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
   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.

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.

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

If you find that I have stated something invalid please feel free let me know and I will make a correction. Last time I checked everything in the guide checks out.
**Owner of the Serenade of Sorrow Funserver**
My Most Recent Video: The Book of Kidou
Posted Image
0

#2 User is offline   SgT-Fatality 

  • Member
  • Pip
  • Group: Members
  • Posts: 29
  • Joined: 03-November 08
  • Gender:Male
  • Location:Switzerland
  • Interests:Parkour !

Posted 09 August 2010 - 03:49 AM

Thanks a lot for this tutorial ! Will help a lot of guys like me ! :(
Into the Wild
Sorry for my mistakes in english
0

#3 User is offline   lesone 

  • Enthusiast
  • Group: Retired
  • Posts: 294
  • Joined: 07-June 08
  • Gender:Male
  • Location:Zpain
  • Interests:Programming--
  • Server OS:Windows

Posted 09 August 2010 - 04:48 AM

Easy script :(

Thanks for this Halestorm, really useful for newie scripters.
Posted Image
0

#4 User is offline   HalestormXV 

  • The Ultimatum
  • PipPipPipPipPipPip
  • Group: Members
  • Posts: 1,031
  • Joined: 07-June 08
  • Gender:Male

Posted 10 August 2010 - 07:10 PM

My pleasure. Not many people make C++ Tutorials anymore.

Currently going to work on a basic AI Tutorial. I have to do some searching first to see if we already have one which I think may have been deleted.
**Owner of the Serenade of Sorrow Funserver**
My Most Recent Video: The Book of Kidou
Posted Image
0

#5 User is offline   lesone 

  • Enthusiast
  • Group: Retired
  • Posts: 294
  • Joined: 07-June 08
  • Gender:Male
  • Location:Zpain
  • Interests:Programming--
  • Server OS:Windows

Posted 13 August 2010 - 03:44 AM

Well I think you should write the tutorial when parox finish new AI. Much features will change...
Posted Image
0

#6 User is offline   RaBBiT 

  • Another persian boy
  • Pip
  • Group: Members
  • Posts: 25
  • Joined: 06-August 10
  • Gender:Male
  • Location:EARTH
  • Interests:WoW and learn how to fix bugs on emus.

Posted 23 August 2010 - 03:52 AM

pardon me but isn't the boss name captain randal?what the "COT" do here : #define COT_CAPTAIN_RANDAL 48264 ,also are these underlines will appear in game?!!
also can any one write costume quest script please?
regards
Posted Image
0

#7 User is offline   Garvey 

  • is a cool guy
  • Group: Super Moderator
  • Posts: 331
  • Joined: 23-November 09
  • Gender:Male
  • Location:England
  • Server OS:Windows

Posted 27 August 2010 - 09:40 AM

I'm assuming COT is Caverns Of Time... but I don't see a Captain Randal anywhere on Wowhead, nor does the ID you have used for him seem to be a valid NPC :S
But I, being poor, have only my dreams;
I have spread my dreams under your feet;
Tread softly because you tread on my dreams.
0

#8 User is offline   jackpoz 

  • ArcEmu Lemon Priest
  • PipPipPipPipPipPipPipPip
  • Group: Developers
  • Posts: 2,153
  • Joined: 19-June 08
  • Gender:Male
  • Location:Italy
  • Server OS:Windows

Posted 28 August 2010 - 03:03 PM

little cleanup. less insults, thank you guys :P
Posted Image We develop dreams. Your dreams ;)
Posted ImagePosted Image
1

#9 User is offline   Navid 

  • Persian Prance of ArcEmu
  • Group: Super Moderator
  • Posts: 718
  • Joined: 30-June 09
  • IRC:Lurker-
  • Gender:Male
  • Location:Iran
  • Interests:PHP,C++,ArcEmu and exactly our lovely community and specially money xD
  • Server OS:Windows

Posted 28 August 2010 - 03:42 PM

Thank you Jack .

and you guys,control yourself and do your fights in other place ,you won't allow to do anything in these forums .
I'm here to check,lurk and kill you so behave or you will be lurked

Posted Image
0

#10 User is offline   Verführer 

  • Member
  • Pip
  • Group: Members
  • Posts: 17
  • Joined: 02-June 11
  • Gender:Male
  • Location:127.0.0.1
  • Server OS:Windows

Posted 13 June 2011 - 01:50 PM

Hi there, please don't laugh at me, I'm new at programming bosses.

Quote

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.


Where can I find these libraries? Are they in my VIsual C++ project? And where should I put the code in to compile it?
So schrieb ich in Stein mein ehrlos' Vermächtnis, und blutet es noch in meinem Gedächtnis,
denn hin und wieder dann und wann, schmerzt die Erinnerung daran.
0

#11 User is offline   sanctum32 

  • Occasional Poster
  • PipPip
  • Group: Members
  • Posts: 118
  • Joined: 28-November 10
  • Gender:Male

Posted 14 June 2011 - 03:16 AM

maybe useless question for some, but does someone has requests or suggestions of functions for bosses scripting? if no, do not replay answers "NO"... thanks
Posted Image
Posted Image
Sorry for my bad english
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users