InGame v2.0

Post gaming related scripts
_3D_
Posts: 277
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 alpha forever.
_3D_
Posts: 277
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 alpha forever.
_3D_
Posts: 277
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 alpha forever.
_3D_
Posts: 277
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 alpha forever.
_3D_
Posts: 277
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 alpha forever.
_3D_
Posts: 277
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 alpha forever.
_3D_
Posts: 277
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 259 times
AHKv2.0 alpha forever.
_3D_
Posts: 277
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 alpha forever.
_3D_
Posts: 277
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 234 times
AHKv2.0 alpha forever.
_3D_
Posts: 277
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 alpha forever.
_3D_
Posts: 277
Joined: 29 Jan 2014, 14:40

Callback creator

02 Dec 2019, 12:00

Hi there 7 mounts later.

Optimizing last code

Code: Select all

$Tab::
	Send("~")
	SetTimer(()=>(Send("{7 3}")), when:=-500)
	SetTimer(()=>(Send("{9 3}")), when-=1500)
	SetTimer(()=>(Send("{5 3}")), when-=1500)			
return
Here we have 3 identical callback arguments. BUT what if there a callback creator?

Code: Select all

snd(n)=>()=>Send("{" n " 3}")
And the result:

Code: Select all

$Tab::
	Send("~")
	SetTimer(snd(7), when:=-500)
	SetTimer(snd(9), when-=1500)
	SetTimer(snd(5), when-=1500)			
return
snd(n)=>()=>Send("{" n " 3}")
As result we have callback with argument(s) that is very useful.
EDIT:
OK. What the code mean?
Any fat arrow function return expression after fat arrow fatarrow(argument)=>expression. Creator return reference to fat arrow function (that is the trick). Due to argument is visible to internal fat arrow function, internal fat arrow function can "see" it. At the other hand when fat arrow function is set to SetTimer() argument is replaced with current value of argument. That's it.

Enjoy!
AHKv2.0 alpha forever.
_3D_
Posts: 277
Joined: 29 Jan 2014, 14:40

SetTimer() - Simple Example

10 Dec 2019, 14:11

A Simple example about SetTimer() with fat arrow.

Code: Select all

#SingleInstance Force

1::caller(()=>(MouseGetPos(mX, mY) tooltip(mC:=PixelGetColor(mX, mY))))
2::caller(()=>tooltip(mC))
3::caller()

#!Q::ExitApp

caller(arg:="") {
	static ref:= ""
	
	try	SetTimer(ref,   "OFF")
	tooltip()
	try	SetTimer(ref:=arg,100)
}
This Code void color under mouse pointer.
Here we see 3 different aspects of using fat arrow functions.
1. Sending reference of fat arrow function as argument.
2. Starting reference in SetTimer().
3. Creating global variables inside fat arrow function.

Enjoy!
AHKv2.0 alpha forever.
_3D_
Posts: 277
Joined: 29 Jan 2014, 14:40

[AHKv2.0-a108] Object, Array and Map

22 Dec 2019, 07:04

How I think Object, Array and Map must work in AHKv2.0 (current version a108)
Object

Code: Select all

;Override Object --------------------------------------------------------------
;Override Object.__Get --------------------------------------------------------
Object.Prototype.DefineMethod('__Get' , func("Object__Get" ))
Object__Get(this, name, params*) {
	if(this.HasOwnProp(name))
		 return this.name[params*]
	else return ''	
} 
;Override Object.__Call -------------------------------------------------------
Object.Prototype.DefineMethod('__Call', func("Object__Call"))
Object__Call(this, name, params*) {
	if(this.HasOwnMethod(name))
		 return this.name(params*)
	else return ''	
} ;----------------------------------------------------------------------------
ARRAY:
1. Array.Has(index) must return type of value at index if valid otherwise ""
2. Array.__Item.Get(index) must return value at index if valid otherwise ""
3. Array.__Item.Set(value, index)
  • if index == 0 must work as Array.InsertAt(1, value)
  • if index > Array.Length must work as Array[Array.Length:= index]:= value
  • if index > 0 && index <= Array.Length as Array[index]:= value
Implementation:

Code: Select all

;Override Array ---------------------------------------------------------------
Array.Prototype.DefineMethod("__Has", (this, indx) => (
	indx:= (indx < 0? this.Length + indx + 1: indx),
	(indx > 0 && indx <= this.Length)
)	)
global Arr__Item := Array.Prototype.GetOwnPropDesc('__Item')
;Override Array.Has -----------------------------------------------------------
Array.Prototype.DefineMethod('Has', (this, indx) => (
	this.__Has(indx) ? type(%Arr__Item.Get%(this, indx)) : ''
)	)
;Override Array.__Item --------------------------------------------------------
Array.Prototype.DefineProp('__Item', {
	get: (this, indx) => (this.__Has(indx) ? %Arr__Item.Get%(this, indx) : ''),	
	set: Func('Array__ItemSet')	
}	)
Array__ItemSet(this, value, indx) {
	if(indx == 0) {
		this.InsertAt(1, value)
		return value
	}
	this.Length:= (indx > this.Length? indx: this.Length)
	return %Arr__Item.Set%(this, value, indx) ;exception if index < -this.Length 
} ;----------------------------------------------------------------------------
And tests:

Code: Select all

ar:= [2,,()=>4]
ar[0]          := "ONE" ;ar.InsertAt(1, "ONE")
ar[ar.Length+2]:= "SIX" ;ar.[ar.Length+=2]:= "SIX"

for id in [0, 1, 2, 3, 4, 5, 6, 7] {
	r:= ar.Has(id)
	MsgBox('ARRAY[ "' id '" ] >>> '
	   .   'Has' (r? '': ' not') ' index "' id '"' (r? ' with value type ' r: '')
	   . '`nvalue= ' (r == 'Func'? ar[id].call(): ar[id]))
}
MAP:
1. Map.Has(index) must return type of value at index if exist otherwise ""
2. Map.__Item.Get(index) must return value at index if exist otherwise ""
Implementation:

Code: Select all

;Override Map -----------------------------------------------------------------
;Override Map.__New -----------------------------------------------------------
Map.Prototype.DefineMethod('__New', Func('Map__New'))
Map__New(this, params*) {
	loop params.length {
		;replace all omited keys or vals with ''
		this[params[A_Index]]:= params[A_Index+1]
		A_Index++
}	}			
global Map__Item := Map.Prototype.GetOwnPropDesc('__Item')
global Map__Has  := Map.Prototype.GetMethod('Has')
;Override Map.Has -------------------------------------------------------------
Map.Prototype.DefineMethod('Has', (this, indx) => (
	%Map__Has%(this, indx) ? type(%Map__Item.Get%(this, indx)): ''
)	)
;Override Map.__Item ----------------------------------------------------------
Map.Prototype.DefineProp('__Item', {
	get: (this, indx) => (
	%Map__Has%(this, indx) ? %Map__Item.Get%(this, indx) : '')
}	) ; -----------------------------------------------------------------------
And tests:

Code: Select all

mp:= Map.new("A", 1, , ()=>2, "C")

for id in ["", "A", "B", "C"] {
	r:= mp.Has(id)
	MsgBox('MAP[ "' id '" ] >>> '
	   .   'Has' (r? '': ' not') ' key "' id '"' (r? ' with value type ' r: '')
	   . '`nvalue= ' (r == 'Func'? mp[id].call(): mp[id]))
}
Last edited by _3D_ on 17 Jan 2020, 09:49, edited 2 times in total.
AHKv2.0 alpha forever.
_3D_
Posts: 277
Joined: 29 Jan 2014, 14:40

[AHKv2.0-a108] Disable SHIFT+DELETE

31 Dec 2019, 07:29

There no known method to disable Shift+Delete shortcut in windows file explorer.
So my First try:

Code: Select all

#NoTrayIcon
#SingleInstance Force
;Copyright (c) D.Donchev

#!Q::ExitApp ;extra exit
#IF (hand:= WinActive("ahk_exe explorer.exe"))
~+Del::
~+LButton::	;user bring content menu and click at Delete with Shift
~+RButton::
	if(hwnd:= WinWaitActive("ahk_class #32770",,2)) {
		ControlSetEnabled(0, "Button1", hwnd) ;disable Yes control
		Sleep(50)
		ControlSend("{Tab}", hwnd)			  ;select No control
		Text:=ControlGetText("Button1", hwnd)
		ControlSetText(Text, "Button2", hwnd) ;change No control to Yes
											  ;to keep active letter
		ControlSetText("DISABLED", "Button1", hwnd)
		;init any new pair hand:hwnd to wait
		SetTimer(()=>( 					
			WinWaitClose(hwnd) Sleep(50) ControlSend("{Del}", hand)
		), -1)
	}
return
#IF
I do some tests and it works.
BTW :xmas: :xmas: :xmas: Happy new Year 2020
AHKv2.0 alpha forever.
_3D_
Posts: 277
Joined: 29 Jan 2014, 14:40

[AHKv2.0-a108] type_Is() / type_Of() / type_Me()

17 Jan 2020, 07:32

[AHKv2.0-a108]
type_Is(this, type) This function check is this can be represent as type (is in this inheritance chain type type).

Code: Select all

type_Is(this, type) {
	try	while(this.__Class != 'Any')
			if((this:= this.base).__Class == type)
				return 1
	return 0	
}
type_Of(this) This function return inheritance chain string of this.

Code: Select all

type_Of(this) {
	try { 
		loop  
			str .= (this:= this.base).__Class '.'
		until(this.base.__Class == 'Any')	
		return str 'Any'
	} return 'ComObject'
}
type_Me(this, type) This function show results from type_Is() and type_Of().

Code: Select all

type_Me(this, type) {
	MsgBox('type is (' type ') = ' (type_Is(this, type)? 'TRUE':'FALSE') '`n`n' type_Of(this))
}
Type must be string as next: 'Any', 'Primitive', 'String', 'Number', 'Integer', 'Float', 'Object', 'Func', 'Closure', 'BoundFunc', 'Class', 'File', 'Gui', 'Array', 'Map', <User name class>.

ComObject type_Is() will return FALSE and type_Of() will return ComObject Answer why here Objects

Usage:

Code: Select all

type_Me(1, 'Integer') ;TRUE
type_Me((()=>).Bind(1), 'Func') ;TRUE
type_Me(FileOpen('afile.txt', 'rw'), 'File') ;TRUE
; -------------------------------------------------------------
VarSetCapacity(var, 24, 0)
type_Me(ComObject(0x400C, &var), 'Object') ;FALSE
You can put this 3 functions in Lib folder of AHK as type.ahk
Last edited by _3D_ on 26 Jan 2020, 09:23, edited 2 times in total.
AHKv2.0 alpha forever.
_3D_
Posts: 277
Joined: 29 Jan 2014, 14:40

[AHKv2.0-a108] Gdip port

22 Jan 2020, 09:16

Attachments
Gdip.ahk
(89.6 KiB) Downloaded 212 times
Last edited by _3D_ on 26 Jan 2020, 07:42, edited 1 time in total.
AHKv2.0 alpha forever.
guest3456
Posts: 3453
Joined: 09 Oct 2013, 10:31

Re: [AHKv2.0-a108] Gdip port

24 Jan 2020, 23:17

_3D_ wrote:
22 Jan 2020, 09:16
No comment!
[AHKv2.0-a108][BUG] DllCall
saw your v2 gdip thread

just want you to know that we've been keeping an updated GDIP library that is compatible with both v1 and v2 here at this link, and we've fixed some bugs too:
https://github.com/mmikeww/AHKv2-Gdip

i've just updated it to work with the latest

_3D_
Posts: 277
Joined: 29 Jan 2014, 14:40

[AHKv2.0-a108] Object_Array_Map

04 Feb 2020, 07:00

As type() not so useful in a108, I revised Object_Array_Map to be more simple.

Code: Select all

;Override Object ==============================================================
;Override Object.__Get --------------------------------------------------------
Object.Prototype.DefineMethod('__Get' , (this, name, params*) =>
	this.HasOwnProp(name)? this.name[params*]: ''
) 
;Override Object.__Call -------------------------------------------------------
Object.Prototype.DefineMethod('__Call', (this, name, params*) =>
	this.HasOwnMethod(name)? this.name(params*): ''
)
;Override Array ===============================================================
;Override Array.Has -----------------------------------------------------------
Array.Prototype.DefineMethod('Has', (this, indx) => (
	indx:= (indx < 0? this.Length + indx + 1: indx),
	(indx > 0 && indx <= this.Length)
)	)
;Override Array.__Item --------------------------------------------------------
global Arr__Item := Array.Prototype.GetOwnPropDesc('__Item')
Array.Prototype.DefineProp('__Item', {
	get: (this, indx) => (this.Has(indx) ? %Arr__Item.Get%(this, indx) : ''),	
	set: (this, value, indx) => (indx == 0) ? (this.InsertAt(1, value), this[1])
			: (this.Length:= (indx > this.Length? indx: this.Length),
			   %Arr__Item.Set%(this, value, indx)) ;exception if index < -this.Length 
}	)
;Override Map =================================================================
;Override Map.__New -----------------------------------------------------------
Map.Prototype.DefineMethod('__New', Func('Map__New'))
Map__New(this, params*) {
	loop params.length ;replace all omited keys or vals with ''
		this[params[A_Index++]]:= params[A_Index]
}
Map(params*) => Map.new(params*)	;Override Map() to be the same as Map.new()		
global Map__Item := Map.Prototype.GetOwnPropDesc('__Item')
;Override Map.__Item ----------------------------------------------------------
Map.Prototype.DefineProp('__Item', {
	get: (this, indx) => this.Has(indx) ? %Map__Item.Get%(this, indx) : ''
}	)
Enjoy!
Last edited by _3D_ on 11 Feb 2020, 05:57, edited 1 time in total.
AHKv2.0 alpha forever.
_3D_
Posts: 277
Joined: 29 Jan 2014, 14:40

Function Arguments

11 Feb 2020, 05:35

Function "generator" (arg)=>()=><expression> is cool, but will we have the same functionality and the function arguments?

Code: Select all

function(1, 2, 3)
function(arg1, arg2, arg3) {
	MsgBox('ARG1= ' arg1 '`nARG2= ' arg2 '`nARG3= ' arg3)
}
It is usual code. We see that function arguments look like an Array:

Code: Select all

function([1, 2, 3]*)
function(arg1, arg2, arg3) {
	MsgBox('ARG1= ' arg1 '`nARG2= ' arg2 '`nARG3= ' arg3)
}
Works!
So instead of discrete arguments we can call function with Array()*

Code: Select all

function(argument(1)*)
argument(arg) => [arg, arg+1, arg+2]
function(arg1, arg2, arg3) {
	MsgBox('ARG1= ' arg1 '`nARG2= ' arg2 '`nARG3= ' arg3)
}
Works again!
Of course there some limitations for example ByRef:

Code: Select all

A:= [1, 2, 3]

function(A*)
function(A*)

function(ByRef arg1, arg2, arg3) {
	MsgBox('ARG1= ' arg1 '`nARG2= ' arg2 '`nARG3= ' arg3)
	arg1:= 7
}
A[1] not changed. Why?
It is not possible to pass properties of objects (such as foo.bar), Clipboard or other built-in variables to a function by reference. Instead, the function acts as though ByRef was omitted.
In other words IF argument is generated by function (property is a function) ByRef not work.

Enjoy!
AHKv2.0 alpha forever.
_3D_
Posts: 277
Joined: 29 Jan 2014, 14:40

[a108] Class Debug

23 Feb 2020, 13:40

There will not be comments because of disagreement with changes in AHKv2.0

Code: Select all

class Debug { ;using class as superglobal var ---------------------------------
	static File:= ''		;log file
	static out( cond:=''	;rule condition
			  , mess:=''	;debug message
			  , valu:=''	;if  condition message
			  , zero:='')	;if !condition message
	{	OutputDebug(str:= mess ' ' (cond? valu: zero)) ;use DebugView.exe
		;if Debug.File
			try Debug.File.WriteLine(str) Debug.File.Read(0)
			;catch e			;"whatever exceptions in a108"
			;	OutputDebug e.what ' at ' e.line ': ' e.message
		return cond								 
}	} ;------------------------------------------------------------------------
AHKv2.0 alpha forever.

Return to “Gaming”

Who is online

Users browsing this forum: No registered users and 3 guests