AutoHotKey - Functions cannot contain functions error - autohotkey

I'm new to AutoHotKey and I wanted to create a script macro for a flash game but when I run it, it creates an error.
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
condChecker := false
state := true
Mine()
{
Sleep, rand(10,80)
Send, {Space}
while(state = true)
{
PixelGetColor, gemColor, 982, 433
if(gemColor = B93557)
{
state := true
{
else(gemColor = 96885A)
{
state := false
}
Sleep, rand(90,120)
}
}
^-::
loop 10000
{
getState()
if(state = true)
{Mine()}
else
{Sleep, rand(70,150)}
}
When I press Run Script on the ahk file, a menu pops up saying
Error at line 20.
Line Text else(gemColor = 96885A)
Error: Functions cannot contain functions.
The program will now exit.
I don't know where to start with this error and I read up on other forums saying that my formatting was incorrect.

A couple of various things:
The curly brace after state := true should be the other way (}, not {)
There is no default rand function in AHK, you are probably either looking for Random, or you have a custom function called rand that you is not shown in your question. In any case, I'll write a function rand(a,b) that will return an integer value between a and b
rand(a, b)
{
Random, rand, a, b
return rand
}
Additionally, there is another function getState() that is being invoked inside the loop 10000. I'm not sure what it is supposed to do (or if you meant something like GetKeyState instead), but I'll assume that you have that covered on your end.
As #Pranav Hosangadi mentioned, you likely wanted an else if statement instead of just an else statement on this line: else(gemColor = 96885A)
Are you sure you want SendMode Input? Although it does have superior speed than standard Send, its use is normally limited to typing text in a text box. It seems that you are trying to send a keystroke to a flash game, so you might want to check whether that functioning as you intend it to.
When writing a end curly brace (}) to conclude an if() or else() clause, you need to put it on its own line. (i.e. change
if(state = true)
{Mine()}
else
{Sleep, rand(70,150)}
to something like
if(state = true)
{
Mine()
}
else
{
Sleep, rand(70,150)
}
or even (since the if and else statements here only trigger one line of code each)
if(state = true)
Mine()
else
Sleep, rand(70,150)
So, that was a bit long, but here is the final code:
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
; ---> Double check this! ---> SendMode Input
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
condChecker := false
state := true
Mine()
{
Sleep, rand(10,80)
Send, {Space}
while(state = true)
{
PixelGetColor, gemColor, 982, 433
if(gemColor = B93557)
{
state := true
}
else if(gemColor = 96885A)
{
state := false
}
Sleep, rand(90,120)
}
}
rand(a, b)
{
Random, rand, a, b
return rand
}
^-::
loop 10000
{
;getState()
if(state = true)
Mine()
else
Sleep, rand(70,150)
}
lmk if something doesn't work properly, and I'll try to update this response

Related

AutoHotKey SetKeyDelay option does not appear to work

I have a very simple AutoHotKey script which I wish to introduce a visible delay between the characters typed ...I have read the documentation on SetKeyDelay but the example below does not seem to provide any key delay ...any thoughts ? I would expect that when I type rpa and the hit enter key, the characters would type slowly ...more like a human typing.
SetKeyDelay ,3000,200
::rpa::
Send {Text}
(
while ( iterator?.hasNext() ) {
def comp = iterator.next()
if (comp.sku != null ) {
def row = [
"sku" : comp.sku,
"ProductGroup": comp.attribute1,
"BusinessUnit": comp.attribute2
]
}
}
)
return
When a new script is created the SendMode Input; line is automatically inserted.
Remove the SendMode Input; fixed the issue.

AutoHotKey infinite while loop

Is there a way to create something like this in AutoHotKey?
bool isReady = false;
while (!isReady) {
// Do something here
isReady = true;
}
I tried to experiment with While loop, but it ended with just 1 loop regardless of the condition I give the program. I am currently using Version 1.0.47.06.
I read the documentation here: http://www.autohotkey.com/docs/commands/While.htm I tried to give the while loop a value of true. But it only executed once. (I was expecting it to loop forever, until I terminate the script).
condition := true
while (condition)
{
MsgBox, condition
}
while (true)
{
MsgBox, true
}
Your code is correct, but the While command requires version 1.0.48+.
You should update to the latest version of AHK here - http://ahkscript.org/download/
To create a infinite loop , you can use this syntax:
Loop
{
; Your other code goes here
}

Combination of specific key and any other key

I would like to turn F15 into a macro key. Pressing another key while F15 is held should call a function that will read a .ini file for instructions.
I know that I can it this like this, but I'd rather not have the giant list:
DoMacro(key) { ... }
F15 & a::DoMacro('a')
F15 & b::DoMacro('b')
F15 & c::DoMacro('c')
.
.
.
I tried fiddling around with Input, but I couldn't figure out any way to capture (or even pass through) non-character keys. Is there any alternative to the long list?
Unfortunately there is no 100% nice way to do this in AHK (unless you know a way to do it through API calls which I don't).
I think the best you could make out of this situation is this:
GetAnyKey(timeout) {
Input, PressedKey, T%timeout% L1, {F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{F14}{F15}{F16}{F17}{F18}{F19}{F20}{F21}{F22}{F23}{F24}{PrintScreen}{Del}{Home}{End}{PgUp}{PgDn}{ScrollLock}{Pause}{Ins}{BS}{Space}{Left}{Right}{Up}{Down}{Left}{Right}{NumLock}{NumPad1}{NumPad2}{NumPad3}{NumPad4}{NumPad5}{NumPad6}{NumPad7}{NumPad8}{NumPad9}{NumPad0}{NumPadAdd}{NumPadSub}{NumPadMult}{NumPadDiv}{NumPadEnter}{NumPadDot}{NumPadEnd}{NumPadHome}{NumPadPgDn}{NumPadPgUp}{NumpadClear}{NumpadDown}{NumpadIns}{NumpadLeft}{NumpadRight}{AppsKey}{LShift}{RShift}{LCtrl}{RCtrl}{LAlt}{RAlt}{LWin}{RWin}
If (ErrorLevel = "Timeout")
Return
If PressedKey
Key := PressedKey
Else
Key := SubStr(ErrorLevel,8)
Return Key
}
F13::
Key := GetAnyKey(1)
If (Key && GetKeyState("F13", "P")) {
DoMacro(Key)
}
Return
DoMacro(Key) {
MsgBox, F13 and %Key% have been pressed!
}
I removed the hotkey (F13) from the Input key list, so that it doesn't trigger the Input when you wait too long.
So, if you change the hotkey you have to change the input list accordingly.

Recursive function causing my script to exit

When I call this function it runs for a few minutes and then the script exits. I have found if I set the sleep period higher it takes longer for it to exit. Are there any ways I can write this so that it never exits? I think it has to do with the memory being used. The delay between loops has to be 500ms or lower.
Waitbeforefight()
{
Random, Wbf, 500, 500
sleep %Wbf%
ImageSearch, FoundX2, FoundY2, 855, 915, 1024, 1071, *30 E:\Desktop\Capture23.png
if ErrorLevel = 2
{
MsgBox Could not conduct the search.
ExitApp
}
else if ErrorLevel = 1
{
return
}
else
{
sleep %Wbf%
Waitbeforefight()
}
}
Even when I make a simple script like this it exits.
func1()
{
sleep 50
func1()
}
F1::
{
func1()
}
As Jongware commented,
It exits because the stack overflows: both of functions call themselves, and never return. Change the recursive call into a continuous loop to solve it.
After attempting an image search, there are three paths your function can take:
If the search couldn't be conducted, the script exits.
If the image wasn't found, the function returns.
Otherwise, the image was found and the function repeats.
Since the first two cases are exiting the function, it is very simple to change your function to use a loop: just remove the recursive call and wrap the content of the function in a Loop {}.
Waitbeforefight()
{
Loop
{
Random, Wbf, 500, 500
sleep %Wbf%
ImageSearch, FoundX2, FoundY2, 855, 915, 1024, 1071, *30 E:\Desktop\Capture23.png
if ErrorLevel = 2
{
MsgBox Could not conduct the search.
ExitApp
}
else if ErrorLevel = 1
{
return
}
else
{
sleep %Wbf%
; Instead of calling self, just allow the loop to continue.
}
}
}

What does for (;;) mean in Perl?

I was looking though a fellow developers code when I saw this ..
for (;;){
....
....
....
}
I have never seen ";;" used in a loop. What does this do exactly?
It loops forever. ';;' equates to no start value, no stop condition and no increment condition.
It is equivalent to
while (true)
{
...
}
There would usually be a conditional break; statement somewhere in the body of the loop unless it is something like a system idle loop or message pump.
All 3 parts are optional. An empty loop initialization and update is a noop. An empty terminating condition is an implicit true. It's essentially the same as
while (true) {
//...
}
Note that you it doesn't have to be all-or-nothing; you can have some part and not others.
for (init; cond; ) {
//...
}
for (; cond; update) {
//...
}
for (init; ; update) {
//...
}
Just like in C, the for loop has three sections:
a pre-loop section, which executes before the loop starts.
a continuing condition section which, while true, will keep the loop going.
a post-iteration section which is executed after each iteration of the loop body.
For example:
for (i = 1, acc = 0; i <= 10; i++)
acc += i;
will add up the numbers from 1 to 10 inclusive (in C and, assuming you use Perl syntax like $i and braces, in Perl as well).
However, nothing requires that the sections actually contain anything and, if the condition is missing, it's assumed to be true.
So the for(;;) loop basically just means: don't do any loop setup, loop forever (breaks notwithstanding) and don't do any iteration-specific processing. In other words, it's an infinite loop.
Infinite loop. A lot of the time it will be used in a thread to do some work.
boolean exit = false;
for(;;) {
if(exit) {
break;
}
// do some work
}
Infinite Loop (until you break out of it).
It's often used in place of:
while(true) { // Do something }
It's the same as
while(true) {
...
}
It loops forever.
You don't need to specify all of the parts of a for loop. For example the following loop (which contains no body, or update token) will perform a linear search of myArray
for($index = -1; $myArray[++$index] != $target;);