Blue Eye Logo

Blue Eye Macro

Automation is freedom
It is currently Thu Nov 21, 2024 8:40 pm

All times are UTC




Post new topic Reply to topic  [ 92 posts ]  Go to page 1, 2, 3, 4, 5 ... 10  Next
Author Message
 Post subject: Perfect Bot v1.3
Thanked: 7 time(s)  Unread post Posted: Mon Jan 24, 2011 11:10 pm 
Partner / Developer
Partner / Developer
User avatar



Joined: Mon Jan 18, 2010 11:51 am
Posts: 4525
Been thanked: 1346 time(s)
Has thanked: 133 time(s)
Contribution Points: 33209
Here is my first attempt at a full blown game bot.

The bot is for the game Perfect World, which is a free MMORPG with more than 50 million players world wide.

The bot will Hunt, track down monsters, kill them, automatically pick up drops and cash.
It will keep your character safe by healing, activating buffs, meditating to regen HP / MP and even if you should die, (which I didn't during my 4 days non-stop testing) the bot will automatically revive, heal it self, and fly back to the desired hunting ground, and continue where it left off.

If your HP or MP gets low during a fight, it will automatically use HP/MP potions, if you set the tress-hold percentages higher than those for meditation, it will use potions instead of meditating, to save time, level faster, but you will need to spent more money on potions.

If a monster attacks you while you are meditating, meditation will immediately be aborted, and the bot will start defending itself.

Also the bot will automatically travel from place to place as it levels up, to ensure you are always leveling at the best spot.

The different coordinates are stored inside a txt file which contains the leveling path.

For my testing I created the following leveling path file:
Code:
Syntax: :Level: X-Coordinate Y-Coordinate Z-Coodinate(height) Range

Level = From which level should the provided coordinates apply.
X-Coordinate = The X coordinate of the desired hunting ground.
Y-Coordinate = The Y coordinate of the desired hunting ground.
Z-Coordinate = The height at which your character should fly at, when flying towards this location.
Range = How far away from these coordinates should your character be allowed to run before returning to the desired location.

Example:
:1: 150 150 25 5
:3: 250 250 35 5
This will make any level 1 character remain within a range of 5 of the coordinates 150/150 and will remain a flying height of 25 while flying, once reaching level 2, your character will remain at the level 1 hunting grounds since no path for level 2's was provided.
As soon as your character reaches level 3, it will automatically fly to 250/250 in a flying height of 35, and once there, remain within a range of 5

Enter your leveling paths below this line (do not remove this line).
--------------------------------------------------------------------
:1: 356 452 28 5
:3: 352 439 28 5
:7: 390 479 30 6
:9: 350 322 32 6
:11: 316 543 58 8
:18: 389 566 60 6
:21: 392 592 60 6
:26: 455 630 60 6

You can download my leveling path file here:
Attachment:
Perfect World Path.txt [1.22 KiB]
Downloaded 833 times


The macro will load this txt file in to memory, and use it to determine where to go hunting at which levels.

Everything the macro needs to know while running is read directly from memory, meaning it does not matter at what resolution your game is running.
All inputs to the game, is done by manipulating memory / sending messages directly to the window, this means the window does not have to be focused while it is playing, you can use your computer for other stuff while the bot plays the game.

However, Do not minimize the game! If you do - the dialog to fly to new coordinates will appear in the wrong spot, and instead of entering the coordinates in the coordinates window, you will be shouting them out loud in the chat, so make sure the game is not minimized, which does not mean it has to be visible on the screen, you can drag it to the side, place another window on top of it etc.


To use the macro, all you need to do is load it in to Blue Eye Macro, Right click the macro and select Edit. Now specify your key bindings and available buffs in the lower left corner (variables) if your character does not have a healing spell, or any of the 5 available buffs, just leave the keys empty, and Blue Eye will automatically ignore the spells that require these keys.

Also make sure to go through the settings in the top of the macro, to specify the file path to your leveling path file, as well as other general settings for the macro.

Before starting the macro for the first time, make sure to Manually open the "Coordinates Assistant" at move the window to the top left corner of the screen, you can then close the dialog again, and start the macro.
The location of the dialog will automatically be remembered by the game, and wont change when you re-launch the game, so you will only need to do this once.
Attachment:
coordinatesAssistant.png
coordinatesAssistant.png [ 767.88 KiB | Viewed 10658 times ]



Required variables are:
  • LevelPath (the location of your leveling path txt file, e.g. c:\Perfect World leveling path.txt)
  • AttackKey (the keyboard shortcut for attacking, e.g. {<f2>})
  • LootKey (the keyboard shortcut for picking up loot, e.g. {<f4>})
  • MeditateKey (the keyboard shortcut for meditation, e.g. {<f5>})

All the memory addresses have been found using Cheat Engine, and all of them are saved as variables in the top of the macro, this makes it easier to "upgrade" the macro to use new memory addresses, in case they change with a future update of the game client.

The latest version of the macro can be downloaded directly from the repository.

Here is the complete (and massive) code for it
Code:
Code:
 begin
     //
     // For help using/configuring this bot, please refer to http://www.blueeye-macro.com/viewtopic.php?f=269&t=885
     //
     // Note: Make sure to ALWAYS set the location of the "Coordinates Assistant" to the top left corner before starting the macro!
     // The location of the dialog will be remembered the next time you start the game, so you just need to do this once
     //
     // USER CONFIGURATION START
     //
     // Key bindings: Set your key bindings in the lower left corner variables
     // Example: To set a keybinding to the F1-Key, enter: {<F1>}
     // Example: To set a keybinding to the numeric 1-key, enter: 1
     //
     // The filepath to your leveling paths file e.g. c:\leveling path.txt (See/share examples of this file at http://www.blueeye-macro.com)
     Variable.Set("LevelPath", "c:\Perfect World Path.txt")
     // If you die this many times, the macro will automatically abort
     Variable.Set("StopMacroIfDeadTimes", "3")
     // Only run the macro for the following amount of minutes (How long does your armor and weapon durability last? (if you care))
     Variable.Set("WarpToTownAndStopMacroAfterMinutes", "120")
     // How often (in %) should a a single pre-attack spell be cast, before finishing off the monster with your primary attack (Good for a slowing spell)
     Variable.Set("PreAttackPercentage", "90")
     // How often (in %) should a human-like pause be inserted between monsters? (Makes you appear less bot-like)
     Variable.Set("HumanPausePercentage", "5")
     // At which percentage of your full HP / MP should meditation begin (Set HP to 0 if you dont want to use meditation for HP regen (if you have healing spell))
     Variable.Set("MeditateAtHPPercentage", "40")
     Variable.Set("MeditateAtMPPercentage", "30")
     // Between each monster, use healing spell if your HP gets bellow this percentage
     Variable.Set("UseHealingSpellAtHPPercentage", "85")
     // If you have a healing spell, how long does it take to cast? (in ms. 1000 ms = 1 sec. 1500 ms = 1,5 sec etc.)
     Variable.Set("HealingSpellCastTime", "1000")
     // During fights, at which HP / MP percentage should potions be used
     Variable.Set("UseHealthPotionAtHPPercentage", "35")
     Variable.Set("UseManaPotionAtMPPercentage", "70")
     //
     // USER CONFIGURATION END
     //
     // Static configuration
     Variable.Set("processName", "elementclient")
     Variable.Set("windowName", "Element Client")
     // Store memory addresses / window name in variables, to make it easier to update if the memory addresses change with a game update
     Variable.Set("maxHPMemoryAddress", "elementclient.exe+65BFCC,20,4b4")
     Variable.Set("maxMPMemoryAddress", "elementclient.exe+65BFCC,20,4b8")
     Variable.Set("currentHPMemoryAddress", "elementclient.exe+65BFCC,20,474")
     Variable.Set("currentMPMemoryAddress", "elementclient.exe+65BFCC,20,478")
     Variable.Set("currentLevelMemoryAddress", "elementclient.exe+65BFCC,20,46c")
     Variable.Set("currentLocationXMemoryAddress", "elementclient.exe+65bfcc,20,384,3c")
     Variable.Set("currentLocationYMemoryAddress", "elementclient.exe+65bfcc,20,384,44")
     Variable.Set("currentLocationHeightMemoryAddress", "elementclient.exe+65bfcc,20,384,40")
     Variable.Set("hasTargetMemoryAddress", "elementclient.exe+65BFCC,20,1088,38")
     Variable.Set("topMostDialogLocationXMemoryAddress", "elementclient.exe+0065BFCC,4,8,70,98")
     Variable.Set("topMostDialogLocationYMemoryAddress", "elementclient.exe+0065BFCC,4,8,70,9c")
     Variable.Set("deathDialogLocationXMemoryAddress", "elementclient.exe+0065BFCC,4,8,4a0,98")
     Variable.Set("deathDialogLocationYMemoryAddress", "elementclient.exe+0065BFCC,4,8,4a0,9c")
     Variable.Set("reachDestinationCheckBoxMemoryAddress", "elementclient.exe+65BFE4,270,2bc,1f0,119")
     Variable.Set("windowActiveMemoryAddress", "elementclient.exe+65B90C,48c")
     // Adjust variables
     Variable.Set("deathCount", "0")
     Variable.Set("killCount", "0")
     Variable.Add (Math)("HealingSpellCastTime", "750")
     // Convert minutes into milliseconds
     Variable.Multiply (Math)("WarpToTownAndStopMacroAfterMinutes", "60000")
     // Make sure the required key bindings have been set
     Function.Execute("Check keybindings")
     // Make sure the window doesnt freeze when it looses focus (to support playing with the game minimized and without focus)
     Memory.Freeze value("{processName}", "{windowActiveMemoryAddress}", "4", "1")
     // Make sure to reset targets when starting the bot by pressing escape
     Window.Send keys("{windowName}", "yes", "0", "{<esc>}")
     Macro.Pause("750")
     if  Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "1")
          begin
               Window.Display message box("Please make sure you dont have an npc targeted when starting the Macro! the Macro will now exit", "no")
               Macro.Abort()
          end
     // Activate our buffs before starting, and start the stop watches, keeping track of the buff durations
     Function.Execute("Init buffs")
     begin loop()
          Function.Execute("Output status")
          Function.Execute("Use potions")
          Function.Execute("Ensure buffs are still active")
          Function.Execute("Release corpse, heal and fly back if dead")
          Function.Execute with timeout("Ensure within specified hunting ground", "300000")
          Function.Execute("Output status")
          Function.Execute("Release corpse, heal and fly back if dead")
          Function.Execute("Perform healing if required")
          Function.Execute("Output status")
          Function.Execute with timeout("Get target", "2500")
          if  Function.Did not timeout("Get target")
               begin
                    Function.Execute("Release corpse, heal and fly back if dead")
                    Function.Execute with timeout("Kill target", "60000")
                    Function.Execute("Perform healing if required")
                    if  Function.Did timeout("Kill target")
                         begin
                              // If the target does not die within 1 minute, the monster probably cant get to us, so it cant die, select a new target
                              Window.Send keys("{windowName}", "yes", "0", "{targetKey}")
                              Macro.Pause("250")
                              Function.Execute with timeout("Kill target", "60000")
                              Function.Execute("Perform healing if required")
                         end
               end
          Function.Execute with timeout("Get loot", "10000")
          Function.Execute("Output status")
          Function.Execute("Release corpse, heal and fly back if dead")
          Function.Execute("Output status")
          Function.Execute("Meditate if required")
          Function.Execute("Simulate human pause")
          if  Macro.Execution time has exceeded("{WarpToTownAndStopMacroAfterMinutes}")
               begin
                    Window.Send keys("{windowName}", "yes", "0", "{<esc>}")
                    Macro.Pause("1000")
                    Window.Send keys("{windowName}", "yes", "0", "{TownPortalKey}")
                    Macro.Pause("500")
                    Macro.Abort()
               end
     end
 end

function("Simulate human pause")
     if  Randomizer.Maybe("{HumanPausePercentage}")
          begin
               Variable.Set random number("pauseTimes", "5", "15")
               begin loop("{pauseTimes}")
                    Macro.Pause("500")
                    // If we are attacked, abort human pause to be able to defend ourselves first
                    if  Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "1")
                         begin
                              Function.Abort()
                         end
               end
          end
function

function("Use potions")
     if  Variable.Is not empty("HealthPotionKey")
          begin
               Function.Execute("Calculate current HP percentage")
               if  Variable.Is less than (Math)("currentHPpercentage", "{UseHealthPotionAtHPPercentage}")
                    begin
                         Window.Send keys("{windowName}", "yes", "0", "{HealthPotionKey}")
                    end
          end
     if  Variable.Is not empty("ManaPotionKey")
          begin
               Function.Execute("Calculate current MP percentage")
               if  Variable.Is less than (Math)("currentMPpercentage", "{UseManaPotionAtMPPercentage}")
                    begin
                         Window.Send keys("{windowName}", "yes", "0", "{ManaPotionKey}")
                    end
          end
function

function("Check keybindings")
     if  Variable.Is empty("AttackKey")
          or
          Variable.Is empty("LootKey")
          or
          Variable.Is empty("MeditateKey")
          or
          Variable.Is empty("TownPortalKey")
          or
          Variable.Is empty("TargetKey")
          begin
               Window.Display message box("Please 'Right click' --> 'Edit Macro' and make sure to specify key bindings for at least: Target, Attack, Loot, Town portal and Meditation", "no")
               Macro.Abort()
          end
function

function("Init buffs")
     if  Variable.Is not empty("Buff1Key")
          and
          Variable.Is not empty("Buff1Duration")
          begin
               Window.Send keys("{windowName}", "yes", "0", "{Buff1Key}")
               if  Variable.Is less than (Math)("Buff1Duration", "1000")
                    begin
                         // Convert the duration from minutes to milliseconds
                         Variable.Evaluate (Math)("({Buff1Duration}*60)*1000", "Buff1Duration")
                    end
               Macro.Restart stopwatch("Buff1Watch")
               Macro.Pause("2000")
          end
     if  Variable.Is not empty("Buff2Key")
          and
          Variable.Is not empty("Buff2Duration")
          begin
               Window.Send keys("{windowName}", "yes", "0", "{Buff2Key}")
               if  Variable.Is less than (Math)("Buff2Duration", "1000")
                    begin
                         Variable.Evaluate (Math)("({Buff2Duration}*60)*1000", "Buff2Duration")
                    end
               Macro.Restart stopwatch("Buff2Watch")
               Macro.Pause("2000")
          end
     if  Variable.Is not empty("Buff3Key")
          and
          Variable.Is not empty("Buff3Duration")
          begin
               Window.Send keys("{windowName}", "yes", "0", "{Buff3Key}")
               if  Variable.Is less than (Math)("Buff3Duration", "1000")
                    begin
                         Variable.Evaluate (Math)("({Buff3Duration}*60)*1000", "Buff3Duration")
                    end
               Macro.Restart stopwatch("Buff3Watch")
               Macro.Pause("2000")
          end
     if  Variable.Is not empty("Buff4Key")
          and
          Variable.Is not empty("Buff4Duration")
          begin
               Window.Send keys("{windowName}", "yes", "0", "{Buff4Key}")
               if  Variable.Is less than (Math)("Buff4Duration", "1000")
                    begin
                         Variable.Evaluate (Math)("({Buff4Duration}*60)*1000", "Buff4Duration")
                    end
               Macro.Restart stopwatch("Buff4Watch")
               Macro.Pause("2000")
          end
     if  Variable.Is not empty("Buff5Key")
          and
          Variable.Is not empty("Buff5Duration")
          begin
               Window.Send keys("{windowName}", "yes", "0", "{Buff5Key}")
               if  Variable.Is less than (Math)("Buff5Duration", "1000")
                    begin
                         Variable.Evaluate (Math)("({Buff5Duration}*60)*1000", "Buff5Duration")
                    end
               Macro.Restart stopwatch("Buff5Watch")
               Macro.Pause("2000")
          end
function

function("Ensure buffs are still active")
     // If we are attacked, abort to be able to defend ourselves first
     if  Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "1")
          begin
               Function.Abort()
          end
     if  Macro.Stopwatch exists("Buff1Watch")
          begin
               Macro.Read stopwatch("Buff1Watch", "buff1Time")
               if  Variable.Is greater than (Math)("buff1Time", "{Buff1Duration}")
                    begin
                         Window.Send keys("{windowName}", "yes", "0", "{Buff1Key}")
                         Macro.Restart stopwatch("Buff1Watch")
                         Macro.Pause("2000")
                    end
          end
     if  Macro.Stopwatch exists("Buff2Watch")
          begin
               Macro.Read stopwatch("Buff2Watch", "buff2Time")
               if  Variable.Is greater than (Math)("buff2Time", "{Buff2Duration}")
                    begin
                         Window.Send keys("{windowName}", "yes", "0", "{Buff2Key}")
                         Macro.Restart stopwatch("Buff2Watch")
                         Macro.Pause("2000")
                    end
          end
     if  Macro.Stopwatch exists("Buff3Watch")
          begin
               Macro.Read stopwatch("Buff3Watch", "buff3Time")
               if  Variable.Is greater than (Math)("buff3Time", "{Buff3Duration}")
                    begin
                         Window.Send keys("{windowName}", "yes", "0", "{Buff3Key}")
                         Macro.Restart stopwatch("Buff3Watch")
                         Macro.Pause("2000")
                    end
          end
     if  Macro.Stopwatch exists("Buff4Watch")
          begin
               Macro.Read stopwatch("Buff4Watch", "buff4Time")
               if  Variable.Is greater than (Math)("buff4Time", "{Buff4Duration}")
                    begin
                         Window.Send keys("{windowName}", "yes", "0", "{Buff4Key}")
                         Macro.Restart stopwatch("Buff4Watch")
                         Macro.Pause("2000")
                    end
          end
     if  Macro.Stopwatch exists("Buff5Watch")
          begin
               Macro.Read stopwatch("Buff5Watch", "buff5Time")
               if  Variable.Is greater than (Math)("buff5Time", "{Buff5Duration}")
                    begin
                         Window.Send keys("{windowName}", "yes", "0", "{Buff5Key}")
                         Macro.Restart stopwatch("Buff5Watch")
                         Macro.Pause("2000")
                    end
          end
function

function("Output status")
     begin
          Memory.Get value("{processName}", "{currentLevelMemoryAddress}", "4", "outputLvl")
          Memory.Get value("{processName}", "{currentHPMemoryAddress}", "4", "outputHP")
          Memory.Get value("{processName}", "{currentMPMemoryAddress}", "4", "outputMP")
          Variable.Evaluate (Text)("Level: {outputLvl}, Kills: {killCount}, Deaths: {deathCount}, HP: {outputHP}, MP: {outputMP}", "statusOutput")
          Macro.Report progress("{statusOutput}")
     end
function

function("Calculate current HP percentage")
     begin
          Memory.Get value("{processName}", "{currentHPMemoryAddress}", "4", "currentHP")
          Memory.Get value("{processName}", "{maxHPMemoryAddress}", "4", "maxHP")
          Variable.Evaluate (Math)("({currentHP}/{maxHP})*100", "currentHPpercentage")
     end
function

function("Calculate current MP percentage")
     begin
          Memory.Get value("{processName}", "{currentMPMemoryAddress}", "4", "currentMP")
          Memory.Get value("{processName}", "{maxMPMemoryAddress}", "4", "maxMP")
          Variable.Evaluate (Math)("({currentMP}/{maxMP})*100", "currentMPpercentage")
     end
function

function("Meditate if required")
     // If we are attacked, abort to be able to defend ourselves
     if  Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "1")
          begin
               Function.Abort()
          end
     begin
          Function.Execute("Calculate current HP percentage")
          Function.Execute("Calculate current MP percentage")
     end
     if  Variable.Is less than (Math)("currentHPpercentage", "{MeditateAtHPPercentage}")
          or
          Variable.Is less than (Math)("currentMPpercentage", "{MeditateAtMPPercentage}")
          begin
               Window.Send keys("{windowName}", "yes", "0", "{MeditateKey}")
               begin loop()
                    Macro.Pause("750")
                    Function.Execute("Output status")
                    Memory.Get value("{processName}", "{currentHPMemoryAddress}", "4", "hpCheckCurrent")
                    // If we are attacked, or at 100% HP / MP then abort meditation
                    if  Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "1")
                         or
                         Memory.Value is("{processName}", "{currentHPMemoryAddress}", "4", "{maxHP}")
                         and
                         Memory.Value is("{processName}", "{currentMPMemoryAddress}", "4", "{maxMP}")
                         begin
                              Window.Send keys("{windowName}", "yes", "0", "{MeditateKey}")
                              Macro.Pause("1000")
                              Window.Send keys("{windowName}", "yes", "0", "{LootKey}")
                              Function.Abort()
                         end
               end
          end
function

function("Perform healing if required")
     // If we specified a key for the spell "Iron heart" (or another healing spell)
     if  Variable.Is not empty("HealingKey")
          begin
               Function.Execute("Calculate current HP percentage")
               if  Variable.Is less than (Math)("currentHPpercentage", "{UseHealingSpellAtHPPercentage}")
                    begin
                         Macro.Pause("250")
                         Window.Send keys("{windowName}", "yes", "0", "{HealingKey}")
                         Macro.Pause("{HealingSpellCastTime}")
                    end
          end
function

function("Release corpse, heal and fly back if dead")
     if  Memory.Value is("{processName}", "{currentHPMemoryAddress}", "4", "0")
          begin
               Variable.Increment (Math)("deathCount")
               // Move the "You are dead" box to coordinate 0,0
               Memory.Set value("{processName}", "{deathDialogLocationXMemoryAddress}", "4", "0")
               Memory.Set value("{processName}", "{deathDialogLocationYMemoryAddress}", "4", "0")
               Macro.Pause("1000")
               // Click "Release corpse"
               Window.Send mouse click("{windowName}", "yes", "0", "125", "71", "left")
               Macro.Pause("10000")
               if  Variable.Is equal to("deathCount", "{StopMacroIfDeadTimes}")
                    begin
                         Variable.Evaluate (Text)("The bot was aborted because you died {deathCount} times", "output")
                         Window.Display message box("{output}", "no")
                         Macro.Abort()
                    end
               Function.Execute("Use potions")
               Function.Execute("Meditate if required")
               Macro.Pause("1000")
               Function.Execute("Init buffs")
               Function.Execute with timeout("Ensure within specified hunting ground", "300000")
          end
function

function("Get target")
     begin loop()
          if  Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "1")
               begin
                    // If we already have a target, abort
                    Function.Abort()
               end
          Window.Send keys("{windowName}", "yes", "0", "{TargetKey}")
          Macro.Pause("250")
          Function.Execute("Use potions")
     end
function

function("Get loot")
     begin
          Function.Execute("Get player location")
          Variable.Evaluate (Text)("{x}{y}{z}", "locationHash")
          Macro.Pause("200")
          // If we are being attacked, dont waste any time picking up drops
          if  Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "1")
               begin
                    Function.Abort()
               end
          begin loop()
               begin loop("8")
                    Window.Send keys("{windowName}", "yes", "0", "{LootKey}")
                    Macro.Pause("200")
               end
               Function.Execute("Use potions")
               Function.Execute("Get player location")
               Variable.Evaluate (Text)("{x}{y}{z}", "newLocationHash")
               if  Variable.Is equal to("locationHash", "{newLocationHash}")
                    or
                    Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "1")
                    begin
                         // Abort if we finished picking up drops (stopped moving), or if we are under attack.
                         Function.Abort()
                    end
               Variable.Set("locationHash", "{newLocationHash}")
          end
     end
function

function("Kill target")
     if  Variable.Is not empty("PreAttackKey")
          and
          Randomizer.Maybe("{PreAttackPercentage}")
          begin
               Function.Execute("Get player location")
               Variable.Evaluate (Text)("{x}{y}{z}", "locationHash")
               Window.Send keys("{windowName}", "yes", "0", "{PreAttackKey}")
               Macro.Pause("750")
               Function.Execute("Get player location")
               Variable.Evaluate (Text)("{x}{y}{z}", "newLocationHash")
               if  Variable.Is not equal to("locationHash", "{newLocationHash}")
                    begin loop("7")
                         // If we had to move to get close enough to our target, wait a bit while casting the PreAttack spell
                         Variable.Set("locationHash", "{newLocationHash}")
                         Macro.Pause("750")
                         Function.Execute("Get player location")
                         Variable.Evaluate (Text)("{x}{y}{z}", "newLocationHash")
                         if  Variable.Is equal to("locationHash", "{newLocationHash}")
                              begin
                                   Macro.Break from loop()
                              end
                    end
          end
     begin loop()
          Window.Send keys("{windowName}", "yes", "0", "{AttackKey}")
          Macro.Pause("40")
          Function.Execute("Use potions")
          Macro.Pause("40")
          // If our target is dead or we died ourselves, stop attacking
          if  Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "0")
               or
               Memory.Value is("{processName}", "{currentHPMemoryAddress}", "4", "0")
               begin
                    Variable.Increment (Math)("killCount")
                    // Quickly press esc to avoid wasting MP on a monster that is already dead.
                    Window.Send keys("{windowName}", "yes", "0", "{<esc>}")
                    Macro.Pause("100")
                    Function.Abort()
               end
     end
function

function("Ensure within specified hunting ground")
     // If we are attacked, abort to be able to defend ourselves before flying anywhere
     if  Memory.Value is("{processName}", "{hasTargetMemoryAddress}", "1", "1")
          begin
               Function.Abort()
          end
     begin
          Function.Execute("Get desired location")
          Function.Execute("Get player location")
          Variable.Evaluate (Math)("{x} - {desiredX}", "rangeX")
          if  Variable.Is less than (Math)("rangeX", "0")
               begin
                    Variable.Multiply (Math)("rangeX", "-1")
               end
          Variable.Evaluate (Math)("{y} - {desiredY}", "rangeY")
          if  Variable.Is less than (Math)("rangeY", "0")
               begin
                    Variable.Multiply (Math)("rangeY", "-1")
               end
          if  Variable.Is less than (Math)("rangeX", "{desiredRange}")
               and
               Variable.Is less than (Math)("rangeY", "{desiredRange}")
               begin
                    // If we are already within the specified range of our prefered hunting ground, dont go anywhere
                    Function.Abort()
               end
          Variable.Evaluate (Text)("{desiredX} {desiredY}", "location")
          Window.Get size("{windowName}", "yes", "width", "unused")
          Variable.Subtract (Math)("width", "35")
          // If we are able to fly, activate wings, to help avoiding getting stuck
          if  Variable.Is not empty("FlyKey")
               begin
                    Window.Send keys("{windowName}", "yes", "0", "{FlyKey}")
               end
          Macro.Pause("50")
          // Open the Path dialog
          Window.Send mouse click("{windowName}", "yes", "0", "{width}", "110", "left")
          Macro.Pause("750")
          Window.Send mouse click("{windowName}", "yes", "0", "293", "381", "left")
          Macro.Pause("250")
          Window.Send keys("{windowName}", "yes", "0", "{<enter>}")
          Macro.Pause("250")
          Window.Send mouse click("{windowName}", "yes", "0", "270", "40", "left")
          Macro.Pause("250")
          begin loop("25")
               // Delete whatever has already been entered
               Window.Send keys("{windowName}", "yes", "0", "{<backspace>}")
               Macro.Pause("5")
          end
          Window.Send keys("{windowName}", "yes", "0", "{location}")
          Macro.Pause("50")
          Window.Send keys("{windowName}", "yes", "0", "{<enter>}")
          Macro.Pause("200")
          Window.Send keys("{windowName}", "yes", "0", "{location}")
          Macro.Pause("50")
          Window.Send keys("{windowName}", "yes", "0", "{<enter>}")
          Macro.Pause("200")
          Window.Send mouse double click("{windowName}", "yes", "0", "250", "60", "left")
          Macro.Pause("250")
          // Make sure the Auto-Path-Height box is located at coordinate 0,0
          Memory.Set value("{processName}", "{topMostDialogLocationXMemoryAddress}", "4", "0")
          Memory.Set value("{processName}", "{topMostDialogLocationYMemoryAddress}", "4", "0")
          // Enable "Reach Destination"
          Memory.Set value("{processName}", "{reachDestinationCheckBoxMemoryAddress}", "1", "1")
          Macro.Pause("25")
          Window.Send mouse click("{windowName}", "yes", "0", "145", "43", "left")
          Macro.Pause("150")
          begin loop("15")
               // Delete whatever "Height" previously entered
               Window.Send keys("{windowName}", "yes", "0", "{<backspace>}")
               Macro.Pause("5")
          end
          Window.Send keys("{windowName}", "yes", "0", "{desiredHeight}")
          Macro.Pause("50")
          Window.Send mouse click("{windowName}", "yes", "0", "108", "106", "left")
          Variable.Set("locationHash", "0")
          begin loop()
               // Wait for our character to stop moving, meaning we reached our destination
               Macro.Pause("2500")
               Function.Execute("Get player location")
               Variable.Evaluate (Text)("{x}{y}{z}", "newLocationHash")
               if  Variable.Is equal to("locationHash", "{newLocationHash}")
                    begin
                         // if the location "hash" is unchanged, meaning we reached our destination, close the Path window
                         Window.Send mouse click("{windowName}", "yes", "0", "108", "106", "left")
                         Macro.Pause("250")
                         Window.Send keys("{windowName}", "yes", "0", "{<esc>}")
                         Macro.Pause("250")
                         Function.Abort()
                    end
               Variable.Set("locationHash", "{newLocationHash}")
          end
     end
function

function("Get desired location")
     // If this is the first run, we will load the hunting ground paths in to memory
     if  Variable.Does not exist("paths")
          begin
               File.Read text("{LevelPath}", "paths")
               if  Variable.Does not exist("paths")
                    begin
                         Variable.Evaluate (Text)("A level path file was not found at {LevelPath}, the macro will now quit (for help please visit http://www.blueeye-macro.com)", "errorOutput")
                         Window.Display message box("{errorOutput}", "no")
                         Macro.Abort()
                    end
               Variable.Extract partial text (Regex)("paths", "(?s)-{25,}(.*)", "1", "paths")
               if  Variable.Is not match (Regex)("paths", ":1:(?: [0-9]+){4}")
                    begin
                         Variable.Evaluate (Text)("A level path file was found, but it does not contain a leveling path for at least level 1. The macro will now quit, for help please visit http://www.blueeye-macro.com)", "errorOutput")
                         Window.Display message box("{errorOutput}", "no")
                         Macro.Abort()
                    end
          end
     begin
          // Find the area coordinate that applies to our current level (or go with the nearest level path lower than our current level)
          Memory.Get value("{processName}", "{currentLevelMemoryAddress}", "4", "lvl")
          begin loop()
               Variable.Evaluate (Text)(":{lvl}: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)", "pattern")
               if  Variable.Is match (Regex)("paths", "{pattern}")
                    begin
                         Macro.Break from loop()
                    end
               Variable.Decrement (Math)("lvl")
               if  Variable.Is less than (Math)("lvl", "0")
                    begin
                         Window.Display message box("Failed determining the leveling path for your level", "no")
                         Macro.Abort()
                    end
          end
          Variable.Extract partial text (Regex)("paths", "{pattern}", "1", "desiredX")
          Variable.Extract partial text (Regex)("paths", "{pattern}", "2", "desiredY")
          Variable.Extract partial text (Regex)("paths", "{pattern}", "3", "desiredHeight")
          Variable.Extract partial text (Regex)("paths", "{pattern}", "4", "desiredRange")
     end
function

function("Get player location")
     begin
          // Get our current location, with all decimals
          Memory.Get value("{processName}", "{currentLocationXMemoryAddress}", "float", "x")
          Variable.Evaluate (Math)("401+({x}/10)", "x")
          Memory.Get value("{processName}", "{currentLocationYMemoryAddress}", "float", "y")
          Variable.Evaluate (Math)("551+({y}/10)", "y")
          Memory.Get value("{processName}", "{currentLocationHeightMemoryAddress}", "float", "z")
          Variable.Divide (Math)("z", "10")
     end
function


Download:
Keep in mind the macro requires the predefined variables located in the lower left corner of the designer, so I suggest downloading the macro from the repository, instead of copy pasting the above code.

I would very much appreciate any feedback / ideas for improvements from you guys.

Testing:
When I tested the bot, I went from level 1 to level 31 in a couple of days, leaving my computer on overnight.
I should also mention this bot was created / tested using a character of the class "Cleric" (Winged Elf), but I believe the bot will work just fine with other classes as well, but this have not been tested.

Warning:
The use of any 3d party tool like Blue Eye Macro to play your character on any official Perfect World server, is likely to be considdered a violation of the games regulations.
It is solely your responsibility to ensure no such regulations are violated - or use at your own risk.

Credits:
A big thanks to Martin for helping out with the tasks of locating base pointers and development of the macro.

_________________
Blue Eye - Developer / Moderator
Code:
Gigus


Please read the rules about contribution points - click here

Do you know everything about BE, the forum, licenses and contribution points?
Please take a minute to read this introduction & guidelines.


Top
 Profile  
Reply with quote  
 Post subject: Re: Perfect Bot v1
Thanked: 0 time(s)  Unread post Posted: Tue Jan 25, 2011 11:59 am 
Lifetime VIP Contributor
Lifetime VIP Contributor
User avatar



Joined: Sat Apr 24, 2010 12:51 pm
Posts: 355
Location: Tallinn
Been thanked: 18 time(s)
Has thanked: 1 time(s)
Contribution Points: 4647
oh my, this is just perfect, im goin to download PWorld today i suppose :shock:

_________________
Full time IT student/worker - BE showed me the way, so may the code be with you all!
Image


Top
 Profile  
Reply with quote  
 Post subject: Re: Perfect Bot v1
Thanked: 0 time(s)  Unread post Posted: Tue Jan 25, 2011 1:56 pm 
Partner / Developer
Partner / Developer
User avatar



Joined: Mon Jan 18, 2010 11:51 am
Posts: 4525
Been thanked: 1346 time(s)
Has thanked: 133 time(s)
Contribution Points: 33209
Good luck :)

Please let me know how it works out, I want to create a version 2 of the bot as soon as possible, once I get some feedback, and a few tweaks applied.

Currently I am working on improving the performance of the macro, to use as few CPU resources as possible, and I am implementing some "Simulate human behavior" functions.

_________________
Blue Eye - Developer / Moderator
Code:
Gigus


Please read the rules about contribution points - click here

Do you know everything about BE, the forum, licenses and contribution points?
Please take a minute to read this introduction & guidelines.


Top
 Profile  
Reply with quote  
 Post subject: Re: Perfect Bot v1
Thanked: 0 time(s)  Unread post Posted: Tue Jan 25, 2011 1:57 pm 
Partner / Developer
Partner / Developer
User avatar



Joined: Mon Jan 18, 2010 11:51 am
Posts: 4525
Been thanked: 1346 time(s)
Has thanked: 133 time(s)
Contribution Points: 33209
I will try to finish the video tonight or tomorrow showing exactly how to use / setup the macro, and demo the different features within it.

_________________
Blue Eye - Developer / Moderator
Code:
Gigus


Please read the rules about contribution points - click here

Do you know everything about BE, the forum, licenses and contribution points?
Please take a minute to read this introduction & guidelines.


Top
 Profile  
Reply with quote  
 Post subject: Re: Perfect Bot v1
Thanked: 0 time(s)  Unread post Posted: Tue Jan 25, 2011 2:33 pm 
Lifetime VIP Contributor
Lifetime VIP Contributor
User avatar



Joined: Sun Jan 23, 2011 6:41 am
Posts: 62
Been thanked: 1 time(s)
Has thanked: 0 time(s)
Contribution Points: 1061
definitely. I would love to take a look. Looks advanced. :D


Top
 Profile  
Reply with quote  
 Post subject: Re: Perfect Bot v1
Thanked: 0 time(s)  Unread post Posted: Tue Jan 25, 2011 2:39 pm 
Partner / Developer
Partner / Developer
User avatar



Joined: Mon Jan 18, 2010 11:51 am
Posts: 4525
Been thanked: 1346 time(s)
Has thanked: 133 time(s)
Contribution Points: 33209
The hardest part of the macro, was really not the macro itself, it was locating all the damn memory pointers hehe, I think I have spent like 20-30 hours locating memory pointers, and 5-10 hours writing the actual macro.

_________________
Blue Eye - Developer / Moderator
Code:
Gigus


Please read the rules about contribution points - click here

Do you know everything about BE, the forum, licenses and contribution points?
Please take a minute to read this introduction & guidelines.


Top
 Profile  
Reply with quote  
 Post subject: Re: Perfect Bot v1
Thanked: 0 time(s)  Unread post Posted: Tue Jan 25, 2011 4:36 pm 
Lifetime VIP Contributor
Lifetime VIP Contributor
User avatar



Joined: Sun Jan 23, 2011 6:41 am
Posts: 62
Been thanked: 1 time(s)
Has thanked: 0 time(s)
Contribution Points: 1061
oh wow, I tried to watch how you did that on one of your videos but looks difficult


Top
 Profile  
Reply with quote  
 Post subject: Re: Perfect Bot v1
Thanked: 1 time(s)  Unread post Posted: Tue Jan 25, 2011 4:46 pm 
Partner / Developer
Partner / Developer
User avatar



Joined: Mon Jan 18, 2010 11:51 am
Posts: 4525
Been thanked: 1346 time(s)
Has thanked: 133 time(s)
Contribution Points: 33209
I wish it was like that video this time hehe...

It was way harder with this game for some reason, besides I had to find some "weird" addresses, like the location of different windows inside the game, so Blue Eye knows where to send mouse clicks to etc.

And the player location was not stored in memory, I had to find a crazy formula to calculate the current coordinates of my character:
Code:
 // Get our current location, with 5 decimals
          Memory.Get value("{processName}", "{currentLocationXMemoryAddress}", "float", "x")
          Variable.Evaluate (Math)("401+({x}/10)", "x")
          Variable.Round (Math)("x", "5")
          Memory.Get value("{processName}", "{currentLocationYMemoryAddress}", "float", "y")
          Variable.Evaluate (Math)("551+({y}/10)", "y")
          Variable.Round (Math)("y", "5")
          Memory.Get value("{processName}", "{currentLocationHeightMemoryAddress}", "float", "z")
          Variable.Divide (Math)("z", "10")
          Variable.Round (Math)("z", "5")


Notice the calculations to figure out our X coordinate? we read it from memory, then perform the following calculation: 401+({x}/10) x being the value we read from memory.
This gives us our exact X coordinate, with a ton of decimals, so everything is very precise, and works like a charm, but it took me a while to figure that one out hehe.

_________________
Blue Eye - Developer / Moderator
Code:
Gigus


Please read the rules about contribution points - click here

Do you know everything about BE, the forum, licenses and contribution points?
Please take a minute to read this introduction & guidelines.


Top
 Profile  
Reply with quote  
 Post subject: Re: Perfect Bot v1
Thanked: 0 time(s)  Unread post Posted: Tue Jan 25, 2011 9:13 pm 
Partner / Developer
Partner / Developer
User avatar



Joined: Mon Jan 18, 2010 11:51 am
Posts: 4525
Been thanked: 1346 time(s)
Has thanked: 133 time(s)
Contribution Points: 33209
I updated the code to use slightly less CPU resources when running, and also removed the non-mandatory variables from the lower left side in the editor, so they no longer have a predefined value.
Since the user is supposed to fill in these himself, if they apply to his character.

The updated version has been submitted to the repository.

_________________
Blue Eye - Developer / Moderator
Code:
Gigus


Please read the rules about contribution points - click here

Do you know everything about BE, the forum, licenses and contribution points?
Please take a minute to read this introduction & guidelines.


Top
 Profile  
Reply with quote  
 Post subject: Re: Perfect Bot v1.1
Thanked: 0 time(s)  Unread post Posted: Thu Jan 27, 2011 9:20 pm 
Partner / Developer
Partner / Developer
User avatar



Joined: Mon Jan 18, 2010 11:51 am
Posts: 4525
Been thanked: 1346 time(s)
Has thanked: 133 time(s)
Contribution Points: 33209
I updated the bot to version 1.1, it will now no longer leave any drops behind if a lot of drops appears at the same time.

It will consume less CPU resources.

It will make sure not to waste time picking up drops, flying to a new location etc, while you are being attacked, if a monster attacks you, first priority will always be to kill the monster before carrying on any other tasks.

PreAttackKey has been added, if you specify a key for this binding, then this key will be pressed before attacking a monster with the AttackKey.
A setting has been added in the top of the macro, to specify how big a percentage of the targeted monsters, should be attacked by the spell located at "PreAttackKey" before finishing them off with the primary attacking spell.

The default setting is 50%, this means that if you specify a "PreAttackKey" then after getting a new target, there will be a 50% chance of firring that spell first.
This makes the bot appear less bot-like, as it will seam to be using different spells in a random order, as a regular player might.

Also if you have a slowing spell of any kind, it makes sense to cast that before attacking it, which will make the monster take longer to get to you, so you just might be able to completely kill the monster before it even reaches you.

Also the progress will be reported more frequently, which is handy if you have BE visible on the screen but placed another window above the game window, or moved the game window all the way out to the side.

Now for a WARNING:
Do not minimize the game window any longer!
The game does not show the coordinate helper in the proper spot, if the game is minimized, which means the bot will be entering coordinates in the chat window, instead of the Fly to coordinates window.

The game does not have to be focused, you can still use your computer in the meantime, place other windows on top of the game window, or even drag the game window all the way to the side, as long as you just don't minimize the game!


The repository has been updated as well.

Enjoy :)

_________________
Blue Eye - Developer / Moderator
Code:
Gigus


Please read the rules about contribution points - click here

Do you know everything about BE, the forum, licenses and contribution points?
Please take a minute to read this introduction & guidelines.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 92 posts ]  Go to page 1, 2, 3, 4, 5 ... 10  Next

All times are UTC


You cannot post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group