HREngine - Hearthstone Bot by MMOCrawlerbots.com

03/28/2014 07:42 Bl@ze!#1
[Only registered and activated users can see links. Click Here To Register...]
Hearthcrawler - Your Bot for Hearthstone
[Only registered and activated users can see links. Click Here To Register...]
MMOCrawlerbots.com just launched the Hearthcrawler. It plays your character in Hearthstone.

Getting Started
Hearthcrawler can be downloaded and installed very easily. Beside Hearthstone (Battle.net) and a valid Battle.net Account you will only need Microsofts .NET Framework 4 in order to run Hearthcrawler.

You can also view our Video-Guide: [Only registered and activated users can see links. Click Here To Register...]

What is Hearthcrawler?
Hearthcrawler is a Bot that will play Hearthstone for you automatically.
You can choose between different Game-Modes, Card Decks and Costum Classes.


Hearthcrawler Features
  • Support for all 713 Cards
  • Supports Arena, Ranked & Unranked, Practice Mode
  • Custom Classes: create your own AI behaviour fitting your decks
  • Card Behaviour Editor: Edit Card playing options without programming knowledge

1. Download & Installation
  • Download Hearthstone (if you haven't yet): [Only registered and activated users can see links. Click Here To Register...]
    Run the setup and follow instructions in order to install Hearthstone.
  • Register for a Battle.net Account (if you haven't yet): [Only registered and activated users can see links. Click Here To Register...]
    The registration if free.
  • Download and extract Hearthcrawler files: [Only registered and activated users can see links. Click Here To Register...]
    After downloading you have to extract the files inside 'latest.zip' into a folder of your choice (eg. Hearthstone).
    Right-click latest.zip and choose "Extract all files..." (WinXP and above) or use tools like WinZIP, WinRAR, etc..

    [Only registered and activated users can see links. Click Here To Register...]
  • Install Microsoft .NET Framework (if you haven't yet)
    If you are running WinXP (or above) with automatic Updates, the Framework should already be installed.
    To install the Framework manually, go to the Hearthcrawler-Folder and execute the file dotNetFx40_Full_setup.exe or download the file on the official Microsoft Website: [Only registered and activated users can see links. Click Here To Register...]
  • If you have completed the steps above, you're almost ready to go!

2. Licensing Hearthcrawler

Hearthcrawler is now very mature and has left the beta stage. In order to continue using Hearthcrawler, you have to purchase a license.
We cover our past development costs and the future development with the licensing fees!
  • Choose your preferred License: [Only registered and activated users can see links. Click Here To Register...]
  • Select between 1-Month-License and Lifetime-License (Special Discount for 3 Lifetime Licenses)
[Only registered and activated users can see links. Click Here To Register...]
  • Finish the Payment-Process - Your License-Key will be shown up in your Browser window.
    The License-Key will be sent to your E-Mail, too.
  • Start Hearthcrawler (we recommend to use the updater.exe - so you'll always use the latest version)
    Copy & Paste your License-Key into Hearthcrawler.

    [Only registered and activated users can see links. Click Here To Register...]

    Congratulations - You are now ready to use Hearthcrawler



3. Using Hearthcrawler

Installation finished, License activated - now you're ready to use Hearthcrawler.

[Only registered and activated users can see links. Click Here To Register...]
  • Start Hearthstone
  • Click the 'Inject'-Button after Hearthstone has finished loading.
    Hearthcrawler now connects to the Hearthstone Process in order to load information, like Card Decks.
  • Choose your preferred Deck
    Beside Default-Decks you are able to choose Custom-Decks, too.
  • Choose Game-Mode (Ranked, Unranked, Practice, Arena)
    In Practice Mode you are able to choose preferred opponents (Mage, Hunter, etc)
  • Click the 'Start Bot' Button
  • Done :thumbup:


3) Important and useful Links
Use the Links below, to get more information about Hearthcrawler, Extensions or Support.

Support
03/28/2014 10:17 dermueller#2
you made my day :) cant wait...
03/28/2014 10:52 {Dn.}Shinigami#3
:) Very nice!
03/28/2014 11:02 silent.hunter#4
Good news! :)
03/28/2014 11:07 XpressMe#5
hope that a 0 costs Rouge Deck will be in custom classes or someone do it fast :)
cant whait till midnight :)

want to play with it ^^
03/28/2014 11:11 Bl@ze!#6
Just my stats after using it about 12 hours with my custom profile. (Ranked, 29 wins and 60 looses, quite good since this is just a test profile and not perfect for my deck)
[Only registered and activated users can see links. Click Here To Register...]
03/28/2014 13:31 iiSerouZ#7
Holy shit, u r a beast.

God bless u!
03/28/2014 13:36 m4rd0k#8
Work on xp?
03/28/2014 14:13 Bl@ze!#9
Well the client launches on XP but haven't tested it. It is compiled with XP support - so let us try it when it is released.
03/28/2014 15:07 smirk#10
looking forward to test it tonight :)!
03/28/2014 15:39 {Dn.}Shinigami#11
How much it will cost after Beta? And how long beta will go on?
03/28/2014 16:06 hamburger1#12
Currently we can't provide you the exact date and cost for the programm. But once we think that the programm is running smooth and stable we will make an announcement (about 3 days befor offical release) wit all needed informations!
03/28/2014 17:46 Javasova#13
Here we go.
Could you say something more about the given classes?
03/28/2014 17:59 Bl@ze!#14
Quote:
Originally Posted by javasova View Post
Here we go.
Could you say something more about the given classes?
There is one class at this moment which will be released. This class is called "General" and supports nearly everything including hero power. (except warlock, for now)

I use this as a priest and mage - and this very successful. It supports minions, minions with battle cry, taunts, spells with attack against the enemy.

This class especially can do the following:
  • Kill enemy with all required cards (hand, battlefield etc.) if possible
  • Kill minions with 1 shot if possible
  • Kill enemy minions with taunt ability
  • Kill enemy minions with multiple of my minions
  • Kill the enemy himself

But - with a custom class nearly everything is possible. An API documentation is coming, soon. (Reflecting the API of HREngine.dll will show you most things in your favorite IDE, but an documentation is also in work)

This class is simple - have a look at it:

Code:
using HREngine.API;
using HREngine.API.Utilities;
using System;
using System.Collections.Generic;

namespace HREngine.Bots
{
   internal class PossibleTurnAttack
   {
      public int Cost;
      public int Attack;
      public int NeededAttack;
      public List<HRCard> Cards;
   }

   /// <summary>
   /// [EN]
   /// This Bot implements a simple AI to fight against enemies.
   /// Features:
   ///    - Attacking Taunts
   ///    - Spawn Taunts
   ///    - Attack Hero if available.
   ///
   /// [DE]
   /// Dieser Bot implementiert eine einfache KI um gegen Gegner
   /// zu kämpfen.
   /// Funktionen:
   ///    - Kämpfe gegen Gegner mit Spott
   ///    - Lege Karten mit Spott
   ///    - Kämpfe gegen Held
   /// </summary>
   public class Bot : API.IBot
   {
      /// <summary>
      /// [EN]
      /// Initializes a new instance of the <see cref="Bot"/> class.
      ///
      /// [DE]
      /// Initialisiert eine neue Instanz dieses Bots.
      /// </summary>
      public Bot()
      {
         // [EN]
         // Setting required event handler to implement bot logic.
         OnBattleLocalPlayerTurn = HandleBattleLocalPlayerTurnHandler;
      }

      private PossibleTurnAttack GetPossibleTurnAttack(int NeededAttackPower, int MaxCards = -1)
      {
         PossibleTurnAttack result = new PossibleTurnAttack();
         result.NeededAttack = NeededAttackPower;
         result.Cards = new List<HRCard>();

         try
         {
            var p = HRPlayer.GetLocalPlayer();

            // Loop through all minions that can attack...
            List<HRCard> playerBattleField = HRCard.GetCards(HRPlayer.GetLocalPlayer(), HRCardZone.PLAY);
            foreach (var card in playerBattleField)
            {
               if (HRBattle.CanUseCard(card.GetEntity()))
               {
                  if (MaxCards == -1)
                  {
                     result.Attack += card.GetEntity().GetATK();
                     result.Cards.Add(card);
                  }
                  else
                  {
                     if (result.Cards.Count + 1 == MaxCards)
                     {
                        if (result.Attack + card.GetEntity().GetATK() >= NeededAttackPower)
                        {
                           result.Attack += card.GetEntity().GetATK();
                           result.Cards.Add(card);
                        }
                     }
                     else
                     {
                        result.Attack += card.GetEntity().GetATK();
                        result.Cards.Add(card);
                     }
                  }

                  if (result.Attack >= result.NeededAttack || result.Cards.Count == MaxCards)
                     break;
               }
            }

            if (result.Attack < result.NeededAttack)
            {
               // Try with hero power?
               if (p.GetHeroPower().GetCost() <= p.GetNumAvailableResources())
               {
                  if (p.GetHeroPower().GetATK() > 0)
                  {
                     result.Attack += p.GetHeroPower().GetATK();
                     result.Cost += p.GetHeroPower().GetCost();
                     result.Cards.Add(p.GetHeroCard());
                  }
               }

               // Try with remaining cards..
               if (result.Attack < result.NeededAttack)
               {
                  List<HRCard> playerHandField = HRCard.GetCards(p, HRCardZone.HAND);

                  foreach (var card in playerBattleField)
                  {
                     int leftResources = p.GetNumAvailableResources() - result.Cost;

                     if (card.GetEntity().IsSpell() && card.GetEntity().GetATK() > 0)
                     {
                        if (card.GetEntity().GetCost() <= leftResources)
                        {
                           result.Attack += card.GetEntity().GetATK();
                           result.Cost += card.GetEntity().GetCost();
                           result.Cards.Add(card);
                        }
                     }
                     else if (card.GetEntity().IsMinion() && card.GetEntity().GetATK() > 0)
                     {
                        if (card.GetEntity().HasBattlecry())
                        {
                           if (card.GetEntity().GetCost() <= leftResources)
                           {
                              result.Attack += card.GetEntity().GetATK();
                              result.Cost += card.GetEntity().GetCost();
                              result.Cards.Add(card);
                           }
                        }
                     }

                     if (result.Attack >= result.NeededAttack)
                        break;
                  }
               }
            }
         }
         catch (Exception)
         {
            HRLog.Write("GetPossibleTurnAttack caused an exception");
            throw;
         }

         return result;
      }

      /// <summary>
      /// [EN]
      /// This handler is executed when the local player turn is active.
      ///
      /// [DE]
      /// Dieses Event wird ausgelöst wenn der Spieler am Zug ist.
      /// </summary>
      private void HandleBattleLocalPlayerTurnHandler()
      {
         try
         {
            SafeHandleBattleLocalPlayerTurnHandler();
         }
         catch (Exception Exception)
         {
            HRLog.Write(Exception.Message);
            HRLog.Write(Environment.StackTrace);
         }

         HRBattle.FinishRound();
      }

      private void SafeHandleBattleLocalPlayerTurnHandler()
      {
         bool didHeroPower = false;

         // PRIEST: Heal if Health < 18
         if (HRPlayer.GetLocalPlayer().GetRemainingHP() < 18 &&
            HRPlayer.GetLocalPlayer().GetClass() == HRClass.PRIEST)
         {
            try
            {
               TryHeroPower();
            }
            catch (Exception)
            {
               HRLog.Write("TryHeroPower caused an exception");
               throw;
            }

            didHeroPower = true;
         }

         try
         {
            TryPossibleWin();
         }
         catch (Exception)
         {
            HRLog.Write("TryPossibleWin caused an exception.");
            throw;
         }

         try
         {
            TrySpawnBattleCry();
         }
         catch (Exception)
         {
            HRLog.Write("TrySpawnBattleCry caused an exception.");
         }

         try
         {
            TrySpawnRest();
         }
         catch (Exception)
         {
            HRLog.Write("TrySpawnRest caused an exception");
            throw;
         }

         try
         {
            TryPossibleOneShots();
         }
         catch (Exception)
         {
            HRLog.Write("TryPossibleOneShots caused an exception.");
            throw;
         }

         // TryFight
         try
         {
            TryFight();
         }
         catch (Exception)
         {
            HRLog.Write("TryFight caused an exception");
            throw;
         }

         if (!didHeroPower)
         {
            try
            {
               TryHeroPower();
            }
            catch (Exception)
            {
               HRLog.Write("TryHeroPower caused an exception");
               throw;
            }
         }
      }

      private void TryHeroPower()
      {
         var nextMinion = GetNextMinion(new List<int>());
         if (nextMinion == null)
            nextMinion = HRPlayer.GetEnemyPlayer().GetHero().GetCard();

         HRBattle.UseHeroPower(nextMinion.GetEntity());
      }

      private void TrySpawnRest()
      {
         var p = HRPlayer.GetLocalPlayer();

         List<HRCard> hand = HRCard.GetCards(p, HRCardZone.HAND);

         foreach (var card in hand)
         {
            if (card.GetEntity().IsMinion() || card.GetEntity().IsSpell())
            {
               if (HRBattle.CanPlayCard(card.GetEntity()))
               {
                  if (!HRBattle.Push(card))
                     HRLog.Write(String.Format("Pushing card failed with card {0}", card.GetEntity().GetName()));
                  else
                  {
                     if (HRBattle.IsInTargetMode())
                     {
                        var nextMinion = GetNextMinion(new List<int>());
                        if (nextMinion != null)
                           HRBattle.Target(nextMinion.GetEntity());
                        else
                           HRBattle.Target(HRPlayer.GetEnemyPlayer().GetHero());
                     }
                  }
               }
            }
            else
            {
               HRLog.Write(
                  String.Format("Card ({0}) is not a minion or spell and cannot be used.",
                  card.GetEntity().GetName()));
            }
         }
      }

      private void TrySpawnBattleCry()
      {
         var p = HRPlayer.GetLocalPlayer();

         List<HRCard> hand = HRCard.GetCards(p, HRCardZone.HAND);
         foreach (var card in hand)
         {
            if (card.GetEntity().HasBattlecry() && HRBattle.CanUseCard(card.GetEntity()))
            {
               if (!HRBattle.Push(card))
                  HRLog.Write(String.Format("Pushing battlecry card failed with card {0}", card.GetEntity().GetName()));
            }
         }
      }

      private void TryFight()
      {
         List<int> lsCheckedEntities = new List<int>();
         HRCard nextMinion = null;

         using (var imp = new HRDeadlockBypass("TryFight"))
         {
            do
            {
               nextMinion = GetNextMinion(lsCheckedEntities);

               if (nextMinion != null)
               {
                  var possibleAttack = GetPossibleTurnAttack(nextMinion.GetEntity().GetRemainingHP());
                  if (possibleAttack.Attack >= nextMinion.GetEntity().GetRemainingHP() &&
                     possibleAttack.Cost <= HRPlayer.GetLocalPlayer().GetNumAvailableResources() &&
                     possibleAttack.Cards.Count > 0)
                  {
                     HRLog.Write(String.Format("Fighting with {0}", nextMinion.GetEntity().GetName()));
                     PerformAttackFromPossibleTurnAttack(possibleAttack, nextMinion.GetEntity());
                  }
                  lsCheckedEntities.Add(nextMinion.GetEntity().GetEntityId());
               }

               if (imp.HasDeadlock && nextMinion != null)
               {
                  HRLog.Write(String.Format("Deadlock occured with entity {0} and ID {1}",
                     nextMinion.GetEntity().GetName(),
                     nextMinion.GetEntity().GetEntityId()));
               }
            } while (!imp.HasDeadlock && nextMinion != null);
         }

         // Try to attack his hero...?
         var e = HRPlayer.GetEnemyPlayer();
         if (!e.HasATauntMinion())
         {
            var possibleAttack = GetPossibleTurnAttack(e.GetHero().GetRemainingHP());
            if (possibleAttack.Cost <= HRPlayer.GetLocalPlayer().GetNumAvailableResources())
            {
               PerformAttackFromPossibleTurnAttack(possibleAttack, e.GetHero());
            }
         }
      }

      private void TryPossibleWin()
      {
         var e = HRPlayer.GetEnemyPlayer();
         if (e.HasATauntMinion() || !e.GetHeroCard().GetEntity().CanBeAttacked())
            return;

         var p = HRPlayer.GetLocalPlayer();

         PossibleTurnAttack possiblePower = GetPossibleTurnAttack(e.GetHero().GetRemainingHP());
         if (possiblePower.Attack >= e.GetHero().GetRemainingHP() && possiblePower.Cost <= p.GetNumAvailableResources())
         {
            HRLog.Write(String.Format("Prepare next win, killing {0}", e.GetHero().GetName()));
            PerformAttackFromPossibleTurnAttack(possiblePower, e.GetHero());
         }
      }

      private void PerformAttackFromPossibleTurnAttack(PossibleTurnAttack possiblePower, HREntity entity)
      {
         if (entity == null)
            return;

         if (!entity.CanBeAttacked())
         {
            HRLog.Write(String.Format("Entity {0} cannot be attacked", entity.GetName()));
            return;
         }

         if (possiblePower.Cards == null)
            return;

         foreach (var item in possiblePower.Cards)
         {
            if (item.GetEntity().IsHero())
               HRBattle.UseHeroPower(entity);
            else
            {
               HRCardZone zone = item.GetEntity().GetZone();
               switch (zone)
               {
                  case HRCardZone.PLAY:
                     HRBattle.Attack(item.GetEntity(), entity);
                     break;

                  case HRCardZone.HAND:
                     if (item.GetEntity().IsMinion() && item.GetEntity().HasBattlecry())
                     {
                        HRBattle.Push(item);
                        HRBattle.Attack(item.GetEntity(), entity);
                     }
                     else if (item.GetEntity().IsSpell())
                     {
                        HRBattle.Push(item);
                        if (HRBattle.IsInTargetMode())
                           HRBattle.Target(entity);
                     }
                     break;

                  default:
                     break;
               }
            }
         }
      }

      private void TryPossibleOneShots()
      {
         List<int> lsCheckedEntities = new List<int>();
         HRCard nextMinion = null;

         using (var imp = new HRDeadlockBypass("TryPossibleOneShots"))
         {
            do
            {
               nextMinion = GetNextMinion(lsCheckedEntities);
               if (nextMinion != null)
               {
                  var possibleAttack = GetPossibleTurnAttack(nextMinion.GetEntity().GetRemainingHP(), 1);
                  if (possibleAttack.Attack >= nextMinion.GetEntity().GetRemainingHP() &&
                     possibleAttack.Cost <= HRPlayer.GetLocalPlayer().GetNumAvailableResources() && possibleAttack.Cards.Count == 1)
                  {
                     HRLog.Write(String.Format("Perform 1 Hit to {0}", nextMinion.GetEntity().GetName()));
                     PerformAttackFromPossibleTurnAttack(possibleAttack, nextMinion.GetEntity());
                  }

                  lsCheckedEntities.Add(nextMinion.GetEntity().GetEntityId());
               }

               if (imp.HasDeadlock && nextMinion != null)
               {
                  HRLog.Write(String.Format("Deadlock occured with entity {0} and ID {1}",
                     nextMinion.GetEntity().GetName(),
                     nextMinion.GetEntity().GetEntityId()));
               }
            } while (!imp.HasDeadlock && nextMinion != null);
         }
      }

      private HRCard GetNextMinion(List<int> lsCheckedEntities)
      {
         HRCard nextMinion = null;

         var e = HRPlayer.GetEnemyPlayer();
         List<HRCard> battleField = HRCard.GetCards(e, HRCardZone.PLAY);
         foreach (var card in battleField)
         {
            if (lsCheckedEntities.Contains(card.GetEntity().GetEntityId()))
               continue;

            if (card.GetEntity().CanBeAttacked())
            {
               if (nextMinion == null)
               {
                  if (!e.HasATauntMinion() || card.GetEntity().HasTaunt())
                     nextMinion = card;
               }
               else
               {
                  if (card.GetEntity().GetRemainingHP() < nextMinion.GetEntity().GetRemainingHP())
                  {
                     if (!e.HasATauntMinion() || card.GetEntity().HasTaunt())
                        nextMinion = card;
                  }
                  else if (card.GetEntity().GetRemainingHP() == nextMinion.GetEntity().GetRemainingHP())
                  {
                     // kill minions with higher attack first
                     if (card.GetEntity().GetATK() > nextMinion.GetEntity().GetATK())
                     {
                        if (!e.HasATauntMinion() || card.GetEntity().HasTaunt())
                           nextMinion = card;
                     }
                  }
               }
            }
         }

         return nextMinion;
      }
   }
}
03/28/2014 18:03 show83#15
Will test it as soon as possible :)