InGame v2.0

Post gaming related scripts
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

[POWER of FAT ARROW functions] Part I - Mostly harmless.

23 Aug 2018, 14:06

Preamble:
https://lexikos.github.io/v2/docs/Varia ... #fat-arrow () => expr it is simple sintax but let see what it can do.
Examples:
Lets begin with something simple.

Code: Select all

sup:= 7
function()
function() {
	global			;global scope to function()
	out:= 10
	;function name is visible inside whole containing body
	scop( 5)
	;scop()'s variables scope is the same as scope containing scop()		
	scop(arg) => (msgBox("arg= " arg " out= " out " sup= " sup))
}
To be demonstrated variables visibility all fat arrow functions will be pressent as sub functions. If function() "see" global variables scop() will "see" them too.
The most important things in one alghoritm is divergency and cyclicality.
Let see what about if/else/loop/for/do/while/until.

Code: Select all

glo:= 7
obj:= {one:"oneVal", two:"twoVal"}

function()
function() {
	global
	extr()
	extr() => (
		(if glo == 13		;no action
			MsgBox("true " (glo==13))
		),
		(loop 10			;no action
			MsgBox("loop A_Index= " A_Index)
		),
		(while glo > 0		;no action
			MsgBox("while A_Index= " A_Index)
		),
		(for k,v in obj		;no action
			MsgBox("key:val= [" k ":" v "]")
	)	)
}
As if/else/loop/for/do/while/until are not expressions so they not work.
About IF.

Code: Select all

function()	
function() { ;ternary instead if/else
	_if(5)
	_if(arg) => (arg == 5? MsgBox(arg "==5"): ;if a==5 then MsgBox(arg "==5")
						   MsgBox(arg "!=5")  ;		   else MsgBox(arg "!=5")
				)							  ;"" must be used as nothing
   ;_if(arg) => (arg == 5? MsgBox(arg): "")	  ;	  at both places (then/else)		
}
About LOOP/WHILE.

Code: Select all

function()
function() { ;recursion instead loop/while
	_loop(10)		
	_loop(arg) => (	
		arg > 0	? tooltip(arg) sleep(1000) _loop(arg-1) ;no comma 
				: tooltip()
	)
}
Don`t forget recursion is powerful but must be guaranteed end of recursion and think about stack (most arguments - most stack).
Different expressions not enclosed and not comma separated it is possible but not well.
Yet another recursion example.

Code: Select all

function()
function() {
	;global		
	local sta	;_for use local variable
				;to keep value in recursion
	_for()
	_for() => ( ;for(sta:=10; sta > 2; sta:=sta-1) {
				;	tooltip("sta= " sta)
				;	sleep(mis)
				;}
				;tooltip()
		(sta:= sta? sta-1: 10),
		(sta > 2 ? tooltip("sta= " sta) sleep(1000) _for()
				 : tooltip()
	)	)
}
And another one but here fat arrow function inside fat arrow function.

Code: Select all

function()
MsgBox("global= " glo) 
function() {
	global
	out:= 10
	recu()			
	recu() => (
		(glo:= glo? glo: 20), ;create global variable (if global)
							  ;comma is a must
		(out > 0? sub_%mod(out, 2)%()				;new line
				  sleep(1000) out-- recu()			;no comma
				: ""
		),
		;fat arrow function in fat arrow function
		sub_1() => (tooltip("1= " out " glo= " (glo-=1)))					  
	)
	sub_0() => (tooltip("0= " out " glo= " (glo-=1)))
}
Conclusions:

Code: Select all

;think for fat arrow function as expresion that must return result
FatArrowFunc([byRef]arg) => (	
	;variables
	;	byRef - work as usual
	;	scope - the same as scope of containing scope
	;	create variables -	as part of expression
	;		global 	;no affect even persist
	;		local	;"
	;		static 	;"
	;			 -	newly created variable can be
	;				local for fatArrowFunc()
	;				or
	;				global (if global persyst in containing scope)
	;			 -	there no mechanism subfunction to create
	;				variable into containing function
	
	(<var:= expr/func>), ;comma is a must if new variable created
						 ;() and , is not mandatory but using them
						 ;		   is best for syntax and readability
	(<expr/func>)	;space or new line separate expressions
					;using () and comma is the best and clear syntax
				
	;if/else/loop/for/do/while/until
	;	and so on not expressions not ussable  
	
	((arg)? (<expr/func>): (<expr/func>))
	
	;best syntax - brakets and commas
	;FatArrowFunc(arg) => (
	;	(<expression>),
	;	(<expression>),
	;	((<expression>) ? (<expression>)
	;				  	: (<expression>)
	;	),
	;	"" ;do nothing (NOP)
	;)
	
	;retun		;forbiden
	;			;think that return is at => place
	;					 =>
	;FatArrowFunc(arg) { return (
	;	(<expr>),
	;	(<expr>)
	;)
	;}
	
	;last expression is return value
)
All examples in one only code:

Code: Select all

#SingleInstance Force
;Copyright (c) D.Donchev

mis:= 200
sup:= 7
obj:= {one:"oneVal", two:"twoVal"}

function()
msgBox("glo= " glo)	;see recu()

function() {
	global			;function() scope to global
	out:= 10
;scop example ==========
	scop( 5)		;function name is visible
					;inside whole containing body
	scop(arg) => ( 	;scop() variable scope is the same as
					;scope containing scop()
		msgBox("arg= " arg " out= " out " sup= " sup)
	)
;}	
;cycl example ==========	
	cycl(10)		;recursion
	cycl(arg) => (	;recursion instead loop
		arg > 0	? tooltip(arg) sleep(mis) cycl(arg-1) ;no comma 
				: tooltip()
	)
;}	
;recu example ==========	
	recu()			;visibility
	recu() => (
		(glo:= glo? glo: 20), ;create global variable (if global)
							  ;comma is a must
		
		(out > 0? sub%mod(out, 2)%()				;new line
				  sleep(mis) out-- recu()			;no comma
				: ""
		),	;enclosure ternary expression
		;fat arrow function  in fat arrow function
		sub1() => (tooltip("1= " out " glo= " (glo-=1)))					  
	) 
	sub0() => (tooltip("0= " out " glo= " (glo-=1)))
;}
;_for example ==========
	local sta	;_for use local variable
				;to keep value in recursion
	_for()
	_for() => ( ;for(sta:=10; sta > 2; sta:=sta-1) {
				;	tooltip("sta= " sta)
				;	sleep(mis)
				;}
				;tooltip()
		(sta:= sta? sta-1: 10), 
		(sta > 2 ? tooltip("sta= " sta) sleep(mis) _for()
				 : tooltip()
	)	)
;}	
;extr example ==========	
	extr()
	extr() => (
		(if glo == 13		;no action
			MsgBox("true " (glo==13))
		),
		(loop 10			;no action
			MsgBox("loop A_Index= " A_Index)
		),
		(while sup > 0		;no action
			MsgBox("while A_Index= " A_Index)
		),
		(for k,v in obj		;no action
			MsgBox("key:val= [" k ":" v "]")
	)	)
}
ExitApp
#!Q::ExitApp
Working example - fat arrow function as function argument.

Code: Select all

myToolTip("111", 200, 200, 20, 3000)
myToolTip("222", 100, 100,   , 2000)

myToolTip(text, x:="", y:="", w:="", time:="") {
	tooltip(text, x, y, w)
	if(time is "number")
		SetTimer(()=>tooltip(,,,w), time<0?time:-time) ;fat as argument
}
Fat arrow functions and classes.

Code: Select all

class A {
	static var:= 1
	met() {
		return 2
	}
	fat()=>(3)
}

for k,v in A
	MsgBox(k " : " v " -> " type(v))
	
MsgBox("outside A => " fat()) ;fat() is global becouse class definition is global

Code: Select all

	_Class  : A -> String		(ok)
	var		: 1 -> Integer		(ok)
	met		:	-> Func			(ok)
	
	fat is invisible lol -->	(no)
		is not a member of A	(ok)
All fat arrow functions defined inside class definition becomes global.

Code: Select all

#SingleInstance Force
;Copyright (c) D.Donchev

class Def {
	static ClassVar
	one:= 1
	two:= 2

	;Example (1) run last set fat function
	ini(arg:="") {
		if(type(arg) == "Func")
			this.ClassVar:= arg				;set
		if(type(this.ClassVar) != "Func")
			this.ClassVar:= ()=>"default"	;default
			
		MsgBox(%this.ClassVar%())			;action
	}
	;Example (2) run argument fat func or internal
	tos(arg:="") {
		;arg:= type(arg) == "Func"? arg: ()=>"no format"
		if(type(arg) != "Func")
			arg:= ()=>"no format"
		return %arg%(this)
}	}
Ins:= new Def
;Example (1) ----------
Def.ini()	;default
Ins.ini()	;default
;expect: if ClassVar not set then init
;OK
Def.ini(()=>"class new")	;class new
Ins.ini()					;class new
;expect: if class ClassVar is changed then instance ClassVar changed
;OK
Ins.ini(()=>"instanse new") ;instanse new
Def.ini()					;class new
Ins.ini()					;instance new
;expect: ;if instance ClassVar is changed then class ClassVar NOT changeg
;OK
;Examle (2) ----------
MsgBox(Ins.tos())
;expected: run internal default fat func
;OK
MsgBox(Ins.tos((this) => ("myown= " this.one " then " this.two)))
;expected: run argument fat func
;OK
MsgBox(Ins.tos((this) => ( ;recursion demo
	;for(k, v in this)
	;	res.= k " : " v " | "
	;return res
	
	;3 lines - without pushing arguments
	;(_enum:= this._NewEnum()),
	;_act()=>(_enum.Next(k,v)? ((res .= k ":" v "|"), _act()): res),
	;_act()
	
	;2 lines - stack breaker (LOL)
	_act(_enum)=>(_enum.Next(k,v)? ((res .= k ":" v "|"), _act(_enum)): res),
	_act(this._NewEnum())
)))
;expected: recursion must end
;OK

ExitApp
#!Q::ExitApp ;if something wrong
Comments inside the code. Most important is that all functions related to classes must have at least one argument because all methods are called with first argument this.
Again:
Enclose all individual expression in () and separate expressions with comas. Enclose all expressions in () like {} for best reading. "" can be used as nothing (NOP). Ternary instead IF/ELSE and recursion instead LOOP/WHILE.

Code: Select all

[FatArrowFunctionName]([agruments])=>(
	(expression),
	(expression) ;last expression is return value
)
Enjoy!
AHKv2.0 use the future now.
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

dd_pixelGetColor.ahk

31 Aug 2018, 03:53

An old project that I use all the time.
https://autohotkey.com/boards/viewtopic ... 400#p17615
Some in time I add snapShot() that get bmp from screen and save it to file. So this day I revised snapShot() and let see what happen:
The first code:

Code: Select all

snapShot() {
	Suspend("On")  ;disable hotkeys to be used in InputBox
	param:= InputBox("SnapShot",,"W150 H100")
	Suspend("Off") ;enable hotkeys
	
	loop (param:= StrSplit(param, [",",":","|"," "])).length() ;delimiters
		if param[A_Index] {
			goto("CASE_" (++cnt)) ;switch
			CASE_1: ;begin point x coordinate
				x:= param[A_Index]
				continue
			CASE_2: ;begin point y coordinate
				y:= param[A_Index]
				continue
			CASE_3: ;width or end point x coordinate   
				if RegExMatch(param[A_Index], "i)W([\d]+)", arg)
					 w:= arg[1]
				else w:= param[A_Index] - x + 1 ;calculate x2-x1+1
				continue
			CASE_4: ;height or end point y coordinate
				if RegExMatch(param[A_Index], "i)H([\d]+)", arg)
					 h:= arg[1]
				else h:= param[A_Index] - y + 1 ;calculate y2-y1+1
				break ;break loop
		}
	Gdip_SaveBitmapToFile(pBmp:= Gdip_BitmapFromScreen(x "|" y "|" w "|" h), ".\" x "-" y ".bmp")
		Gdip_DisposeImage(pBmp)
}
I see that too many madness in code.
First revise:

Code: Select all

snapShot() {
	Suspend("On")  ;disable hotkeys to be used in InputBox
	loop Parse, InputBox("SnapShot",,"W150 H100"), ",:| " ;delimiters
		if A_LoopField {
			goto("CASE_" (++cnt)) ;switch
			CASE_1: ;begin point x coordinate
				x:= A_LoopField
				continue
			CASE_2: ;begin point y coordinate
				y:= A_LoopField
				continue
			CASE_3: ;width or end point x coordinate   
				w:= RegExMatch(A_LoopField, "i)W([\d]+)", arg)? arg[1]: A_LoopField - x + 1 ;calculate x2-x1+1
				continue
			CASE_4: ;height or end point y coordinate
				h:= RegExMatch(A_LoopField, "i)H([\d]+)", arg)? arg[1]: A_LoopField - y + 1 ;calculate y2-y1+1
				break ;break loop
		}
	Suspend("Off") ;enable hotkeys	
	Gdip_SaveBitmapToFile(pBmp:= Gdip_BitmapFromScreen(x "|" y "|" w "|" h), ".\" x "-" y ".bmp")
		Gdip_DisposeImage(pBmp)
}
Loop Parse instead StrSplit - faster and less ram.
Now how to avoid Goto? A simple test function:

Code: Select all

#SingleInstance Force
;Copyright (c) D.Donchev
fun()
fun() {
	x:= y:= w:= h:= 0 ;define variables for fat functions
	;fat functions throws exceptions if not number result
	static xywh :=	[()=>(x:= A_LoopField + 0)
					,()=>(y:= A_LoopField + 0)
					,()=>(w:= RegExMatch(A_LoopField, "i)W([\d]+)", _)? _[1]: A_LoopField - x + 1)
					,()=>(h:= RegExMatch(A_LoopField, "i)H([\d]+)", _)? _[1]: A_LoopField - y + 1)]
	;possible syntaxes
	;100 200 109 209
	;100 200 W10 209
	;100 200 109 H10
	;100 200 W10 H10
	;Suspend("On" ) ;disable hotkeys 
	cntr:= 1
	loop Parse, i:= InputBox("SnapShot",,"W150 H100"), ",:| " 	;i - just for test
		if A_LoopField 			;skip "" (100: 200: W10: H10) 
			try xywh[cntr++]()	;keep 0 for incorrect syntax parameter
			catch
				MsgBox("Incorrect syntax: parameter " cntr-1 ":= " A_LoopField)
	until(cntr > 4)
	MsgBox(i "`nX`t:= " x "`nY`t:= " y "`nW`t:= " w "`nH`t:= " h)
	;Gdip_SaveBitmapToFile(pBmp:= Gdip_BitmapFromScreen(x "|" y "|" w "|" h), ".\" x "-" y ".bmp")
	;	Gdip_DisposeImage(pBmp)
	;Suspend("Off")
}
ExitApp
#!Q::ExitApp ;quit
Function needed 4 parameters x, y, w, h
- x and y - start point coordinate
- w and h - end point coordinate or width and height (see syntax in code)
And the result without comments:

Code: Select all

snapShot() {
	x:= y:= w:= h:= 0 ;define variables for fat functions
	static xywh :=	[()=>(x:= A_LoopField + 0)
					,()=>(y:= A_LoopField + 0)
					,()=>(w:= RegExMatch(A_LoopField, "i)W([\d]+)", _)? _[1]: A_LoopField - x + 1)
					,()=>(h:= RegExMatch(A_LoopField, "i)H([\d]+)", _)? _[1]: A_LoopField - y + 1)]
	Suspend("On" )
	cntr:= 1
	loop Parse, InputBox("SnapShot",,"W150 H100"), ",:| " 	
		if A_LoopField 			
			try xywh[cntr++]()	
	until(cntr > 4)
	Suspend("Off")
	
	Gdip_SaveBitmapToFile(pBmp:= Gdip_BitmapFromScreen(x "|" y "|" w "|" h), ".\" x "-" y ".bmp")
		Gdip_DisposeImage(pBmp)
}
And the whole project:

Code: Select all

#SingleInstance Force
;Copyright (c) D.Donchev

CoordMode("Mouse", "Screen")
CoordMode("Pixel", "Screen")
	pToken:= Gdip_Startup()
	Gui:= GuiCreate("-Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs")
	Gui.Show("NA")
  
	hwnd:= WinExist()
	hbm := CreateDIBSection(mwW:=75, mwH:=35)
	hdc := CreateCompatibleDC()
	obm := SelectObject(hdc, hbm)
	G   := Gdip_GraphicsFromHDC(hdc)
  
	Gdip_SetSmoothingMode(G, 4)
	pBrush := Gdip_BrushCreateSolid(0x7FC0C0C0)
	Gdip_FillRectangle(G, pBrush,  0, 0, mwW, mwH), Gdip_DeleteBrush(pBrush)
	MouseGetPos mX, mY
	UpdateLayeredWindow(hwnd, hdc, mX, mY, mwW, mwH)
	OnMessage(0x200, ()=>PostMessage(0xA1, 2))
	ShowHide:= RunStop:= 1
	SetTimer("mainWindowContent", 100)
  
mainWindowContent() {
	global
	MouseGetPos mX, mY
	color  := Gdip_GetPixel(Gdip_BitmapFromScreen(mX "|" mY "|1|1", 0x40CC0020), 0, 0) & 0xFFFFFF
	tcolor := (color > 0x800000)? "FF000000": "FFFFFFFF"
	pBrush := Gdip_BrushCreateSolid(0xFF000000|color)
	Gdip_FillRectangle(G, pBrush,  5,  5, mwW-10, mwH-10), Gdip_DeleteBrush(pBrush)
	Gdip_TextToGraphics(G, format("{1:4d}:{2:4d}", mX, mY), "X0 Y6 Center C" tcolor " R4 S10 Bold", "Verdana", mwW, 47)
	Gdip_TextToGraphics(G, format("{1:06X}", color)       , "X0 Y17 Center C" tcolor " R4 S10 Bold", "Verdana", mwW, 47)
	UpdateLayeredWindow(hwnd, hdc)
}

!Space::RunStop :=!RunStop , GuiControl()
#Space::ShowHide:=!ShowHide, GuiControl()
#M:: ;move mouse pointer to possition
	m:= StrSplit(InputBox("Position(X Y)",,"W150 H100",mX " " mY), [",",":","|"," "])
	MouseMove(m[1], m[m.length()])            
return
#!S::snapShot()		
#!F4::ExitApp
#!F1::msgBOX(""
	. "ALT+Space`tRun/Stop`n"
	. "WIN+Space`tShow/Hide`n"
	. "WIN+M`t`tMouseMove`n"
	. "WIN+ALT+S`tSnapShot`n"
	. "WIN+ALT+F1`tHelp`n"
	. "WIN+ALT+F4`tExit")
GuiControl() {
	global
	SetTimer("mainWindowContent", "Off")
	Gui.Hide()
	if ShowHide {
		SetTimer("mainWindowContent", RunStop? "On": "Off")
		Gui.Show()
} 	}
snapShot() {
	x:= y:= w:= h:= 0 ;define variables for fat functions
	static xywh :=	[()=>(x:= A_LoopField + 0)
					,()=>(y:= A_LoopField + 0)
					,()=>(w:= RegExMatch(A_LoopField, "i)W([\d]+)", _)? _[1]: A_LoopField - x + 1)
					,()=>(h:= RegExMatch(A_LoopField, "i)H([\d]+)", _)? _[1]: A_LoopField - y + 1)]
	Suspend("On" )
	cntr:= 1
	loop Parse, InputBox("SnapShot",,"W150 H100"), ",:| " 	
		if A_LoopField 			
			try xywh[cntr++]()	
	until(cntr > 4)
	Suspend("Off")
	
	Gdip_SaveBitmapToFile(pBmp:= Gdip_BitmapFromScreen(x "|" y "|" w "|" h), ".\" x "-" y ".bmp")
		Gdip_DisposeImage(pBmp)
}
Enjoy!
AHKv2.0 use the future now.
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

fast and furious

23 Sep 2018, 02:55

A simple speed test about sending and running functions as arguments.

Code: Select all

#SingleInstance Force
;Copyright (c) D.Donchev

loops:= 100000
;test function
funct() {
	return ""
}
fatfu()=>""
;complete argument check ------------------------------------------------------
ff_1(arg:="") {
	return %(type(arg) == "Func"? arg: ()=>)%()
}
;run if only ------------------------------------------------------------------
ff_2(arg:="") {
	if(type(arg) == "Func")
		return %arg%()
}
;try to run -------------------------------------------------------------------
ff_3(arg:="") {
	try return %arg%()
}
;ternary run ------------------------------------------------------------------
ff_4(arg:="") {
	return type(arg) == "Func"? %arg%(): ""
}
loop 4 {
	fn:= A_Index
	elaps:= A_TickCount
	loop loops
		ff_%fn%()				;ternary run faster - fast check
		;ff_%fn%(Func("funct"))	;try run faster - nothing to check
		;ff_%fn%(Func("fatfu"))	;try run faster - nothing to check
		;ff_%fn%(()=>"") 		;try run faster - nothing to check
	elaps:= A_TickCount - elaps
	MsgBox(fn ":=" elaps)
}
The conclusions:
1. If everything fine - try run is faster - due to no any additional check.
2. If is needed check - ternary run is faster - due to faster check.
It is script language and user must keep language rules. So complete propriety check not possible.

Enjoy!
AHKv2.0 use the future now.
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

Auto-Kill

09 Feb 2019, 14:37

An small but powerful script that keep buffs updated and auto kill.
There 4 buffs attached to Numpad1, 2, 3, 4 and auto attack attached to 1.

Code: Select all

#SingleInstance Force
;Copyright (c) D.Donchev

SendMode("Event")
CoordMode("Mouse", "Screen")
CoordMode("Pixel", "Screen")
CoordMode("Tooltip", "Screen")

SetKeyDelay(150, 90)
kill:= buff:= 0
msgBOX("Auto-Kill loaded!",,"T3")
goSub("!B")
goSub("$CapsLock")

#!Q::ExitApp	;end of script

$CapsLock::
	if(kill:=!kill) {
		Send(1)
		ImageSearch(whereX, whereY, 0, 0, A_ScreenWidth, A_ScreenHeight, "Auto-Kill-GRB.bmp")
		if ErrorLevel
			 kill:= 0
		else color:= pixelGetColor(whereX, whereY)
	}
	display()
	setTimer( GRB_KILL() => (pixelGetColor(whereX, whereY) != color? Send(1):""), kill? 100: "OFF")
return	

!B::
	if(buff:=!buff) {
		goSub("$Numpad1")
		sleep(500)
		goSub("$Numpad2")
		sleep(500)
		goSub("$Numpad3")
		sleep(500)
		goSub("$Numpad4")
	}
	display()
return

;NumpadX - forced run corresponding buff and reset it timer
$Numpad1:: numpad1(), SetTimer(numpad1() => (buff? Send("{Numpad1 5}"): ""), buff? 180000: "OFF")
$Numpad2:: numpad2(), SetTimer(numpad2() => (buff? Send("{Numpad2 5}"): ""), buff? 170000: "OFF")
$Numpad3:: numpad3(), SetTimer(numpad3() => (buff? Send("{Numpad3 5}"): ""), buff? 300000: "OFF")
$Numpad4:: numpad4(), SetTimer(numpad4() => (buff? Send("{Numpad4 5}"): ""), buff? 900000: "OFF")

display() {
	global
	tooltip("Kill <" (kill? "ON": "OFF") "> | Buff <" (buff? "ON": "OFF") ">", A_ScreenWidth/2-70, A_ScreenHeight-75, 20)
}
Action:
1. After start script call all 4 buffs, set there timers and attack nearest mob.
2. If some buff for some reason missed - player can forced run it and reset it timer.
3. ALT+B - reload all 4 buffs.
4 CapsLock - start / pause auto attack nearest mob.

Enjoy!

Latest release https://www.autohotkey.com/boards/viewtopic.php?f=19&t=2400&p=264240#p264240
Last edited by _3D_ on 21 Feb 2019, 08:50, edited 1 time in total.
AHKv2.0 use the future now.
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

Re: All about SetTimer

13 Feb 2019, 09:46

There was too many questions about this timers.
Lets start with the syntax: SetTimer [Callback, PeriodOnOffDelete, Priority]
parameter #2: control the status of timer
parameter #3: control the priority of timer
parameter #1: must be "String" or "Function Object"

Now let see what this parameter Callback must be:

Code: Select all

counter:= 0
MyFunc() {
	global
	tooltip("Hi there. It is MyFunc. " (++counter))
}
SetTimer("MyFunc",   500)	;start timer to run MyFunc any 500ms
while(counter <= 10)		;do nothing until counter become > 10
{}
SetTimer("MyFunc", "OFF")	;stop timer to run MyFunc
In this example Callback parameter is "String" - this way MyFunc is send to timer ByName.

Code: Select all

counter:= 0
MyFunc() {
	global
	tooltip("Hi there. It is MyFunc. " (++counter))
}
SetTimer(Func("MyFunc"),   500)	;start timer to run MyFunc any 500ms
while(counter <= 10)		;do nothing until counter become > 10
{}
SetTimer(Func("MyFunc"), "OFF")	;stop timer to run MyFunc
In this example Callback parameter is "Func" - this way MyFunc is send to timer ByRef.
As we see there just one transformation from "String" to "Func" (that SetTimer can do itself).

Code: Select all

counter:= 0
settimer(MyClosure()=>(tooltip("Hi there. It is MyClosure. " (++counter))), 500)
while(counter <= 10)
{}
settimer("MyClosure", "OFF")
In this case timer started by "Func" but stoped by "String" (It is because SetTimer itself conversion).
This last example have one more modification (my favorit)

Code: Select all

counter:= 0
settimer(MyClosure:=()=>(tooltip("Hi there. It is MyClosure. " (++counter))), 500) ;closure without name but MyClosure get reference to closure
while(counter <= 10)
{}
settimer(MyClosure, "OFF")
Here "Func" / "Func".
Till now nothing special just examples and one side effect function:

Code: Select all

Callback(arg:= "") {
	if(type(arg) != "Func" && type(arg:=Func(arg)) != "Func")
		return ()=>"NULL" ; ()=>""
	return arg		
}
It is one IF converting "String" to "Func" if exist and instead exception Callback return function that do nothing ()=>"". This function convert anything to "Func".
So, and why?

Code: Select all

class Buff { ;first version
	__New(timer, callRun, callOff, state) {
		this.timer:= timer
		this.callRun:= Callback(callRun)
		this.callOff:= Callback(callOff)
		this.state:= state
	}
	switch(state:="") { ;switch ON / switch OFF
		global
		if(state? state: %this.state%) {
			%this.callRun%() ;uncomment if you need to run now and timed
			settimer(this.callRun, this.timer) ;run timed
		} else {
			settimer(this.callRun,      "OFF") ;stop
			%this.callOff%()	
}	}	}
And finally the buff example from last post
WAS:

Code: Select all

!B::
	if(buff:=!buff) {
		goSub("$Numpad1"), sleep(500)
		goSub("$Numpad2"), sleep(500)
		goSub("$Numpad3"), sleep(500)
		goSub("$Numpad4")
	}
	display()
return
$Numpad1:: numpad1(), SetTimer(numpad1() => (buff? Send("{Numpad1 5}"): ""), buff? 180000: "OFF")
$Numpad2:: numpad2(), SetTimer(numpad2() => (buff? Send("{Numpad2 5}"): ""), buff? 170000: "OFF")
$Numpad3:: numpad3(), SetTimer(numpad3() => (buff? Send("{Numpad3 5}"): ""), buff? 300000: "OFF")
$Numpad4:: numpad4(), SetTimer(numpad4() => (buff? Send("{Numpad4 5}"): ""), buff? 900000: "OFF")
NOW:

Code: Select all

npad1:= new Buff(180000, ()=>(Send("{Numpad1 5}")), "", "buff")
npad2:= new Buff(170000, ()=>(Send("{Numpad2 5}")), "", "buff")
npad3:= new Buff(300000, ()=>(Send("{Numpad3 5}")), "", "buff")
npad4:= new Buff(900000, ()=>(Send("{Numpad4 5}")), "", "buff")

!B::
	buff:=!buff
	goSub("$Numpad1"), sleep(500)
	goSub("$Numpad2"), sleep(500)
	goSub("$Numpad3"), sleep(500)
	goSub("$Numpad4")
	display()
return
$Numpad1:: npad1.switch()
$Numpad2:: npad2.switch()
$Numpad3:: npad3.switch()
$Numpad4:: npad4.switch()
Enjoy!
AHKv2.0 use the future now.
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

All about timed buffs

17 Feb 2019, 02:11

I did it in times complicated.
At the beginning idea was to be connected all similar actions to a single variable. And when value of this variable is changed then actions run or stopped together. BUT at the end I made one more class that collect itself list of "similar" actions.
Class Buff:

Code: Select all

class Buff {
	__New(timer, htkey, metod) {
		this.timer:= timer
		this.metod:= metod
		
		HotKey(htkey, ()=>this.switch()) ;"reference" to this.method
	}
	switch(state:=1) { ;switch ON / switch OFF
		if(state) {
			   this.metod.call() ;uncomment if you need to run now and timed
			   settimer(this.metod, this.timer) ;run timed
		} else settimer(this.metod,      "OFF") ;stop
}	}	}
I keep only things that is needed in this concrete case and cut all checks. Now Class Buff keep less data, run less code and create Hotkey.

And list of Buffs
Class Flag:

Code: Select all

class Flag {
	internalList:= []
	internalFlag:=  0
	status {
		get { 
			return this.internalFlag
		}
		set {
			this.internalFlag:= value
			loop this.internalList.length()
				this.internalList[A_Index].switch(this.internalFlag)
			return this.internalFlag
	}	}
	add(arg) {
		this.internalList.Push(arg)
}	}
The main idea: let we have value and when value changed then do action in list. Class Flag need Class Buff like list elements. The same all checks stripped down.

And what ?
Main code:

Code: Select all

warrior:= new Flag
warrior.add(new Buff(180000, "$Numpad1", ()=>Send("{Numpad1 5}")))
warrior.add(new Buff(170000, "$Numpad2", ()=>Send("{Numpad2 5}")))
warrior.add(new Buff(300000, "$Numpad3", ()=>Send("{Numpad3 5}")))
warrior.add(new Buff(900000, "$Numpad4", ()=>Send("{Numpad4 5}")))

!B::warrior.status:=!warrior.status
Thats ALL :P

Enjoy!
AHKv2.0 use the future now.
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

Auto-Kill-GRB again

19 Feb 2019, 08:39

After couple of days testing and optimizing - new Auto-Kill-GRB.
Why?
1. Meta-functions provide a broader way of controlling access to properties and methods of an object, but are more complicated and error-prone. I change properties to a single function.
2. Using Auto-Buff - interrupt fast killing. I reworked management:
NOW
1. When run - script just load and wait
2. Alt+G - start action or reload script (reset it).
3. Alt+B - start / stop Auto-Buff.
4. Capslock - start / stop Auto-Kill.
5. WIN+Alt+Q - Exit
Auto-Kill-GRB.ahk just code without picture and exe.

Code: Select all

#SingleInstance Force
;Copyright (c) D.Donchev

SendMode("Event")
CoordMode("Mouse", "Screen")
CoordMode("Pixel", "Screen")
CoordMode("Tooltip", "Screen")

SetKeyDelay(150, 90)
warrior:= new Flag
warrior.add(new Buff(181000, "$Numpad1", ()=>Send("{Numpad1 5}")))
warrior.add(new Buff(170000, "$Numpad2", ()=>Send("{Numpad2 5}")))
warrior.add(new Buff(300000, "$Numpad3", ()=>Send("{Numpad3 5}")))
warrior.add(new Buff(900000, "$Numpad4", ()=>Send("{Numpad4 5}")))

display()
!G::
	if(rungrb:=!rungrb) {
		goSub("!B")
		kill:= 0
		goSub("$CapsLock")
	} else Reload
return
$CapsLock::
	if(kill:=!kill) {
		Send(1)
		ImageSearch(whereX, whereY, 0, 0, A_ScreenWidth, A_ScreenHeight, "Auto-Kill-GRB.bmp")
		if ErrorLevel
			 kill := 0
		else color:= pixelGetColor(whereX, whereY)
	}
	setTimer(()=>(pixelGetColor(whereX, whereY) != color? Send(1):""), kill? 100: "OFF")
	display()
return	
!B:: warrior.status(-1), display()
#!Q::ExitApp
; ----------
display() {
	global
	tooltip(rungrb? "<" OnOff(kill) "> KILL | BUFF <" OnOff(warrior.internalFlag) ">"
				  : "< Auto Kill - loaded >"
			, A_ScreenWidth/2-90, A_ScreenHeight-75, 20)
	OnOff(arg)=>(arg? "ON": "OFF")
}
class Buff {
	__New(timer, htkey, metod) {
		this.timer:= timer
		this.metod:= metod
		
		HotKey(htkey, ()=>this.switch()) ;"reference" to this.method
	}
	switch(state:=1) { ;switch ON / switch OFF
		if(state) {
			   this.metod.call() ;uncomment if you need to run now and timed
			   settimer(this.metod, this.timer) ;run timed
		} else settimer(this.metod,      "OFF") ;stop
}	}
class Flag {
	internalList:= []
	internalFlag:=  0
	status(arg) { ;sigle function that managed internalFlag (shorter and more readable)
		this.internalFlag:= arg < 0? !this.internalFlag: arg
		loop this.internalList.length()
			this.internalList[A_Index].switch(this.internalFlag)
	}	
	add(arg) {
		this.internalList.Push(arg)
}	}
Enjoy!
Attachments
Auto-Kill-GRB.zip
(539.74 KiB) Downloaded 22 times
AHKv2.0 use the future now.
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

Crazy Class - alpha

01 Mar 2019, 15:34

This is a side effect from class Buff and class Flag.
And as result most complicated method to do something simple.
class Ahk2

Code: Select all

class Ahk2 {
	ahkTrig:= 0
	__New(ahkHkey, ahkFunc, ahkView) {
		try	Hotkey(ahkHkey[1], ()=>ahkFunc[1].call(this))
		try Hotkey(ahkHkey[2], ()=>ahkFunc[2].call(this))
		
		(this.ahkView:= ahkView).call("INIT")
}	}
Class Ahk2 is something like holder that generate some actions. But let see how it works.

Code: Select all

a:= new Ahk2(["1", "2"]
			,[(this)=>(this.ahkView.call("Ahk2 ACTIVE " . (this.ahkTrig:=1))) ;FAT function "1"
			 ,(this)=>(this.ahkView.call("Ahk2 PASIVE " . (this.ahkTrig:=0))) ;FAT function "2"
			 ] ;-------------------- end of list
			,(outp)=>(tooltip(outp))
			)  ;-------------------- end of constructor call
#!Q::ExitApp
What this code do?
1. Generate Hotkey 1 with "FAT function 1"
2. Generate Hotkey 2 with "FAT function 2"
3. Void message with action status.
And the ordinary code.

Code: Select all

1::tooltip("Ahk2 ACTIVE " . (ahkTrig:=1))
2::tooltip("Ahk2 PASIVE " . (ahkTrig:=0))
One more example:

Code: Select all

a:= new Ahk2(["1"]
			,[(this)=>((outp:= "Ahk2 ")
					  ,(outp.= (this.ahkTrig:=!this.ahkTrig)? "ACTIVE ": "PASIVE ")	
					  ,(this.ahkView.call(outp . this.ahkTrig))
					  ) ;----------- FAT function trigger
			 ] ;-------------------- end of list
			,(outp)=>(tooltip(outp))
			)  ;-------------------- end of constructor call
#!Q::ExitApp
What this code do?
1. Generate Hotkey 1 with "FAT function trigger"
2. Void message with action status=
And the ordinary code.

Code: Select all

1::tooltip("Ahk2 " ((ahkTrig:=!ahkTrig)? "ACTIVE ": "PASIVE ") . ahkTrig)
So as I said most complicated method.
Enjoy!
AHKv2.0 use the future now.
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

Auto-Kill-GRB version 3

20 Mar 2019, 18:28

The idea was to write a mechanism that can cover many different cases to activate and control main buffs in my game.
Lets see one examle:
  • When gamer press Numpad1 script send Numpad1 5 times and repeat send Numpad1 5 times any given timed period
  • When gamer press Numpad2 script send Numpad2 5 times and repeat send Numpad2 5 times any given timed period
  • When gamer press Numpad3 script send Numpad2 5 times and repeat send Numpad3 5 times any given timed period
  • When gamer press Numpad4 script send Numpad4 5 times and repeat send Numpad4 5 times any given timed period
  • When gamer press Alt+B (All Buffs) script activate / deactivate all registered in groug buffs (emulate sending Numpad1 Numpad2 Numpad3 Numpad4 to activate buffs / deactivate timers)
In last version of Auto-Kill-GRB was that mechanism but it was only for similar tasks.
In new version:
Timed item : class that contain single timed action.

Code: Select all

class TimedHKey {
	stat:= 0
	__New(hkey, time, acti, hint, view:="", trig:= 1) { ;1 - timed call ON / -1 - timed call ALTERNATE (trigger)
			this.time:= time
		    this.acti:= (type(acti) == "Func"? acti: ()=>"").Bind(this)
		    this.hint:= (type(hint) == "Func"? hint: ()=>"").Bind(this)
			Hotkey(hkey, ()=>this.Call(trig))
		try { ; if no function when create
			this.view:= view.Bind(this)
			this.view.Call()
	}	}
	Call(arg:="") {
		if(arg != "") 								   ; "" prevent activity but keep view
			if(this.stat:= arg < 0? !this.stat: arg) { ; -1 - trigger / 1 - ON / 0 - OFF
					this.acti.call()
					SetTimer(this.acti, this.time)
			} else	SetTimer(this.acti, "OFF")
		try this.view.call()
}	}
ALL things like activity (acti), hint, view - now become functions - it is more flexible than just data.
What this class do?
1. Creat Hotkey with hkey and function this.Call()
2. Set activity function that will be called in this.time period
3. Set view function this.view

This class alone can create hotkey with given activity and given view (display activity).

Timed group : Lets create group of timed items to be controlled together.

Code: Select all

class TimedHKeyGroup {
	stat:= 0
	list:=[]
	__New(hint, view) {
		this.hint:= (type(hint) == "Func"? hint: ()=>"").Bind(this)
		this.view:= (type(view) == "Func"? view: ()=>"").Bind(this)
	}
	Call(arg:="") {
		outp:= this.hint.Call()
		this.stat:= arg != ""? arg < 0? !this.stat: arg: this.stat
		loop this.list.length() {
			if(arg != "")
				this.list[A_Index].Call(arg)
			outp.= this.list[A_Index].hint.Call()
		}	
		try this.view.Call(outp)	
	}
	Add(hkey) {
		if(type(hkey.view) != "Func")
			hkey.view:=()=>this.Call()
		this.list.Push(hkey)
		this.Call()
}	}
This class keep list of timed items, activate/deactivate its together and display its statuses together.
Again hint and view as functions.
In action : how this two classes worked together?

Code: Select all

ItemHint(this, hint:="") { ; --------------------------------------------------
	return this.stat? hint: "•"
} ; ---------------------------------------------------------------------------
warr:= new TimedHKeyGroup(()=>"WARR ",(this, outp)=>(tooltip(outp, A_WindowWidth/2, A_WindowHeight-75, 20)))
warr.Add(new TimedHKey("$Numpad1", 181000, ()=>(Send("{Numpad1 5}")), (this)=>ItemHint(this,"1")))
warr.Add(new TimedHKey("$Numpad2", 170000, ()=>(Send("{Numpad2 5}")), (this)=>ItemHint(this,"2")))
warr.Add(new TimedHKey("$Numpad3", 300000, ()=>(Send("{Numpad3 5}")), (this)=>ItemHint(this,"3")))
warr.Add(new TimedHKey("$Numpad4", 900000, ()=>(Send("{Numpad4 5}")), (this)=>ItemHint(this,"4")))
!B:: warr.Call(-1)
Any added item have personal hotkey that do activity and keep activity in time period. In addition group can activate/deactivate its item`s activity together and display its item`s status.
Auto-Kill group : with only one element (for now) in the future here ill add items for auto-heal and kill-count.

Code: Select all

TimedAK(this) { ; -------------------------------------------------------------
	static X:= 0, Y:= 0, A_TimedAKBmp:= "Auto-Kill-GRB.bmp"
	global A_WindowWidth, A_WindowHeight
	loop 3 { ; !!! now then timed == x2 (6 times)
		if(ImageSearch(X, Y, X, Y, A_WindowWidth, A_WindowHeight, A_TimedAKBmp))
			return
		Send(1)
	}
	X:= Y:= 0
	this.stat:= 0
	SetTimer(this.acti, "OFF")
} ; ---------------------------------------------------------------------------
kill:= new TimedHKeyGroup(()=>"KILL ",(this, outp)=>(tooltip(outp, A_WindowWidth/2-50, A_WindowHeight-75,19)))
kill.Add(new TimedHKey("$CapsLock", 100, Func("TimedAK"), (this)=>ItemHint(this,"A"),,-1))
Item try 6 times to find nearest opponent to kill or else stopped till next activation. (if no more mobs - stop auto-kill)

The full code : it is well tested code that worked.

Code: Select all

#SingleInstance Force
;Copyright (c) D.Donchev

SetTitleMatchMode(3)
if(!WinExist(title:= "TheNameOfTheGame")) {
	MsgBox(title " not exist!")
	ExitApp
}
WinActivate(title)
WinGetPos(,, A_WindowWidth, A_WindowHeight, title)

SendMode("Event")
SetKeyDelay(150, 90)

ItemHint(this, hint:="") { ; --------------------------------------------------
	return this.stat? hint: "•"
} ; ---------------------------------------------------------------------------
warr:= new TimedHKeyGroup(()=>"WARR ",(this, outp)=>(tooltip(outp, A_WindowWidth/2, A_WindowHeight-75, 20)))
warr.Add(new TimedHKey("$Numpad1", 181000, ()=>(Send("{Numpad1 5}")), (this)=>ItemHint(this,"1")))
warr.Add(new TimedHKey("$Numpad2", 170000, ()=>(Send("{Numpad2 5}")), (this)=>ItemHint(this,"2")))
warr.Add(new TimedHKey("$Numpad3", 300000, ()=>(Send("{Numpad3 5}")), (this)=>ItemHint(this,"3")))
warr.Add(new TimedHKey("$Numpad4", 900000, ()=>(Send("{Numpad4 5}")), (this)=>ItemHint(this,"4")))
TimedAK(this) { ; -------------------------------------------------------------
	static X:=0, Y:= 0, A_TimedAKBmp:= "Auto-Kill-GRB.bmp"
	global A_WindowWidth, A_WindowHeight
	loop 3 { ; !!! now then timed == x2 (6 times)
		if(ImageSearch(X, Y, X, Y, A_WindowWidth, A_WindowHeight, A_TimedAKBmp))
			return
		Send(1)
	}
	X:= Y:= 0
	this.stat:= 0
	SetTimer(this.acti, "OFF")
} ; ---------------------------------------------------------------------------
kill:= new TimedHKeyGroup(()=>"KILL ",(this, outp)=>(tooltip(outp, A_WindowWidth/2-50, A_WindowHeight-75,19)))
kill.Add(new TimedHKey("$CapsLock", 100, Func("TimedAK"), (this)=>ItemHint(this,"A"),,-1))

 !B:: warr.Call(-1)
#!Q::ExitApp
; classes and functions ------------------------------------------------------- 
class TimedHKey {
	stat:= 0
	__New(hkey, time, acti, hint, view:="", trig:= 1) {
			this.time:= time
		    this.acti:= (type(acti) == "Func"? acti: ()=>"").Bind(this)
		    this.hint:= (type(hint) == "Func"? hint: ()=>"").Bind(this)
			Hotkey(hkey, ()=>this.Call(trig))
		try {
			this.view:= view.Bind(this)
			this.view.Call()
	}	}
	Call(arg:="") {
		if(arg != "")
			if(this.stat:= arg < 0? !this.stat: arg) {
					this.acti.call()
					SetTimer(this.acti, this.time)
			} else	SetTimer(this.acti, "OFF")
		try this.view.call()
}	}
class TimedHKeyGroup {
	stat:= 0
	list:=[]
	__New(hint, view) {
		this.hint:= (type(hint) == "Func"? hint: ()=>"").Bind(this)
		this.view:= (type(view) == "Func"? view: ()=>"").Bind(this)
	}
	Call(arg:="") {
		outp:= this.hint.Call()
		this.stat:= arg != ""? arg < 0? !this.stat: arg: this.stat
		loop this.list.length() {
			if(arg != "")
				this.list[A_Index].Call(arg)
			outp.= this.list[A_Index].hint.Call()
		}	
		try this.view.Call(outp)	
	}
	Add(hkey) {
		if(type(hkey.view) != "Func")
			hkey.view:=()=>this.Call()
		this.list.Push(hkey)
		this.Call()
}	}
Numpad1 - forced start Numpad1 buff and keep it timed.
Numpad2 - forced start Numpad2 buff and keep it timed.
Numpad3 - forced start Numpad3 buff and keep it timed.
Numpad4 - forced start Numpad4 buff and keep it timed.
Alt+B - activate / deactivate all Numpad buffs. (You don`t need to activate all 4 buffs but can stop them all together)
CapsLock - activate / deactivate Auto-Kill in any 100ms.
Win+Alt+Q - Exit

Enjoy! Don`t forget to change "TheNameOfTheGame" with name of the game :P
Attachments
Auto-Kill-GRB.zip
(539.73 KiB) Downloaded 19 times
AHKv2.0 use the future now.
_3D_
Posts: 211
Joined: 29 Jan 2014, 14:40

Stuck in Sleep.

04 May 2019, 02:11

Let see an ordinary code:

Code: Select all

$Tab::
			Send("~")		;select
Sleep( 500) Send("{7 3}")	;Bloody Arc
Sleep(1500) Send("{9 3}")	;Divine Burst
Sleep(1500) Send("{5 3}")	;Hell's Claw
return
It is usually used code to produce skill chain in game. It work perfect but what if script have more than one skill chain?
I mention that when more Sleep() in script worked simultaneously in different Hotkeys then given "sleeps" messed up each other and in addition scrip become less responsible.
So what to do to avoid stuck in sleep?

Code: Select all

$Tab::
when:= 0			
			  Send("~")
SetTimer(()=>(Send("{7 3}")), when-= 500)
SetTimer(()=>(Send("{9 3}")), when-=1500)
SetTimer(()=>(Send("{5 3}")), when-=1500)			
return
Now script load timers quickly and return to main action, then interpreter will do all actions in separate thread.

Enjoy!
AHKv2.0 use the future now.

Return to “Gaming”

Who is online

Users browsing this forum: No registered users and 8 guests