Blizzhackers

Home of the Dupe since 2001

* Login   * Register    * FAQ    * Search

Join us on IRC: #bh@irc.synirc.net (or Mibbit Web IRC)


It is currently Sat Jun 23, 2018 9:26 am


All times are UTC [ DST ]





Post new topic Reply to topic  [ 54 posts ]  Go to page Previous  1, 2, 3, 4
Author Message
 Post subject: Re: [AutoIt] Creating Bots (for newbies)
PostPosted: Fri Aug 05, 2011 5:48 am 
 
User
User

Joined: Fri Aug 05, 2011 5:45 am
Hello I play a game called Flash flash revolution which can be found at flashflashrevolution.com. I usually play this game on a standalone flash player and was wondering how I would go about creating a bot using AutoIt to automatically hit the arrows I need it to hit in order to perfect any song. If there's no way to do this using a standalone player how would I go about doing it while playing within the browser? Thank you.

Top
 Profile  
 Post subject: Re: [AutoIt] Creating Bots (for newbies)
PostPosted: Sat Jun 02, 2012 2:22 am 
 
User
User

Joined: Sat Jun 02, 2012 2:17 am
I want to make a Diablo 3 bot for Royal Crypts urns/coffins farming. I've seen some bots, but they're slow and stupid and I have my char tweaked for botting (265% gf and 50 yards gold radius pickup, which equal to a whole screen pickup @ 1920x1200 resolution). I would like to make a bot which would be left/right clicking and using spells (1-4 on keyboard) and just sweeping the area in 30-60 secs, as I do it in about 1-1.5 min, and I'm not the fastest guy around, and certainly cant compare to a scripted bot.

Any hints or tutorials would be really helpful. (On a side note, I'm a programmer my self, just don't know the syntax or semantics of AutoIt)

Top
 Profile  
 Post subject: Re: [AutoIt] Creating Bots (for newbies)
PostPosted: Mon Jun 01, 2015 2:05 pm 
 
Banned
Banned
User avatar

Joined: Sat Sep 06, 2008 7:18 am
Location: USA, TX
Hello all past and future posters!

I just wanted to let everyone know that I was banned back on: Mon Apr 20, 2009 5:37 pm.

I was unbanned a couple of hours ago (thank you, lord2800)!

_________________
Image

Top
 Profile  
 Post subject: Re: [AutoIt] Creating Bots (for newbies)
PostPosted: Mon Jun 01, 2015 6:14 pm 
 
User
User
User avatar

Joined: Tue Mar 01, 2005 8:31 pm
You tag won't change though. If DM logs into the ACP BH is down again :p

_________________
Image

Top
 Profile  
 Post subject: Re: [AutoIt] Creating Bots (for newbies)
PostPosted: Tue Jun 02, 2015 4:06 am 
 
Banned
Banned
User avatar

Joined: Sat Sep 06, 2008 7:18 am
Location: USA, TX
You tag won't change though. If DM logs into the ACP BH is down again :p

I like it! I am the only "banned" user who can post! 8)

_________________
Image

Top
 Profile  
 Post subject: Re: [AutoIt] Creating Bots (for newbies)
PostPosted: Tue Jun 02, 2015 2:00 pm 
 
User
User
User avatar

Joined: Tue Mar 01, 2005 8:31 pm
Nope

_________________
Image

Top
 Profile  
 Post subject: Re: [AutoIt] Creating Bots (for newbies)
PostPosted: Tue Jun 02, 2015 2:09 pm 
 
Banned
Banned
User avatar

Joined: Sat Sep 06, 2008 7:18 am
Location: USA, TX
Nope

You are polluting my beautiful thread. :(

_________________
Image

Top
 Profile  
 Post subject: Re: [AutoIt] Creating Bots (for newbies)
PostPosted: Sun Mar 04, 2018 11:01 am 
 
Banned
Banned
User avatar

Joined: Sat Sep 06, 2008 7:18 am
Location: USA, TX
Hello.

NOTE:
This entire point of this post is for educational purposes only; not to do anything malicious.
Please do note: Using bots or hacks or external 3rd party programs (even AutoIt3) is against the ToS / EULA on Diablo II / Battle.net.

Today, we're going to create a genetic algorithm with AutoIt3 for the sole purpose of logging onto a character with Diablo II.

We're going to use three include files with our script. We'll call our script "AI.au3."
#include <MsgBoxConstants.au3>   ; Message box constants (for "magic numbers" for icons selected)
#include <math.au3>            ; For deciding if a number is an EVEN or ODD value
#include <Array.au3>            ; For _ArrayXYZ() functions


We're going to structure this after a procedural C program.
main()

Func main()
EndFunc


Then we're going to sit down and design this program instead of randomly copying and pasting stuff that we found on an internet forum on the internet.
Perhaps I'll post the source code (script code?) at the very end, just so you can copy/paste it and run it/use it/whatever it is you choose to do.

Let's first address the problems and outline our basic criteria of the problem. We need to ask ourselves a lot of questions and provide ourselves with a lot of answers.

Here's a small criteria list outlining what we desire this particular *.au3 script to do:
  • Select a desired character by referencing a 'character slot' (1-8) with random pathing of N number of moves at maximum (no minimum)

Sounds like a tall order to be made! Let's get to it, shall we?

We're going to need some basic data to start off with. What will we need inside of the main() function?
  • Starting character position
  • Target character to stop on (referenced by slot 1-8)
  • An array to hold all the individual moves to be made

These sound like simple variables and not functions. Let's fill in the gaps and see what we have so far (because we're kids from 2000-2005 and demand instant gratification):
main()

Func main()
   Local $curSlot = 1
   Local $targetSlot = 8
   Local $maxMoves = 16

   Local $filteredPath
EndFunc


This looks fairly simple so far. Let's add some more complexity, shall we? We'll let our imagination fly initially.
; This function returns an array of Nth elements before ending on the "targetSlot" of the character desired
Local $path = generateRandomPath($curSlot, $targetSlot, $maxMoves)


Now we need to describe what generateRandomPath() should actually do. I think we already did that, though. I'll do it again for completeness.
  • Return an array of moves to make at random (the last Nth moves should place you on the target slot)

Okay. What now? We're in a bind! We need to think about how generateRandomPath() will generate random moves.
First: We'll need an array. That sounds in order. We'll also need to loop through this array, assigning each element a value that represents a move-to-make. Then return the array to the caller.

The data that the array should hold should be some form of encoded data that represents moves. We can use a global enumeration data-type to represent the individual moves.

Let's get crackin'!
Global Enum $MOVE_UP = 1, $MOVE_DOWN = 2, $MOVE_LEFT = 3, $MOVE_RIGHT = 4

...

Func generateRandomPath(ByRef $curSlot, Const ByRef $targetSlot, Const ByRef $maxMoves)
   ; Temporary array to return to the caller
   Local $path[$maxMoves]

   For $n = 0 To $maxMoves
      ; do stuff
   Next

   Return $path
EndFunc


Great. We have an array of Nth elements. We loop through our entire array. We return our array. Now all we need to do is modify the contents of the array.

We could just return a random value from: $MOVE_UP to $MOVE_RIGHT, but that would be boring! Watch:
For $n = 0 To $maxMoves
   ; Randomly assign a movement direction (this will try to run you into a wall a lot / other 'invalid' moves)
   $path[$n] = Random($MOVE_UP, $MOVE_RIGHT)
Next


That's a solution, but it's too low quality for myself. I prefer to write things that actually work. I don't like writing dirty things anymore than I like being dirty!

We should probably write another function to deal with generating random moves. I'll call it: generateRandomMove()! It only needs to know our current slot.
This function will return a random and legal (sanitized data) move to the caller. This in turn will populate the array of random moves.

For $n = 0 To $maxMoves
   ; Randomly assign a movement direction (this will try to run you into a wall a lot / other 'invalid' moves)
   $path[$n] = generateRandomMove($curSlot)
Next


That's better. Now we're tasked with describing what generateRandomMove($curSlot) should do. How do we prevent invalid (illegal) moves?
We can review the data we're working with. This is kind of a quirky thing to do, but hey! It works. It's math.

We have 1-8 character slots:
[1, 2, 3, 4, 5, 6, 7, 8]

[1, 2]
[3, 4]
[5, 6]
[7, 8]


We can clearly see that characters on the left side of the wall are all odd numbers. Those on the opposing side are even numbers.
We can then say: For if a number is odd: It can not travel left anymore. For if a number is even: It cannot travel right anymore.
We must also declare that: For if a number is on the location of 2 or less: It cannot travel up. For if a number is 7 or more: It cannot travel down.

These rules can be cut up into functions themselves! We will call these: Helper functions. We can describe a function per rule.
Global Enum $ODD_NUM = 1, $EVEN_NUM = 2

...

Func canMoveUp(Const ByRef $curSlot)
   If ($curSlot > 2) Then
     Return True
   EndIf

   Return False
EndFunc

Func canMoveDown(Const ByRef $curSlot)
   If ($curSlot < 7) Then
     Return True
   EndIf

   Return False
EndFunc

Func canMoveRight(Const ByRef $curSlot)
   Local Const $retValue = _MathCheckDiv($curSlot, 2)

   Switch ($retValue)
   Case $ODD_NUM
     If ($curSlot < 8) Then
       Return True
     EndIf
   EndSwitch

   Return False
EndFunc

Func canMoveLeft(Const ByRef $curSlot)
   Local Const $retValue = _MathCheckDiv($curSlot, 2)

   Switch ($retValue)
   Case $EVEN_NUM
     If ($curSlot > 1) Then
       Return True
     EndIf
   EndSwitch

   Return False
EndFunc


Now we have a quick way of deciding what is or is not a valid move. Let's re-examine our function body:
Func generateRandomMove(ByRef Const $curSlot)
EndFunc


Not too exciting (yet)... We should perhaps use an array to hold all valid moves, then select one randomly and return it. Sounds like a good time for yet, another function!
What should we name this function? I'm thinking: getValidMoves()! Sounds very explicit and unambiguous.

It definitely needs to know our current standing position, so we'll pass it that data. It doesn't look like we'll need anything else.
Func getValidMoves(ByRef Const $curSlot)
EndFunc


We have a clear-cut objective within this function. It needs to return all possible moves we can take from our current position and return this array of data to the caller.
Func getValidMoves(ByRef Const $curSlot)
   Local $validMoves[0] ; An empty array

   If (canMoveUp($curSlot)) Then
      _ArrayAdd($MOVE_UP, $validMoves)
   EndIf

   If (canMoveDown($curSlot)) Then
      _ArrayAdd($MOVE_DOWN, $validMoves)
   EndIf

   ; We can only move LEFT or RIGHT! Not both!
   If (canMoveLeft($curSlot)) Then
      _ArrayAdd($MOVE_LEFT, $validMoves)
   ElseIf (canMoveRight($curSlot)) Then
      _ArrayAdd($MOVE_RIGHT, $validMoves)
   EndIf

   Return $validMoves
EndFunc


Now we can see a little better of how generateRandomMove() might look:
Func generateRandomMove(ByRef Const $curSlot)
   Local $validMoves = getValidMoves($curSlot) ; Array of possibly valid moves from our current position
EndFunc


This is excellent! So to fall back on some basic math and diagram (because everyone loves diagrams) to help explain this.

If we're currently on slot #1:
1, 2
3, 4
5, 6
7, 8


Our valid options are only: $MOVE_RIGHT and $MOVE_DOWN (slot #2 and slot #3 respectively).
The array will be populated like so: $validMoves = [ $MOVE_DOWN, $MOVE_RIGHT ]

What else is left to do in: generateRandomMove() you may wonder? Of course! We need to randomly select from the array and return it.
Func generateRandomMove(ByRef Const $curSlot)
   Local $validMoves = getValidMoves($curSlot) ; Array of possibly valid moves from our current position

   ; Return a randomly valid move stored in our validated bucket (1 - 4)
   Return $validMoves[Random(0, UBound($validMoves) - 1, 1)]
EndFunc


Then: We need to update our player's current position in "Bob's" brain (I've decided to refer to this as a human named "Bob").
For $n = 0 To $maxMoves
   ; Randomly assign a movement direction (this will try to run you into a wall a lot / other 'invalid' moves)
   $path[$n] = generateRandomMove($curSlot)
   ; We need to update Bob's brain here
Next


What sounds like a good function name? I'll go with... updateCurSlotPos()! Seems logical. We will need to pass it the last made move ($path[$n]) and our current slot position:
For $n = 0 To $maxMoves
   ; Randomly assign a movement direction (this will try to run you into a wall a lot / other 'invalid' moves)
   $path[$n] = generateRandomMove($curSlot)
   updateCurSlotPos($curSlot, $path[$n])
Next


Oh wait! Wrong one. We need to create a helper function named: updateCurSlotPos() first, huh?
Func updateCurSlotPos(ByRef $curSlot, ByRef Const $move)
   Switch ($move)
     Case $MOVE_UP
       $curSlot -= 2
     Case $MOVE_DOWN
       $curSlot += 2
     Case $MOVE_LEFT
       $curSlot -= 1
     Case $MOVE_RIGHT
       $curSlot += 1
   EndSwitch
EndFunc


This about wraps everything up! We've a complete script that generates a random path starting from Nth position and stops at... Oh! No! It doesn't stop on the desired slot.

We merely need to append to the array that holds our path and redirect it to our desired target slot, then return the array!
Let's re-cap on what we have in total so far (from top to bottom):
#include <MsgBoxConstants.au3>   ; Message box constants (for "magic numbers" for icons selected)
#include <math.au3>            ; For deciding if a number is an EVEN or ODD value
#include <Array.au3>            ; For _ArrayXYZ() functions

Global Enum $MOVE_UP = 1, $MOVE_DOWN = 2, $MOVE_LEFT = 3, $MOVE_RIGHT = 4
Global Enum $ODD_NUM = 1, $EVEN_NUM = 2

main()

Func main()
   Local $curSlot = 1
   Local $targetSlot = 8
   Local $maxMoves = 16

   Local $path = generateRandomPath($curSlot, $targetSlot, $maxMoves)
EndFunc

Func generateRandomPath(ByRef $curSlot, Const ByRef $targetSlot, Const ByRef $maxMoves)
   Local $path[$maxMoves]

   For $n = 0 To $maxMoves - 1
      $path[$n] = generateRandomMove($curSlot)
      updateCurSlotPos($curSlot, $path[$n])
   Next

   Return $path
EndFunc

Func generateRandomMove(ByRef Const $curSlot)
   Local $validMoves = getValidMoves($curSlot)

   Return Random($validMoves[0], $validMoves[UBound($validMoves) - 1])
EndFunc

Func getValidMoves(ByRef Const $curSlot)
   Local $validMoves[0]

   If (canMoveUp($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_UP)
   EndIf

   If (canMoveDown($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_DOWN)
   EndIf

   If (canMoveLeft($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_LEFT)
   ElseIf (canMoveRight($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_RIGHT)
   EndIf

   Return $validMoves
EndFunc

Func updateCurSlotPos(ByRef $curSlot, ByRef Const $move)
   Switch ($move)
     Case $MOVE_UP
       $curSlot -= 2
     Case $MOVE_DOWN
       $curSlot += 2
     Case $MOVE_LEFT
       $curSlot -= 1
     Case $MOVE_RIGHT
       $curSlot += 1
   EndSwitch
EndFunc

Func canMoveUp(Const ByRef $curSlot)
   If ($curSlot > 2) Then
     Return True
   EndIf

   Return False
EndFunc

Func canMoveDown(Const ByRef $curSlot)
   If ($curSlot < 7) Then
     Return True
   EndIf

   Return False
EndFunc

Func canMoveRight(Const ByRef $curSlot)
   Local Const $retValue = _MathCheckDiv($curSlot, 2)

   Switch ($retValue)
   Case $EVEN_NUM
     If ($curSlot < 8) Then
       Return True
     EndIf
   EndSwitch

   Return False
EndFunc

Func canMoveLeft(Const ByRef $curSlot)
   Local Const $retValue = _MathCheckDiv($curSlot, 2)

   Switch ($retValue)
   Case $ODD_NUM
     If ($curSlot > 1) Then
       Return True
     EndIf
   EndSwitch

   Return False
EndFunc


To find the shortest path to the target slot is fairly simple. We need to know how many elements we need to add to the array first (we also need to know if we're already on it, by chance).
Round((Abs($curSlot - $targetSlot) / 2))


This will return the distance (in terms of "moves" needed to be made; which is perfect) between your current slot and the target slot.

Ready for another diagram? Nah! You can scroll up. If we're on slot #1 at the end and we're trying to get to slot #8: We need to make: 4 moves (RIGHT, DOWN, DOWN, DOWN; or any variation).

This feels so straight-forward: We only need to loop N amount of times and call on _AddArray() per random move towards the target slot.
   Local $movesToTarget = (Round((Abs($curSlot - $targetSlot) / 2)) - 1)

   If ($movesToTarget <> 0) Then
     For $i = 0 To $movesToTarget

       ; Are we "above" the target slot?
       If ($targetSlot < $curSlot) Then
         If (canMoveUp($curSlot)) Then
            _ArrayAdd($path, $MOVE_UP)
            updateCurSlotPos($curSlot, $MOVE_UP)
         ElseIf (canMoveLeft($curSlot) Then
            _ArrayAdd($path, $MOVE_LEFT)
            updateCurSlotPos($curSlot, $MOVE_LEFT)
         EndIf
       EndIf

       ; Are we "below" the target slot?
       If ($targetSlot > $curSlot) Then
         If (canMoveDown($curSlot)) Then
            _ArrayAdd($path, $MOVE_DOWN)
            updateCurSlotPos($curSlot, $MOVE_DOWN)
         ElseIf (canMoveRight($curSlot)) Then
            _ArrayAdd($path, $MOVE_RIGHT)
            updateCurSlotPos($curSlot, $MOVE_RIGHT)
         EndIf
       EndIf
     Next
   EndIf


Add a dash of randomization to it:
_ArrayShuffle($path, Abs($maxMoves - $movesToTarget))


... Voila! We're done.

The program now looks like this (the entire thing):
#include <MsgBoxConstants.au3>   ; Message box constants (for "magic numbers" for icons selected)
#include <math.au3>            ; For deciding if a number is an EVEN or ODD value
#include <Array.au3>            ; For _ArrayXYZ() functions

Global Enum $MOVE_UP = 1, $MOVE_DOWN = 2, $MOVE_LEFT = 3, $MOVE_RIGHT = 4

main()

Func main()
   Local $curSlot = 1
   Local $targetSlot = 8
   Local $maxMoves = 1

   Local $path = generateRandomPath($curSlot, $targetSlot, $maxMoves)

   _ArrayDisplay($path, "FULL PATH")
EndFunc

Func generateRandomPath(ByRef $curSlot, Const ByRef $targetSlot, Const ByRef $maxMoves)
   Local $path[$maxMoves]

   For $n = 0 To $maxMoves - 1
      $path[$n] = generateRandomMove($curSlot)
      updateCurSlotPos($curSlot, $path[$n])
   Next

   If ($curSlot <> $targetSlot) Then
     Local $pathToTarget[0]

     Local Const $targetSide = _MathCheckDiv($targetSlot, 2)
     If ($targetSide == $MATH_ISDIVISIBLE) Then
       If (canMoveRight($curSlot)) Then
         _ArrayAdd($pathToTarget, $MOVE_RIGHT)
         updateCurSlotPos($curSlot, $MOVE_RIGHT)
       EndIf
     ElseIf ($targetSide == $MATH_ISNOTDIVISIBLE) Then
       If (canMoveLeft($curSlot)) Then
         _ArrayAdd($pathToTarget, $MOVE_LEFT)
         updateCurSlotPos($curSlot, $MOVE_LEFT)
       EndIf
     EndIf

     While ($curSlot <> $targetSlot)
       ; Are we "above" the target slot?
       If ($targetSlot < $curSlot) Then
         If (canMoveUp($curSlot)) Then
            _ArrayAdd($pathToTarget, $MOVE_UP)
            updateCurSlotPos($curSlot, $MOVE_UP)
         EndIf
       EndIf

       ; Are we "below" the target slot?
       If ($targetSlot > $curSlot) Then
         If (canMoveDown($curSlot)) Then
            _ArrayAdd($pathToTarget, $MOVE_DOWN)
            updateCurSlotPos($curSlot, $MOVE_DOWN)
         EndIf
       EndIf
     WEnd

     _ArrayShuffle($pathToTarget)
     _ArrayConcatenate($path, $pathToTarget)
   EndIf

   Return $path
EndFunc

Func generateRandomMove(ByRef Const $curSlot)
   Local $validMoves = getValidMoves($curSlot)

   Return $validMoves[Random(0, UBound($validMoves) - 1, 1)]
EndFunc

Func getValidMoves(ByRef Const $curSlot)
   Local $validMoves[0]

   If (canMoveUp($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_UP)
   EndIf

   If (canMoveDown($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_DOWN)
   EndIf

   If (canMoveLeft($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_LEFT)
   ElseIf (canMoveRight($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_RIGHT)
   EndIf

   Return $validMoves
EndFunc

Func updateCurSlotPos(ByRef $curSlot, ByRef Const $move)
   Switch ($move)
     Case $MOVE_UP
       $curSlot -= 2
     Case $MOVE_DOWN
       $curSlot += 2
     Case $MOVE_LEFT
       $curSlot -= 1
     Case $MOVE_RIGHT
       $curSlot += 1
   EndSwitch
EndFunc

Func canMoveUp(Const ByRef $curSlot)
   If ($curSlot > 2) Then
     Return True
   EndIf

   Return False
EndFunc

Func canMoveDown(Const ByRef $curSlot)
   If ($curSlot < 7) Then
     Return True
   EndIf

   Return False
EndFunc

Func canMoveRight(Const ByRef $curSlot)
   Local Const $retValue = _MathCheckDiv($curSlot, 2)

   Switch ($retValue)
   Case $MATH_ISDIVISIBLE
     If ($curSlot < 8) Then
       Return True
     EndIf
   EndSwitch

   Return False
EndFunc

Func canMoveLeft(Const ByRef $curSlot)
   Local Const $retValue = _MathCheckDiv($curSlot, 2)

   Switch ($retValue)
   Case $MATH_ISNOTDIVISIBLE
     If ($curSlot > 1) Then
       Return True
     EndIf
   EndSwitch

   Return False
EndFunc


Of course: This is only the portion of a script that would be utilized after you've successfully entered the character selection screen.

This could be used on Single Player just as well as it could be used on Open Battle.net or even Battle.net itself.

This is a sample of the output with 20 maxMoves being made (starting position: slot #1; ending positon: slot #8):
[0]|4 - "MOVE_RIGHT" (1 -> 2)
[1]|3 - "MOVE LEFT" (2 -> 1)
[2]|2 - "MOVE_DOWN" (1 -> 3)
[3]|4 - "MOVE_RIGHT" (3 -> 5)
[4]|2 - "MOVE_DOWN" (5 -> 6)
[5]|1 - "MOVE UP" (6 -> 4)
[6]|2 - "MOVE_DOWN" (4 -> 6)
[7]|2 - "MOVE_DOWN" (6 -> 8)
[8]|3 - "MOVE LEFT" (8 -> 7)
[9]|1 - "MOVE UP" (7 -> 5)
[10]|4 - "MOVE_RIGHT" (5 -> 6)
[11]|1 - "MOVE UP" (6 -> 4)
[12]|1 - "MOVE UP" (4 -> 2)
[13]|3 - "MOVE LEFT" (2 -> 1)
[14]|2 - "MOVE_DOWN" (1 -> 3)
[15]|4 - "MOVE_RIGHT" (3 -> 4)
[16]|1 - "MOVE UP" (4 -> 2)
[17]|2 - "MOVE_DOWN" (2 -> 4)
[18]|1 - "MOVE UP" (4 -> 2)
[19]|2 - "MOVE_DOWN" (2 -> 4)
[20]|2 - "MOVE_DOWN" (4 -> 6)
[21]|2 - "MOVE_DOWN" (6 -> 8 (our target))

_________________
Image

Top
 Profile  
 Post subject: Re: [AutoIt] Creating Bots (for newbies)
PostPosted: Tue Mar 06, 2018 9:10 am 
 
Banned
Banned
User avatar

Joined: Sat Sep 06, 2008 7:18 am
Location: USA, TX
This project was started by: WiseWolf.
His thread: WiseWolf's account refresher.

- main.au3
#CS This was made by unguidedone@youtube in 2004
### I hope you enjoy using this script to refresh your mule army lol it sure has made my account management a lot easer.
### a lot of code was add / remove and i cannot count the versions of this but its stable
### however this does have very large limitations of it cannot detect a realm down or cdkey in use
### I am working on asm / c / c++ and trying to avoid autoit as much as possible because c++ is just so powerful but the learning it will take a while :\
### EDIT: Remodelled by Muted@BH -- 03/06/2018 01:52 (local time)
#CE

AutoItSetOption("WinWaitDelay", 250)   ; Default = 250ms (25% of 1 second)
AutoItSetOption("MouseCoordMode", 2)   ; 2 = relative coords to the client area of the active window
AutoItSetOption("PixelCoordMode", 2)   ; 2 = relative coords to the client area of the defined window
AutoItSetOption("MustDeclareVars", 1)   ; 1 = Variables must be pre-declared.
AutoItSetOption("WinTitleMatchMode", 3)   ; 3 = Exact title match
AutoItSetOption("WinTextMatchMode", 2)   ; 2 = 2 = Quick mode

; NOTE: This option will be modified later by the configuration file
AutoItSetOption("SendKeyDelay", Random(Random(500, 2000), Random(3500, 7500)))

; Non-standard functions for use in the manipulation of the game of: Diablo II
#include <D2Functions.au3>

;~ Call the main function to initate the program
main()

Func main()
   SRandom(@MSEC)

   Static Local $initialized = False

   If ($initialized == False) Then
     $initialized = True

     ; Terminates any open instances of "game.exe" (default = "game.exe")
    ; If (endProc(False) == True) Then
   ;    writeToLog(False, $LOG_NOTE, "Script initialization [ terminating game process ]")
    ; EndIf

     ; Verifies that all related files exist; creates necessary files at the user's request
     verifyFileTree()
   EndIf

   ;~ An array of all listed accounts / passwords in the config.ini file
   Local Const $accounts = getD2accountsInfo()

   ; Index referring to the current account we're on
   Local $accInfoIndex = 1

   Local $running = True

   While $running
     Sleep(1000)

     ;startD2($accounts[$accInfoIndex][0], "-skiptobnet -window -nosound -invincible")
     ;loginToAccount($accounts[$accInfoIndex][0], $accounts[$accInfoIndex][1])

     Local Const $quantityToRefresh = getD2charsToRefreshInfo($accounts[$accInfoIndex][0])
     Local $slots[0]

     For $n = 1 To $quantityToRefresh
       _ArrayAdd($slots, $n)
     Next

     _ArrayShuffle($slots)

     For $i = 0 To $quantityToRefresh - 1
       refreshCharacters($slots[$i])
     Next

     $accInfoIndex += 1

     $running = False
   WEnd

   ;endProc(False)

   Sleep(5000)

   ; Delete the locally generated BnetLog.txt file
   If (FileDelete("BnetLog.txt") == 0) Then
     writeToLog(False, $LOG_NOTE, "BnetLog.txt not deleted")
   EndIf
EndFunc

Func loginToAccount(Const ByRef $accountName, Const ByRef $accountPassword)
   writeToLog(False, $LOG_NOTE_LOGIN, "", True, $accountName)

   sendD2Keys($accountPassword)
   sendD2Keys("{ENTER}")

   ; INSERT ERROR CHECKING ROUTINE
   ;writeToLog($accountName, "FAILED")

   Return False
EndFunc

Func startD2(Const ByRef $accountName, Const ByRef $commandLineArguments)
#cs
   If (endProc() == True) Then
     writeToLog(False, $LOG_NOTE, "Script initialization [ terminating game process ]")
   EndIf
#ce

   ; Initializes Diablo II before running it (sets the registry flags AND path)
   initializeD2($accountName, $commandLineArguments)
EndFunc

Func initializeD2(Const ByRef $accountName, Const ByRef $commandLineArguments)
   Local Const $d2filepath = getD2FilePath()

   writeToLog(False, $LOG_NOTE, "Initializing Diablo II...", True, $accountName)

   ; Set the account name to auto-logon with
   RegWrite("HKEY_CURRENT_USER\Software\Blizzard Entertainment\Diablo II", "Last BNet", "REG_SZ", $accountName)

   If (@error <> 0) Then
     fatalErrorEscape("Unable to write to the registry [HKEY_CURRENT_USER\Software\Blizzard Entertainment\Diablo II\Last BNet]!")
   EndIf

   ; Set the commandline argument flag to be used
   RegWrite("HKEY_CURRENT_USER\Software\Blizzard Entertainment\Diablo II", "UseCmdLine", "REG_DWORD", 0x00000001)

   If (@error <> 0) Then
     fatalErrorEscape("Unable to write to the registry [HKEY_CURRENT_USER\Software\Blizzard Entertainment\Diablo II\UseCmdLine]!")
   EndIf

   ; Set commandline arguments to be used
   RegWrite("HKEY_CURRENT_USER\Software\Blizzard Entertainment\Diablo II", "CmdLine", "REG_SZ", $commandLineArguments)

   If (@error <> 0) Then
     fatalErrorEscape("Unable to write to the registry [HKEY_CURRENT_USER\Software\Blizzard Entertainment\Diablo II\CmdLine]!")
   EndIf

   If (Run($d2filepath) == 0) Then
     fatalErrorEscape("Unable to start Diablo II for an unknown reason -> " & @error)
   EndIf

   $d2hwnd = WinWait($d2classTitle, "", 30)

   If ($d2hwnd == 0) Then
     fatalErrorEscape("Diablo II window not found!!!")
   EndIf

   ; Ensures Diablo II is activated, in focus and moved to: (0, 0)
   pollD2()

   ; DELAY NEEDS TO BE REPLACED WITH PIXEL POINT CHECKS!
   Sleep(5000)
EndFunc


- D2Functions.au3
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;~ FILE NAME: D2Functions.au3
;~ LAST EDIT DATE: 3/6/2018 - 01:52
;~ LAST EDITED BY: Muted@BH (Muted @ syn.irc.net #bh)
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#cs
   PIXEL DETECTION FOR MENUS (3 points of contact each)

   MAIN MENU:
   -   0x040404 275x, 305y
   -   0x040404 275x, 365y
   -   0x28241C 535x, 420y

   BNET LOGIN:
   -   0x080404 325x, 325y
   -   0x3C3C3C 344x, 378y
   -   0x201814 475x, 465y

   CHAR. SELECTION:
   -   0x686868 750x, 100y
   -   0x747474 705x, 555y
   -   0x5C5C5C 65x, 550

   BNET LOBBY:
   -   0x141414 605x, 40y
   -   0x686458 665x, 460y
   -   0x040404 400x, 485y

   CHANNEL SCREEN:
   -   0x0C0C08 455x, 510y
   -   0x0C0C08 640x, 500y
   -   0x303094 400x, 470y

   CREATE GAME DIALOG MENU:
   -   0x040404 680x, 290y
   -   0x242424 665x, 90y
   -   0x241C10 500x, 90y

   IN GAME:
   -   0xB08848 305x, 585y stamina
   -   0x000058 730x, 540y blue orb
   -   0x5C0000 65x, 530y  red orb
#ce

#include-once

#include <MsgBoxConstants.au3>   ; Message box constants (for "magic numbers" for icons selected)
#include <WinAPIFiles.au3>      ; ReadIni() function
#include <TrayConstants.au3>    ; TrayTip() constant definitions
#include <AutoItConstants.au3>   ; ControlSend() constant definitions
#include <math.au3>            ; For deciding if a number is an EVEN or ODD value
#include <Array.au3>            ; For _ArrayXYZ() functions

AutoItSetOption("MustDeclareVars", 1)

Global $RESTART_ERROR_TOLERANCE = 1
Global $d2hwnd = WinGetHandle("[CLASS:Diablo II]")
Global const $d2classTitle = "[CLASS:Diablo II]"
Global $d2title = "Diablo II"
Global $scriptTitle = "wisewolf - Account Refresher"

; Log types (specifically for: writeToLog())
Global Enum $LOG_NOTE, $LOG_ERROR, $LOG_FATAL_ERROR, $LOG_NOTE_LOGIN, $LOG_NOTE_LOGOUT, $LOG_NOTE_CREATING_GAME, $LOG_NOTE_EXITING_GAME
Global Enum $MENU_MAIN, $MENU_NO_INTERNET, $MENU_REALM_DOWN, $MENU_CHAR_SELECTION, $MENU_LOBBY, $MENU_CHANNEL
Global Enum $MOVE_UP = 1, $MOVE_DOWN = 2, $MOVE_LEFT = 3, $MOVE_RIGHT = 4
Global Enum $ODD_NUM = 1, $EVEN_NUM = 2

Func isMenu($menuName)
EndFunc

; Returns all account names listed under "ACCOUNTS" section
Func getD2accountsInfo()
   Local Const $configFilePath = "config.ini"
   Local Const $accountsAndPasswords = IniReadSection($configFilePath, "ACCOUNTS & PASSWORDS")

   ; If the section doesn't exist or is empty (or the file doesn't exist): The program terminates early
   ; Alternative error handling procedure: Offer to create a default config.ini and /then/ terminate
   If (@error <> 0) Then
     fatalErrorEscape("ACCOUNTS & PASSWORDS section not found!")
   EndIf

   Return $accountsAndPasswords
EndFunc

; Returns number character slots to refresh
Func getD2charsToRefreshInfo(Const ByRef $accountName)
   Local Const $configFilePath = "config.ini"
   Local Const $accountsAndSlots = IniReadSection($configFilePath, "CHARACTER SLOTS")

   If (@error <> 0) Then
     fatalErrorEscape("CHARACTER SLOTS section not found OR has no key/value pairs!")
   EndIf

   Local $charSlots = 0

   For $n = 1 To $accountsAndSlots[0][0]
     if ($accountsAndSlots[$n][0] == $accountName) Then
       $charSlots = Int($accountsAndSlots[$n][1])
     EndIf
   Next

   If ($charSlots == 0) Then
     fatalErrorEscape("The account: " & $accountName & " has no listed value!")
   EndIf

   Return $charSlots
EndFunc

; Reads the registry and gets the executable path of the Diablo II game (game.exe)
Func getD2FilePath()
   Local Const $sFilePath = RegRead("HKEY_CURRENT_USER\Software\Blizzard Entertainment\Diablo II", "Program")

   If (@error <> 0) Then
     fatalErrorEscape("Unable to read registry key")
   EndIf

   Return $sFilePath
EndFunc

; Attempts to kill the Diablo II process (process name then program class name)
Func endProc(Const $waitOnKill = True, Const $procName = "game.exe")
   Local Const $retValue = endProcByPID($procName)

   If ($retValue < 5) Then
     Switch ($retValue)
     Case 4
       If (endProcByTitle($waitOnKill, $procName) == False) Then
         Return False
       EndIf
     Case Default
       fatalErrorEscape()
     EndSwitch
   EndIf

   Return True
EndFunc

; Tries to find the game via process name ("game.exe")
Func endProcByPID(ByRef Const $procName)
   If (ProcessExists($procName)) Then
     If (ProcessClose($procName) == 1) Then

       ; Magic constant value to represent all is good
       Return 5
     Else
       writeToLog(False, $LOG_ERROR, "Diablo II's process (" & $procName & ") could not be found! Returned: " & @error)
       Return @error
     EndIf
   EndIf

   ; "case 4" represents: "Cannot verify if process exists"
   Return 4
EndFunc

; Tries to find the game via class title name ("Diablo II")
Func endProcByTitle(Const $waitOnKill, ByRef Const $procName)
   Local Const $retValue = WinClose($d2hwnd)
   Local Static $titleNotFoundError = 0

   If ($titleNotFoundError >= $RESTART_ERROR_TOLERANCE) Then
     writeToLog(False, $LOG_ERROR, "Diablo II's process (" & $procName & ") could not be found!!!!")
     $titleNotFoundError = 0
     Return False
   EndIf

   ; The window title was found; Reset error counter, terminate the process
   If ($retValue == 1) Then
     $titleNotFoundError = 0
     WinKill($d2hwnd)
     Return True
   ElseIf ($titleNotFoundError >= 0 And $titleNotFoundError <= $RESTART_ERROR_TOLERANCE And $waitOnKill == True) Then
     Local $tempHandle = WinWait("", $d2classTitle, 60)

     If ($tempHandle <> 0) Then
       writeToLog(False, $LOG_ERROR, "Diablo II's process (" & $procName & ") could not be found! Count: " & $titleNotFoundError)
       $d2hwnd = $tempHandle
       $titleNotFoundError = 0
       endProcByTitle($d2hwnd)
     EndIf

     $titleNotFoundError += 1

     endProcByTitle($procName)
   EndIf

   Return False
EndFunc

; Posts a Message Box notice to the user, then writes to the logs, then aborts the script
Func fatalErrorEscape($text = "FATAL ERROR")
   writeToLog(False, $LOG_FATAL_ERROR, $text)
   MsgBox($MB_ICONERROR, "FATAL ERROR", "Please read the logs for more information!" & @CRLF & @CRLF & "" & @ScriptDir & "\logs.txt", 30)
   Exit(0)
EndFunc

; Uses the keyboard to select a character
; It enters the lobby then exits after a randomized delay
Func refreshCharacters(Const ByRef $slotNum)
   If (WinWait($d2hwnd, $d2classTitle, 60) == 0) Then
     fatalErrorEscape("WinWait() 60 second timeout triggered")
   EndIf

   ; This will definitely cause an issue with detectability -- The game client can easily tell when the title has been modified
   If (WinSetTitle($d2hwnd, "", "Character - " & $slotNum & " / 8") == 0) Then
     fatalErrorEscape("Unable to find Diablo II's window!")
   EndIf

   ; Update global variable referring to Diablo II's title
   $d2title = "Character - " & $slotNum & " / 8"

   writeToLog(False, $LOG_NOTE, "Setting Diablo II's title to: " & $d2title)

   Local Const $configFilePath = "config.ini"
   Local Const $delays = IniReadSection($configFilePath, "DELAYS")

   If (@error <> 0) Then
     fatalErrorEscape("Unable to read DELAYS section of config.ini file OR no key/value pairs were found!")
   EndIf

   Local $minMainMenuDelay = 0
   Local $maxMainMenuDelay = 0
   Local $minCharSelectionDelay = 0
   Local $maxCharSelectionDelay = 0
   Local $minPreLobbyDelay = 0
   Local $maxPreLobbyDelay = 0
   Local $minChannelLobby = 0
   Local $maxChannelLobby = 0
   Local $minKeyInput = 0
   Local $maxKeyInput = 0
   Local $randomRangedDelay = 0

   Local $KEY_FLAGS[11] = [ False, False, False, False, False, False, False, False, False, False, False ]

   For $n = 1 To $delays[0][0]
     if ($delays[$n][0] == "minMainMenu") Then
       $minMainMenuDelay = Int($delays[$n][1])
       $KEY_FLAGS[0] = True
     ElseIf ($delays[$n][0] == "maxMainMenu") Then
       $maxMainMenuDelay = Int($delays[$n][1])
       $KEY_FLAGS[1] = True
     ElseIf ($delays[$n][0] == "minCharSelection") Then
       $minCharSelectionDelay = Int($delays[$n][1])
       $KEY_FLAGS[2] = True
     ElseIf ($delays[$n][0] == "maxCharSelection") Then
       $maxCharSelectionDelay = Int($delays[$n][1])
       $KEY_FLAGS[3] = True
     ElseIf ($delays[$n][0] == "minPreLobby") Then
       $minPreLobbyDelay = Int($delays[$n][1])
       $KEY_FLAGS[4] = True
     ElseIf ($delays[$n][0] == "maxPreLobby") Then
       $maxPreLobbyDelay = Int($delays[$n][1])
       $KEY_FLAGS[5] = True
     ElseIf ($delays[$n][0] == "minChannelLobby") Then
       $minChannelLobby = Int($delays[$n][1])
       $KEY_FLAGS[6] = True
     ElseIf ($delays[$n][0] == "maxChannelLobby") Then
       $maxChannelLobby = Int($delays[$n][1])
       $KEY_FLAGS[7] = True
     ElseIf ($delays[$n][0] == "minKeyInput") Then
       $minKeyInput = Int($delays[$n][1])
       $KEY_FLAGS[8] = True
     ElseIf ($delays[$n][0] == "maxKeyInput") Then
       $maxKeyInput = Int($delays[$n][1])
       $KEY_FLAGS[9] = True
     ElseIf ($delays[$n][0] == "randomRangedDelay") Then
       $randomRangedDelay = Int($delays[$n][1])
       $KEY_FLAGS[10] = True
     EndIf
   Next

   ; "opt" or "AutoItSetOption" can be called to modify script-level options
   ; "SendKeyDelay" modifies the delay in between sending emulated input
   ;AutoItSetOption("SendKeyDelay", Random($minKeyInput, $maxKeyInput))
   AutoItSetOption("SendKeyDelay", 0)

   ; Delay to sit on the character selection screen (5s - 40s)
   ;Sleep(Random(Random($minCharSelectionDelay, ($minCharSelectionDelay + $randomRangedDelay)), Random($maxCharSelectionDelay, ($maxCharSelectionDelay + $randomRangedDelay))))

   writeToLog(False, $LOG_NOTE, "Send key stroke!")

   Local $maxMoves = Random(1, 200)

   Local $path = generateRandomPath(1, $slotNum, $maxMoves)

   _ArrayDisplay($path, "KEYS TO PRESS")

   sendEncodedKeys($path)

   ; Delay to sit in the lobby
   ;Sleep(Random(Random($minPreLobbyDelay, ($minPreLobbyDelay + $randomRangedDelay)), Random($maxPreLobbyDelay, ($maxPreLobbyDelay + $randomRangedDelay))))

   ; Exit the lobby screen
   ;sendD2Keys("{ESC}")

   ; Delay to sit in the character selection screen
   ;Sleep(Random(Random($minCharSelectionDelay, ($minCharSelectionDelay + $randomRangedDelay)), Random($maxCharSelectionDelay, ($maxCharSelectionDelay + $randomRangedDelay))))
EndFunc

Func sendEncodedKeys(ByRef Const $path)
   For $n = 0 To UBound($path) - 1
     Local $key = decodePathKey($path[$n])

     If (ControlSend($d2hwnd, "", "", $key, $SEND_DEFAULT) == 0) Then
       fatalErrorEscape("Unable to send keys to Diablo II window!")
     EndIf
   Next

   ; Enter the lobby with said character
   ;sendD2Keys("{ENTER}")
EndFunc

Func decodePathKey(ByRef Const $key)
   Switch ($key)
     Case $MOVE_UP
       Return ("{UP}")
     Case $MOVE_DOWN
       Return ("{DOWN}")
     Case $MOVE_LEFT
       Return ("{LEFT}")
     Case $MOVE_RIGHT
       Return ("{RIGHT}")
   EndSwitch
EndFunc

; Verifies that a single file exists; returns false if it does not
Func verifyFile(Const $fileName)
   Local Const $filePath = $fileName
   Local Const $fileExist = FileExists($filePath)

   If ($fileExist == 0) Then
     Return False
   EndIf

   Return True
EndFunc

; Verifies that all files (config.ini and logs.txt) exist
Func verifyFileTree()
   If (verifyFile("config.ini") == False) Then
     createDefaultConfigFile()
   EndIf

   If (verifyFile("logs.txt") == False) Then
     createDefaultLogFile()
   EndIf
EndFunc

; Creates a default config.ini file if the user desires
Func createDefaultConfigFile()

   ; If the user clicks "YES": Generate a new default config.ini file
   If (MsgBox($MB_YESNO, "ERROR - config.ini not found", _
                  @ScriptDir & "\config.ini was not found" & @CRLF & @CRLF & _
                  "Would you like to create the default config.ini file?") == $IDYES) Then

     Local Const $fileStream = FileOpen("config.ini", $FO_APPEND)

     If ($fileStream == -1) Then
       MsgBox($MB_ICONERROR, $scriptTitle & " - FATAL ERROR", "Unable to write to: config.ini")
       Exit(0)
     EndIf

     If (FileWrite($fileStream, _
       "[ACCOUNTS & PASSWORDS]" & @CRLF _
       & "Name = insert_account_name_#1_here" & @CRLF _
       & "Name = insert_account_name_#2_here" & @CRLF & @CRLF _
       & "" _
       & "[PASSWORDS]" & @CRLF _
       & "insert_account_name_#1_here = insert_account_password_#1_here" & @CRLF _
       & "insert_account_name_#2_here = insert_account_password_#2_here" & @CRLF & @CRLF _
       & "" _
       & "[DELAYS]" & @CRLF _
       & "minMainMenu = 30000" & @CRLF _
       & "maxMainMenu = 60000" & @CRLF _
       & "minCharSelection = 10000" & @CRLF _
       & "maxCharSelection = 30000" & @CRLF _
       & "minPreLobby = 60000" & @CRLF _
       & "maxPreLobby = 180000" & @CRLF _
       & "minChannelLobby = 10000" & @CRLF _
       & "maxChannelLobby = 60000" & @CRLF _
       & "minKeyInput = 5000" & @CRLF _
       & "maxKeyInput = 10000" & @CRLF _
       & "randomRangedDelay = 10000" & @CRLF & @CRLF _
       & "" _
       & "[ACCOUNT SWAP DELAYS]" & @CRLF _
       & "delayEvery = 1" & @CRLF _
       & "accountSwapDelay = 14400000") == 0) Then
         MsgBox($MB_ICONERROR, $scriptTitle & " - ERROR", "Unable to write to: config.ini", 30)
     EndIf

     If (FileClose($fileStream) == 0) Then
       MsgBox($MB_ICONERROR, $scriptTitle & " - FATAL ERROR", "Filehandle is invalid: config.ini")
       Exit(0)
     EndIf
   EndIf
EndFunc

; Creates a blank "default" logs.txt file if the user desires
Func createDefaultLogFile()

   ; If the user clicks "YES": Generate a new default log file
   If (MsgBox($MB_YESNO, "ERROR - logs.txt not found", "logs.txt was not found" & @CRLF & @CRLF & "Would you like to create the default log file?") == $IDYES) Then
     Local Const $fileStream = FileOpen("logs.txt", $FO_APPEND)

     If ($fileStream == -1) Then
       MsgBox($MB_ICONERROR, $scriptTitle & " - FATAL ERROR", "Unable to write to: logs.txt")
       Exit(0)
     EndIf

     If (FileClose($fileStream) == 0) Then
       MsgBox($MB_ICONERROR, $scriptTitle & " - FATAL ERROR", "Filehandle is invalid: logs.txt")
       Exit(0)
     EndIf
   EndIf
EndFunc

; Writes to the logs.txt file (states = START, END, FAILED and NOTE)
Func writeToLog(Const ByRef $tolerateNoWrite, Const ByRef $LOG_TYPE, Const $text = "", Const $TRAY_FLAG = False, Const $accountName = "")
   Local Const $fileStream = FileOpen("logs.txt", $FO_APPEND)

   If ($tolerateNoWrite == False) Then
     If ($fileStream == -1) Then
       MsgBox($MB_ICONERROR, $scriptTitle & " - FATAL ERROR", "Unable to write to: logs.txt")
       Exit(0)
     EndIf
   EndIf

   Local Const $currTime = "[" & @YEAR & "/" & @MON & "/" & @MDAY & " - " & @HOUR & ":" & @MIN & ":" & @SEC & "]"

   Switch ($LOG_TYPE)
     Case $LOG_NOTE
       If (FileWrite($fileStream, $currTime & " " & "SCRIPT AUTOMATION" & @CRLF & "NOTE: " & $text & @CRLF & @CRLF) == 0) Then
         MsgBox($MB_ICONERROR, $scriptTitle & " - ERROR", "Unable to write to: logs.txt", 30)
       EndIf
     Case $LOG_ERROR
       If (FileWrite($fileStream, $currTime & " " & "SCRIPT AUTOMATION" & @CRLF & "ERROR: " & $text & @CRLF & @CRLF) == 0) Then
         MsgBox($MB_ICONERROR, $scriptTitle & " - ERROR", "Unable to write to: logs.txt", 30)
       EndIf
     Case $LOG_FATAL_ERROR
       If (FileWrite($fileStream, $currTime & " " & "SCRIPT AUTOMATION" & @CRLF & "FATAL ERROR: " & $text & @CRLF & @CRLF) == 0) Then
         MsgBox($MB_ICONERROR, $scriptTitle & " - ERROR", "Unable to write to: logs.txt", 30)
       EndIf
     Case $LOG_NOTE_LOGIN
       If (FileWrite($fileStream, $currTime & " " & $accountName & @CRLF & "Logging in..." & @CRLF & @CRLF) == 0) Then
         MsgBox($MB_ICONERROR, $scriptTitle & " - ERROR", "Unable to write to: logs.txt", 30)
       EndIf
     Case $LOG_NOTE_LOGOUT
       If (FileWrite($fileStream, $currTime & " " & $accountName & @CRLF & "Logging out..." & @CRLF & @CRLF) == 0) Then
         MsgBox($MB_ICONERROR, $scriptTitle & " - ERROR", "Unable to write to: logs.txt", 30)
       EndIf
     Case $LOG_NOTE_CREATING_GAME
       If (FileWrite($fileStream, $currTime & " " & $accountName & @CRLF & "Creating game: " & $text & @CRLF & @CRLF) == 0) Then
         MsgBox($MB_ICONERROR, $scriptTitle & " - ERROR", "Unable to write to: logs.txt", 30)
       EndIf
     Case $LOG_NOTE_EXITING_GAME
       If (FileWrite($fileStream, $currTime & " " & $accountName & @CRLF & "Exiting game..." & @CRLF & @CRLF) == 0) Then
         MsgBox($MB_ICONERROR, $scriptTitle & " - ERROR", "Unable to write to: logs.txt", 30)
       EndIf
   EndSwitch

   If ($TRAY_FLAG == True) Then
     ; Clear the TrayTip - https://www.autoitscript.com/autoit3/docs/functions/TrayTip.htm
     TrayTip("", "", 0, $TIP_NOSOUND)

     Switch ($LOG_TYPE)
     Case $LOG_NOTE
         TrayTip("wisewolf - SCRIPT AUTOMATION", "NOTE: " & @CRLF & $text, 10, $TIP_ICONASTERISK)
       Case $LOG_ERROR
         TrayTip("wisewolf - SCRIPT AUTOMATION", "ERROR: " & @CRLF & $text, 10, $TIP_ICONHAND)
       Case $LOG_FATAL_ERROR
         TrayTip("wisewolf - SCRIPT AUTOMATION", "FATAL ERROR: " & @CRLF & $text, 10, $TIP_ICONHAND)
       Case $LOG_NOTE_LOGIN
         TrayTip("wisewolf - SCRIPT AUTOMATION", $accountName & @CRLF & "Logging in...", 10, $TIP_ICONASTERISK)
       Case $LOG_NOTE_LOGOUT
         TrayTip("wisewolf - SCRIPT AUTOMATION", $accountName & @CRLF & "Logging out...", 10, $TIP_ICONASTERISK)
       Case $LOG_NOTE_CREATING_GAME
         TrayTip("wisewolf - SCRIPT AUTOMATION", $accountName & @CRLF & "Creating game: " & $text, 10, $TIP_ICONASTERISK)
       Case $LOG_NOTE_EXITING_GAME
         TrayTip("wisewolf - SCRIPT AUTOMATION", $accountName & @CRLF & "Exiting game...", 10, $TIP_ICONASTERISK)
     EndSwitch
   EndIf

   If (FileClose($fileStream) == 0) Then
     MsgBox($MB_ICONERROR, $scriptTitle & " - FATAL ERROR", "Filehandle is invalid: logs.txt")
     Exit(0)
   EndIf
EndFunc

Func sendD2Keys(Const ByRef $keys)
#cs
   pollD2() + Send() is a 'safe' way in the sense that it'll pop the window up before typing
   ControlSend() will send key strokes in the background -- ATTACHES A THREAD TO CALLED PROCESS (detectable / possible ban)
#ce

   ;pollD2()
   ;Send($keys)

   If (ControlSend($d2hwnd, "", "", $keys, $SEND_DEFAULT) == 0) Then
     fatalErrorEscape("Unable to send keys to Diablo II window!")
   EndIf
EndFunc

Func pollD2()
   If (WinActivate($d2hwnd, $d2classtitle) == 0) Then
     fatalErrorEscape("Unable to find Diablo II window!")
   EndIf

   If (WinMove($d2hwnd, $d2classtitle, 0, 0) == 0) Then
     fatalErrorEscape("Unable to find Diablo II window!")
   EndIf

   $d2hwnd = WinWaitActive($d2hwnd, $d2classtitle)

   If ($d2hwnd == 0) Then
     fatalErrorEscape("Unable to find Diablo II window!")
   EndIf
EndFunc

; [Artificial Intelligence] Genetic algorithm to randomize pathing to selected character
Func generateRandomPath(ByRef $curSlot, Const ByRef $targetSlot, Const ByRef $maxMoves)
   Local $path[$maxMoves]

   ;MsgBox(0, "NOTE", "curSlot: " & $curSlot)

   For $n = 0 To $maxMoves - 1
      $path[$n] = generateRandomMove($curSlot)
      updateCurSlotPos($curSlot, $path[$n])
   Next

   If ($curSlot <> $targetSlot) Then
     MsgBox(0, "NOT ON TARGET (single logic)", "curSlot: " & $curSlot & @CRLF & "targetSlot: " & $targetSlot)
     Local $pathToTarget[0]

     Local Const $targetSide = _MathCheckDiv($targetSlot, 2)
     If ($targetSide == $MATH_ISDIVISIBLE) Then
       If (canMoveRight($curSlot)) Then
         _ArrayAdd($pathToTarget, $MOVE_RIGHT)
         updateCurSlotPos($curSlot, $MOVE_RIGHT)
       EndIf
     ElseIf ($targetSide == $MATH_ISNOTDIVISIBLE) Then
       If (canMoveLeft($curSlot)) Then
         _ArrayAdd($pathToTarget, $MOVE_LEFT)
         updateCurSlotPos($curSlot, $MOVE_LEFT)
       EndIf
     EndIf

     While ($curSlot <> $targetSlot)
       ; Are we "above" the target slot?
       If ($targetSlot < $curSlot) Then
         If (canMoveUp($curSlot)) Then
            _ArrayAdd($pathToTarget, $MOVE_UP)
            updateCurSlotPos($curSlot, $MOVE_UP)
         EndIf
       EndIf

       ; Are we "below" the target slot?
       If ($targetSlot > $curSlot) Then
         If (canMoveDown($curSlot)) Then
            _ArrayAdd($pathToTarget, $MOVE_DOWN)
            updateCurSlotPos($curSlot, $MOVE_DOWN)
         EndIf
       EndIf
     WEnd

     _ArrayShuffle($pathToTarget)
     _ArrayConcatenate($path, $pathToTarget)
   EndIf

   Return $path
EndFunc

Func generateRandomMove(ByRef Const $curSlot)
   Local $validMoves = getValidMoves($curSlot)
   ;_ArrayDisplay($validMoves, "$validMoves")

   Return $validMoves[Random(0, UBound($validMoves) - 1, 1)]
EndFunc

Func getValidMoves(ByRef Const $curSlot)
   Local $validMoves[0]

   If (canMoveUp($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_UP)
   EndIf

   If (canMoveDown($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_DOWN)
   EndIf

   If (canMoveLeft($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_LEFT)
   ElseIf (canMoveRight($curSlot)) Then
      _ArrayAdd($validMoves, $MOVE_RIGHT)
   EndIf

   Return $validMoves
EndFunc

Func updateCurSlotPos(ByRef $curSlot, ByRef Const $move)
   Switch ($move)
     Case $MOVE_UP
       $curSlot -= 2
     Case $MOVE_DOWN
       $curSlot += 2
     Case $MOVE_LEFT
       $curSlot -= 1
     Case $MOVE_RIGHT
       $curSlot += 1
   EndSwitch
EndFunc

Func canMoveUp(Const ByRef $curSlot)
   If ($curSlot > 2) Then
     Return True
   EndIf

   Return False
EndFunc

Func canMoveDown(Const ByRef $curSlot)
   If ($curSlot < 7) Then
     Return True
   EndIf

   Return False
EndFunc

Func canMoveRight(Const ByRef $curSlot)
   Local Const $retValue = _MathCheckDiv($curSlot, 2)

   Switch ($retValue)
   Case $ODD_NUM
     If ($curSlot < 8) Then
       Return True
     EndIf
   EndSwitch

   Return False
EndFunc

Func canMoveLeft(Const ByRef $curSlot)
   Local Const $retValue = _MathCheckDiv($curSlot, 2)

   Switch ($retValue)
   Case $EVEN_NUM
     If ($curSlot > 1) Then
       Return True
     EndIf
   EndSwitch

   Return False
EndFunc


This another prime example of how even a simple language such as AutoIt3 can be bent into something useful.

_________________
Image

Top
 Profile  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 54 posts ]  Go to page Previous  1, 2, 3, 4

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 0 guests


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

Search for:
Jump to:  
cron