AutoHotkey Community

It is currently May 26th, 2012, 7:35 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: May 7th, 2009, 9:22 pm 
Offline

Joined: May 7th, 2009, 9:03 pm
Posts: 13
Hey everyone. I am trying to write a script for turn-based web RPG. Just in case - the game's creator has given a go-ahead for 3rd party scripting.

Before I paste the code I have, let me briefly describe the goal. The point is very simple - automate killing monsters. Here is the program logic. I check each attack because I may not have the mana to perform it.

Step 1) Check if monster is alive. If Alive, use IDS attack. If dead, Heal.
Step 2) Check if IDS is available. If yes, use it and GOSUB, Step 1). If no, check if DS attack is available.
Step 3) Check if DS is available. If yes, use it, and GOSUB Step 1). If no, check if regular Attack is available.
Step 4) Check if Attack is available. If yes, use it and GOSUB, Step 1). If no, GOSUB Heal
Step 5) Healing routine. Click Healing. Check if page stopped loading. If yes, click Hunt - if no, wait. Check if page stopped loading after clicking Hunt.

That's it in a nutshell. My problem is that I don't have a loop that's set in stone. The monster may die after the first two attacks or the fight may drag on for a while. I tried using GOSUB to tell the script to jump to specific steps if the monster is still alive and depending on availability of attacks. I put "Step 1" in my main loop, but I receive an Enclosure error when I try to compile: Error: A Goto/Gosub must not jump into a block that doesn't enclose it.

Here is the code I have so far.

I would greatly appreciate if someone could tell me how to best string these steps together for AHK so my script stays flexible. Thank you in advance!

Code:
loop, 90
{
MONSTER:
ImageSearch, MONX, MONY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\looted.bmp ;Check if Monster is dead
   if ErrorLevel = 1
      Gosub, IDS
   if ErrorLevel = 0
      Gosub, HEAL
}

/*
Below is the IDS routine.  The app tries to find IDS, if it does, it clicks it. if it fails it goes to DS.
*/

IDS:
ImageSearch, IDSX, IDSY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\ids.bmp ;Check IDS location
if ErrorLevel = 1
   Gosub, DS
if ErrorLevel = 0
   2IDSX := IDSX + 10
   2IDSY := IDSY + 10
   Click %2IDSX% %2IDSY%
   Gosub, MONSTER
return


/*
Below is the DS routine. The app tries to find the DS, if it does, it clicks it. If it fails, it goes to Attack.
*/

DS:
ImageSearch, DSX, DSY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\ds.bmp ;Check DS location
if ErrorLevel = 1
   Gosub, ATTACK
if ErrorLevel = 0
   2DSX := DSX + 10
   2DSY := DSY + 10
   Click %2DSX% %2DSY%
   Gosub, MONSTER
return

/*
Below is the Attack routine. The app tries to find the Attack, if it does, it clicks it. If it fails, it goes to Healing Routine.
*/
ATTACK:
ImageSearch, ATTACKX, ATTACKY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\attack.bmp ;Check Attack location
if ErrorLevel = 1
   Gosub, HEAL
if ErrorLevel = 0
   2ATTACKX := ATTACKX + 10
   2ATTACKY := ATTACKY + 10
   Click %2ATTACKX% %2ATTACKY%
   Gosub, MONSTER
return

/*
Below is the healing routine where the app finds the healing link, clicks it, waits for page to load.  Then finds the hunt area link,
clicks it, waits for page to load.
*/

HEAL:
ImageSearch, HEALX, HEALY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\heal.bmp ;Check Healer location
2HEALX := HEALX + 10
2HEALY := HEALY + 10
Click %2HEALX% %2HEALY%
loop
{
ImageSearch, LOADINGX, LOADINGY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\loading.bmp ;Check if page is still loading
if ErrorLevel = 1
   Continue
if ErrorLevel = 0
   Sleep, 100
}
ImageSearch, HUNTX, HUNTY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\cg.bmp ;Check Hunt location
2HUNTX := HUNTX + 10
2HUNTY := HUNTY + 10
Click %2HUNTX% %2HUNTY%
loop
{
ImageSearch, LOADINGX, LOADINGY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\loading.bmp ;Check if page is still loading
if ErrorLevel = 1
   Continue
if ErrorLevel = 0
   Sleep, 100
}
return


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 7th, 2009, 10:35 pm 
Offline

Joined: May 7th, 2009, 9:03 pm
Posts: 13
I am looking at the Seek example in AHK Help. Phi (the creator) used Gosub from within a loop, but I guess my problem is that I have a Gosub that references BACK to a loop...

Crap, I might have to rethink the logic behind my script...

Does anyone have any suggestions on how I can string the above steps together?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 7th, 2009, 11:21 pm 
Offline
User avatar

Joined: March 19th, 2008, 12:43 am
Posts: 5480
Location: the tunnel(?=light)
Well I can't see why you can't initiate Monster from SetTimer, which you can use in effect like a loop, then when the script reaches the termination point you can just turn the timer off?

_________________
Image
Try Quick Search for Autohotkey or see the tutorial for newbies.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 8th, 2009, 12:44 am 
Offline

Joined: May 7th, 2009, 9:03 pm
Posts: 13
I understand what you mean, but everything depends on whether the monster is alive or dead - hence why I check its status after each attack.

If the monster is still alive, I need to attack (with progressively weaker attacks as my mana decreases). If the monster is dead then I need to heal+return to battle via the "Heal routine" at the end of the file.

One thing I've tried is making the check on whether the monster is alive a part of each attack by calling the monster check health module after each attack.

To be honest it's very hard to keep on when even something as simple as this...

Code:
INS::Pause

!z::
ImageSearch, 2IDSX, 2IDSY, 777, 700, 1150, 750, C:\GAME\ids.bmp
if ErrorLevel = 1
{
   MsgBox NOT FOUND
}
if ErrorLevel = 0
{
   2IDSX := IDSX + 20
   2IDSY := IDSY + 20
   Click %2IDSX% %2IDSY%
   Sleep, 100
   MsgBox DONE
}


...fails to work.

I really don't know what the hell.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 8th, 2009, 3:09 am 
Offline
User avatar

Joined: March 19th, 2008, 12:43 am
Posts: 5480
Location: the tunnel(?=light)
34t wrote:
To be honest it's very hard to keep on when even something as simple as this...fails to work.


I have a feeling I know what's wrong with this little script though:

Code:
INS::Pause

!z::
ImageSearch, IDSX, IDSY, 777, 700, 1150, 750, C:\GAME\ids.bmp
if ErrorLevel = 1
{
   MsgBox NOT FOUND
}
if ErrorLevel = 0
{
   2IDSX := IDSX + 20
   2IDSY := IDSY + 20
   Click %2IDSX% %2IDSY%
   Sleep, 100
   MsgBox DONE
}


But back to the larger script, did you try just literally writing out everything you'd like to work? I think I made a literal representation of it:

Code:
Loop, 90
{
  ImageSearch, MONx, MONy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\looted.bmp
  if (ErrorLevel)
  {
    ImageSearch, IDSx, IDSy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\ids.bmp
    if (ErrorLevel)
    {
      ImageSearch, DSx, DSy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\ds.bmp
      if (ErrorLevel)
      {
        ImageSearch, ATTACKx, ATTACKy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\attack.bmp
        if (ErrorLevel)
        {
          ImageSearch, HEALx, HEALy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\heal.bmp
          HEALx += 10
          HEALy += 10
          Click %HEALx% %HEALy%
          loop
          {
            ImageSearch, LOADINGx, LOADINGy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\loading.bmp
            if (ErrorLevel)
              Continue
          }
          ImageSearch, HUNTx, HUNTy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\cg.bmp
          HUNTx += 10
          HUNTy += 10
          Click %HUNTx% %HUNTy%
          loop
          {
            ImageSearch, LOADINGx, LOADINGy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\loading.bmp
            if (ErrorLevel)
              Continue
            }
            return
          }
          Else
          {
            ATTACKx += 10
            ATTACKy += 10
            Click %ATTACKx% %ATTACKy%
            Return
          }
        }
        Else
        {
          DSx += 10
          DSy += 10
          Click %DSx% %DSy%
          Return
          }
        }
        Else
        {
          IDSx += 10
          IDSy += 10
          Click %IDSx% %IDSy%
          return
        }
      }
      Else
      {
        ImageSearch, HEALX, HEALY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\heal.bmp
        HEALx += 10
        HEALy += 10
        Click %HEALx% %HEALy%
        Loop
        {
          ImageSearch, LOADINGx, LOADINGy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\loading.bmp
          if (ErrorLevel)
            Continue
        }
        ImageSearch, HUNTx, HUNTy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\cg.bmp
        HUNTx += 10
        HUNTy += 10
        Click %HUNTx% %HUNTy%
        Loop
        {
          ImageSearch, LOADINGx, LOADINGy, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\loading.bmp
          if (ErrorLevel)
            Continue
        }
        Return
  }
}

_________________
Image
Try Quick Search for Autohotkey or see the tutorial for newbies.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 8th, 2009, 6:50 am 
Offline

Joined: May 7th, 2009, 9:03 pm
Posts: 13
GREAT SUCCESS! (Although I'm still keeping my fingers crossed).

My biggest problem before was trusting the BMP format too much. Things started falling into place after I included a "*20" so my ImageSearch had some flexibility.

Currently I have a script that is smart - it makes selections depending on whether the monster is alive AND on whether I have the mana to perform a certain action. Furthermore this script can work with any size monitor and any window position (as long as the images are fully viewable).

I would like to make my script better!.

I am playing the game in Firefox and would like each action to take place after the page finishes loading instead of after a set SLEEP amount of time. This is easy enough to accomplish by checking that the little circle in the upper-right corner of Firefox has stopped spinning (via ImageSearch).

I can even intigrate this additional ImageSearch into my Subs (instead of immediatly going to the next Sub, run the FINISHLOADING 'routine').

The problem I face is making this routine somehow continue running until the page stops loading!

Here's a part of my script:
Code:
HEAL:
ImageSearch, HEALX, HEALY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\heal.bmp ;Go to the Healer
   2HEALX := HEALX + 5
   2HEALY := HEALY + 5
   Click %2HEALX% %2HEALY%
ImageSearch, HEALX, HEALY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\loading.bmp ;Check that the page has finished loading
if ErrorLevel = 1 ;Keep searching if page is still loading

;***!!!***!!!***

if ErrorLevel = 0 ;Go to next routine if page is loaded
   Gosub, HUNT


My problem is that I have zero idea of what to put in the "***!!!***!!!***" spot that would keep the ImageSearch going until the page is fully loaded.

I would greatly appreciate any suggestions because I don't know any loop-back options. I'm thinking of how I can put a loop there, but it sounds impossible?

P.S. Thank you for your help sinkfaze, it helped me keep going past my first stupid mistakes :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 8th, 2009, 10:40 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
I don't know how much your script has changed, but briefly looking at the script in your first post, you may be misunderstanding If and Gosub:
Code:
IDS:
ImageSearch, IDSX, IDSY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\ids.bmp ;Check IDS location
if ErrorLevel = 1
   Gosub, DS
if ErrorLevel = 0
   2IDSX := IDSX + 10
   ; Judging by the indentation, the following lines should belong to the above IF.  THEY DON'T.  ONLY the line above does.  Use { braces } to group lines.
   2IDSY := IDSY + 10
   Click %2IDSX% %2IDSY%
   ; This cannot work because MONSTER is contained within the loop.  However, it is NOT NECESSARY, because the 'return' below will return to the point that 'Gosub, IDS' was called, which is inside the MONSTER loop.
   Gosub, MONSTER
return
A revised subroutine might look like:
Code:
IDS:
ImageSearch, IDSX, IDSY, 0, 0, A_ScreenWidth, A_ScreenHeight, C:\GAME\ids.bmp ;Check IDS location
if ErrorLevel = 1
   Gosub, DS
if ErrorLevel = 0
{
   2IDSX := IDSX + 10
   2IDSY := IDSY + 10
   Click %2IDSX% %2IDSY%
}
return
However, merging the subroutines as sinkfaze has done might be better.

You might like to read Blocks, Gosub, and Goto.
Quote:
keep the ImageSearch going until the page is fully loaded.
Assuming loading.bmp contains the "finished loading" image,
Code:
Gosub WaitUntilLoaded
;...
WaitUntilLoaded:
Loop
{   ; Note that OutputVarX/Y may be omitted if we don't need them:
    ImageSearch, , , 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\loading.bmp
    if ErrorLevel = 0
        break ; Done loading, continue with script.
    Sleep, 100
}
return ; Continues execution at the line after Gosub.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 9th, 2009, 2:42 am 
Offline

Joined: May 7th, 2009, 9:03 pm
Posts: 13
Thank you very much for your post Lexikos, it was a great help! The WaitUntilLoaded sub you propose works flawlessly and speeds up the script a ton. I will be reusing that piece of code many times because it makes life MUCH simpler than relying on Sleep.

There currently is no loop, although I need to make one for when the user wants to execute the script (which by itself represents one completed battle) multiple times - e.g. fight several enemies in a row. I have tried inserting ALL the subs into a loop (AHK forces me to insert all of them into a loop because otherwise I get the dreaded A Goto/Gosub must not jump into a block that doesn't enclose it error) with mixed results. The best I have been able to get is a loop that runs forever (regardless of the "Loop, #" specification) and that for some reason first uses the DS attack instead of IDS the moment it fights a new monster after returning from the Healer. The worst case scenario is one where the scripts gets endlessly stuck in the HEAL sub :( I have a few ideas I want to explore, but suggestions are really appreciated.

Below I include all of my code as it currently is. I took your advice to heart and added curly braces everywhere as best practice, (for some reason my script worked as intended without them, but better safe than sorry :shock: ). I must admit that I have a hard time understanding "Return"... where will the script return to after it sees that command at the end of the sub?

I will also read on the three articles you linked to.

This is my current code:
Code:
Home::Pause
!Home::Reload

/*
Remember to change the location of the image files and test the image search areas before running.  Using temporary

hotkey x before finishing testing a loop and GUI.
*/

x::
/*
This sub attempts to use the IDS attack.  Goes to DS attack sub if it can't
*/
IDS:
ImageSearch, IDSX, IDSY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ids.bmp
if ErrorLevel = 1
{
   Gosub DS
}
else
{
   2IDSX := IDSX + 5
   2IDSY := IDSY + 5
   Click %2IDSX% %2IDSY%
   Gosub LOADING
   Gosub MONSTER
}
return


/*
This sub checks if the monster has died.  If the monster is dead, it goes to Healing sub, if it's still alive, then it

goes to IDS attack sub. All attack subs check if the monster is dead after executing.
*/
MONSTER:
ImageSearch, , , 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\looted.bmp ;Check if Monster is dead
if ErrorLevel = 1
{
   Gosub IDS
}
if ErrorLevel = 0
{
   Gosub HEAL
}
return

/*
This is the DS attack sub. If the DS attack is unavailable, the sub goes to the regular Attack sub.
*/
DS:
ImageSearch, DSX, DSY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ds.bmp
if ErrorLevel = 1
{
   Gosub ATTACK
}
if ErrorLevel = 0
{
   2DSX := DSX + 5
   2DSY := DSY + 5
   Click %2DSX% %2DSY%
   Gosub LOADING
   Gosub MONSTER
}
return


/*
This is the regular Attack sub. If this sub can't find regular attack that's always available then it knows the monster

is dead and goes to the Healing sub.
*/
ATTACK:
ImageSearch, ATTACKX, ATTACKY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\attack.bmp
if ErrorLevel = 1
{
   Gosub HEAL
}
if ErrorLevel = 0
{
   2ATTACKX := ATTACKX + 5
   2ATTACKY := ATTACKY + 5
   Click %2ATTACKX% %2ATTACKY%
   Gosub LOADING
   Gosub MONSTER
}
return


/*
This is the Healing sub where the app finds and clicks the healing link that is always available in the same place.  It

then finds a clicks the link to  to the previous hunting area.  This link may be different, but the general location is

always the same.
*/
HEAL:
ImageSearch, HEALX, HEALY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\heal.bmp
{
   2HEALX := HEALX + 5
   2HEALY := HEALY + 5
   Click %2HEALX% %2HEALY%
   Gosub LOADING
}
ImageSearch, ATTACKX, ATTACKY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\last.bmp
if ErrorLevel = 0
{
   2ATTACKY := ATTACKY + 30
   Click %ATTACKX% %2ATTACKY%
   Gosub LOADING
}
return


/*
This sub determines whether a page has finished loading in Firefox 3.0. The image it uses is of the little circle of

light-grey dots in the upper-right corner of Firefox.
*/
LOADING:
Loop
{
ImageSearch, , , 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\loading.bmp
   if ErrorLevel = 0
   break ;Page has finished loading, continue with script.
   Sleep, 100
}
return


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 9th, 2009, 4:25 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
34t wrote:
I must admit that I have a hard time understanding "Return"... where will the script return to after it sees that command at the end of the sub?
"Returns from a subroutine to which execution had previously jumped via function-call, Gosub, Hotkey activation, GroupActivate, or other means. " In this case, it returns to the line where you called the subroutine using Gosub.

Assuming ErrorLevel is always either 0 or 1 in the MONSTER subroutine, it will never return. This is bad because each time you use Gosub, information is left on the call stack. There is limited space on the call stack, so eventually the program will crash.

As I tried to point out previously, it is not necessary to explicitly jump back to MONSTER if everything begins and ends there. MONSTER can be in the loop, and everything else can simply return to it.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 9th, 2009, 7:50 am 
Offline
User avatar

Joined: March 19th, 2008, 12:43 am
Posts: 5480
Location: the tunnel(?=light)
I tried to show you the loop method because it will be difficult to make a script that will run well by trying to jump back and forth between subroutines using GoSub. In the loop I made of your script whenever a return is encountered it returns to the beginning of the loop, hence in effect back to the "MONSTER" subroutine.

It's a little more burdensome since the code can become a little more difficult to read but ultimately it should what you want it to do better than the method you're currently attempting. You can comment in the script in much the same way that you did before to keep track of things, like this:

Code:
Loop, 90
{
  /*
  Checks to see if the monster is dead
  */
  ImageSearch, MONx, MONy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\looted.bmp
  if (ErrorLevel) ; if not found proceeds to check for IDS
  {
    /*
    Checks for IDS
    */
    ImageSearch, IDSx, IDSy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ids.bmp
    if (ErrorLevel) ; if not found proceeds to check for DS
    {
      /*
      Checks for DS
      */
      ImageSearch, DSx, DSy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ds.bmp
      if (ErrorLevel); if not found proceeds to Attack
      {
        /*
        Checks for Attack
        */
        ImageSearch, ATTACKx, ATTACKy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\attack.bmp
        if (ErrorLevel); if not found proceeds to Heal
        {
          /*
          Checks for Heal
          */
          ImageSearch, HEALx, HEALy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\heal.bmp
          HEALx += 5
          HEALy += 5
          Click %HEALx% %HEALy%
          loop
          {
            ImageSearch, LOADINGx, LOADINGy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\loading.bmp
            if (ErrorLevel)
              Continue
          }
          ImageSearch, HUNTx, HUNTy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\cg.bmp
          HUNTx += 5
          HUNTy += 5
          Click %HUNTx% %HUNTy%
          loop
          {
            ImageSearch, LOADINGx, LOADINGy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\loading.bmp
            if (ErrorLevel)
              Continue
            }
            return
          }
          Else
          {
            ATTACKx += 5
            ATTACKy += 5
            Click %ATTACKx% %ATTACKy%
            Return
          }
        }
        Else
        {
          DSx += 5
          DSy += 5
          Click %DSx% %DSy%
          Return
          }
        }
        Else
        {
          IDSx += 5
          IDSy += 5
          Click %IDSx% %IDSy%
          return
        }
      }
      Else
      {
        ImageSearch, HEALX, HEALY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\heal.bmp
        HEALx += 5
        HEALy += 5
        Click %HEALx% %HEALy%
        Loop
        {
          ImageSearch, LOADINGx, LOADINGy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\loading.bmp
          if (ErrorLevel)
            Continue
        }
        ImageSearch, HUNTx, HUNTy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\cg.bmp
        HUNTx += 5
        HUNTy += 5
        Click %HUNTx% %HUNTy%
        Loop
        {
          ImageSearch, LOADINGx, LOADINGy, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\loading.bmp
          if (ErrorLevel)
            Continue
        }
        Return
  }
}


Also, I'd like to point out some shorthand I'm using in the code you might find helpful. You'll notice in places where you're using this:

Code:
if ErrorLevel = 1
  << some action >>
if ErrorLevel = 0
  << some action >>


I use just this:

Code:
if (ErrorLevel)
  << some action >>


The (ErrorLevel) tells the script to check if ErrorLevel is set to something other than 0, and if it is then it will proceed with some action. Even though you can tell the script to do something if ErrorLevel is 0, in this instance the script will assume by default that if the "if" condition is not met it should break and return to the beginning of the loop (and that's what we want it to do anyway).

Also, in places where you're passing math operations to additional variables:

Code:
ImageSearch, IDSX, IDSY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ids.bmp
if ErrorLevel = 1
{
   Gosub DS
}
else
{
   2IDSX := IDSX + 5
   2IDSY := IDSY + 5
   Click %2IDSX% %2IDSY%


I do something slightly different:

Code:
ImageSearch, IDSX, IDSY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ids.bmp
if ErrorLevel = 1
{
   Gosub DS
}
else
{
   IDSX += 5
   IDSY += 5
   Click %IDSX% %IDSY%


If you're more comfortable creating a separate variable for those, that's fine, but just know you're not required to. You always add something to a variable and save it to itself:

Code:
ISDX := ISDX + 5


Or you can use the shorthand addition operator to do the exact same thing:

Code:
ISDX += 5


It won't matter that you do so since the ImageSearch command will reset the value of the variables on the next run anyway. You can find more information about those operators on the Variables and Expressions section of the help manual.

_________________
Image
Try Quick Search for Autohotkey or see the tutorial for newbies.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 10th, 2009, 3:12 am 
Offline

Joined: May 7th, 2009, 9:03 pm
Posts: 13
Thank you for your help Lexikos and sinkfaze. I have also realized that I will need a main loop and that checking whether the monster is alive or dead is the best candidate for said loop.

I have since tried two ways of implementing this loop: the one suggested by sinkfaze (where everything is nested) and the one where checking monster is the main loop and attacks, along with LOADING are called via SUBs.

Nested Version
First I pasted together a version of this script and then I tried the version that sinkfaze presented. Both ran into the problem of stopping after performing one action. If I reloaded the script and hit the hotkey again the script would perform the next logical action, but then stop. Technically I could defeat a monster this way, but the script would also refuse to click the link for a new encounter after finding cg.bmp.

Main Loop that calls SUBs Version
I've had more success with this version of the script (will include the code at the end). The basic premise is that checking if the monster is dead yet (and then healing if it is dead) is part of the main loop. If the main loop detects that the monster is alive, then it calls the IDS SUB. If this SUB fails to find IDS it in turn calls the DS sub and so down the line. The problem I ran into this this script is that it WILL NOT STOP. :D It's really funny, but regardless of what arguments I include for the loop ("Loop, 2" for eample), this script will continue to cycle FOREVER :P

Sometimes this script makes a mistake and selects ATTACK while DS is still available (for eample). I have noticed these occurances growing more common. For example, sometimes the script fails to find IDS even though it's available and chooses DS instead. I'm fairly sure that neither page loading nor shade variation in ImageSearch have anything to do with this. I tried to give more Sleep time in the LOAD sub and increased the pixel color variation in ImageSearch with zero changes in behavior. I really can't figure out what can be going wrong - suggestions appreciated.

Issues I've Run Into
1) I flat-out don't understand where the "return" command returns the script to.
---Does it matter if the "return" is outside the last curly bracket of a SUB?
---If the main loop calls a SUB that has a "return" at the end, does the script jump to the BEGINNING of the main loop when it hits return or to the line that follows the GOSUB command that was used?
---If a SUB jumps to another SUB and the second SUB resolves to a "return", does the script jump back to the first SUB or to the beginning of the script?

2) I was unable to understand "(ErrorLevel)". From what I understood, when its used it means the script should perform a certain action on a failure, but continue on a success? Or break on a success?



This is the current version of the code I have. I'm ready to say that I'm satisfied with how it performs, but I need to figure out how to make the loop execute a specific number of times. This is in preparation for writing a simple GUI where I can enter the number of times to execute the script and this number will carry over as a variable to the Loop.

Code:
PGUP::Pause
!PGUP::Reload

/*
Remember to change the location of the image files and test the image search areas before running.  Using temporary hotkey x before finishing testing a loop and GUI.
*/

x::
Loop, 2
{
ImageSearch, , , 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\looted.bmp ;Check if Monster is dead.
if ErrorLevel
{
   Gosub IDS
}
else ;If the monster IS dead, then start the Healing routine.
{
   ImageSearch, HEALX, HEALY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\heal.bmp
   {
      HEALX += 5
      HEALY += 5
      Click %HEALX% %HEALY%
      Gosub LOADING
   }
   ImageSearch, LASTX, LASTY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\last.bmp
   {
      LASTY += 30
      Click %LASTX% %LASTY%
      Gosub LOADING
   }
}
}








/*
This sub attempts to use the IDS attack.  Goes to DS attack sub if it can't
*/
IDS:
ImageSearch, IDSX, IDSY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ids.bmp
if ErrorLevel
{
   Gosub DS
}
else
{
   IDSX += 5
   IDSY += 5
   Click %IDSX% %IDSY%
   Gosub LOADING
   return
}




/*
This is the DS attack sub. If the DS attack is unavailable, the sub goes to the regular Attack sub.
*/
DS:
ImageSearch, DSX, DSY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ds.bmp
if ErrorLevel
{
   Gosub ATTACK
}
else
{
   DSX += 5
   DSY += 5
   Click %DSX% %DSY%
   Gosub LOADING
   return
}




/*
This is the regular Attack sub. If this sub can't find regular attack that's always available then it knows the monster

is dead and goes to the Healing sub.
*/
ATTACK:
ImageSearch, ATTACKX, ATTACKY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\attack.bmp
if ErrorLevel
{
   return
}
else
{
   ATTACKX += 5
   ATTACKY += 5
   Click %ATTACKX% %ATTACKY%
   Gosub LOADING
   return
}


/*
This sub determines whether a page has finished loading in Firefox 3.0. The image it uses is of the little circle of

light-grey dots in the upper-right corner of Firefox.
*/
LOADING:
Loop
{
   ImageSearch, , , 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\loading.bmp
   if ErrorLevel = 0
   {
      break ;Page has finished loading, continue with script.
      Sleep, 150
   }
}
return


P.S. Sinkfaze - Thank you for your suggestions on how to optimize my script. I changed the way my script performs math operations and that cut down on the mess significantly! :D


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 10th, 2009, 5:19 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
34t wrote:
---If the main loop calls a SUB that has a "return" at the end, does the script jump to the BEGINNING of the main loop when it hits return or to the line that follows the GOSUB command that was used?
Quote:
Source: AutoHotkey Documentation: Gosub
"Return" causes the script to jump back to the first command beneath the Gosub and resume execution there.

34t wrote:
---If a SUB jumps to another SUB and the second SUB resolves to a "return", does the script jump back to the first SUB or to the beginning of the script?
It returns to the caller of the current/most recent subroutine (Gosub, function call, etc.) Perhaps a simple experiment will help:
Code:
MsgBox 1
Gosub Sub1
MsgBox 5
ExitApp

Sub1:
MsgBox 2
Gosub Sub2
MsgBox 4
return

Sub2:
MsgBox 3
return

Quote:
2) I was unable to understand "(ErrorLevel)". From what I understood, when its used it means the script should perform a certain action on a failure, but continue on a success? Or break on a success?
ErrorLevel has no special behaviour that sets it apart from other variables when used with IF. If ErrorLevel contains a true value, the body if the IF will execute. If it contains a false value, the body of the IF will not execute, but if it has an ELSE, that will execute. Any empty or zero value is considered false, and anything else is considered true.
34t wrote:
---Does it matter if the "return" is outside the last curly bracket of a SUB?
"Curly brackets" (also known as braces) have no effect for subroutines/labels. Similarly, the braces following ImageSearch have no real effect.

If the "last curly bracket" is the terminating brace of the IF..ELSE, then it does matter: it is probably what causes the script to select a wrong move. For instance:
Code:
IDS:
ImageSearch, IDSX, IDSY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ids.bmp
if ErrorLevel
{
   Gosub DS
}
else
{
   ;...
   return ; If the ImageSearch succeeded, we return and all is OK. Otherwise:
}
; Once 'Gosub DS' completes, execution will resume here.
;...
DS:
In most cases, RETURN should be used at the end of the subroutine to return to whatever called the subroutine. Note that this isn't necessary for the ATTACK subroutine since both branches of the IF use RETURN. Also note that if a RETURN is placed below the IF..ELSE, the RETURN at the end of the ELSE is redundant.

I'd say you have two options:
  • Put a return at the end of each subroutine to logically define it and ensure execution will return to the caller of the subroutine (the line below Gosub).
  • "Invert" the IF's condition and rely on the absence of return, cutting code size as a side-effect. For instance:
Code:
PGUP::Pause
!PGUP::Reload

/*
Remember to change the location of the image files and test the image search areas before running.  Using temporary hotkey x before finishing testing a loop and GUI.
*/

x::
Loop, 2
{
   ImageSearch, , , 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\looted.bmp ;Check if Monster is dead.
   if ErrorLevel
   {
      Gosub IDS
   }
   else ;If the monster IS dead, then start the Healing routine.
   {
      ImageSearch, HEALX, HEALY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\heal.bmp
      HEALX += 5
      HEALY += 5
      Click %HEALX% %HEALY%
      Gosub LOADING

      ImageSearch, LASTX, LASTY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\last.bmp
      LASTY += 30
      Click %LASTX% %LASTY%
      Gosub LOADING
   }
}
return ; <--- End hotkey subroutine.


/*
This sub attempts to use the IDS attack.  Goes to DS attack sub if it can't
*/
IDS:
ImageSearch, IDSX, IDSY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ids.bmp
if ErrorLevel = 0
{
   IDSX += 5
   IDSY += 5
   Click %IDSX% %IDSY%
   Gosub LOADING
   return
}
; Otherwise: fall through to DS below.

/*
This is the DS attack sub. If the DS attack is unavailable, the sub goes to the regular Attack sub.
*/
DS:
ImageSearch, DSX, DSY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\ds.bmp
if ErrorLevel = 0
{
   DSX += 5
   DSY += 5
   Click %DSX% %DSY%
   Gosub LOADING
   return
}
; Otherwise: fall through to ATTACK below.


/*
This is the regular Attack sub. If this sub can't find regular attack that's always available then it knows the monster is dead and goes to the Healing sub.
*/
ATTACK:
ImageSearch, ATTACKX, ATTACKY, 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\attack.bmp
if ErrorLevel = 0
{
   ATTACKX += 5
   ATTACKY += 5
   Click %ATTACKX% %ATTACKY%
   Gosub LOADING
   ; Fall through to 'return' below.
}
return


/*
This sub determines whether a page has finished loading in Firefox 3.0. The image it uses is of the little circle of light-grey dots in the upper-right corner of Firefox.
*/
LOADING:
Loop
{
   ImageSearch, , , 0, 0, A_ScreenWidth, A_ScreenHeight, *20 C:\GAME\loading.bmp
   if ErrorLevel = 0
   {
      break ;Page has finished loading, continue with script.
   }
   Sleep, 150
}
return
Note the placement of braces in the LOADING subroutine. In your code, the Sleep will never be executed because it is inside the IF and below BREAK. In my original example, I omitted the braces so only BREAK is contained by the IF.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: dmg, krajan, over21, RaptorX and 61 guests


You can 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

Search for:
Powered by phpBB® Forum Software © phpBB Group