TT6 MoveTo engine public

03/04/2009 16:08 bingbongman#511
Ich bin es nochmal, wieder mit einem Ident. Problem. Und zwar versteh ich nicht ganz welche Werte ich hier eintragen muss.

PHP Code:
y offset of cell 0,0
invPosX00 
50
invPosY00 
90 

Gruß Bing. :o
03/04/2009 16:59 kknb#512
die x und y position von dem ersten itemplatz oben links im inventar.
03/04/2009 17:09 Specter cason#513
die koordinaten der des inventarslots ganz oben links

€: zu spät :D
03/04/2009 18:21 kknb#514
toni deine loot func sieht interessant aus, hab dazu nen kleines script gemacht um die db zu füllen (zum beispiel vor beginn des fightscriptes)

Code:
#include "tt6.au3"
#include <array.au3>

Dim $CLBlackList[1]  
BuildCLBlackList(100)


func BuildCLBlackList($fillbl)
		KeySend($INtgtkey)
	for $i = 0 to $fillbl
		$itemid = _memoryread($memnpcidselect,$hprocess)
		$CLBlackList[$i] = $itemid
		ReDim $CLBlackList[Ubound($CLBlackList)+1]      
		keysend("o") ; taste für nächstes item
		sleep(20)
	Next
EndFunc
03/04/2009 19:46 tonitusch666#515
ah ok, danke, ich hatte die CLblacklist Befüllung schon in nem post vorher drinnen und dann hier vergssen zu posten, also das mit dem redim ist spannend, ich pack mal die ältere version oben mit rein und merge dann das im final mit deiner idee...
03/04/2009 20:06 kknb#516
boah ich depp...ich hatte mir zwar die erste version von deiner lootfunk angeguckt, aber aus mir noch unerklärlichen gründen muss ich den ersten teil übersehen haben.
03/05/2009 12:21 NBA#517
Klingt cool. Wird der Gegenstand dann auch im Klartext in eine Datei geschrieben?
Bzw. Könnte man das dann so ergonomisch machen, das er z.B.

Nicht Aufgehobene Gegenstände:
-Grausiger Cestus (davon 1)
-Eisenbarren (davon 3)
-Stygiersteine (davon 8)


Schreibt? So wegen der übersicht...
03/05/2009 12:45 MyDooMisHaxXor#518
Quote:
Originally Posted by NBA View Post
Klingt cool. Wird der Gegenstand dann auch im Klartext in eine Datei geschrieben?
Bzw. Könnte man das dann so ergonomisch machen, das er z.B.

Nicht Aufgehobene Gegenstände:
-Grausiger Cestus (davon 1)
-Eisenbarren (davon 3)
-Stygiersteine (davon 8)


Schreibt? So wegen der übersicht...
Dann müsste man ja von jedem gegenstand die id haben oder? Und da es dafür wohl keine statische gibt wird das wohl nix. Die abfrage nach der blacklist bezieht sich hier wohl mehr auf die abfrage ob ein schildtruhe etc im weg ist welches man am anfang des runs abfragt bevor items gefallen sind. Oder habe ich da was falsch verstanden?
03/05/2009 13:55 NBA#519
Hab mal etwas weiter "übersetzt"

Code:
TT6 V1.4 quick introduction  - Deutsche Version, übersetzt von NBArena (http://www.elitepvpers.com/forum/guild-wars)                      28.2.2009

---------------------------


Was es ist:
- von größtem Interese ist die MoveTo() engine welche die
  Bewegung von bots zu einer vordefinierten Position erleichtert.
- eine kollektion von nützlichen Funktionen für normale Anwendungsgebiete.
- Abstraktion von Mausclick-Positionen und Tastenanschlägen welche vom Benutzer
  Konfigurierbar sind und es erlauben den Bot-Code unberührt zu lassen ohne
  benutzer adaption.



API:



* Bewegungs Engine (Movement engine):


Die Bewegung muss durch einen Aufruf von
PrepMoveTo()
vorbereitet werden.

Eines der folgenden API muss nach einer Bewegungssequenz aufgerufen werden.
StopMoveTo()
KeepMoveTo()
Der Unterschied zwischen Stop und Keep ist, dass Stop die Bewegung wirklich stopt.
Keep stopt die engine nur logisch. Du musst KeepMoveTo() verwenden falls du
durch ein Portal rennen willst. Der finale WayPoint muss sich kurz vor dem Portal befinden.


MoveTo($mode, $x, $y, $random = False, $dcheck = False)

  
MoveTo(...) ist das Herz von dem Bewegungs-System, du definierst deine WayPoints
bei einer sequenz von Aufrufen. Normalerweise mach es kein return bis es die gegebene Position
erreicht hat, aber es gibt ein paar extra parameter welche in speziellen Situationen benutzt werden können.




						While Not MoveTo(0,0,0)

							Sleep(10)

							 "Aber wenn du ein paar sehr wichtige Dinge zur Versicherung oder  								  Check hast, kannst du es hier parallel laufen lassen. Sei   								  versichert das du den Aufrufskreislauf erreichst, welcher 								  10ms ist"

						WEnd 

 mode = 0 : Macht eine Interaktion und einen Return.
            Der Aufruf Kreislauf ist 10ms. Ein Funktionenaufruf returnt nicht.
            Du kannst folgendes machen:
            InitDest(...)
            "Manche extra speziellen Sachen nachdem wir zur destination rotiert sind"



mode = 1 : initzialisiert MoveTo-Position und geht dorthin.
	   Dies ist der Standart zum rumrennen.

mode = 2 :     Autorun Modus
		Wenn ein Stop entdeckt, z.B. durch ein hinwerfen oder einen Cast welchen du in einem paralleln 
		thread gemacht hast, z.B. durch Adlibenable, wird versucht automatisch weiterzurennen. Das passiert 
		nach 500ms.
		Um zu versichern, dass deine Casts, durch die Moveto, nicht unterbrochen werden, musst du die Cast-Sequenz 			durch DisableStopCheck() beschützen.

		Beispiel:
		DisableStopCheck()
		"cast deinen Skill (z.B. Schattenform)"
		"vergiss nicht ein sleep(blabla) einzubauen"
		EnableStopCheck()
Code:
TT6 V1.4 quick introduction  - Deutsche Version, übersetzt von NBArena (http://www.elitepvpers.com/forum/guild-wars)                      28.2.2009

---------------------------


Was es ist:
- von größtem Interese ist die MoveTo() engine welche die
  Bewegung von bots zu einer vordefinierten Position erleichtert.
- eine kollektion von nützlichen Funktionen für normale Anwendungsgebiete.
- Abstraktion von Mausclick-Positionen und Tastenanschlägen welche vom Benutzer
  Konfigurierbar sind und es erlauben den Bot-Code unberührt zu lassen ohne
  benutzer adaption.



API:



* Bewegungs Engine (Movement engine):


Die Bewegung muss durch einen Aufruf von
PrepMoveTo()
vorbereitet werden.

Eines der folgenden API muss nach einer Bewegungssequenz aufgerufen werden.
StopMoveTo()
KeepMoveTo()
Der Unterschied zwischen Stop und Keep ist, dass Stop die Bewegung wirklich stopt.
Keep stopt die engine nur logisch. Du musst KeepMoveTo() verwenden falls du
durch ein Portal rennen willst. Der finale WayPoint muss sich kurz vor dem Portal befinden.


MoveTo($mode, $x, $y, $random = False, $dcheck = False)

  
MoveTo(...) ist das Herz von dem Bewegungs-System, du definierst deine WayPoints
bei einer sequenz von Aufrufen. Normalerweise mach es kein return bis es die gegebene Position
erreicht hat, aber es gibt ein paar extra parameter welche in speziellen Situationen benutzt werden können.




						While Not MoveTo(0,0,0)

							Sleep(10)

							 "Aber wenn du ein paar sehr wichtige Dinge zur Versicherung oder  								  Check hast, kannst du es hier parallel laufen lassen. Sei   								  versichert das du den Aufrufskreislauf erreichst, welcher 								  10ms ist"

						WEnd 

 mode = 0 : Macht eine Interaktion und einen Return.
            Der Aufruf Kreislauf ist 10ms. Ein Funktionenaufruf returnt nicht.
            Du kannst folgendes machen:
            InitDest(...)
            "Manche extra speziellen Sachen nachdem wir zur destination rotiert sind"



mode = 1 : initzialisiert MoveTo-Position und geht dorthin.
	   Dies ist der Standart zum rumrennen.

mode = 2 :     Autorun Modus
		Wenn ein Stop entdeckt, z.B. durch ein hinwerfen oder einen Cast welchen du in einem paralleln 
		thread gemacht hast, z.B. durch Adlibenable, wird versucht automatisch weiterzurennen. Das passiert 
		nach 500ms.
		Um zu versichern, dass deine Casts, durch die Moveto, nicht unterbrochen werden, musst du die Cast-Sequenz 			durch DisableStopCheck() beschützen.

		Beispiel:
		DisableStopCheck()
		"cast deinen Skill (z.B. Schattenform)"
		"vergiss nicht ein sleep(blabla) einzubauen"
		EnableStopCheck()		

mode = 3 : Block Modus
	   Manchmal kann es passieren, dass du während der Bewegung geblockt wirst.
	   In einfacher Bewegung würde die Function nie zurückspringen und dein Programm würde
	   in einer Schleife hängen. Um das zu verhindern kannst du, falls nötig, den Block Modus hernehmen.
	   Wenn ein Block dedectiert wird, wird eine Gloable Flag gesetzt und die Bewegungs-Engine beendet sich
	   bis 
		1)die Flag ungesetzt wird durch $gotBlocked = False
		2)einen neue Sequenz wird Initialisiert durch PrepMoveTo()

	
	   z.B.        

           PrepMoveTo()

           MoveTo(3,...)

           MoveTo(3,...)

           MoveTo(3,...)

           if $gotBlocked Then

            "cast irgenteinen Schattenschrit"

             ; gehe zu neuen startpunkt und syncronisiere mit herkömmlichen pfad

	           MoveTo(3,...)

	           MoveTo(3,...)

	           MoveTo(3,...)        

           Endif

           

           MoveTo(3,...)

           MoveTo(3,...)

           StopMoveTo()

           if $gotBlocked Then

            "omg keine chance wir müssen aufgeben"

           Endif

           .... weitermachen...



Wenn der Block passiert bist du fähig eine Ausnahme-Routine zu erstellen, fall es Sinn macht.



Flags:

dcheck - ermöglicht die deathcheck Routine, welche es dir erlaubt kills zu erkennen.
Funktioniert genauso wie die Block Routine. Du musst $isDead anschaun und es nach deiner Ausnahme-Routine durch $isDead = False zurücksetzen. Weil Tod anders gehandelt wird als beim Block, wird $isDead NICHT durch einen Aufruf von PrepMoveTo()
zurückgesetzt!

random - Fügt einige Variationen zu den MoveTo-Punkten (ca. 100) hinzu. Du solltest das machen damit die Bewegung mehr human
aussieht. Natürlicht ist das keine Garantie, das dein Bot nicht entdeckt wird!


InitDest($dx, $dy, $dcheck = False) wird normalerweise intern genutzt und ist nur wichtig mit mode 0.



DisableStopCheck()

EnableStopCheck() 

Deaktiviert/Aktiviert den check falls wir während der Bewegung gestopt wurden (z.B. durch cast oder hinfallen)
Wichtig: Muss benutzt werden um casts zu schützen, da wir im autorunmodus immer rennen.



* Kollektion von Functionen. Fühl dich frei es an deine Bedürfnisse anzupassen
Fast fertig mit Version 1.4!
03/05/2009 15:20 NBA#520
Deutsche Übersetzung von ReamMe v1.4 Fertig!

Code:
TT6 V1.4 quick introduction  - Deutsche Version, übersetzt von NBArena (http://www.elitepvpers.com/forum/guild-wars)                      28.2.2009

---------------------------


Was es ist:
- von größtem Interese ist die MoveTo() engine welche die
  Bewegung von bots zu einer vordefinierten Position erleichtert.
- eine kollektion von nützlichen Funktionen für normale Anwendungsgebiete.
- Abstraktion von Mausclick-Positionen und Tastenanschlägen welche vom Benutzer
  Konfigurierbar sind und es erlauben den Bot-Code unberührt zu lassen ohne
  benutzer adaption.



API:



* Bewegungs Engine (Movement engine):


Die Bewegung muss durch einen Aufruf von
PrepMoveTo()
vorbereitet werden.

Eines der folgenden API muss nach einer Bewegungssequenz aufgerufen werden.
StopMoveTo()
KeepMoveTo()
Der Unterschied zwischen Stop und Keep ist, dass Stop die Bewegung wirklich stopt.
Keep stopt die engine nur logisch. Du musst KeepMoveTo() verwenden falls du
durch ein Portal rennen willst. Der finale WayPoint muss sich kurz vor dem Portal befinden.


MoveTo($mode, $x, $y, $random = False, $dcheck = False)

  
MoveTo(...) ist das Herz von dem Bewegungs-System, du definierst deine WayPoints
bei einer sequenz von Aufrufen. Normalerweise mach es kein return bis es die gegebene Position
erreicht hat, aber es gibt ein paar extra parameter welche in speziellen Situationen benutzt werden können.




						While Not MoveTo(0,0,0)

							Sleep(10)

							 "Aber wenn du ein paar sehr wichtige Dinge zur Versicherung oder  								  Check hast, kannst du es hier parallel laufen lassen. Sei   								  versichert das du den Aufrufskreislauf erreichst, welcher 								  10ms ist"

						WEnd 

 mode = 0 : Macht eine Interaktion und einen Return.
            Der Aufruf Kreislauf ist 10ms. Ein Funktionenaufruf returnt nicht.
            Du kannst folgendes machen:
            InitDest(...)
            "Manche extra speziellen Sachen nachdem wir zur destination rotiert sind"



mode = 1 : initzialisiert MoveTo-Position und geht dorthin.
	   Dies ist der Standart zum rumrennen.

mode = 2 :     Autorun Modus
		Wenn ein Stop entdeckt, z.B. durch ein hinwerfen oder einen Cast welchen du in einem paralleln 
		thread gemacht hast, z.B. durch Adlibenable, wird versucht automatisch weiterzurennen. Das passiert 
		nach 500ms.
		Um zu versichern, dass deine Casts, durch die Moveto, nicht unterbrochen werden, musst du die Cast-Sequenz 			durch DisableStopCheck() beschützen.

		Beispiel:
		DisableStopCheck()
		"cast deinen Skill (z.B. Schattenform)"
		"vergiss nicht ein sleep(blabla) einzubauen"
		EnableStopCheck()		

mode = 3 : Block Modus
	   Manchmal kann es passieren, dass du während der Bewegung geblockt wirst.
	   In einfacher Bewegung würde die Function nie zurückspringen und dein Programm würde
	   in einer Schleife hängen. Um das zu verhindern kannst du, falls nötig, den Block Modus hernehmen.
	   Wenn ein Block dedectiert wird, wird eine Gloable Flag gesetzt und die Bewegungs-Engine beendet sich
	   bis 
		1)die Flag ungesetzt wird durch $gotBlocked = False
		2)einen neue Sequenz wird Initialisiert durch PrepMoveTo()

	
	   z.B.        

           PrepMoveTo()

           MoveTo(3,...)

           MoveTo(3,...)

           MoveTo(3,...)

           if $gotBlocked Then

            "cast irgenteinen Schattenschrit"

             ; gehe zu neuen startpunkt und syncronisiere mit herkömmlichen pfad

	           MoveTo(3,...)

	           MoveTo(3,...)

	           MoveTo(3,...)        

           Endif

           

           MoveTo(3,...)

           MoveTo(3,...)

           StopMoveTo()

           if $gotBlocked Then

            "omg keine chance wir müssen aufgeben"

           Endif

           .... weitermachen...



Wenn der Block passiert bist du fähig eine Ausnahme-Routine zu erstellen, fall es Sinn macht.



Flags:

dcheck - ermöglicht die deathcheck Routine, welche es dir erlaubt kills zu erkennen.
Funktioniert genauso wie die Block Routine. Du musst $isDead anschaun und es nach deiner Ausnahme-Routine durch $isDead = False zurücksetzen. Weil Tod anders gehandelt wird als beim Block, wird $isDead NICHT durch einen Aufruf von PrepMoveTo()
zurückgesetzt!

random - Fügt einige Variationen zu den MoveTo-Punkten (ca. 100) hinzu. Du solltest das machen damit die Bewegung mehr human
aussieht. Natürlicht ist das keine Garantie, das dein Bot nicht entdeckt wird!


InitDest($dx, $dy, $dcheck = False) wird normalerweise intern genutzt und ist nur wichtig mit mode 0.



DisableStopCheck()

EnableStopCheck() 

Deaktiviert/Aktiviert den check falls wir während der Bewegung gestopt wurden (z.B. durch cast oder hinfallen)
Wichtig: Muss benutzt werden um casts zu schützen, da wir im autorunmodus immer rennen.



* Kollektion von Functionen. Fühl dich frei es an deine Bedürfnisse anzupassen



; Checkt, ob die derzeitige Position sich ein einem Areal befindet (500 zu 500).

CheckArea($xval, $yval)



;Zufällige Sleep-Function mit +-5 Variation

RndSleep($val)



; collect all loot limited by max check value // Sammel alle Drops auf, limitiert durch ein Maximum.

CollectLoot($max)



; Aufgeben

Func Resign()



;Transfer zur Gildenhalle, kann von/zur Gildenhalle genutzt werden.

Func TransferGH()



; Identifiziert alle Drops von der Startreihe zur Endreihe (0-8), nutzt ein ident-werkzeug von reihe/slot (0-4)

IdentItems($StartRow, $EndRow, $IdentCol, $IdentRow)



; Sendet Mausevents zu einem nicht Aktiven Fenster

; Knopf = links, rechts, keiner

; Event = Runter, Hoch, click, doppelclick, Bewegung

MouseSend($btn, $evt, $xpos, $ypos)



; Sendet ein einziges Keyboard event zu einem nicht aktiven Fenster

; event = gedrückt, hoch, runter
; Wichtig: Unterstüzt nur kleinbuchstaben und Fx, NUMx und einige spezielle Tasten:

; ENTER, LEERTASTE, TAB, ZURÜCK, ENDE, POS1 (HOME), DRUCK, EINFG, ENTF, LINKS, RECHTS, HOCH, RUNTER, @

Wichtig: Bei manchen Tastaturlayouts funktionieren diese Tasten evtl. nicht. Falls dies der Fall ist,
kontrolliere, ob deine GW Tastenzuweisung dazu passt. Wenn diese nicht passt, nutzte ControlSend() .

KeySend($inkey, $evt ="pressed")


Nützlich um Nebeneffekte im Hintergrund zu verhindern, z.B. "Shifting" (Bot sendet Global die Shifttaste), während man ControlSend() hernimmt. Die derzeitige Implentation ist sehr einfach und wird nur auf einem Minimum von Tasten funktionieren. Wenn du Tastendrücke hintereinander senden willst, schreib ein sleep dazwischen (z.B. Sleep(50), wartet 50ms)




Hinweise:

- all settings and globals can be overwritten outside the included tt6.au,

  but you have to be sure that you really understand what you are doing
  Alle einstellungen und Globals können ausserhalb der einbezogenen tt6.au3 geändert werden.
  Aber musst sicher sein, das du wirklich verstehst was du tust.

  z.B.

  #include "tt6.au3"

  ; Für meinen Bot will ich ein anderes Koordinatensystem hernehmen.

  Opt("MouseCoordMode", 0)

  ; Ich will eine andere GW Instanz hernehmen.

  $client = "Guild Wars1"

  $PID = WinGetProcess($client)

  Global $hprocess = _MemoryOpen($PID)

  Global $hwnd = WinGetHandle($client)

  ; Ich will die Rotationsgeschwindigkeit verkleinern.

  $accelmul = 0.9



- Probier die geschriebenen Beispiele aus und start mit einem kleinem copy&paste

  Projekt aus, um sicherzugehen das deine Einstellungen richtig funktionieren.

  

Nachwort:

- Die engine wurde als Source Code zur integration in irgentein Projekt und zum debuggen und lernen gepostet.


- Modifikationen und Tipps für erweiterung sind willkommen. Ich kann keinen Support garantieren.


- Wie immer ist die elitepvpers Community sehr hilfsreich dadurch, Leute bei ihren Software Projekten einzuweisen.
  Es ist also eine gute Idee dort nachzufragen, da dort auch eine nettes FAQ wachsen wird.

-Zum Schluss will ich mich bei der Elitepvpers Community für das Feedback und die Inspiration, die tt6.au3 als  kleines  	Spass Projekt zu implementieren, bedanken. 
 Ziehs dir rein: www.elitepvpers.com
Ja, ich weiss, an manchen stellen würden mir eure English/Deutschleher ne pure 6 geben ^^ ..

Aber egal, hier habt ihr sie (s. o.)
03/05/2009 16:05 Rosemarie Lein#521
Ich habe eine frage und zwar habe ich die tt6.au3 ingecludet. nun steht in der ersten Reihe wie gehabt: "#include <tt6.au3>"
Jetzt habe ich aber im Script Verzeichnis eine tt6.au3 und im Include Ordner im AutoIt Ordner. Welche wird jetzt verwendet?
03/05/2009 16:23 Specter cason#522
es wird glaub die verwendet die im selben ordner wie der skript is
03/05/2009 17:25 kknb#523
Quote:
Originally Posted by MyDooMisHaxXor View Post
Dann müsste man ja von jedem gegenstand die id haben oder? Und da es dafür wohl keine statische gibt wird das wohl nix. Die abfrage nach der blacklist bezieht sich hier wohl mehr auf die abfrage ob ein schildtruhe etc im weg ist welches man am anfang des runs abfragt bevor items gefallen sind. Oder habe ich da was falsch verstanden?

ne haste zu 100% richtig erfasst.
03/05/2009 20:19 NBA#524
Hm....das ist schade...
03/05/2009 21:59 Treur Der Sonne#525
Hi guys!

Working at a problem with MoveTo interactions between multiple Guild Wars instances, I devised out a ModMoveTo.au3 that makes those interaction possible, grace to a new parameter added to all functions called "$task". The version I got here manages up to four instances and can be expansioned easily.
It's only the beta, not only since I received a time ban of 14 days but also because I want to add more functions making several interactions possible and easier. And I used the old tt6.au3 v1.3. If you find any mistakes or better solutions or if u have any questions - don't hesitate to interject them.
I hope you enjoy the idea and the implementation.

#
#
Hi Leute!

Beim Arbeiten an einem Problem, das Interaktion unter mehreren Guild Wars Fenstern benötigt, habe ich eine ModMoveTo.au3 entworfen, die solche Interaktionen möglich macht, dank eines neuen Parameter namens "$task", um den ich alle Funktionen erweitert habe. Die Version, die ich hier poste, ist für bis zu vier Guild Wars Instanzen gedacht und kann für noch mehr erweitert werden.
Das ist nur eine Beta, nicht nur da ich 14 Tage gebannt war, sondern auch weil noch andere Funktionen hinzugefügt werden, die einige Interaktionen möglich und einfacher machen. Und ich habe die alte tt6.au3 v1.3 genutzt.
Wenn ihr Fehler oder bessere Lösungsvorschläge habt, oder einfach etwas nicht versteht - werft sie einfach ein.
Ich hoffe, euch gefällt die Idee und die Umsetzung.

Code:
; ModMoveTo.au3
; Modded Version of TT6's MoveTo
; Made to interact between up to 4 Guild Wars Windows
; 05.03.2009

#include <Process.au3>
#include <WindowsConstants.au3>
#include "nomadmemory.au3"
#include-once

; settings
Opt("WinTitleMatchMode", 3)
Opt("MouseCoordMode", 2)
Opt("PixelCoordMode", 2)

; mems compatible to update.ini by __wadim
Const $memx = 			IniRead("update.ini","SECTION D","POSX","Not found") 		; position x
Const $memy = 			IniRead("update.ini","SECTION D","POSY","Not found") 		; position y
Const $memmap = 		IniRead("update.ini","SECTION D","CHECK_MAP","Not found") 	; post=0, load =2, area=1
Const $memnpcidselect = IniRead("update.ini","SECTION D","NPC_ID_SELECT","Not found") ; id of selected object
Const $memnpcidnear =	IniRead("update.ini","SECTION D","NPC_ID_NEAR","Not found") ; id of nearest object
Const $memcourse = 		IniRead("update.ini","SECTION 9-A","CAMCOURSE","Not found") ; angle of compass/view direction
Const $memdeath = 		IniRead("update.ini","SECTION 9-A","DEATH","Not found") 	; alive = 0 or death = 1 
Const $memmovechar = 	IniRead("update.ini","SECTION 9-A","MOVECHAR","Not found") 	; keyboard input events
Const $memtleft = $memmovechar + 0x10 ; turn left
Const $memtright = $memmovechar + 0x14 ; turn right

; globals for movement engine
#cs
$arTask[task no] gives the Name of a Guild Wars Task
$arHprocess[task no] gives the Process ID for a Guild Wars Task
$arHwnd[task no] gives the Handle of a Guild Wars Task
Valid Integers for [task no] are 0..3
#ce
Global $arTask[4]
$arTask[0] = IniRead("tt6.ini","id","task0","Guild Wars")
$arTask[1] = IniRead("tt6.ini","id","task1","Guild Wars1")
$arTask[2] = IniRead("tt6.ini","id","task2","Guild Wars2")
$arTask[3] = IniRead("tt6.ini","id","task3","Guild Wars3")
Global $arHprocess[4]
$arHprocess[0] = _MemoryOpen(WinGetProcess($arTask[0]))
$arHprocess[1] = _MemoryOpen(WinGetProcess($arTask[1]))
$arHprocess[2] = _MemoryOpen(WinGetProcess($arTask[2]))
$arHprocess[3] = _MemoryOpen(WinGetProcess($arTask[3]))
Global $arHwnd[4]
$arHwnd[0] = WinGetHandle($arTask[0])
$arHwnd[1] = WinGetHandle($arTask[1])
$arHwnd[2] = WinGetHandle($arTask[2])
$arHwnd[3] = WinGetHandle($arTask[3])
#cs
$arNums[task no][Global no] includes following old Globals: 
$gotox = 0
$gotoy = 1
$dist = 2
$olddist = 3
angle = 4
$increment = 5
$callcnt = 6
Valid Integers for [task no] are 0..3
#ce
Global $arNums[4][7]
$arNums[0][0] = 0.0
$arNums[0][1] = 0.0
$arNums[0][2] = 0.0
$arNums[0][3] = 0.0
$arNums[0][4] = 0.0
$arNums[0][5] = 0
$arNums[0][6] = 0
$arNums[1][0] = 0.0
$arNums[1][1] = 0.0
$arNums[1][2] = 0.0
$arNums[1][3] = 0.0
$arNums[1][4] = 0.0
$arNums[1][5] = 0
$arNums[1][6] = 0
$arNums[2][0] = 0.0
$arNums[2][1] = 0.0
$arNums[2][2] = 0.0
$arNums[2][3] = 0.0
$arNums[2][4] = 0.0
$arNums[2][5] = 0
$arNums[2][6] = 0
$arNums[3][0] = 0.0
$arNums[3][1] = 0.0
$arNums[3][2] = 0.0
$arNums[3][3] = 0.0
$arNums[3][4] = 0.0
$arNums[3][5] = 0
$arNums[3][6] = 0
#cs
$arBoolean[task no][Global no] includes following old Globals: 
$running = 0
$isDead = 1
$stopCheck = 2
$blockCheck = 3
$gotBlocked = 4
Valid Integers for [task no] are 0..3
#ce
Global $arBoolean[4][5]
$arBoolean[0][0] = False
$arBoolean[0][1] = False
$arBoolean[0][2] = False
$arBoolean[0][3] = False
$arBoolean[0][4] = False
$arBoolean[1][0] = False
$arBoolean[1][1] = False
$arBoolean[1][2] = False
$arBoolean[1][3] = False
$arBoolean[1][4] = False
$arBoolean[2][0] = False
$arBoolean[2][1] = False
$arBoolean[2][2] = False
$arBoolean[2][3] = False
$arBoolean[2][4] = False
$arBoolean[3][0] = False
$arBoolean[3][1] = False
$arBoolean[3][2] = False
$arBoolean[3][3] = False
$arBoolean[3][4] = False
Const $accelmul = 1.0
Const $pi = 4 * ATan(1)

; keys for keyboard input simulation adapt in the tt6.ini
Const $DIactkey = IniRead("tt6.ini","keys","DIactkey","SPACE")
Const $FLactkey = IniRead("tt6.ini","keys","FLactkey","ä")
Const $ANtgtkey = IniRead("tt6.ini","keys","ANtgtkey","v")
Const $FNtgtkey = IniRead("tt6.ini","keys","FNtgtkey","c")
Const $INtgtkey = IniRead("tt6.ini","keys","INtgtkey","ö")
Const $GHpnlkey = IniRead("tt6.ini","keys","GHpnlkey","g")
Const $ARmovkey = IniRead("tt6.ini","keys","ARmovkey","r")
Const $RDmovkey = IniRead("tt6.ini","keys","RDmovkey","x")
Const $TLmovkey = IniRead("tt6.ini","keys","TLmovkey","a")
Const $TRmovkey = IniRead("tt6.ini","keys","TRmovkey","d")
Const $OCchtkey = IniRead("tt6.ini","keys","OCchtkey","RETURN")

; positions for mouse clicks adapt in the tt6.ini
Const $DTclickX = Int(IniRead("tt6.ini","click positions","DTclickX",0))
Const $DTclickY = Int(IniRead("tt6.ini","click positions","DTclickY",0))
Const $LTclickX = Int(IniRead("tt6.ini","click positions","LTclickX",0))
Const $LTclickY = Int(IniRead("tt6.ini","click positions","LTclickY",0))
Const $GHclickX = Int(IniRead("tt6.ini","click positions","GHclickX",0))
Const $GHclickY = Int(IniRead("tt6.ini","click positions","GHclickY",0))
Const $STclickX = Int(IniRead("tt6.ini","click positions","STclickX",0))
Const $STclickY = Int(IniRead("tt6.ini","click positions","STclickY",0))
Const $SBclickX = Int(IniRead("tt6.ini","click positions","SBclickX",0))
Const $SBclickY = Int(IniRead("tt6.ini","click positions","SBclickY",0))
Const $HMclickX = Int(IniRead("tt6.ini","click positions","HMclickX",0))
Const $HMclickY = Int(IniRead("tt6.ini","click positions","HMclickY",0))

;generate inventory access matrix adapt positions in the tt6.ini
Const $invMaxR = 8 ;max number of rows 0..8
Const $invMaxC = 4 ;max number of columns 0..4
Global $invPos[$invMaxC+1] [$invMaxR+1][2];matrix of positions [0]=x, [1]=y
$invPos[0][0][0] = Int(IniRead("tt6.ini","inventory offsets","invPosX00",0))
$invPos[0][0][1] = Int(IniRead("tt6.ini","inventory offsets","invPosY00",0))
$invPos[0][1][1] = Int(IniRead("tt6.ini","inventory offsets","invPosYR1",0))
$invPos[0][2][1] = Int(IniRead("tt6.ini","inventory offsets","invPosYR2",0))
$invPos[0][3][1] = Int(IniRead("tt6.ini","inventory offsets","invPosYR3",0))
$invPos[0][4][1] = Int(IniRead("tt6.ini","inventory offsets","invPosYR4",0))
$invPos[0][5][1] = Int(IniRead("tt6.ini","inventory offsets","invPosYR5",0))
$invPos[0][6][1] = Int(IniRead("tt6.ini","inventory offsets","invPosYR6",0))
$invPos[0][7][1] = Int(IniRead("tt6.ini","inventory offsets","invPosYR7",0))
$invPos[0][8][1] = Int(IniRead("tt6.ini","inventory offsets","invPosYR8",0))
$invPosXdelta = Int(IniRead("tt6.ini","inventory offsets","invPosXdelta",0))
Code:
For $ri=1 To 8
	$invPos[0][$ri][0] = $invPos[0][0][0] ;x offset of 0 element constant in every row
Next

For $ri=0 To 8
	For $ci=1 To 4
		$invPos[$ci][$ri][0] = $invPos[0][$ri][0] + $invPosXdelta *$ci ; x offset increases by number of column
		$invPos[$ci][$ri][1] = $invPos[0][$ri][1] ; y offset equal to 0 position in every row
	Next
Next

; stop movement
Func StopMoveTo($task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	If Not $arBoolean[$task][4] Then
		KeySend($ARmovkey, "", "", $task)
	EndIf
	$arNums[$task][5] = 0	
	$arNums[$task][6] = 0
	$arBoolean[$task][0] = False
	$arBoolean[$task][2] = False
	$arBoolean[$task][3] = False
EndFunc

; end movement but keep running e.g. to exit
Func KeepMoveTo($task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	$arNums[$task][5] = 0 
	$arNums[$task][6] = 0
	$arBoolean[$task][0] = False
	$arBoolean[$task][2] = False
	$arBoolean[$task][3] = False
EndFunc

; prepare movement
Func PrepMoveTo($task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	$arNums[$task][5] = 0
	$arNums[$task][6] = 0
	$arBoolean[$task][2] = False
	$arBoolean[$task][3] = False
	$arBoolean[$task][4] = False
EndFunc

; disables check if we stopped runnning unintended (eg by cast or knock down)
; note: must be used to protect casts as we try to start running again immediately in auto mode
Func DisableStopCheck($task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	If $arBoolean[$task][2] Then
		$arBoolean[$task][2] = False
	EndIf
EndFunc

; enables check again
Func EnableStopCheck($task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	If ($arBoolean[$task][3] = False) And ($arBoolean[$task][2] = False) Then
		$arBoolean[$task][2] = True
	EndIf
EndFunc

; calc table for rotation angle calculation
Global $course_table[100]
$course_table[0] = 0.0000
$course_table[1] = 0.0150
$course_table[2] = 0.0372
$course_table[3] = 0.0438
$course_table[4] = 0.0702
$course_table[5] = 0.1031
$course_table[6] = 0.1377
$course_table[7] = 0.1466
$course_table[8] = 0.1751
$course_table[9] = 0.1824
$course_table[10] = 0.2076
$course_table[11] = 0.2462
$course_table[12] = 0.2551
$course_table[13] = 0.2750
$course_table[14] = 0.3154
$course_table[15] = 0.3337
$course_table[16] = 0.3528
$course_table[17] = 0.3612
$course_table[18] = 0.3800
$course_table[19] = 0.4078
$course_table[20] = 0.4273
$course_table[21] = 0.4458
$course_table[22] = 0.4670
$course_table[23] = 0.4845
$course_table[24] = 0.5120
$course_table[25] = 0.5361
$course_table[26] = 0.5656
$course_table[27] = 0.5936
$course_table[28] = 0.6285
$course_table[29] = 0.6445
$course_table[30] = 0.6643
$course_table[31] = 0.6848
$course_table[32] = 0.6991
$course_table[33] = 0.7136
$course_table[34] = 0.7214
$course_table[35] = 0.7452
$course_table[36] = 0.7746
$course_table[37] = 0.8052
$course_table[38] = 0.8283
$course_table[39] = 0.8410
$course_table[40] = 0.8666
$course_table[41] = 0.8826
$course_table[42] = 0.9062
$course_table[43] = 0.9195
$course_table[44] = 0.9363
$course_table[45] = 0.9531
$course_table[46] = 0.9759
$course_table[47] = 1.0020
$course_table[48] = 1.0203
$course_table[49] = 1.0448
$course_table[50] = 1.0636
$course_table[51] = 1.0882
$course_table[52] = 1.0957
$course_table[53] = 1.1124
$course_table[54] = 1.1474
$course_table[55] = 1.1669
$course_table[56] = 1.1833
$course_table[57] = 1.2264
$course_table[58] = 1.2469
$course_table[59] = 1.2670
$course_table[60] = 1.2876
$course_table[61] = 1.2957
$course_table[62] = 1.3056
$course_table[63] = 1.3331
$course_table[64] = 1.3529
$course_table[65] = 1.3769
$course_table[66] = 1.3975
$course_table[67] = 1.4162
$course_table[68] = 1.4366
$course_table[69] = 1.4684
$course_table[70] = 1.4844
$course_table[71] = 1.5089
$course_table[72] = 1.5223
$course_table[73] = 1.5420
$course_table[74] = 1.5721
$course_table[75] = 1.5994
$course_table[76] = 1.6089
$course_table[77] = 1.6203
$course_table[78] = 1.6485
$course_table[79] = 1.6632
$course_table[80] = 1.6791
$course_table[81] = 1.6807
$course_table[82] = 1.7258
$course_table[83] = 1.7630
$course_table[84] = 1.7801
$course_table[85] = 1.8172
$course_table[86] = 1.8256
$course_table[87] = 1.8400
$course_table[88] = 1.8654
$course_table[89] = 1.8804
$course_table[90] = 1.9119
$course_table[91] = 1.9391
$course_table[92] = 1.9605
$course_table[93] = 1.9822
$course_table[94] = 2.0091
$course_table[95] = 2.0203
$course_table[96] = 2.0433
$course_table[97] = 2.0654
$course_table[98] = 2.0749
$course_table[99] = 2*$pi

; calculate rotation angle
Func GetCourse($val)
	$i=0
	$valL = Abs($val)
	While $course_table[$i] < $valL
		$i +=1
		if $i = 100 Then ;error
			ConsoleWrite(StringFormat("GetCourse: bad call: %.4f",$valL))
			Exit
		EndIf
	WEnd
	return Int($i * 10 * $accelmul)
EndFunc

; initialise new destination
Func InitDest($dx, $dy, $dcheck = False,$task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	;no movement if we are dead or got blocked
	If $arBoolean[$task][1] Or $arBoolean[$task][4] Then
		Return
	EndIf
	; set global destination
	$arNums[$task][0] = $dx
	$arNums[$task][1] = $dy
	
	; calc distance
	$posx = _memoryread($memx,$arHprocess[$task],'float')
	$posy = _memoryread($memy,$arHprocess[$task],'float')
	$arNums[$task][2] = Sqrt(($posx-$dx)^2 + ($posy-$dy)^2)
	$arNums[$task][3] = $arNums[$task][2]
	
	;set call counter for cyclic loop
	$arNums[$task][6] = 1

	; set stop level for angles in relation to distance
	if $arNums[$task][2] > 2000 Then
		$stoplvl = 1.8
	Elseif $arNums[$task][2] > 1200 Then
		$stoplvl = 1.5
	Elseif $arNums[$task][2] > 700 Then
		$stoplvl = 1.2
	Elseif $arNums[$task][2] > 400 Then
		$stoplvl = 0.8
	Elseif $arNums[$task][2] > 200 Then
		$stoplvl = 0.6
	Else 
		$stoplvl = 0.2
	EndIf
	
	; calc angle
	$arNums[$task][4] = ACos(($arNums[$task][0] - $posx)/$arNums[$task][2])
	if $arNums[$task][1] < $posy Then
		$arNums[$task][4] = -$arNums[$task][4]
	EndIf
	
	; rotate view to destination			
	Do
		; transition via q2<->q3 by pseudo course angle
		$curcou = _memoryread($memcourse,$arHprocess[$task],'float')
		if (($arNums[$task][4] > $pi/2) And ($curcou < $arNums[$task][4] - $pi)) Then
			$curcou = 2*$pi + $curcou
		EndIf
		if (($arNums[$task][4] < -$pi/2) And ($curcou > $pi+$arNums[$task][4])) Then
			$curcou = -2*$pi + $curcou
		EndIf

		; big delta -> stop running
		if Abs($arNums[$task][4] - $curcou) > $stoplvl Then
			if $arBoolean[$task][0] = True Then
				KeySend($ARmovkey, "", "", $task)
				$arBoolean[$task][0] = False
			EndIf
		EndIf
			
		$accel = GetCourse(Abs($arNums[$task][4] - $curcou))

		; rotate
		if $arNums[$task][4] < $curcou Then
			KeySend($TRmovkey, "down", "", $task)
			Sleep($accel)
			KeySend($TRmovkey, "up", "", $task)
		Else
			KeySend($TLmovkey, "down", "", $task)
			Sleep($accel)
			KeySend($TLmovkey, "up", "", $task)
		EndIf
		Sleep(100)
		
		; check for death
		if  $dcheck And _memoryread($memdeath,$arHprocess[$task]) = 1 Then
			$arBoolean[$task][1] = True
			Return
		EndIf		
	Until (Abs($arNums[$task][4] - $curcou) <0.1)
EndFunc

; cyclic function for movement to destination (must be called every 10ms)
Func MoveToCore($dcheck = False,$task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	;no movement if we are dead or got blocked
	If $arBoolean[$task][1] Or $arBoolean[$task][4] Then
		Return True
	EndIf
	
	; get data
	$posx = _memoryread($memx,$arHprocess[$task],'float')
	$posy = _memoryread($memy,$arHprocess[$task],'float')
	$curcou = _memoryread($memcourse,$arHprocess[$task],'float')

	; calc distance
	$arNums[$task][2] = Sqrt(($posx-$arNums[$task][0])^2 + ($posy-$arNums[$task][1])^2)
	
	; try to catch problem in case we missed target
	if $arNums[$task][3] < $arNums[$task][2] -100.0 Then
		InitDest($arNums[$task][0], $arNums[$task][1], $dcheck, $task)
	EndIf

	; store distance every 500ms, initial value is set in InitDest(), check for special situations
	If Mod($arNums[$task][6], 50) = 0 Then
		; set death flag and exit
		if  $dcheck And _memoryread($memdeath,$arHprocess[$task]) = 1 Then
			$arBoolean[$task][1] = True
			Return True
		EndIf
		; restart running in case we got stopped
		if $arBoolean[$task][2] And (Abs($arNums[$task][3] - $arNums[$task][2]) < 20.0) Then
			$arBoolean[$task][0] = False
		EndIf
		; set blocked flag and exit
		if $arBoolean[$task][3] And (Abs($arNums[$task][3] - $arNums[$task][2]) < 20.0) Then
			$arBoolean[$task][4] = True
			Return True
		EndIf
		$arNums[$task][3] = $arNums[$task][2]
	EndIf
	;increment call counter
	$arNums[$task][6] +=1
	
	; check running
	If $arBoolean[$task][0] = False Then
		$arBoolean[$task][0] = True
		KeySend($ARmovkey, "", "", $task)
	EndIf

	; calc angle
	$arNums[$task][4] = ACos(($arNums[$task][0] - $posx)/$arNums[$task][2])
	If $arNums[$task][1] < $posy Then
		$arNums[$task][4] = -$arNums[$task][4]
	EndIf
	
	; correct angle on the fly
	If (Abs($arNums[$task][4] - $curcou) >0.05) And ($arNums[$task][5] = 0) Then
		
		; transition via q2<->q3 by pseudo course angle
		$curcou = _memoryread($memcourse,$arHprocess[$task],'float')
		If (($arNums[$task][4] > $pi/2) And ($curcou < $arNums[$task][4] - $pi)) Then
			$curcou = 2*$pi + $curcou
		EndIf
		If (($arNums[$task][4] < -$pi/2) And ($curcou > $pi+$arNums[$task][4])) Then
			$curcou = -2*$pi + $curcou
		EndIf

		$arNums[$task][5] = GetCourse(Abs($arNums[$task][4] - $curcou))
		
		; rotate
		If $arNums[$task][4] < $curcou Then
			KeySend($TRmovkey, "down", "", $task)
			$arNums[$task][5] -=10
		Else
			KeySend($TLmovkey, "down", "", $task)
			$arNums[$task][5] -=10
		EndIf
	ElseIf ($arNums[$task][5] > 0) Then
		$arNums[$task][5] -=10
		If $arNums[$task][6] <= 0 Then
			KeySend($TRmovkey, "up", "", $task)
			KeySend($TLmovkey, "up", "", $task)
		EndIf
	EndIf
	
	; reached position
	If $arNums[$task][2] < 130.0 Then
		$arNums[$task][5] = 0
		KeySend($TRmovkey, "up", "", $task)
		KeySend($TLmovkey, "up", "", $task)
		Return True
	EndIf
	Return False
EndFunc

; movement function 
;  mode = 0 : do one iteration and return, used in very special situations only
;  mode = 1 : init destination and move there
;  mode = 2 : autorun mode, if a stop is detected it will be tried to run again automatically
;  mode = 3 : block mode, if a block is detected we set flag and exit
;  random adds some variation to movement positions
;  dcheck enables deathcheck 
Func MoveTo($mode, $x, $y, $random = False, $dcheck = False, $task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	$xl = $x
	$yl = $y
	If $random Then
		$xl = $x + Int(Random(-100,100))
		$yl = $y + Int(Random(-100,100))
	EndIf
	If $mode = 0 Then
		$arBoolean[$task][2] = False
		$arBoolean[$task][3] = False
		Return MoveToCore($dcheck, $task)
	ElseIf $mode = 1 Then
		$arBoolean[$task][2] = False
		$arBoolean[$task][3] = False
		InitDest($xl, $yl, $dcheck, $task)
		While Not MoveToCore($dcheck, $task)
			Sleep(10)
		WEnd
	ElseIf $mode = 2 Then
		$arBoolean[$task][2] = True
		$arBoolean[$task][3] = False
		InitDest($xl, $yl, $dcheck, $task)
		While Not MoveToCore($dcheck, $task)
			Sleep(10)
		WEnd
	ElseIf $mode = 3 Then
		$arBoolean[$task][2] = False
		$arBoolean[$task][3] = True
		InitDest($xl, $yl, $dcheck, $task)
		While Not MoveToCore($dcheck, $task)
			Sleep(10)
		WEnd
	Else  ;error
		ConsoleWrite(StringFormat("MoveTo: bad mode: %d",$mode))
		Exit
	EndIf
EndFunc

; check if position is in area
Func CheckArea($xval, $yval, $task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	$ret = False
	$pX = _memoryread($memx,$arHprocess[$task],'float')
	$pY = _memoryread($memy,$arHprocess[$task],'float')
	
	if ($pX < $xval + 250) And ($pX > $xval - 250) And ($pY < $yval + 250) And ($pY > $yval - 250) Then
		$ret = True
	EndIf
	Return $ret	
EndFunc
Code:
; random sleep function with p% variation (default = 5%)
Func RndSleep($val, $amplitude = 0.05)
	$sle = Random($val * (1 - $amplitude), $val * (1 + $amplitude), 1)
	Sleep($sle)
EndFunc

; collect all loot limited by max check value
Func CollectLoot($max, $task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	KeySend($INtgtkey, "", "", $task)
	RndSleep(150)
	$cnt =0
	While (_memoryread($memnpcidselect,$arHprocess[$task]) > 0) And ($cnt < $max)
		KeySend($DIactkey, "", "", $task)
		RndSleep(250)
		KeySend($INtgtkey, "", "", $task)
		RndSleep(250)
		$cnt +=1
	WEnd
EndFunc

; resign
Func Resign($wdelay = 50, $task = 0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	keysend("-", "", "", $task)
	Sleep($wdelay)
	keysend("r", "", "", $task)
	Sleep($wdelay)
	keysend("e", "", "", $task)
	Sleep($wdelay)
	keysend("s", "", "", $task)
	Sleep($wdelay)
	keysend("i", "", "", $task)
	Sleep($wdelay)
	keysend("g", "", "", $task)
	Sleep($wdelay)
	keysend("n", "", "", $task)
	Sleep($wdelay)
	keysend("RETURN", "", "", $task)
	RndSleep(4000)
	ControlClick($arTask[$task], "", "", "left", 1, $DTclickX, $DTclickY)
EndFunc

; transfer to GH, may be used from/to GH
Func TransferGH($task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	KeySend($GHpnlkey, "", "", $task)
	RndSleep(500)
	ControlClick($arTask[$task], "", "", "left", 1, $GHclickX, $GHclickY)
	Sleep(200)
	While Not ((_memoryread($memmap,$arHprocess[$task])) = 2)
		Sleep(100)
	WEnd
	While (_memoryread($memmap,$arHprocess[$task])) <> 0
		Sleep(100)
	WEnd
	RndSleep(4000)
	KeySend($GHpnlkey, "", "", $task)
	RndSleep(500)
EndFunc

; ident all items from start row to end row (0..8) using ident kit at row/col (0..4)
Func IdentItems($StartRow, $EndRow, $IdentCol, $IdentRow, $task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	if $EndRow > $invMaxR Then
		$end = $invMaxR
	Else
		$end = $EndRow		
	EndIf
	For $row = $StartRow To $end
		For $col = 0 To $invMaxC
			ControlClick($arTask[$task], "", "", "left", 2, $invPos[$IdentCol][$IdentRow][0], $invPos[$IdentCol][$IdentRow][1])
			RndSleep(150)
			MouseSend("left", "click", $invPos[$col][$row][0], $invPos[$col][$row][1], $task)
			RndSleep(150)				
		Next
	Next
EndFunc

; create long int (32 bit) from 2 short int (16 bit) 
Func MakeLong($LoWord, $HiWord)
	Return BitOR($HiWord * 0x10000, BitAND($LoWord, 0xFFFF))
EndFunc

; send mouse events to non active window
; button = left, right, none
; event = down, up, click, dclick, move
Func MouseSend($btn, $evt, $xpos, $ypos, $task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	$user32 = DllOpen("user32.dll")
	If $user32 = -1 Then
		ConsoleWrite("MouseSend: cannot open user32.dll")
		Exit
	EndIf
	
	;define missing constans
	$MK_LBUTTON       =  0x0001
	$WM_LBUTTONDOWN   =  0x0201
	$MK_RBUTTON       =  0x0002   
	$WM_RBUTTONDOWN   =  0x0204
	$WM_RBUTTONUP     =  0x0205
	
	;map button to event
	If $btn = "left" Then
		$button = $MK_LBUTTON
		$btdown = $WM_LBUTTONDOWN
		$btup = $WM_LBUTTONUP
	ElseIf $btn = "right" Then
		$button = $MK_RBUTTON
		$btdown = $WM_RBUTTONDOWN
		$btup = $WM_RBUTTONUP
	ElseIf $btn = "none" Then
		If Not ($evt = "move") Then
			ConsoleWrite(StringFormat("MouseSend: bad call:  %s , %s",$btn, $evt))
			Exit
		EndIf			
	Else  ;error
		ConsoleWrite(StringFormat("MouseSend: bad button: %s",$btn))
		Exit
	EndIf
	
	;send messages
	$pos = MakeLong($xpos, $ypos)
	Select
	Case $evt = "move"
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_MOUSEMOVE, "int", 0, "long", $pos)
	Case $evt = "down"
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $btdown, "int", $button, "long", $pos)
	Case $evt = "up"
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $btup, "int", 0, "long", $pos)
	Case $evt = "click"
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_MOUSEMOVE, "int", 0, "long", $pos)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $btdown, "int", $button, "long", $pos)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $btup, "int", 0, "long", $pos)
	Case $evt = "dclick"
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_MOUSEMOVE, "int", 0, "long", $pos)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $btdown, "int", $button, "long", $pos)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $btup, "int", 0, "long", $pos)
		Sleep(50)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_MOUSEMOVE, "int", 0, "long", $pos)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $btdown, "int", $button, "long", $pos)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $btup, "int", 0, "long", $pos)		
	EndSelect
	DllClose($user32)
EndFunc

; send single keyboard event to non active window
; event = pressed, down, up
; kdown = key down delay
; note: supports only lower case keys + NUMx, Fx, some special keys and @
Func KeySend($inkey, $evt ="pressed", $kdown = 50, $task=0)
	$task = Int($task)
	If $task<0 Or $task>3 Then
	$task = 0
	EndIf
	$user32 = DllOpen("user32.dll")
	if $user32 = -1 Then
		ConsoleWrite("KeySend: cannot open user32.dll")
		Exit
	EndIf
		
    ; handling for special keys
	Switch StringUpper($inkey)
	Case "@"
		$skey = 0x40
		$lparam = 0x00100001
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_KEYDOWN, "int", 0x71, "int", $lparam)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_CHAR, "int", $skey, "int", $lparam)
		Sleep(20)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_KEYUP, "int", 0x71, "int", BitOR($lparam, 0xC0000000))		
	Case "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12"
		$skey = 0x6f + Int(StringMid($inkey, 2)) 
		ContinueCase
	Case "NUM0", "NUM1", "NUM2", "NUM3", "NUM4", "NUM5", "NUM6", "NUM7", "NUM8" , "NUM9"
		if StringUpper(StringLeft($inkey, 3)) = "NUM" Then
			$skey = 0x60 + Int(StringMid($inkey, 4)) 
		EndIf
		ContinueCase
	Case "RETURN", "SPACE", "TAB", "BACK", "END", "HOME", "SNAPSHOT", "INSERT", "DELETE"
		Switch StringUpper($inkey)
		Case "RETURN"
			$skey = 0x0D
		Case "SPACE"
			$skey = 0x20
		Case "TAB"
			$skey = 0x09
		Case "BACK"
			$skey = 0x08
		Case "END"
			$skey = 0x23
		Case "HOME"
			$skey = 0x24
		Case "SNAPSHOT"
			$skey = 0x2c
		Case "INSERT"
			$skey = 0x2d
		Case "DELETE"
			$skey = 0x2e
		EndSwitch
		$ret = DllCall($user32, "int", "MapVirtualKey", "int", $skey, "int", 0)
		$lparam = BitShift($ret[0], -16)
		$lparam = BitOr($lparam, 1)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_KEYDOWN, "int", $skey, "int", $lparam)
		Sleep($kdown)
		DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_KEYUP, "int", $skey, "int",   BitOR($lparam, 0xC0000000))
	Case Else ; default lower case key handling
		$key = DllCall($user32, "int", "VkKeyScan", "int", Asc(StringLower($inkey)))
		$skey = $key[0]		
		$ret = DllCall($user32, "int", "MapVirtualKey", "int", $skey, "int", 0)
		$lparam = BitShift($ret[0], -16)
		$lparam = BitOr($lparam, 1)
		Select
		Case $evt = "pressed"
			DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_KEYDOWN, "int", $skey, "int", $lparam)
			Sleep($kdown)
			DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_KEYUP, "int", $skey, "int",   BitOR($lparam, 0xC0000000))
		Case $evt = "down"
			DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_KEYDOWN, "int", $skey, "int", $lparam)
		Case $evt = "up"
			DllCall($user32, "int", "PostMessage", "hwnd", $arHwnd[$task], "int", $WM_KEYUP, "int", $skey, "int",   BitOR($lparam, 0xC0000000))
		EndSelect		
	EndSwitch

	DllClose($user32)
EndFunc