[Guide][EN] How to create a CustomClass [UPDATED v8] - MMOCrawlerbots | WoW Bot Forum
Important: Please register to use the 20 minutes trial version or buy the bot!
Bot ready for World of Warcraft 5.4 Build 17538

UpdateLauncher DOWNLOAD

Wow Bot: CrawlerBot Last version: click here State: EU: working US: working

Author Topic: [Guide][EN] How to create a CustomClass [UPDATED v8]  (Read 6003 times)

October 09, 2012, 20:44:52 PM

kampfschaf Offline

  • ****
  • Posts: 349
  • Reputation: 33
  • me gusta.
    • View Profile
Guide to Creating Custom Classes


You want to create a Custom Class but don't know how to do it?
No problem!
All Custom Classes are written in a script language called LUA.
This means you need some basic LUA knowledge to create a Custom Class.
Also, the bot provides several commands that can be used.
This guide will show you how to create your own Custom Class from the beginning.
Have fun!

For a better overview the post is split into four parts:



LUA Basics
Bot Commands
Spell IDs and your first Custom Class
Clues, Tips and Tricks

Translated from riarri's german tutorial.


Edits:
added part I
added part II
added part III
added part IV
some minor formatting fixes
updated for v8 changes
added graphic model of custom class combat
« Last Edit: October 24, 2012, 18:09:55 PM by kampfschaf »
I'm back and slowly getting back into my projects

October 09, 2012, 20:56:12 PM
Reply #1

kampfschaf Offline

  • ****
  • Posts: 349
  • Reputation: 33
  • me gusta.
    • View Profile
LUA Basics

First point are variables.
Variables are used to temporarily store data. There are different types of variables for numbers, characters and conditions.
The condition type variable is called boolean. This type of variable can have the statestrue or false.
The number type variable is called - well, number.
To distinguish between those types is important, as you cannot allocate boolean values to numbers and vice versa. A number will always remain a number, a boolean will always remain a boolean.
There also is a type for strings. When allocating values to a string variable, the value must always be contained in "quotes".

Keep in mind: the variable type is defined by the value first allocated to it.

Examples:

Code: [Select]

a = 1
b = 2
c = true
result = a + b
error = a + b + c

string ="Hello!"
'result' will have the value of 3, while variable 'error' will cause an error, as you cannot add a condition to numbers

If you are familiar with other programming languages you will note that LUA variables do NOT have to be initiated before use; it's optional and can be done with the keyword 'local'.
Code: [Select]
local a=1

Functions
As functions are not necessarily needed to create a CustomClass, there will only be a short part for them.
A function allows us to repeatedly use a code snippet without having to write it over and over again. It can be used with parameters and will return a return value.

Functions are called and executed by their given name. Functions always start with the keyword function followed by the functions given name and its parameters.
Parameters are variables used by the function. When there are more one parameters, they are seperated by commas.
Functions always end by the keyword end, but it's necessary to return a value before ending a function, using the keyword return.

Examples:
Code: [Select]
function [b]function_name[/b]()
return
end

function do_add(_a, _b)
return (_a + _b)
end

result = do_add(1, 2)
the first example function will not return any values, nevertheless you have to use the return keyword. second example function will simply add the second parameter to the first one, returning '3'

Operators

Operators are important to us. They allow us to combine and compare values.
Here's an overview:
== equal
~= not equal
< greater than
> less than
<= greater or equal
>= less or equal

Logical operators can be used to combine conditions, as follows:
and - both conditions must be true.
or - either one or the other (or both of them) must be true
not - the condition will be negated.

Logical operators can be combined as well. They are a necessary pre-knowledge for conditional branching.


Conditional Constructs
This is the CustomClass base. For a conditional construct, you check wether a condition is true or false and then execute a code block.
They keyword 'end' must always be given at the branches end.
For your imagination:
Code: [Select]
[i]pseudo-code[/i]
if (condition is true) then (do some things) end

Following commands are used:
if, then, elseif, else

Here's some simple example for an if-then clause:
if the condition is true, then execute command1, else execute command2


if condition then
   command1
else
   command2
end


if condition1 is true, command1 shall be executed, if condition2 is true command2 shall be executed, in all other cases command3 shall be executed.

if condition1 then
   command1
elseif condition2 then
   command2
else
   command3
end



Conditions also can be connected by logical operators.
Example:
Code: [Select]
if (1<2) then _Log("Aww, 1 is less than 2!") else _Log("Error. Please reboot the universe!") end

if(1<2 and 0==0) then _Log("Yeah, 1 is less than 2 and 0 equals 0 !") else _Log("Error. Please check your hardware!") end

As you may have noticed, "_Log" is a function provided by the bot. We will get to that later on.

One point to remember: commands MUST HAVE a semicolon at their end if they are followed by another command, e.g.

if condition1 then
   command1_1;
   command1_2;
else
   command2_1;
   command2_2;
end
« Last Edit: October 09, 2012, 22:29:16 PM by kampfschaf »
I'm back and slowly getting back into my projects

October 09, 2012, 20:56:35 PM
Reply #2

kampfschaf Offline

  • ****
  • Posts: 349
  • Reputation: 33
  • me gusta.
    • View Profile
Bot Commands

To make a  CustomClass functional, you need some commands for sure. Luckily, the bot provides us with some of them.
--- caution: this list may be not complete! ---

CastSpellByID(spellID,target,wait)
Casts a spell. Parameters:
spellID MUST be provided by you. To get a spells ID, look at the tutorial in this forum section.
target is the target the spell is supposed to be cast on. The variable Target is used here. For an explaination refer to the GetAttacker() command. Using 0 will target your character itself.
wait is an optional parameter and says wether if the bot shall wait for the cast to be finished or not. When the parameter is not provided, true will be used by default.
Example 1: cast fireball on the current bot target and wait for the cast to be finished
Code: [Select]
CastSpellByID(133,Target);
Example2: buff yourself with Arcane Brillance
Code: [Select]
CastSpellByID(1459,0);

HasBuff(id,target)
Checks if the target has a certain buff or debuff.
Parameters:
id the ID of the buff/debuff to be checked for.
target the target that is supposed to have the buff

Example 1: buff Arcane Brilliance if our character does not have it.
Code: [Select]
if not HasBuff(1459,0) then
_Log("buffing Arcane brilliance");
CastSpellByID(1459,0);
NextAction();
end
note the logical operator not before the buffcheck. NextAction(); command will be explained later on.

Example 2: instant pyroblast proc. If your toon has the proc buff, the bot will cast pyroblast.
Code: [Select]
if HasBuff(48108,0) and IsSpellKnown(11366) then
_Log("Instant Pyro!");
CastSpellByID(11366, Target, true);
NextAction();
end

IsSpellKnown(id)
This function checks if your toon does actually know a spell by ID.
Parameter is the spell ID.
This is important as certain spells are not known to all levels and class specializations.
If your toon does know the spell, the function returns the boolean value true, elsewise it returns false.

GetAttackerCount()
Function without parameters that will return the number of npcs attacking your toon. Returns a numerical value.

GetAttacker()
Returns enemy npcs as so-called array. In this array, all enemy npc are stored. If you want to target the first npc attacking your toon, you can detect it by using GetAttacker(1).
Using the variable Target is recommended.

Example: assigning the first attacking npc to variable Target
Code: [Select]
Target = GetAttacker(1)
SetTarget(target)
explaination will follow when riarry provides me with information on how this works :p


FaceTarget(target)
Turns your toon to face the attacker. Parameter Target must have been assigned by GetAttacker(1)!

IsSpellReady(id)
Checks if a spell has finished its cooldown. Parameter is the spells spell id. Returns a boolean value.

SendKey(key)
Sends a keypress to WoW. The designated key must be written in quotes. Special keys are provided in the tips and tricks section.

_Log(msg)
Places a message in the bots log window. As the message is a string, it must be written in quotes.

Examples: write "hello world" to the log window
Code: [Select]
_Log("Hello World!");
write the number of attacking npc into the log window:
Code: [Select]
_Log("Enemy count: " GetAttackerCount());

PlayerHpPercent()
Returns the numerical value of your toons health points in percent.

PlayerManaPercent()
Returns the numerical value of your toons mana points in percent. Also works with rogues energy and warriors rage.

PlayerIsAutoAttacking()
Returns the boolean value either if your toon is performing auto attacks or not.

StartAutoAttack()
guess what, it makes your toon swing its weapons at the currently selected target.
CURRENTLY DOES NOT WORK WITH MONK CLASS!

LueDoString()
Executes LUA Code in WoW. You can access the World of Warcraft API functions
« Last Edit: October 09, 2012, 21:50:21 PM by kampfschaf »
I'm back and slowly getting back into my projects

October 09, 2012, 20:56:45 PM
Reply #3

kampfschaf Offline

  • ****
  • Posts: 349
  • Reputation: 33
  • me gusta.
    • View Profile
Researching SpellIDs

As you have noticed reading the text above, spell IDs are used virtually everywhere. Spell IDs uniquely identify a spell (hence, it's an ID :p) and are not dependant on the WoW clients language.
In conclusion, a spells ID for fireball will remain the same, regardless of the client language.

The easiest way to find out a spell's ID is to look up the spell on wowhead.com.
Simply put the name of the spell into the search bar, press enter and take a look at your adress bar. The spells ID is marked in red.

it should look something like http://www.wowhead.com/spell=133/fireball
your address bar MUST say 'spell=xxx'! otherwise, you have looked up a wrong spell.

If the spell you looked up is a buff, the buff will have the same ID as the spell.


Your first Custom Class

You now should have the basic knowledge for creating your first CustomClass.
First step is to create a new file in the [bot]/CustomClasses folder, rename it to whateveryoulike.lua and open it in a text editor like notepad.
As notepad does not support any type of syntax highlighting, we recommend using the freeware tool "notepad++". Simply google for it.

Second step is to copy the following snippet to the beginning of your file:
Code: [Select]
--settings for the distance at which your toon shall fight, see explaination below
function Settings()
FightDist = 15
PullDist = 35
end

--used for grinding module; not implemented yet but still necessary
function PullMob(MobAddr)
if IsSpellKnown(133) and IsSpellReady(133) then
_Log("pulling,using Fireball");
CastSpellByID(133 , MobAddr , true);
NextAction();
end
end

--necessary for proper routine execution
function NextAction()
if true then return end
end

--this is the part where your combat logic will go
function Fight()
Target = GetAttacker(1)

end

If you read carefully, you should be able to interpret most of this.
In the function Settings() there's two settings that can be done:
FightDist = number is the distance to the target your toon is supposed to fight from.
PullDist = number is the distance to the target npc your toon will pull a npc.
PullMob(MobAddr) function is not used at the moment, but is necessary for the custom class to work properly.


As this example custom class is going to be for a ranged dps class, we set the fight distance to 15 (yards) and the pull distance to 35 yards.
Melee classes will have to used lower values - FightDist = 5 and PullDist = 5 have proven to be viable values.

The function NextAction() does - well, nothing, but it is important to reset the execution of your CustomClass to the beginning.
IF YOU FORGET TO PUT NextAction(); INTO YOUR CONDITIONAL CONSTRUCTS, THE BOT WILL UTTERLY STOP FIGHTING AND DIE A SLOW, TERRIBLE AND PAINFUL DEATH!
It tells the bot to further execute the CustomClass after a command.

Last two things declare two variables: Target, as described in the Bot commands before, and Me.
Me is used to target your toon itself. This can be done by using 0 as well, but using Me makes your code look more readable and understandable.


That's it for preconditions! Now let's make the bot actually do something!

In the following examples, we will set up a CustomClass for mages.

Step 1:
if your mage toon does know the spell "fireball", it shall unleash its fiery power onto your current opponent.
This part has to go into the "Fight()" function between the "Target=GetAttacker(1)" and "end" part of it.
Code: [Select]
function Fight()
Target=GetAttacker(1)
if IsSpellKnown(133) then
_Log("casting fireball!");
CastSpellByID(133, Target, true);
NextAction();
end
end

Step 2:
if your toon mage does know the Inferno Blast spell and it is not on cooldown, it shall cast it onto the current target. Again, this has to go into the Fight() function.
Code: [Select]
if IsSpellKnown(2136) and IsSpellReady(2136) then
_Log("casting inferno blast!");
CastSpellByID(2136, Target, false);
NextAction();
as inferno blast is an instant cast spell, the bot shall not wait until it has finished casting inferno blast. castspellbyid-parameter#3

Step 3:
if your mage toon does know the spell "pyroblast", has the proc-buff "pyroblast!" (enabling him to cast an instant pyroblast) it shall use it on the attacking npc.
as pyroblast is an instant cast spell while your toon has the "pyroblast!" buff, the bot shall not wait for the end of the cast.
instant cast spells do not trigger the global cooldown, so we could use the orc racial spell "boiling blood" beforehand as well, if it is known and not on cooldown.

Code: [Select]
if HasBuff(48108) and IsSpellKnown(11366) then
if IsSpellKnown (20572) and IsSpellReady(20572) then CastSpellByID(20572, Me, false)
_Log("instant pyro!");
CastSpellbyID(11366, Target, false);
NextAction();
end

That's it! Your first CustomClass is ready for testing!

As an overview, the complete CustomClass in one piece:
Code: [Select]
function Settings()
FightDist = 15
PullDist = 35
end

function PullMob(MobAddr)
if IsSpellKnown(133) and IsSpellReady(133) then
_Log("pulling,using Fireball");
CastSpellByID(133 , MobAddr , true);
NextAction();
end
end

function NextAction()
if true then return end
end

function Fight()
Target = GetAttacker(1)


  if IsSpellKnown(133) and IsSpellKnown(133) then
  _Log("Cast fireball!");
  CastSpellByID(133 , Target , true);
  NextAction();
  end --end fireball

  if IsSpellKnown(2136) and IsSpellReady(2136) then
  _Log("Cast inferno blast!");
  CastSpellByID(2136 , Target , false);
  NextAction();
  end --end inferno blast


  if HasBuff(48108) and IsSpellKnown(11366) then
    if IsSpellKnown(20572) and IsSpellReady(20572) then CastSpellByID(11366 , Target , false)
  _Log("instant Pyro!");
  CastSpellByID(11366 , Target , false);
  NextAction();
  end --end instant pyro
end --end Fight()


To test your CustomClass, either
* rename it to "Mage.lua" and put it into the CustomClasses folder of your bot's installation
* give it a name you chose and change the allocation in the 'CustomClass.ini' file, e.g. "Mage=MyMage.lua".

Now place your toon next to an enemy npc and start the bot.

Important note: if you make changes to your CustomClass, you should restart the bot completely.


updated for v8 changes regarding the Fight() function
« Last Edit: October 23, 2012, 11:42:47 AM by kampfschaf »
I'm back and slowly getting back into my projects

October 09, 2012, 20:56:59 PM
Reply #4

kampfschaf Offline

  • ****
  • Posts: 349
  • Reputation: 33
  • me gusta.
    • View Profile
Tabelle: Keys


Key             Code
BACKSPACE       {BACKSPACE}, {BS}, or {BKSP}
BREAK           {BREAK}
CAPS LOCK       {CAPSLOCK}
DEL             {DELETE} or {DEL}
DOWN ARROW      {DOWN}
END             {END}
ENTER           {ENTER}
ESC             {ESC}
HELP            {HELP}
HOME            {HOME}
INS or INSERT   {INS}
LEFT ARROW      {LEFT}
NUM LOCK        {NUMLOCK}
PAGE DOWN         {PGDN}
PAGE UP         {PGUP}
PRINT SCREEN    {PRTSC}
RIGHT ARROW     {RIGHT}
SCROLL LOCK     {SCROLL}
TAB             {TAB}
UP ARROW        {UP}
F1             {F1}
...
F12             {F12}
Keypad add      {ADD}
Keypad subtract {SUBTRACT}
Keypad multiply {MULTIPLY}
Keypad divide   {DIVIDE}
@               {AT}
^               {CARET}
~               {TILDE}
{ }             {LEFTBRACE} {RIGHTBRACE}
( )             {LEFTPAREN} {RIGHTPAREN}
WINKEY          {WIN}





Simple Combat Model View:

« Last Edit: October 24, 2012, 12:03:29 PM by kampfschaf »
I'm back and slowly getting back into my projects

October 09, 2012, 21:19:14 PM
Reply #5

kampfschaf Offline

  • ****
  • Posts: 349
  • Reputation: 33
  • me gusta.
    • View Profile
Finished.

During writing this (~2 hours) my druid gained one and a half level from mining and herbing in Hellfire Peninsula, using my own CustomClass for Balance Druids to kill mobs who disturbed him. (Until some level 90 crossrealm-faggot killed him, I didn't notice it..)

Give it a try, writing your own custom class is quite rewarding.

I am using notepad++ to edit .lua files. The syntax highlighting feature comes in quite handy.
Also, looking at the preset CustomClasses and CustomClasses available in the specific user-made CustomClass forum helped me a lot when writing my balance druid CC from scrap.

If your toon does not fight as intendet, check some things first:

  • Did you include NextAction() in any command written by you? Without it, the bot will not know that it's supposed to continue executing the CustomClass
  • Spellcheck functions and bot commands used. (do all the capital letters match?)
  • check your parameters - did you mix up any?
  • is there an end in the end? :)
  • double-think your logical operators. are there any double negations mixing up the logic?


If you see any mistakes, wrong written words, phrases, errors in the code parts - do not hesitate to PM me, I will fix it ASAP.
« Last Edit: October 09, 2012, 22:33:40 PM by kampfschaf »
I'm back and slowly getting back into my projects

October 09, 2012, 21:34:47 PM
Reply #6

telcy Offline

  • *
  • *
  • Posts: 1695
  • Reputation: 182
    • View Profile
You can use "conditional constructs" :)

October 12, 2012, 03:26:10 AM
Reply #7

webster259 Offline

  • *
  • Posts: 21
  • Reputation: 0
    • View Profile
I'm modifying the custom class for warlock to work with my mining.  I was wondering how you would be able to call a pet if there was not already one present.  Thanks and I really like the way the bot functions.  It's great work.

October 12, 2012, 03:31:39 AM
Reply #8

riarry Offline

  • *
  • Posts: 1024
  • Reputation: 113
    • View Profile
The Guide is outdated. There will be a new version.
Great Multi-Area herb&Mine Profile: SuperFarm 2.0
Awesome Fishing 1-600 with Coinmaster Achievment
--- NO SUPPORT VIA PM ---

October 12, 2012, 06:38:23 AM
Reply #9

kampfschaf Offline

  • ****
  • Posts: 349
  • Reputation: 33
  • me gusta.
    • View Profile
I'm modifying the custom class for warlock to work with my mining.  I was wondering how you would be able to call a pet if there was not already one present.  Thanks and I really like the way the bot functions.  It's great work.

Do all pets give you a certain buff when they are summoned?
I'm back and slowly getting back into my projects

October 12, 2012, 23:17:08 PM
Reply #10

webster259 Offline

  • *
  • Posts: 21
  • Reputation: 0
    • View Profile
No they don't.  I had thought of that as well.  On the note of buffs.  I cannot get my lock to self buff himself with Dark Intent.  I have tried two different versions of code and one prevents my warlock from doing anything in combat at all and the other is just ignored

October 24, 2012, 00:55:12 AM
Reply #11

saubeere Offline

  • **
  • Posts: 64
  • Reputation: 8
    • View Profile
In which order do i put the spells?
Selfbuff->Cast(if ready) -> Cast (Gap filler) -> Procc dependant Casts
?
If i put Procc dependant casts first it prints out
[00:36:36] - UnitBuff: 0
[00:36:36] - UnitBuff: 0
[00:36:36] - UnitBuff: 1
and then proceeds with the fourth spell .

Thx Saub.

October 24, 2012, 09:47:00 AM
Reply #12

kampfschaf Offline

  • ****
  • Posts: 349
  • Reputation: 33
  • me gusta.
    • View Profile
I added a simple combat model graphic to the Hints and Tips part.

Personally I would keep the following order:

  • Heal
  • Combat Stance (e.g. shapeshift for druids, battle stance for warriors and so on)
  • Selfbuffs
  • Procs / own buff dependant Spells
  • Fillers

I added a simple graphic overview of how the bot works down a custom class.
Should be clear that you put fillers to the end.
« Last Edit: October 24, 2012, 12:04:18 PM by kampfschaf »
I'm back and slowly getting back into my projects

October 24, 2012, 12:08:41 PM
Reply #13

kampfschaf Offline

  • ****
  • Posts: 349
  • Reputation: 33
  • me gusta.
    • View Profile
No they don't.  I had thought of that as well.  On the note of buffs.  I cannot get my lock to self buff himself with Dark Intent.  I have tried two different versions of code and one prevents my warlock from doing anything in combat at all and the other is just ignored

I'm going to query the developers for a pet check. Will be useful for Hunters as well.
I'm back and slowly getting back into my projects

October 24, 2012, 23:53:57 PM
Reply #14

webster259 Offline

  • *
  • Posts: 21
  • Reputation: 0
    • View Profile
Is there a way to allow a player to channel a spell?  I want my warlock to be able to channel Drain Soul for the duration but it just keeps casting and recasting after 2-3 seconds of channeling.

 

* Recent Topics

* Useful Stuff