Delete Parent2Gem_Version2.ahk

Delete Parent2Gem_Version2.ahk

; AutoHotkey Version: 1.1x
; Language:       English
; Author:         8thSeaOfRhye
;
;                     #####         Parent2Gem.ahk - Version 2       #####
;
;                     ##### Description of Purpose and Functionality #####
;
; ###            General             ###
; This script translates a String containing the Parenthesis-( i.e. Bracket-)Version of
; a speccing or combining scheme for gemcraft into actual commands for the gems creation.
; Works best in a STANDALONE FLASHPLAYER set to FULLSCREEN.
; It is hopefully easy to use and customize.
; The section which has to be changed is almost right at the top of the following code,
; namely under the command "!C::", and is commented to indicate the exact usage.
;
; The STANDARD HOTKEY is  Alt + c (No shift!!). This corresponds to "!C".
; Check ahkscript.org for Hotkey usage.
;
; CombiningMode is turned on by default. Speccing still works. Suggestion: Don't turn it off...
;
;
; ###  Syntax for the Bracket-Formula ###
;
; Obviously:
; 		r = Red / b = Black / o = orange / y = yellow
;
; Maybe a little less obviously:
;
;		g / k / m = copy of gem in the BOTTOM-LEFT! corner of the 12*3 craftingfield
;
; Furthermore:   ### New Features ###
;
;		the numerals 2 to 9 followed by any of the above = Corresponding color (or duplicate, respectively), upgraded 1 to 8 times
;
;		Examples: 9o / 2g = Orange upgraded 8 times (grade 9) / Base-gem (BottomLeft corner) upgraded once
;		(Needless to say, the upgrading happens via the "u"-button.)
;
; And:
;
;		a / s / d  =  use (left / middle / right) gem in the top row of the 3*12 craftingfield
;
;		(The order is inspired by the position of the keys on a standard keyboard.
;		 Attention: Those three can't be used in combination with numerals.)

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
;
;
;
;

!C::
;             I
; #####      V V       																					 #########
; #####       V        INSERT THE SCHEME TO BE COMBINED INBETWEEN THE QUTATION-MARKS IN THE LINE BELOW   #########
ParentStr := "(((((((g+g)+(g+g))+((g+g)+(g+g)))+(((g+g)+(g+g))+((g+g)+(g+g))))+((((g+g)+(g+g))+((g+g)+(g+g)))+(((g+g)+(g+g))+((g+g)+(g+(g+(g+(g+g))))))))+(((((g+g)+(g+g))+((g+g)+(g+g)))+(((g+g)+(g+g))+((g+g)+(g+(g+(g+(g+g)))))))+((((g+g)+(g+g))+((g+g)+(g+(g+(g+(g+g))))))+(((g+g)+(g+(g+(g+(g+g)))))+((g+(g+(g+g)))+((g+(g+g))+((g+g)+((g+g)+(g+(g+(g+(g+g))))))))))))+((((((g+g)+(g+g))+((g+g)+(g+g)))+(((g+g)+(g+g))+((g+g)+(g+(g+(g+(g+g)))))))+((((g+g)+(g+g))+((g+g)+(g+(g+(g+(g+g))))))+(((g+g)+(g+(g+(g+(g+g)))))+((g+(g+(g+g)))+((g+(g+g))+((g+g)+((g+g)+(g+(g+(g+(g+g)))))))))))+(((((g+g)+(g+g))+((g+g)+(g+(g+(g+(g+g))))))+(((g+g)+(g+(g+(g+(g+g)))))+((g+(g+(g+g)))+((g+(g+g))+((g+g)+((g+g)+(g+(g+(g+(g+g))))))))))+((((g+g)+(g+(g+(g+(g+g)))))+((g+(g+(g+g)))+((g+(g+g))+((g+g)+((g+g)+(g+(g+(g+(g+g)))))))))+(((g+(g+(g+g)))+((g+(g+g))+((g+g)+(g+(g+(g+(g+g)))))))+(((g+(g+g))+((g+g)+(g+(g+(g+(g+(g+g)))))))+(((g+g)+((g+g)+(g+(g+(g+(g+g))))))+((g+(g+(g+(g+(g+g)))))+((g+(g+(g+g)))+((g+(g+g))+((g+(g+g))+((g+g)+(g+(g+(g+(g+(g+g)))))))))))))))))"

; #####   						The default example is some random 1024 combine							 #########

CombineMode := True
LastGemPos := 1

TopLeftCornerX := 1127 				;  ####### ENTER THE COORDINATES OF THE 3*12 CRAFTINGFIELD ON YOUR SCREEN #########
TopLeftCornerY := 175 				;	###### If you don't know how to obtain those values, you'd better  ########
BottomRightCornerX := 1234 			;    ##### ask somebody. They don't have to be really precise.     #######
BottomRightCornerY := 602 			;	  #### AND THAT'S IT! The script should work for you now!  ######

FieldWidth := (BottomRightCornerX - TopLeftCornerX) / 3
FieldHeight := (BottomRightCornerY - TopLeftCornerY) / 12
CraftingField := [BottomRightCornerX -(FieldWidth / 2), BottomRightCornerY -(FieldHeight / 2)]

SetDefaultMouseSpeed, 0
i := 0
j := 0
StkCount := 1
initPos := [TopLeftCornerX + (FieldWidth / 2), BottomRightCornerY - (FieldHeight * 1.5)]
StackFields := []
While i < 12
{
	while j < 3
	{
		StackFields[StkCount, 1] := initPos[1] + (j * FieldWidth)
		StackFields[StkCount, 2] := initPos[2] - (i * FieldHeight)
		StkCount := StkCount + 1
		j := j + 1
	}
	j := 0
	i := i + 1
}

; For FieldNum, FieldValue in StackFields
;	MsgBox % " Coordinates of Stack-Field #" . FieldNum .  ": " . FieldValue[1] . FieldValue[2]

CurrentStk := 0

OGem() {
	global CraftingField
	Send {Numpad7}
	MouseClick, left, CraftingField[1], CraftingField[2]
}
YGem() {
	global CraftingField
	Send {Numpad8}
	MouseClick, left, CraftingField[1], CraftingField[2]
}
BGem() {
	global CraftingField
	Send {Numpad1}
	MouseClick, left, CraftingField[1], CraftingField[2]
}
RGem() {
	global CraftingField
	Send {Numpad4}
	MouseClick, left, CraftingField[1], CraftingField[2]
}

GGem() {
	global CraftingField
	global FieldWidth
	MouseMove, CraftingField[1]-(2*FieldWidth), CraftingField[2]
	send d
}

AddtoStk() {
	global CraftingField
	global CurrentStk
	global StackFields
	if CurrentStk != 0
		{
		Send g
		MouseClickDrag, L, CraftingField[1], CraftingField[2], StackFields[CurrentStk][1], StackFields[CurrentStk][2]
		}
}

MovetoStk() {
	global CraftingField
	global CurrentStk
	global StackFields
	CurrentStk := CurrentStk + 1
	MouseClickDrag, L, CraftingField[1], CraftingField[2], StackFields[CurrentStk][1], StackFields[CurrentStk][2]
}

PopStk() {
	global CraftingField
	global CurrentStk
	global StackFields
	if CurrentStk > 1
		{
		Send g
		MouseClickDrag, L, StackFields[CurrentStk][1], StackFields[CurrentStk][2], StackFields[CurrentStk - 1][1], StackFields[CurrentStk - 1][2]
		CurrentStk := CurrentStk - 1
		}
}

if (CombineMode = True) {
	StrPosEnd := StrLen(ParentStr)
	ElementFound := False
	While ElementFound = False {
		if (SubStr(ParentStr, StrPosEnd, 1) != ")") {
			ElementFound := True
			LastGemPos := StrPosEnd
		}
		StrPosEnd := StrPosEnd - 1
	}
}

StrPos := 1
Parents := []

While StrPos < StrLen(ParentStr) {
	if (SubStr(ParentStr, StrPos, 1) = "(") {
		if ((SubStr(ParentStr, StrPos - 1, 1) = "(") or (StrPos = 1))
			Parents.Insert(False)
		else
			Parents.Insert(True)
	}

	if (SubStr(ParentStr, StrPos, 1) = ")") {
		if (Parents[Parents.MaxIndex()] = True)
			PopStk()
		Parents.remove(Parents.MaxIndex())
	}

	if (SubStr(ParentStr, StrPos, 1) = "o") {
		OGem()
		if (SubStr(ParentStr, StrPos - 1, 1) = "(")
			MovetoStk()
		else
			AddtoStk()
	}

	if (SubStr(ParentStr, StrPos, 1) = "r") {
		RGem()
		if (SubStr(ParentStr, StrPos - 1, 1) = "(")
			MovetoStk()
		else
			AddtoStk()
	}

	if (SubStr(ParentStr, StrPos, 1) = "b") {
		BGem()
		if (SubStr(ParentStr, StrPos - 1, 1) = "(")
			MovetoStk()
		else
			AddtoStk()
	}

	if (SubStr(ParentStr, StrPos, 1) = "y") {
		YGem()
		if (SubStr(ParentStr, StrPos - 1, 1) = "(")
			MovetoStk()
		else
			AddtoStk()
	}

	if ((SubStr(ParentStr, StrPos, 1) = "g") or (SubStr(ParentStr, StrPos, 1) = "k") or (SubStr(ParentStr, StrPos, 1) = "m")) {
		if (LastGemPos != StrPos)
			GGem()
		else
			MouseClickDrag, L, CraftingField[1]-(2*FieldWidth), CraftingField[2], CraftingField[1], CraftingField[2]
		if (SubStr(ParentStr, StrPos - 1, 1) = "(")
			MovetoStk()
		else
			AddtoStk()
	}

	if ((SubStr(ParentStr, StrPos, 1) < 10) and (SubStr(ParentStr, StrPos, 1) > 1)) {
		if (SubStr(ParentStr, StrPos + 1, 1) = "o")
			OGem()
		if (SubStr(ParentStr, StrPos + 1, 1) = "y")
			YGem()
		if (SubStr(ParentStr, StrPos + 1, 1) = "b")
			BGem()
		if (SubStr(ParentStr, StrPos + 1, 1) = "r")
			RGem()
		if (SubStr(ParentStr, StrPos + 1, 1) = "g") {
			if (LastGemPos != StrPos) {
				GGem()
			}
			else
				MouseClickDrag, L, CraftingField[1]-(2*FieldWidth), CraftingField[2], CraftingField[1], CraftingField[2]

			UCount := 1
			While UCount <= SubStr(ParentStr, StrPos + 1, 1) {
				MouseMove, CraftingField[1], CraftingField[2]
				send u
				UCount := UCount + 1
			}

		if (SubStr(ParentStr, StrPos - 1, 1) = "(")
			MovetoStk()
		else
			AddtoStk()
		}
	}

	if (SubStr(ParentStr, StrPos, 1) = "a") {
		MouseClickDrag, L, TopLeftCornerX + (FieldWidth / 2), TopLeftCornerY + (FieldHeight / 2), CraftingField[1], CraftingField[2]
		if (SubStr(ParentStr, StrPos - 1, 1) = "(")
			MovetoStk()
		else
			AddtoStk()

	}
	if (SubStr(ParentStr, StrPos, 1) = "s") {
		MouseClickDrag, L, TopLeftCornerX + (FieldWidth * 1.5), TopLeftCornerY + (FieldHeight / 2), CraftingField[1], CraftingField[2]
		if (SubStr(ParentStr, StrPos - 1, 1) = "(")
			MovetoStk()
		else
			AddtoStk()

	}
	if (SubStr(ParentStr, StrPos, 1) = "d") {
		MouseClickDrag, L, TopLeftCornerX + (FieldWidth * 2.5), TopLeftCornerY + (FieldHeight / 2), CraftingField[1], CraftingField[2]
		if (SubStr(ParentStr, StrPos - 1, 1) = "(")
			MovetoStk()
		else
			AddtoStk()

	}
	StrPos := StrPos + 1
}
Return


Removed unnecessary hotkeys

Removed unnecessary hotkeys

;Control key Ctrl- ^
;Alt key Alt- !
;Shift key Shift- +
;Windows key Win- #

#Persistent
;#NoTrayIcon
#SingleInstance Force
DetectHiddenWindows, On
DetectHiddenText, On
SetTitleMatchMode, RegEx ;match titles and classes using regular expressions
SetTitleMatchMode Slow ;match titles and classes using regular expressions
CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen
OldTicks = 0

GroupAdd, adobe, ahk_class OWL.DocumentWindow
GroupAdd, adobe, ahk_class illustrator
GroupAdd, adobe, ahk_class PSViewC
GroupAdd, adobe, ahk_class Photoshop
GroupAdd, adobe, Photoshop
return

RandomFileName()
{
	FormatTime, fileName,, yyyyMMdd_HHmmss_
	characters := "abcdefghijklmnopqrstuvwxyz"
	Loop 3
	{
		Random, rand, 1, strlen(characters)
		fileName := fileName . substr(characters, rand, 1)
	}
	return fileName
}

UploadFiles()
{
	ToolTip, Uploading files..., -1920+50, 50
	RunWait, C:\Program Files (x86)\cygwin\bin\mintty.exe /bin/bash -l -c send_to_pinkyard.py|clip, C:\Program Files (x86)\cygwin
	ToolTip
	return
}

MakeScreen(arguments)
{
	baseFileName := "Z:\hub\pinkyard\queued\" . RandomFileName()
	PNGFileName := "Z:\tmp.png"
	JPGFileName := "Z:\tmp.jpg"
	RunWait, % "C:\program files (x86)\scrsh.exe --path " . PNGFileName . " " . arguments, "Z:\", Hide
	if %ErrorLevel% = 0
	{
		RunWait, % "Z:\src\optipng\support\optipng.exe -o1 " . PNGFileName, "Z:\", Hide
		RunWait, % "C:\Program Files (x86)\cygwin\bin\convert.exe " . PNGFileName . " -quality 80 " . JPGFileName, "Z:\", Hide
		FileGetSize, JPGFileSize, % JPGFileName
		FileGetSize, PNGFileSize, % PNGFileName
		if % PNGFileSize > JPGFileSize
		{
			path1 := JPGFileName
			path2 := baseFileName . ".jpg"
		}
		else
		{
			path1 := PNGFileName
			path2 := baseFileName . ".png"
		}
		FileCopy, % path1, % path2
		FileDelete, % JPGFileName
		FileDelete, % PNGFileName
		SoundPlay, Z:\clutter\sounds\ping.wav
	}
	return path
}

OnClipboardChange:
	if (A_EventInfo == 1) and (SubStr(clipboard, 1, 7) == "http://")
	{
		StringReplace, clipboard, clipboard, `%5b, [, All
		StringReplace, clipboard, clipboard, `%5d, ], All
	}
	return

FRun(window, path, folder)
{
	if (!window or !WinExist(window))
	{
		Run, %path%, %folder%
	}
	else
	{
		WinShow
		WinActivate
	}
	return
}

;programs
#E::FRun("ahk_class CabinetWClass", "Z:\", "Z:\") ;explorer
Launch_Media::FRun("ahk_class {97E27FAA-C0B3-4b8e-A693-ED7881E99FC1}", "C:\program files (x86)\foobar2000\foobar2000.exe", "C:\Program Files (x86)\foobar2000") ;foobar

+^!U::UploadFiles() ;upload files
+^M::
	if (WinExist("ahk_class TfrmSend")) {
		WinShow
		WinActivate
	}
	return

+^!M::
	if (!WinExist("^WTW")) {
		;RunWait, taskkill /im miranda32.exe /f
		Run, "C:\Program Files\WTW\WTW.exe" -x, "C:\Program Files\WTW"
	} else {
		WinShow
		WinActivate
	}
	return

+^![::FRun(false, "C:\Program Files (x86)\cygwin\bin\mintty.exe -", "C:\Program Files (x86)\cygwin\bin") ;cygwin
 ^![::
	if (!WinExist("ahk_class mintty_thetty")) {
		Run, "C:\Program Files (x86)\cygwin\bin\mintty.exe" --size "120`,40" --position "1050`,45" --class "mintty_thetty" --exec "/bin/bash" --login -i -c 'while /bin/true; do /bin/bash; cygstart "%A_AhkPath%" "Z:\src\hide.ahk"; clear; done', "C:/program files(x86)/cygwin/bin"
		WinWait ahk_class mintty_thetty
	} else {
		WinShow
		WinActivate
	}
	WinSet, Style, -0x004b0000
	return

; putty @burza - activate/run + fix screen position
+^!]::
	Run, "C:\Program Files (x86)\putty\putty.exe" -load burza, "C:\Program Files (x86)"
	WinWaitActive ahk_class PuTTY
	WinMove, , , 100, 100
	return
 ^!]::
	if (!WinExist("ahk_class PuTTY")) {
		Run, "C:\Program Files (x86)\putty\putty.exe" -load burza, "C:\Program Files (x86)"
		WinWait ahk_class PuTTY
		WinMove, , , 100, 100
	} else {
		WinShow
		WinActivate
	}
	return
 ^!/::FRun("CDisplayEx", "C:\Program Files (x86)\CDisplayEx\cdisplayex.exe", "Z:\") ;cdisplay
 ^!;::
	IfWinExist, Mozilla Firefox
	{
		WinShow
		WinActivate
		Send, !d
	}
	else
	{
		Run, "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
	}
	return

+^!N:: ;text editor - activate/run + fix screen position
	IfWinExist, ahk_class Vim
	{
		WinShow
		WinActivate
	} else {
		Run, "C:\Program Files (x86)\cygwin\bin\mintty.exe" --size "240`,90" --position "100`,45" --class "Vim" --exec "vim" --cmd 'cd /cygdrive/z', "C:/program files(x86)/cygwin/bin"
		WinWait, ahk_class Vim
	}
	WinMove, , , 100, 100, 1600, 900
	return

;windows powershell / cmd functionalities
#IfWinActive ahk_class ConsoleWindowClass
^V::SendInput {Raw}%clipboard% ;paste on ctrl+v
^!PgUp::Send ! el{PgUp}{Enter} ;scroll on ctrl+page up
^!PgDn::Send ! el{PgDn}{Enter} ;scroll on ctrl+page down
#IfWinActive

;acdsee functionalities
#IfWinActive ahk_class ACDBrowser
	WheelDown::Send, ^{Down}^{Space}
	WheelUp::Send, ^{Up}^{Space}
#IfWinActive
#IfWinActive ACDSee
	WheelDown::
		if (A_TickCount - OldTicks >= 80) {
			Send, {WheelDown}
			OldTicks := A_TickCount
		}
		return
	]:: ;send to document folder
	RButton & ~LButton::
		FormatTime, Folder,, 'Z:\'
		Send {LAlt down}c
		Send {LAlt up}
		SendInput %Folder%
		Send {Return}
		return
	[:: ;send to upload folder
	~LButton & RButton::
		Send {LAlt down}c
		Send {LAlt up}
		SendInput Z:\hub\pinkyard\queued
		Send {Return}
		Sleep 100
		return
	XButton1::
		WinGet, Transparency, Transparent, A
		if ! Transparency
			WinSet, Transparent, 255, A
		else if Transparency = 255
			WinSet, Transparent, 0, A
		return
	XButton2:: ;start slideshow
		Send {Pause}
		return
#IfWinActive

;other functionalities
!F12::Reload
!M:: ;maximize active window
	ActiveHwnd := WinExist("A")
	PostMessage 0x112, 0xf030 ;WM_SYSCOMMAND, SC_MAXIMIZE
	return
!R:: ;restore active window
	ActiveHwnd := WinExist("A")
	PostMessage 0x112, 0xf120 ;WM_SYSCOMMAND, SC_RESTORE
	return
!W:: ;minimize active window
	if WinActive("WTW$") {
		WinHide
	} else {
		ActiveHwnd := WinExist("A")
		PostMessage 0x112, 0xF020 ;WM_SYSCOMMAND, SC_MINIMIZE
	}
	return
!A::WinSet, AlwaysOnTop, Toggle, A

;transparency
#1::WinSet, Transparent, 0, A
#2::WinSet, Transparent, 64, A
#3::WinSet, Transparent, 255, A
#WheelUp::
	WinGet, Transparency, Transparent, A
	if ! Transparency
		Transparency = 255
	Transparency := Transparency + 16
	if Transparency <= 10
	{
		WinSet, Transparent, 10, A
	}
	else if Transparency >= 255
	{
		WinSet, Transparent, 255, A
		WinSet, Transparent, OFF, A
	}
	else
	{
		WinSet, Transparent, %Transparency%, A
	}
	return
#WheelDown::
	WinGet, Transparency, Transparent, A
	if ! Transparency
		Transparency = 255
	Transparency := Transparency - 16
	if Transparency <= 10
	{
		WinSet, Transparent, 10, A
	}
	else if Transparency >= 255
	{
		WinSet, Transparent, 255, A
		WinSet, Transparent, OFF, A
	}
	else
	{
		WinSet, Transparent, %Transparency%, A
	}
	return

 +PrintScreen::MakeScreen("-g")
 !PrintScreen::MakeScreen("-r active-window --shift -8,-8,+16,+16 --force-gui")
!#PrintScreen::MakeScreen("-r active-monitor")
 #PrintScreen::MakeScreen("-r all-monitors")

;explorer
#IfWinActive ahk_class CabinetWClass
	;new folder
	^n::
		Send {AppsKey}wf
		return
#IfWinActive

#IfWinActive ahk_class PuTTY
	;putty ctrl+alt+pageup/pagedown
	^!PgUp::SendInput {Escape}:tabprev{Return}
	^!PgDn::SendInput {Escape}:tabnext{Return}
	;putty pasting
	+Numpad0::
	+NumpadIns::
	+Insert::
		WinGetPos, winX, winY, winW, winH
		tempX := winX+(winW//2)
		tempY := winY+(winH//2)
		MouseClick, Right, %tempX%, %tempY%
		return
#IfWinActive

#IfWinActive ahk_group adobe
	~LAlt::return
	LAlt UP::Send {Escape}
#IfWinActive

;Control key Ctrl- ^
;Alt key Alt- !
;Shift key Shift- +
;Windows key Win- #

#Persistent
;#NoTrayIcon
#SingleInstance Force
DetectHiddenWindows, On
DetectHiddenText, On
SetTitleMatchMode, RegEx ;match titles and classes using regular expressions
SetTitleMatchMode Slow ;match titles and classes using regular expressions
CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen
OldTicks = 0

GroupAdd, adobe, ahk_class OWL.DocumentWindow
GroupAdd, adobe, ahk_class illustrator
GroupAdd, adobe, ahk_class PSViewC
GroupAdd, adobe, ahk_class Photoshop
GroupAdd, adobe, Photoshop
return

RandomFileName()
{
	FormatTime, fileName,, yyyyMMdd_HHmmss_
	characters := "abcdefghijklmnopqrstuvwxyz"
	Loop 3
	{
		Random, rand, 1, strlen(characters)
		fileName := fileName . substr(characters, rand, 1)
	}
	return fileName
}

UploadFiles()
{
	ToolTip, Uploading files..., -1920+50, 50
	RunWait, C:\Program Files (x86)\cygwin\bin\mintty.exe /bin/bash -l -c send_to_pinkyard.py|clip, C:\Program Files (x86)\cygwin
	ToolTip
	return
}

MakeScreen(arguments)
{
	baseFileName := "Z:\hub\pinkyard\queued\" . RandomFileName()
	PNGFileName := "Z:\tmp.png"
	JPGFileName := "Z:\tmp.jpg"
	RunWait, % "C:\program files (x86)\scrsh.exe --path " . PNGFileName . " " . arguments, "Z:\", Hide
	if %ErrorLevel% = 0
	{
		RunWait, % "Z:\src\optipng\support\optipng.exe -o1 " . PNGFileName, "Z:\", Hide
		RunWait, % "C:\Program Files (x86)\cygwin\bin\convert.exe " . PNGFileName . " -quality 80 " . JPGFileName, "Z:\", Hide
		FileGetSize, JPGFileSize, % JPGFileName
		FileGetSize, PNGFileSize, % PNGFileName
		if % PNGFileSize > JPGFileSize
		{
			path1 := JPGFileName
			path2 := baseFileName . ".jpg"
		}
		else
		{
			path1 := PNGFileName
			path2 := baseFileName . ".png"
		}
		FileCopy, % path1, % path2
		FileDelete, % JPGFileName
		FileDelete, % PNGFileName
		SoundPlay, Z:\clutter\sounds\ping.wav
	}
	return path
}

OnClipboardChange:
	if (A_EventInfo == 1) and (SubStr(clipboard, 1, 7) == "http://")
	{
		StringReplace, clipboard, clipboard, `%5b, [, All
		StringReplace, clipboard, clipboard, `%5d, ], All
	}
	return

FRun(window, path, folder)
{
	if (!window or !WinExist(window))
	{
		Run, %path%, %folder%
	}
	else
	{
		WinShow
		WinActivate
	}
	return
}

;programs
#E::FRun("ahk_class CabinetWClass", "Z:\", "Z:\") ;explorer
Launch_Media::FRun("ahk_class {97E27FAA-C0B3-4b8e-A693-ED7881E99FC1}", "C:\program files (x86)\foobar2000\foobar2000.exe", "C:\Program Files (x86)\foobar2000") ;foobar

+^!U::UploadFiles() ;upload files
+^M::
	if (WinExist("ahk_class TfrmSend")) {
		WinShow
		WinActivate
	}
	return

+^!M::
	if (!WinExist("^WTW")) {
		;RunWait, taskkill /im miranda32.exe /f
		Run, "C:\Program Files\WTW\WTW.exe" -x, "C:\Program Files\WTW"
	} else {
		WinShow
		WinActivate
	}
	return

+^![::FRun(false, "C:\Program Files (x86)\cygwin\bin\mintty.exe -", "C:\Program Files (x86)\cygwin\bin") ;cygwin
 ^![::
	if (!WinExist("ahk_class mintty_thetty")) {
		Run, "C:\Program Files (x86)\cygwin\bin\mintty.exe" --size "120`,40" --position "1050`,45" --class "mintty_thetty" --exec "/bin/bash" --login -i -c 'while /bin/true; do /bin/bash; cygstart "%A_AhkPath%" "Z:\src\hide.ahk"; clear; done', "C:/program files(x86)/cygwin/bin"
		WinWait ahk_class mintty_thetty
	} else {
		WinShow
		WinActivate
	}
	WinSet, Style, -0x004b0000
	return

; putty @burza - activate/run + fix screen position
+^!]::
	Run, "C:\Program Files (x86)\putty\putty.exe" -load burza, "C:\Program Files (x86)"
	WinWaitActive ahk_class PuTTY
	WinMove, , , 100, 100
	return
 ^!]::
	if (!WinExist("ahk_class PuTTY")) {
		Run, "C:\Program Files (x86)\putty\putty.exe" -load burza, "C:\Program Files (x86)"
		WinWait ahk_class PuTTY
		WinMove, , , 100, 100
	} else {
		WinShow
		WinActivate
	}
	return
 ^!/::FRun("CDisplayEx", "C:\Program Files (x86)\CDisplayEx\cdisplayex.exe", "Z:\") ;cdisplay
 ^!;::
	IfWinExist, Mozilla Firefox
	{
		WinShow
		WinActivate
		Send, !d
	}
	else
	{
		Run, "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
	}
	return

+^!N:: ;text editor - activate/run + fix screen position
	IfWinExist, ahk_class Vim
	{
		WinShow
		WinActivate
	} else {
		Run, "C:\Program Files (x86)\cygwin\bin\mintty.exe" --size "240`,90" --position "100`,45" --class "Vim" --exec "vim" --cmd 'cd /cygdrive/z', "C:/program files(x86)/cygwin/bin"
		WinWait, ahk_class Vim
	}
	WinMove, , , 100, 100, 1600, 900
	return

;windows powershell / cmd functionalities
#IfWinActive ahk_class ConsoleWindowClass
^V::SendInput {Raw}%clipboard% ;paste on ctrl+v
^!PgUp::Send ! el{PgUp}{Enter} ;scroll on ctrl+page up
^!PgDn::Send ! el{PgDn}{Enter} ;scroll on ctrl+page down
#IfWinActive

;acdsee functionalities
#IfWinActive ahk_class ACDBrowser
	WheelDown::Send, ^{Down}^{Space}
	WheelUp::Send, ^{Up}^{Space}
#IfWinActive
#IfWinActive ACDSee
	WheelDown::
		if (A_TickCount - OldTicks >= 80) {
			Send, {WheelDown}
			OldTicks := A_TickCount
		}
		return
	]:: ;send to document folder
	RButton & ~LButton::
		FormatTime, Folder,, 'Z:\'
		Send {LAlt down}c
		Send {LAlt up}
		SendInput %Folder%
		Send {Return}
		return
	[:: ;send to upload folder
	~LButton & RButton::
		Send {LAlt down}c
		Send {LAlt up}
		SendInput Z:\hub\pinkyard\queued
		Send {Return}
		Sleep 100
		return
	XButton1::
		WinGet, Transparency, Transparent, A
		if ! Transparency
			WinSet, Transparent, 255, A
		else if Transparency = 255
			WinSet, Transparent, 0, A
		return
	XButton2:: ;start slideshow
		Send {Pause}
		return
#IfWinActive

;other functionalities
!F12::Reload
!M:: ;maximize active window
	ActiveHwnd := WinExist("A")
	PostMessage 0x112, 0xf030 ;WM_SYSCOMMAND, SC_MAXIMIZE
	return
!R:: ;restore active window
	ActiveHwnd := WinExist("A")
	PostMessage 0x112, 0xf120 ;WM_SYSCOMMAND, SC_RESTORE
	return
!W:: ;minimize active window
	if WinActive("WTW$") {
		WinHide
	} else if WinActive("ahk_class OperaWindowClass") {
		SendInput +!^h
	} else {
		ActiveHwnd := WinExist("A")
		PostMessage 0x112, 0xF020 ;WM_SYSCOMMAND, SC_MINIMIZE
	}
	return
!A::WinSet, AlwaysOnTop, Toggle, A

;transparency
#1::WinSet, Transparent, 0, A
#2::WinSet, Transparent, 64, A
#3::WinSet, Transparent, 255, A
#WheelUp::
	WinGet, Transparency, Transparent, A
	if ! Transparency
		Transparency = 255
	Transparency := Transparency + 16
	if Transparency <= 10
	{
		WinSet, Transparent, 10, A
	}
	else if Transparency >= 255
	{
		WinSet, Transparent, 255, A
		WinSet, Transparent, OFF, A
	}
	else
	{
		WinSet, Transparent, %Transparency%, A
	}
	return
#WheelDown::
	WinGet, Transparency, Transparent, A
	if ! Transparency
		Transparency = 255
	Transparency := Transparency - 16
	if Transparency <= 10
	{
		WinSet, Transparent, 10, A
	}
	else if Transparency >= 255
	{
		WinSet, Transparent, 255, A
		WinSet, Transparent, OFF, A
	}
	else
	{
		WinSet, Transparent, %Transparency%, A
	}
	return

 +PrintScreen::MakeScreen("-g")
 !PrintScreen::MakeScreen("-r active-window --shift -8,-8,+16,+16 --force-gui")
!#PrintScreen::MakeScreen("-r active-monitor")
 #PrintScreen::MakeScreen("-r all-monitors")

;screenshots [media player classic]
#IfWinActive ahk_class MediaPlayerClassicW
[::
	Send {F5}
	return
#IfWinActive

;explorer
#IfWinActive ahk_class CabinetWClass
	;new folder
	^n::
		Send {AppsKey}wf
		return
#IfWinActive

#IfWinActive ahk_class PuTTY
	;putty ctrl+alt+pageup/pagedown
	^!PgUp::SendInput {Escape}:tabprev{Return}
	^!PgDn::SendInput {Escape}:tabnext{Return}
	;putty pasting
	+Numpad0::
	+NumpadIns::
	+Insert::
		WinGetPos, winX, winY, winW, winH
		tempX := winX+(winW//2)
		tempY := winY+(winH//2)
		MouseClick, Right, %tempX%, %tempY%
		return
#IfWinActive

#IfWinActive ahk_group adobe
	~LAlt::return
	LAlt UP::Send {Escape}
#IfWinActive


increase sleep

increase sleep

DetectHiddenWindows, On
SetDefaultMouseSpeed, 0
CoordMode, Mouse, Client
target=ahk_class Diablo II
executeCmd=Diablo II.exe -w -sndbkg
executeDir=C:\Diablo II
SetWorkingDir, %executeDir%

WinGet, hwnd, ID, %target%
if (!hwnd) {
    Run, %executeCmd%
    Sleep, 10000
    WinGet, hwnd, ID, %target%
    if (hwnd) {
        WinSet, AlwaysOnTop, on, ahk_id %hwnd%
        WinActivate, ahk_id %hwnd%
        IfWinActive, ahk_id %hwnd%
        {
            BlockInput On
            MouseMove, 400, 308, 0
            MouseClick, left
            Sleep, 500
            MouseClick, left
            Sleep, 5000
            MouseMove, 175, 125, 0
            MouseClick, left
            MouseClick, left
            Sleep, 500
            MouseClick, left
            MouseClick, left
            Sleep, 5000
            BlockInput Off
        }
    }
}

DetectHiddenWindows, On
SetDefaultMouseSpeed, 0
CoordMode, Mouse, Client
target=ahk_class Diablo II
executeCmd=Diablo II.exe -w -sndbkg
executeDir=C:\Diablo II
SetWorkingDir, %executeDir%

WinGet, hwnd, ID, %target%
if (!hwnd) {
    Run, %executeCmd%
    Sleep, 5000
    WinGet, hwnd, ID, %target%
    if (hwnd) {
        WinSet, AlwaysOnTop, on, ahk_id %hwnd%
        WinActivate, ahk_id %hwnd%
        IfWinActive, ahk_id %hwnd%
        {
            BlockInput On
            MouseMove, 400, 308, 0
            MouseClick, left
            Sleep, 500
            MouseClick, left
            Sleep, 5000
            MouseMove, 175, 125, 0
            MouseClick, left
            MouseClick, left
            Sleep, 500
            MouseClick, left
            MouseClick, left
            Sleep, 5000
            BlockInput Off
        }
    }
}


Add setting to disable non-clickable clicks in deep runs

; -----------------------------------------------------------------------------------------
; Clicker Heroes Sw1ft Bot
; by Sw1ftb
; -----------------------------------------------------------------------------------------

#Persistent
#NoEnv
#InstallKeybdHook

#Include %A_ScriptDir%
#Include ch_bot_lib.ahk

SetControlDelay, -1

scriptName=CH Sw1ft Bot
scriptVersion=2.32
minLibVersion=1.31

script := scriptName . " v" . scriptVersion

; -----------------------------------------------------------------------------------------
; -- Mandatory Configuration
; -----------------------------------------------------------------------------------------

irisLevel := 1029 ; try to keep your Iris within 1001 levels of your optimal zone

; Clicker Heroes Ancients Optimizer @ http://s3-us-west-2.amazonaws.com/clickerheroes/ancientssoul.html

; Use the optimizer to set the optimal level and time:
optimalLevel := 2000
speedRunTime := 29 ; minutes (usually between 28 and 30 minutes)

; In the Heroes tab you can verify that you are using the optimal ranger.
gildedRanger := 6 ; the number of your main guilded ranger
; 1:Dread Knight, 2:Atlas, 3:Terra, 4:Phthalo, 5:Banana, 6:Lilin, 7:Cadmia, 8:Alabaster, 9:Astraea

; -----------------------------------------------------------------------------------------
; -- Optional Settings
; -----------------------------------------------------------------------------------------

; (Steam only) Want to run borderless fullscreen?
; 1. In Clicker Heroes, turn on the "Full Screen" option.
; 2. Change "fullScreenOption" to "true" in the ch_bot_lib.ahk file.
; 3. Reload with Alt+F5.

; -- Speed run ----------------------------------------------------------------------------

; If the script starts on the 2nd ranger too early (before lvl 100) or too late (after lvl 200), adjust this setting.
firstStintAdjustment := 0 ; Add or remove time (in seconds) to or from the first hero.

activateSkillsAtStart := true ; usually needed in the late game to get going after ascending

hybridMode := false ; chain a deep run when the speed run finish

ascDownClicks := 26 ; # of down clicks needed to get the ascension button center:ish (after a full speed run)

autoAscend := false ; Warning! Set to true will both salvage relics and ascend without any user intervention!
autoAscendDelay := 10 ; warning timer (in seconds) before ascending

saveBeforeAscending := false ; autosave the game

; If you run the Steam client with autoAscend, you can screenshot every relic you salvage!
screenShotRelics := false

; -- Deep run -----------------------------------------------------------------------------

deepRunTime := 60 ; minutes

clickableHuntDelay := 15 ; hunt for a clickable every 15s
stopHuntThreshold := 30 ; stop hunt when this many minutes remain of a deep run

; Number of gilds to move over at a time
reGildCount := 100 ; don't set this higher than 100 if you plan on moving gilds during a deep run
reGildRanger := gildedRanger + 1

; -- Init run -----------------------------------------------------------------------------

; The assistant will automatically try to set the correct initDownClicks and yLvlInit settings.
; It will also assist with Iris level recommendations.
useConfigurationAssistant := true

; A list of clicks needed to scroll down 4 heroes at a time, starting from the top.
initDownClicks := [0,0,0,0,0,0]

; This y coordinate is supposed to keep itself inside the top lvl up button when scrolling down according to the above "clicking pattern".
yLvlInit := 000

; Manual configuration (if not using the assistant):
; 1. Ascend with a "clickable" available.
; 2. Click Alt+F1 (the script should pick up the clickable).
; 3. Scroll down to the bottom. What ranger is last?
; 4. From the list below, pick the matching settings:

; Astraea      [6,5,6,5,6,3], 241 (Iris > 2010)
; Alabaster    [6,6,5,6,6,3], 259 (Iris > 1760)
; Cadmia       [6,6,6,6,6,3], 240 (Iris > 1510)
; Lilin        [6,6,6,6,6,3], 285 (Iris > 1260)
; Banana       [6,7,6,7,6,3], 240 (Iris > 1010)
; Phthalo      [6,7,7,6,7,3], 273 (Iris > 760)
; Terra        [7,7,7,7,7,3], 240 (Iris > 510)
; Atlas        [7,7,7,8,7,3], 273 (Iris > 260)
; Dread Knight [7,8,7,8,7,4], 257

; E.g. if Phthalo is last, you set initDownClicks to [6,7,7,6,7,3] and yLvlInit to 273.
; In this case your Iris level should be somewhere between 760 and 1010.

; 5. Now click Alt+F2 (the script should level up and upgrade all heroes from Cid to Frostleaf).

; If some heroes where missed, make sure you have picked the suggested setting for your Iris level.
; If you are close to one of these Iris irisThresholds, you should move above it with some margin.
; E.g if your Iris is at 489, you should level it to at least 529, pick the setting for Terra,
; reload the script (Alt+F5), ascend with a clickable and try Alt+F2 again.

deepRunClicks := true ; click the monster during a deep run?
; -- Look & Feel --------------------------------------------------------------------------

; true or false
global playNotificationSounds := true
global playWarningSounds := true
global showSplashTexts := true ; Note that some splash texts will always be shown
global showProgressBar := true

; Splash text window position
xSplash := A_ScreenWidth // 2 - wSplash // 2 ; centered
ySplash := A_ScreenHeight // 2 - 40

; Progress bar position
xProgressBar := 20
yProgressBar := 20

; If you run with a dual/tripple monitor setup, you can move windows
; right or left by adding or subtracting A_ScreenWidth from the x-parameters.

; Left monitor example:
; xSplash := A_ScreenWidth // 2 - wSplash // 2 - A_ScreenWidth
; xProgressBar := 20 - A_ScreenWidth

; -- Skill Combos -------------------------------------------------------------------------

; 1 - Clickstorm, 2 - Powersurge, 3 - Lucky Strikes, 4 - Metal Detector, 5 - Golden Clicks
; 6 - The Dark Ritual, 7 - Super Clicks, 8 - Energize, 9 - Reload

; Test with tools/combo_tester.ahk

comboStart := [15*60, "8-1-2-3-4-5-7-6-9"]
comboEDR := [2.5*60, "2-3-4-5-7-8-6-9", "", "", "", "", "", "8-9-2-3-4-5-7", "2", "2", "2-3-4", "2", "2"]
comboEGolden := [2.5*60, "8-5-2-3-4-7-6-9", "2", "2", "2-3-4", "2", "2"] ; energize 3 (dmg) or 5 (gold)
comboGoldenLuck := [2.5*60, "6-2-3-5-8-9", "2-3-4-5-7", "2", "2", "2-3-4", "2", "2"]

speedRunStartCombo := comboStart
deepRunCombo := comboGoldenLuck

; -----------------------------------------------------------------------------------------

if (libVersion != minLibVersion) {
	showWarningSplash("The bot lib version must be " . minLibVersion . "!")
	ExitApp
}

#Include *i ch_bot_settings.ahk

scheduleReload := false
scheduleStop := false

if (useConfigurationAssistant) {
	configurationAssistant()
}

clientCheck()
handleAutorun()

; -----------------------------------------------------------------------------------------
; -- Hotkeys (+=Shift, !=Alt, ^=Ctrl)
; -----------------------------------------------------------------------------------------

; Show the cursor position with Alt+Middle Mouse Button
!mbutton::
	mousegetpos, xpos, ypos
	msgbox,,% script,% "Cursor position: x" xpos-leftMarginOffset " y" ypos-topMarginOffset
return

; Pause/Unpause script
Pause::Pause
return

; Abort speed/deep runs and auto ascensions with Alt+Pause
!Pause::
	showSplashAlways("Aborting...")
	exitThread := true
	exitDRThread := true
return

; Quick tests:
; Ctrl+Alt+F1 should scroll down to the bottom
; Ctrl+Alt+F2 should switch to the relics tab and then back

^!F1::
	scrollToBottom()
return

^!F2::
	switchToRelicTab()
	switchToCombatTab()
return

; Alt+F1 to F4 are here to test the individual parts of the full speed run loop

!F1::
	getClickable()
return

!F2::
	initRun()
return

!F3::
	switchToCombatTab()
	speedRun()
return

!F4::
	ascend(autoAscend)
return

; Reload script with Alt+F5
!F5::
	global scheduleReload := true
	handleScheduledReload()
return

; Speed run loop.
; Use to farm Hero Souls
^F1::
	loopSpeedRun()
return

; Deep run.
; Use (after a speed run) to get a few new gilds every now and then
^F2::
	deepRun()
return

; Set previous ranger as re-gild target
^F6::
	reGildRanger := reGildRanger > rangers.MinIndex() ? reGildRanger-1 : reGildRanger
	showSplashAlways("Re-gild ranger set to " . rangers[reGildRanger])
return

; Set next ranger as re-gild target
^F7::
	reGildRanger := reGildRanger < rangers.MaxIndex() ? reGildRanger+1 : reGildRanger
	showSplashAlways("Re-gild ranger set to " . rangers[reGildRanger])
return

; Move "reGildCount" gilds to the target ranger (will pause the monster clicker if running)
^F8::
	critical
	playNotificationSound()
	msgbox, 4,% script,% "Move " . reGildCount . " gilds to " . rangers[reGildRanger] . "?"
	ifmsgbox no
		return
	regild(reGildRanger, reGildCount) ; will pause the monster clicker if running
return

; Autosave the game
^F11::
	critical
	monsterClickerPause()
	save()
return

; Toggle boolean (true/false) flags

+^F1::
	toggleFlag("autoAscend", autoAscend)
return

+^F2::
	toggleFlag("screenShotRelics", screenShotRelics)
return

+^F3::
	toggleFlag("playNotificationSounds", playNotificationSounds)
return

+^F4::
	toggleFlag("playWarningSounds", playWarningSounds)
return

+^F5::
	toggleFlag("showSplashTexts", showSplashTexts)
return

+^F11::
	toggleFlag("saveBeforeAscending", saveBeforeAscending)
return

+^F12::
	toggleFlag("debug", debug)
return

; Schedule reload script with Shift+F5
+F5::
	toggleFlag("scheduleReload", scheduleReload)
return

+Pause::
	toggleFlag("scheduleStop", scheduleStop)
return

; -----------------------------------------------------------------------------------------
; -- Functions
; -----------------------------------------------------------------------------------------

; Automatically configure initDownClicks and yLvlInit settings.
configurationAssistant() {
	global

	if (irisLevel < 145) {
		playWarningSound()
		msgbox,,% script,% "Your Iris do not fulfill the minimum level requirement of 145 or higher!"
		exit
	}

	if (irisThreshold(2010)) { ; Astraea
		initDownClicks := [6,5,6,5,6,3]
		yLvlInit := 241
	} else if (irisThreshold(1760)) { ; Alabaster
		initDownClicks := [6,6,5,6,6,3]
		yLvlInit := 259
	} else if (irisThreshold(1510)) { ; Cadmia
		initDownClicks := [6,6,6,6,6,3]
		yLvlInit := 240
	} else if (irisThreshold(1260)) { ; Lilin
		initDownClicks := [6,6,6,6,6,3]
		yLvlInit := 285
	} else if (irisThreshold(1010)) { ; Banana
		initDownClicks := [6,7,6,7,6,3]
		yLvlInit := 240
	} else if (irisThreshold(760)) { ; Phthalo
		initDownClicks := [6,7,7,6,7,3]
		yLvlInit := 273
	} else if (irisThreshold(510)) { ; Terra
		initDownClicks := [7,7,7,7,7,3]
		yLvlInit := 240
	} else if (irisThreshold(260)) { ; Atlas
		initDownClicks := [7,7,7,8,7,3]
		yLvlInit := 273
	} else { ; Dread Knight
		initDownClicks := [7,8,7,8,7,4]
		yLvlInit := 257
	}

	if (irisLevel < optimalLevel - 1001) {
		local levels := optimalLevel - 1001 - irisLevel
		playNotificationSound()
		msgbox,,% script,% "Your Iris is " . levels . " levels below the recommended ""optimal level - 1001"" rule."
	}
}

; Check if Iris is within a certain threshold that can cause a toggling behaviour between different settings
irisThreshold(lvl) {
	global
	local upperThreshold := lvl + 19
	local lowerThreshold := lvl - 20
	if (irisLevel >= lowerThreshold and irisLevel < upperThreshold) {
		playWarningSound()
		msgbox,,% script,% "Threshold proximity warning! You should level up your Iris to " . upperThreshold . " or higher."
	}
	return irisLevel > lvl
}

; Level up and upgrade all heroes
initRun() {
	global

	switchToCombatTab()
	clickPos(xHero, yHero) ; prevent fails

	upgrade(initDownClicks[1],2,,2) ; cid --> brittany
	upgrade(initDownClicks[2]) ; fisherman --> leon
	upgrade(initDownClicks[3]) ; seer --> mercedes
	upgrade(initDownClicks[4],,,,2) ; bobby --> king
	upgrade(initDownClicks[5],2,,,2) ; ice --> amenhotep
	upgrade(initDownClicks[6],,,2) ; beastlord --> shinatobe
	upgrade(0,,,,,true) ; grant & frostleaf

	scrollToBottom()
	buyAvailableUpgrades()
}

upgrade(times, cc1:=1, cc2:=1, cc3:=1, cc4:=1, skip:=false) {
	global

	if (!skip) {
		ctrlClick(xLvl, yLvlInit, cc1)
		ctrlClick(xLvl, yLvlInit + oLvl, cc2)
	}
	ctrlClick(xLvl, yLvlInit + oLvl*2, cc3)
	ctrlClick(xLvl, yLvlInit + oLvl*3, cc4)

	scrollDown(times)
}

loopSpeedRun() {
	global

	mode := hybridMode ? "hybrid" : "speed"
	showSplashAlways("Starting " . mode . " runs...")
	loop
	{
		getClickable()
		sleep % coinPickUpDelay * 1000
		initRun()
		if (activateSkillsAtStart) {
			activateSkills(speedRunStartCombo[2])
		}
		speedRun()
		if (hybridMode) {
			deepRun()
		}
		if (saveBeforeAscending) {
			save()
		}
		ascend(autoAscend)
		handleScheduledReload(true)
		handleScheduledStop()
	}
}

; All heroes/rangers are expected to "insta-kill" everything at max speed (i.e. around
; 7 minutes per 250 levels). Only the last 2-3 minutes should slow down slightly.
speedRun() {
	global

	local stint := 0
	local stints := 0
	local tMax := 7 * 60 ; seconds
	local lMax := 250 ; zones

	local lvlAdjustment := round(firstStintAdjustment * lMax / tMax)
	local zoneLvl := gildedRanger * lMax + lvlAdjustment ; approx zone lvl where we can buy our gilded ranger @ lvl 150
	local lvls := zoneLvl - irisLevel ; lvl's to get there

	local firstStintButton := 1
	local firstStintTime := 0
	local midStintTime := 0

	if (lvls > lMax + 2*60*lMax/tMax) ; add a mid stint if needed
	{
		midStintTime := tMax
		lvls -= lMax
		stints += 1
	} else if (lvls > lMax) {
		firstStintButton := 2
	}

	if (lvls > 0)
	{
		firstStintTime := ceil(lvls * tMax / lMax)
		stints += 1
	}

	local srDuration := speedRunTime * 60
	local totalClickDelay := ceil(srDuration / lvlUpDelay * zzz / 1000 + nextHeroDelay * stints)
	local lastStintTime := srDuration - firstStintTime - midStintTime - totalClickDelay
	stints += 1

	local lastStintButton := gildedRanger = 9 ? 3 : 2 ; special case for Astraea

	if (debug)
	{
		local nl := "`r`n"
		local s := "    " ; Reddit friendly formatting
		local output := ""
		output .= s . "irisLevel = " . irisLevel . nl
		output .= s . "optimalLevel = " . optimalLevel . nl
		output .= s . "speedRunTime = " . speedRunTime . nl
		output .= s . "gildedRanger = " . rangers[gildedRanger] . nl
		output .= s . "-----------------------------" . nl
		output .= s . "initDownClicks = "
		for i, e in initDownClicks {
			output .= e " "
		}
		output .= nl
		output .= s . "yLvlInit = " . yLvlInit . nl
		output .= s . "firstStintAdjustment = " . firstStintAdjustment . "s" . nl
		output .= s . "-----------------------------" . nl
		output .= s . "lvlAdjustment = " . lvlAdjustment . nl
		output .= s . "zoneLvl = " . zoneLvl . nl
		output .= s . "lvls = " . lvls . nl
		output .= s . "srDuration = " . formatSeconds(srDuration) . nl
		output .= s . "firstStintButton = " . firstStintButton . nl
		output .= s . "firstStintTime = " . formatSeconds(firstStintTime) . nl
		output .= s . "midStintTime = " . formatSeconds(midStintTime) . nl
		output .= s . "lastStintTime = " . formatSeconds(lastStintTime) . nl
		output .= s . "totalClickDelay = " . formatSeconds(totalClickDelay) . nl

		clipboard := % output
		msgbox % output
		return
	}

	showSplash("Starting speed run...")

	if (irisLevel < 2 * lMax + 10) ; Iris high enough to start with a ranger?
	{
		switchToCombatTab()
		scrollDown(initDownClicks[1])
		toggleMode() ; toggle to progression mode
		lvlUp(firstStintTime, 0, 3, ++stint, stints) ; nope, let's bridge with Samurai
		scrollToBottom()
	} else {
		scrollToBottom()
		toggleMode() ; toggle to progression mode
		if (firstStintTime > 0) {
			lvlUp(firstStintTime, 1, firstStintButton, ++stint, stints)
			scrollWayDown(3)
		}
	}
	if (midStintTime > 0) {
		lvlUp(midStintTime, 1, 2, ++stint, stints)
		scrollWayDown(2)
	}
	lvlUp(lastStintTime, 1, lastStintButton, ++stint, stints)

	showSplash("Speed run completed.")
}

deepRun() {
	global

	exitDRThread := false

	local drDuration := deepRunTime * 60
	local button := gildedRanger = 9 ? 3 : 2 ; special case for Astraea
	local y := yLvl + oLvl * (button - 1)

	showSplash("Starting deep run...")

	startMouseMonitoring()
	startProgress("Deep Run Progress", 0, drDuration // barUpdateDelay)
	if (deepRunClicks) {
		monsterClickerOn()
	}

	local comboDelay := deepRunCombo[1]
	local comboIndex := 2
	local stopHuntIndex := drDuration - stopHuntThreshold * 60
	local t := 0

	loop % drDuration
	{
		if (exitDRThread) {
			monsterClickerOff()
			stopProgress()
			stopMouseMonitoring()
			showSplashAlways("Deep run aborted!")
			exit
		}
		if (deepRunClicks) {
			clickPos(xMonster, yMonster)
		}
		if (mod(t, comboDelay) = 0) {
			activateSkills(deepRunCombo[comboIndex])
			comboIndex := comboIndex < deepRunCombo.MaxIndex() ? comboIndex+1 : 2
		}
		if (mod(t, lvlUpDelay) = 0) {
			ctrlClick(xLvl, y, 1, 0)
		}
		if (mod(t, clickableHuntDelay) = 0 and t < stopHuntIndex) {
			getClickable()
		}
		t += 1
		updateProgress(t // barUpdateDelay, drDuration - t)
		sleep 1000
	}

	if (deepRunClicks) {
		monsterClickerOff()
	}
	stopProgress()
	stopMouseMonitoring()

	showSplash("Deep run ended.")
	sleep 1000
}

monsterClickerOn() {
	send {shift down}{f1 down}{f1 up}{shift up}
}

monsterClickerPause() {
	send {shift down}{f2 down}{f2 up}{shift up}
}

monsterClickerOff() {
	send {shift down}{pause down}{pause up}{shift up}
}

lvlUp(seconds, buyUpgrades, button, stint, stints) {
	global

	exitThread := false
	local y := yLvl + oLvl * (button - 1)
	local title := "Speed Run Progress (" . stint . "/" . stints . ")"

	startMouseMonitoring()
	startProgress(title, 0, seconds // barUpdateDelay)

	if (buyUpgrades) {
		ctrlClick(xLvl, y)
		buyAvailableUpgrades()
	}
	maxClick(xLvl, y)

	local t := 0

	loop % seconds
	{
		if (exitThread) {
			stopProgress()
			stopMouseMonitoring()
			showSplashAlways("Speed run aborted!")
			exit
		}
		if (mod(t, lvlUpDelay) = 0) {
			ctrlClick(xLvl, y)
		}
		t += 1
		updateProgress(t // barUpdateDelay, seconds - t)
		sleep 1000
	}
	stopProgress()
	stopMouseMonitoring()
}

ascend(autoYes:=false) {
	global
	exitThread := false
	local extraClicks := 6
	local y := yAsc - extraClicks * buttonSize

	if (autoYes) {
		showWarningSplash(autoAscendDelay . " seconds till ASCENSION! (Abort with Alt+Pause)", autoAscendDelay)
		if (exitThread) {
			showSplashAlways("Ascension aborted!")
			exit
		}
	} else {
		playWarningSound()
		msgbox, 260,% script,Salvage Junk Pile & Ascend? ; default no
		ifmsgbox no
			exit
	}

	salvageJunkPile() ; must salvage junk relics before ascending

	switchToCombatTab()
	scrollDown(ascDownClicks)
	sleep % zzz * 2

	; Scrolling is not an exact science, hence we click above, center and below
	loop % 2 * extraClicks + 1
	{
		clickPos(xAsc, y)
		y += buttonSize
	}
	sleep % zzz * 4
	clickPos(xYes, yYes)
	sleep % zzz * 2
}

salvageJunkPile() {
	global

	switchToRelicTab()
	if (autoAscend && screenShotRelics) {
		clickPos(xRelic, yRelic) ; focus
		screenShot()
		clickPos(xRelic+100, yRelic) ; remove focus
	}
	clickPos(xSalvageJunk, ySalvageJunk)
	sleep % zzz * 4
	clickPos(xDestroyYes, yDestroyYes)
	sleep % zzz * 2
}

buyAvailableUpgrades() {
	global
	clickPos(xBuy, yBuy)
	sleep % zzz * 3
}

; Move "gildCount" gilds to given ranger
regild(ranger, gildCount) {
	global
	monsterClickerPause()
	switchToCombatTab()
	scrollToBottom()

	clickPos(xGilded, yGilded)
	sleep % zzz * 2

	ControlSend,, {shift down}, % winName
	clickPos(rangerPositions[ranger].x, rangerPositions[ranger].y, gildCount)
	sleep % 1000 * gildCount/100*5
	ControlSend,, {shift up}, % winName

	clickPos(xGildedClose, yGildedClose)
	sleep % zzz * 2
}

; Toggle between farm and progression modes
toggleMode() {
	global
	ControlSend,, {a down}{a up}, % winName
	sleep % zzz
}

activateSkills(skills) {
	global
	clickPos(xHero, yHero) ; prevent fails
	loop,parse,skills,-
	{
		ControlSend,,% A_LoopField, % winName
		sleep 100
	}
	sleep 1000
}

startMouseMonitoring() {
	setTimer, checkMousePosition, 250
}

stopMouseMonitoring() {
	setTimer, checkMousePosition, off
}

handleScheduledReload(autorun := false) {
	global
	if(scheduleReload) {
		showSplashAlways("Reloading bot...", 1)

		autorun_flag := autorun = true ? "/autorun" : ""
		Run "%A_AhkPath%" /restart "%A_ScriptFullPath%" %autorun_flag%
	}
}

handleScheduledStop() {
	global
	if(scheduleStop) {
		showSplashAlways("Stopping speedruns...", 1)
		scheduleStop := false
		exit
	}
}

handleAutorun() {
	global
	param_1 = %1%
	if(param_1 = "/autorun") {
		showSplashAlways("Autorun speedruns...")
		loopSpeedrun()
	}
}

; -----------------------------------------------------------------------------------------
; -- Subroutines
; -----------------------------------------------------------------------------------------

; Safety zone around the in-game tabs (that triggers an automatic script pause when breached)
checkMousePosition:
	MouseGetPos,,, window
	if (window = WinExist(winName)) {
		WinActivate
		MouseGetPos, x, y

		xL := getAdjustedX(xSafetyZoneL)
		xR := getAdjustedX(xSafetyZoneR)
		yT := getAdjustedY(ySafetyZoneT)
		yB := getAdjustedY(ySafetyZoneB)

		if (x > xL && x < xR && y > yT && y < yB) {
			playNotificationSound()
			msgbox,,% script,Click safety pause engaged. Continue?
		}
	}
return

; -----------------------------------------------------------------------------------------
; Clicker Heroes Sw1ft Bot
; by Sw1ftb
; -----------------------------------------------------------------------------------------

#Persistent
#NoEnv
#InstallKeybdHook

#Include %A_ScriptDir%
#Include ch_bot_lib.ahk

SetControlDelay, -1

scriptName=CH Sw1ft Bot
scriptVersion=2.32
minLibVersion=1.31

script := scriptName . " v" . scriptVersion

; -----------------------------------------------------------------------------------------
; -- Mandatory Configuration
; -----------------------------------------------------------------------------------------

irisLevel := 1029 ; try to keep your Iris within 1001 levels of your optimal zone

; Clicker Heroes Ancients Optimizer @ http://s3-us-west-2.amazonaws.com/clickerheroes/ancientssoul.html

; Use the optimizer to set the optimal level and time:
optimalLevel := 2000
speedRunTime := 29 ; minutes (usually between 28 and 30 minutes)

; In the Heroes tab you can verify that you are using the optimal ranger.
gildedRanger := 6 ; the number of your main guilded ranger
; 1:Dread Knight, 2:Atlas, 3:Terra, 4:Phthalo, 5:Banana, 6:Lilin, 7:Cadmia, 8:Alabaster, 9:Astraea

; -----------------------------------------------------------------------------------------
; -- Optional Settings
; -----------------------------------------------------------------------------------------

; (Steam only) Want to run borderless fullscreen?
; 1. In Clicker Heroes, turn on the "Full Screen" option.
; 2. Change "fullScreenOption" to "true" in the ch_bot_lib.ahk file.
; 3. Reload with Alt+F5.

; -- Speed run ----------------------------------------------------------------------------

; If the script starts on the 2nd ranger too early (before lvl 100) or too late (after lvl 200), adjust this setting.
firstStintAdjustment := 0 ; Add or remove time (in seconds) to or from the first hero.

activateSkillsAtStart := true ; usually needed in the late game to get going after ascending

hybridMode := false ; chain a deep run when the speed run finish

ascDownClicks := 26 ; # of down clicks needed to get the ascension button center:ish (after a full speed run)

autoAscend := false ; Warning! Set to true will both salvage relics and ascend without any user intervention!
autoAscendDelay := 10 ; warning timer (in seconds) before ascending

saveBeforeAscending := false ; autosave the game

; If you run the Steam client with autoAscend, you can screenshot every relic you salvage!
screenShotRelics := false

; -- Deep run -----------------------------------------------------------------------------

deepRunTime := 60 ; minutes

clickableHuntDelay := 15 ; hunt for a clickable every 15s
stopHuntThreshold := 30 ; stop hunt when this many minutes remain of a deep run

; Number of gilds to move over at a time
reGildCount := 100 ; don't set this higher than 100 if you plan on moving gilds during a deep run
reGildRanger := gildedRanger + 1

; -- Init run -----------------------------------------------------------------------------

; The assistant will automatically try to set the correct initDownClicks and yLvlInit settings.
; It will also assist with Iris level recommendations.
useConfigurationAssistant := true

; A list of clicks needed to scroll down 4 heroes at a time, starting from the top.
initDownClicks := [0,0,0,0,0,0]

; This y coordinate is supposed to keep itself inside the top lvl up button when scrolling down according to the above "clicking pattern".
yLvlInit := 000

; Manual configuration (if not using the assistant):
; 1. Ascend with a "clickable" available.
; 2. Click Alt+F1 (the script should pick up the clickable).
; 3. Scroll down to the bottom. What ranger is last?
; 4. From the list below, pick the matching settings:

; Astraea      [6,5,6,5,6,3], 241 (Iris > 2010)
; Alabaster    [6,6,5,6,6,3], 259 (Iris > 1760)
; Cadmia       [6,6,6,6,6,3], 240 (Iris > 1510)
; Lilin        [6,6,6,6,6,3], 285 (Iris > 1260)
; Banana       [6,7,6,7,6,3], 240 (Iris > 1010)
; Phthalo      [6,7,7,6,7,3], 273 (Iris > 760)
; Terra        [7,7,7,7,7,3], 240 (Iris > 510)
; Atlas        [7,7,7,8,7,3], 273 (Iris > 260)
; Dread Knight [7,8,7,8,7,4], 257

; E.g. if Phthalo is last, you set initDownClicks to [6,7,7,6,7,3] and yLvlInit to 273.
; In this case your Iris level should be somewhere between 760 and 1010.

; 5. Now click Alt+F2 (the script should level up and upgrade all heroes from Cid to Frostleaf).

; If some heroes where missed, make sure you have picked the suggested setting for your Iris level.
; If you are close to one of these Iris irisThresholds, you should move above it with some margin.
; E.g if your Iris is at 489, you should level it to at least 529, pick the setting for Terra,
; reload the script (Alt+F5), ascend with a clickable and try Alt+F2 again.

; -- Look & Feel --------------------------------------------------------------------------

; true or false
global playNotificationSounds := true
global playWarningSounds := true
global showSplashTexts := true ; Note that some splash texts will always be shown
global showProgressBar := true

; Splash text window position
xSplash := A_ScreenWidth // 2 - wSplash // 2 ; centered
ySplash := A_ScreenHeight // 2 - 40

; Progress bar position
xProgressBar := 20
yProgressBar := 20

; If you run with a dual/tripple monitor setup, you can move windows
; right or left by adding or subtracting A_ScreenWidth from the x-parameters.

; Left monitor example:
; xSplash := A_ScreenWidth // 2 - wSplash // 2 - A_ScreenWidth
; xProgressBar := 20 - A_ScreenWidth

; -- Skill Combos -------------------------------------------------------------------------

; 1 - Clickstorm, 2 - Powersurge, 3 - Lucky Strikes, 4 - Metal Detector, 5 - Golden Clicks
; 6 - The Dark Ritual, 7 - Super Clicks, 8 - Energize, 9 - Reload

; Test with tools/combo_tester.ahk

comboStart := [15*60, "8-1-2-3-4-5-7-6-9"]
comboEDR := [2.5*60, "2-3-4-5-7-8-6-9", "", "", "", "", "", "8-9-2-3-4-5-7", "2", "2", "2-3-4", "2", "2"]
comboEGolden := [2.5*60, "8-5-2-3-4-7-6-9", "2", "2", "2-3-4", "2", "2"] ; energize 3 (dmg) or 5 (gold)
comboGoldenLuck := [2.5*60, "6-2-3-5-8-9", "2-3-4-5-7", "2", "2", "2-3-4", "2", "2"]

speedRunStartCombo := comboStart
deepRunCombo := comboGoldenLuck

; -----------------------------------------------------------------------------------------

if (libVersion != minLibVersion) {
	showWarningSplash("The bot lib version must be " . minLibVersion . "!")
	ExitApp
}

#Include *i ch_bot_settings.ahk

scheduleReload := false
scheduleStop := false

if (useConfigurationAssistant) {
	configurationAssistant()
}

clientCheck()
handleAutorun()

; -----------------------------------------------------------------------------------------
; -- Hotkeys (+=Shift, !=Alt, ^=Ctrl)
; -----------------------------------------------------------------------------------------

; Show the cursor position with Alt+Middle Mouse Button
!mbutton::
	mousegetpos, xpos, ypos
	msgbox,,% script,% "Cursor position: x" xpos-leftMarginOffset " y" ypos-topMarginOffset
return

; Pause/Unpause script
Pause::Pause
return

; Abort speed/deep runs and auto ascensions with Alt+Pause
!Pause::
	showSplashAlways("Aborting...")
	exitThread := true
	exitDRThread := true
return

; Quick tests:
; Ctrl+Alt+F1 should scroll down to the bottom
; Ctrl+Alt+F2 should switch to the relics tab and then back

^!F1::
	scrollToBottom()
return

^!F2::
	switchToRelicTab()
	switchToCombatTab()
return

; Alt+F1 to F4 are here to test the individual parts of the full speed run loop

!F1::
	getClickable()
return

!F2::
	initRun()
return

!F3::
	switchToCombatTab()
	speedRun()
return

!F4::
	ascend(autoAscend)
return

; Reload script with Alt+F5
!F5::
	global scheduleReload := true
	handleScheduledReload()
return

; Speed run loop.
; Use to farm Hero Souls
^F1::
	loopSpeedRun()
return

; Deep run.
; Use (after a speed run) to get a few new gilds every now and then
^F2::
	deepRun()
return

; Set previous ranger as re-gild target
^F6::
	reGildRanger := reGildRanger > rangers.MinIndex() ? reGildRanger-1 : reGildRanger
	showSplashAlways("Re-gild ranger set to " . rangers[reGildRanger])
return

; Set next ranger as re-gild target
^F7::
	reGildRanger := reGildRanger < rangers.MaxIndex() ? reGildRanger+1 : reGildRanger
	showSplashAlways("Re-gild ranger set to " . rangers[reGildRanger])
return

; Move "reGildCount" gilds to the target ranger (will pause the monster clicker if running)
^F8::
	critical
	playNotificationSound()
	msgbox, 4,% script,% "Move " . reGildCount . " gilds to " . rangers[reGildRanger] . "?"
	ifmsgbox no
		return
	regild(reGildRanger, reGildCount) ; will pause the monster clicker if running
return

; Autosave the game
^F11::
	critical
	monsterClickerPause()
	save()
return

; Toggle boolean (true/false) flags

+^F1::
	toggleFlag("autoAscend", autoAscend)
return

+^F2::
	toggleFlag("screenShotRelics", screenShotRelics)
return

+^F3::
	toggleFlag("playNotificationSounds", playNotificationSounds)
return

+^F4::
	toggleFlag("playWarningSounds", playWarningSounds)
return

+^F5::
	toggleFlag("showSplashTexts", showSplashTexts)
return

+^F11::
	toggleFlag("saveBeforeAscending", saveBeforeAscending)
return

+^F12::
	toggleFlag("debug", debug)
return

; Schedule reload script with Shift+F5
+F5::
	toggleFlag("scheduleReload", scheduleReload)
return

+Pause::
	toggleFlag("scheduleStop", scheduleStop)
return

; -----------------------------------------------------------------------------------------
; -- Functions
; -----------------------------------------------------------------------------------------

; Automatically configure initDownClicks and yLvlInit settings.
configurationAssistant() {
	global

	if (irisLevel < 145) {
		playWarningSound()
		msgbox,,% script,% "Your Iris do not fulfill the minimum level requirement of 145 or higher!"
		exit
	}

	if (irisThreshold(2010)) { ; Astraea
		initDownClicks := [6,5,6,5,6,3]
		yLvlInit := 241
	} else if (irisThreshold(1760)) { ; Alabaster
		initDownClicks := [6,6,5,6,6,3]
		yLvlInit := 259
	} else if (irisThreshold(1510)) { ; Cadmia
		initDownClicks := [6,6,6,6,6,3]
		yLvlInit := 240
	} else if (irisThreshold(1260)) { ; Lilin
		initDownClicks := [6,6,6,6,6,3]
		yLvlInit := 285
	} else if (irisThreshold(1010)) { ; Banana
		initDownClicks := [6,7,6,7,6,3]
		yLvlInit := 240
	} else if (irisThreshold(760)) { ; Phthalo
		initDownClicks := [6,7,7,6,7,3]
		yLvlInit := 273
	} else if (irisThreshold(510)) { ; Terra
		initDownClicks := [7,7,7,7,7,3]
		yLvlInit := 240
	} else if (irisThreshold(260)) { ; Atlas
		initDownClicks := [7,7,7,8,7,3]
		yLvlInit := 273
	} else { ; Dread Knight
		initDownClicks := [7,8,7,8,7,4]
		yLvlInit := 257
	}

	if (irisLevel < optimalLevel - 1001) {
		local levels := optimalLevel - 1001 - irisLevel
		playNotificationSound()
		msgbox,,% script,% "Your Iris is " . levels . " levels below the recommended ""optimal level - 1001"" rule."
	}
}

; Check if Iris is within a certain threshold that can cause a toggling behaviour between different settings
irisThreshold(lvl) {
	global
	local upperThreshold := lvl + 19
	local lowerThreshold := lvl - 20
	if (irisLevel >= lowerThreshold and irisLevel < upperThreshold) {
		playWarningSound()
		msgbox,,% script,% "Threshold proximity warning! You should level up your Iris to " . upperThreshold . " or higher."
	}
	return irisLevel > lvl
}

; Level up and upgrade all heroes
initRun() {
	global

	switchToCombatTab()
	clickPos(xHero, yHero) ; prevent fails

	upgrade(initDownClicks[1],2,,2) ; cid --> brittany
	upgrade(initDownClicks[2]) ; fisherman --> leon
	upgrade(initDownClicks[3]) ; seer --> mercedes
	upgrade(initDownClicks[4],,,,2) ; bobby --> king
	upgrade(initDownClicks[5],2,,,2) ; ice --> amenhotep
	upgrade(initDownClicks[6],,,2) ; beastlord --> shinatobe
	upgrade(0,,,,,true) ; grant & frostleaf

	scrollToBottom()
	buyAvailableUpgrades()
}

upgrade(times, cc1:=1, cc2:=1, cc3:=1, cc4:=1, skip:=false) {
	global

	if (!skip) {
		ctrlClick(xLvl, yLvlInit, cc1)
		ctrlClick(xLvl, yLvlInit + oLvl, cc2)
	}
	ctrlClick(xLvl, yLvlInit + oLvl*2, cc3)
	ctrlClick(xLvl, yLvlInit + oLvl*3, cc4)

	scrollDown(times)
}

loopSpeedRun() {
	global

	mode := hybridMode ? "hybrid" : "speed"
	showSplashAlways("Starting " . mode . " runs...")
	loop
	{
		getClickable()
		sleep % coinPickUpDelay * 1000
		initRun()
		if (activateSkillsAtStart) {
			activateSkills(speedRunStartCombo[2])
		}
		speedRun()
		if (hybridMode) {
			deepRun()
		}
		if (saveBeforeAscending) {
			save()
		}
		ascend(autoAscend)
		handleScheduledReload(true)
		handleScheduledStop()
	}
}

; All heroes/rangers are expected to "insta-kill" everything at max speed (i.e. around
; 7 minutes per 250 levels). Only the last 2-3 minutes should slow down slightly.
speedRun() {
	global

	local stint := 0
	local stints := 0
	local tMax := 7 * 60 ; seconds
	local lMax := 250 ; zones

	local lvlAdjustment := round(firstStintAdjustment * lMax / tMax)
	local zoneLvl := gildedRanger * lMax + lvlAdjustment ; approx zone lvl where we can buy our gilded ranger @ lvl 150
	local lvls := zoneLvl - irisLevel ; lvl's to get there

	local firstStintButton := 1
	local firstStintTime := 0
	local midStintTime := 0

	if (lvls > lMax + 2*60*lMax/tMax) ; add a mid stint if needed
	{
		midStintTime := tMax
		lvls -= lMax
		stints += 1
	} else if (lvls > lMax) {
		firstStintButton := 2
	}

	if (lvls > 0)
	{
		firstStintTime := ceil(lvls * tMax / lMax)
		stints += 1
	}

	local srDuration := speedRunTime * 60
	local totalClickDelay := ceil(srDuration / lvlUpDelay * zzz / 1000 + nextHeroDelay * stints)
	local lastStintTime := srDuration - firstStintTime - midStintTime - totalClickDelay
	stints += 1

	local lastStintButton := gildedRanger = 9 ? 3 : 2 ; special case for Astraea

	if (debug)
	{
		local nl := "`r`n"
		local s := "    " ; Reddit friendly formatting
		local output := ""
		output .= s . "irisLevel = " . irisLevel . nl
		output .= s . "optimalLevel = " . optimalLevel . nl
		output .= s . "speedRunTime = " . speedRunTime . nl
		output .= s . "gildedRanger = " . rangers[gildedRanger] . nl
		output .= s . "-----------------------------" . nl
		output .= s . "initDownClicks = "
		for i, e in initDownClicks {
			output .= e " "
		}
		output .= nl
		output .= s . "yLvlInit = " . yLvlInit . nl
		output .= s . "firstStintAdjustment = " . firstStintAdjustment . "s" . nl
		output .= s . "-----------------------------" . nl
		output .= s . "lvlAdjustment = " . lvlAdjustment . nl
		output .= s . "zoneLvl = " . zoneLvl . nl
		output .= s . "lvls = " . lvls . nl
		output .= s . "srDuration = " . formatSeconds(srDuration) . nl
		output .= s . "firstStintButton = " . firstStintButton . nl
		output .= s . "firstStintTime = " . formatSeconds(firstStintTime) . nl
		output .= s . "midStintTime = " . formatSeconds(midStintTime) . nl
		output .= s . "lastStintTime = " . formatSeconds(lastStintTime) . nl
		output .= s . "totalClickDelay = " . formatSeconds(totalClickDelay) . nl

		clipboard := % output
		msgbox % output
		return
	}

	showSplash("Starting speed run...")

	if (irisLevel < 2 * lMax + 10) ; Iris high enough to start with a ranger?
	{
		switchToCombatTab()
		scrollDown(initDownClicks[1])
		toggleMode() ; toggle to progression mode
		lvlUp(firstStintTime, 0, 3, ++stint, stints) ; nope, let's bridge with Samurai
		scrollToBottom()
	} else {
		scrollToBottom()
		toggleMode() ; toggle to progression mode
		if (firstStintTime > 0) {
			lvlUp(firstStintTime, 1, firstStintButton, ++stint, stints)
			scrollWayDown(3)
		}
	}
	if (midStintTime > 0) {
		lvlUp(midStintTime, 1, 2, ++stint, stints)
		scrollWayDown(2)
	}
	lvlUp(lastStintTime, 1, lastStintButton, ++stint, stints)

	showSplash("Speed run completed.")
}

deepRun() {
	global

	exitDRThread := false

	local drDuration := deepRunTime * 60
	local button := gildedRanger = 9 ? 3 : 2 ; special case for Astraea
	local y := yLvl + oLvl * (button - 1)

	showSplash("Starting deep run...")

	startMouseMonitoring()
	startProgress("Deep Run Progress", 0, drDuration // barUpdateDelay)
	monsterClickerOn()

	local comboDelay := deepRunCombo[1]
	local comboIndex := 2
	local stopHuntIndex := drDuration - stopHuntThreshold * 60
	local t := 0

	loop % drDuration
	{
		if (exitDRThread) {
			monsterClickerOff()
			stopProgress()
			stopMouseMonitoring()
			showSplashAlways("Deep run aborted!")
			exit
		}
		clickPos(xMonster, yMonster)
		if (mod(t, comboDelay) = 0) {
			activateSkills(deepRunCombo[comboIndex])
			comboIndex := comboIndex < deepRunCombo.MaxIndex() ? comboIndex+1 : 2
		}
		if (mod(t, lvlUpDelay) = 0) {
			ctrlClick(xLvl, y, 1, 0)
		}
		if (mod(t, clickableHuntDelay) = 0 and t < stopHuntIndex) {
			getClickable()
		}
		t += 1
		updateProgress(t // barUpdateDelay, drDuration - t)
		sleep 1000
	}

	monsterClickerOff()
	stopProgress()
	stopMouseMonitoring()

	showSplash("Deep run ended.")
	sleep 1000
}

monsterClickerOn() {
	send {shift down}{f1 down}{f1 up}{shift up}
}

monsterClickerPause() {
	send {shift down}{f2 down}{f2 up}{shift up}
}

monsterClickerOff() {
	send {shift down}{pause down}{pause up}{shift up}
}

lvlUp(seconds, buyUpgrades, button, stint, stints) {
	global

	exitThread := false
	local y := yLvl + oLvl * (button - 1)
	local title := "Speed Run Progress (" . stint . "/" . stints . ")"

	startMouseMonitoring()
	startProgress(title, 0, seconds // barUpdateDelay)

	if (buyUpgrades) {
		ctrlClick(xLvl, y)
		buyAvailableUpgrades()
	}
	maxClick(xLvl, y)

	local t := 0

	loop % seconds
	{
		if (exitThread) {
			stopProgress()
			stopMouseMonitoring()
			showSplashAlways("Speed run aborted!")
			exit
		}
		if (mod(t, lvlUpDelay) = 0) {
			ctrlClick(xLvl, y)
		}
		t += 1
		updateProgress(t // barUpdateDelay, seconds - t)
		sleep 1000
	}
	stopProgress()
	stopMouseMonitoring()
}

ascend(autoYes:=false) {
	global
	exitThread := false
	local extraClicks := 6
	local y := yAsc - extraClicks * buttonSize

	if (autoYes) {
		showWarningSplash(autoAscendDelay . " seconds till ASCENSION! (Abort with Alt+Pause)", autoAscendDelay)
		if (exitThread) {
			showSplashAlways("Ascension aborted!")
			exit
		}
	} else {
		playWarningSound()
		msgbox, 260,% script,Salvage Junk Pile & Ascend? ; default no
		ifmsgbox no
			exit
	}

	salvageJunkPile() ; must salvage junk relics before ascending

	switchToCombatTab()
	scrollDown(ascDownClicks)
	sleep % zzz * 2

	; Scrolling is not an exact science, hence we click above, center and below
	loop % 2 * extraClicks + 1
	{
		clickPos(xAsc, y)
		y += buttonSize
	}
	sleep % zzz * 4
	clickPos(xYes, yYes)
	sleep % zzz * 2
}

salvageJunkPile() {
	global

	switchToRelicTab()
	if (autoAscend && screenShotRelics) {
		clickPos(xRelic, yRelic) ; focus
		screenShot()
		clickPos(xRelic+100, yRelic) ; remove focus
	}
	clickPos(xSalvageJunk, ySalvageJunk)
	sleep % zzz * 4
	clickPos(xDestroyYes, yDestroyYes)
	sleep % zzz * 2
}

buyAvailableUpgrades() {
	global
	clickPos(xBuy, yBuy)
	sleep % zzz * 3
}

; Move "gildCount" gilds to given ranger
regild(ranger, gildCount) {
	global
	monsterClickerPause()
	switchToCombatTab()
	scrollToBottom()

	clickPos(xGilded, yGilded)
	sleep % zzz * 2

	ControlSend,, {shift down}, % winName
	clickPos(rangerPositions[ranger].x, rangerPositions[ranger].y, gildCount)
	sleep % 1000 * gildCount/100*5
	ControlSend,, {shift up}, % winName

	clickPos(xGildedClose, yGildedClose)
	sleep % zzz * 2
}

; Toggle between farm and progression modes
toggleMode() {
	global
	ControlSend,, {a down}{a up}, % winName
	sleep % zzz
}

activateSkills(skills) {
	global
	clickPos(xHero, yHero) ; prevent fails
	loop,parse,skills,-
	{
		ControlSend,,% A_LoopField, % winName
		sleep 100
	}
	sleep 1000
}

startMouseMonitoring() {
	setTimer, checkMousePosition, 250
}

stopMouseMonitoring() {
	setTimer, checkMousePosition, off
}

handleScheduledReload(autorun := false) {
	global
	if(scheduleReload) {
		showSplashAlways("Reloading bot...", 1)

		autorun_flag := autorun = true ? "/autorun" : ""
		Run "%A_AhkPath%" /restart "%A_ScriptFullPath%" %autorun_flag%
	}
}

handleScheduledStop() {
	global
	if(scheduleStop) {
		showSplashAlways("Stopping speedruns...", 1)
		scheduleStop := false
		exit
	}
}

handleAutorun() {
	global
	param_1 = %1%
	if(param_1 = "/autorun") {
		showSplashAlways("Autorun speedruns...")
		loopSpeedrun()
	}
}

; -----------------------------------------------------------------------------------------
; -- Subroutines
; -----------------------------------------------------------------------------------------

; Safety zone around the in-game tabs (that triggers an automatic script pause when breached)
checkMousePosition:
	MouseGetPos,,, window
	if (window = WinExist(winName)) {
		WinActivate
		MouseGetPos, x, y

		xL := getAdjustedX(xSafetyZoneL)
		xR := getAdjustedX(xSafetyZoneR)
		yT := getAdjustedY(ySafetyZoneT)
		yB := getAdjustedY(ySafetyZoneB)

		if (x > xL && x < xR && y > yT && y < yB) {
			playNotificationSound()
			msgbox,,% script,Click safety pause engaged. Continue?
		}
	}
return


+ bind for showmenu

+ bind for showmenu

; # = Win  ! = Alt  ^ = Control  + = Shift

!RButton::
   Run, c:\bb_devel\bbcli.exe -c "(ShowMenu 1)"
Return

+!h::
   Run, c:\bb_devel\bbcli.exe -c "(SwitchVertexViaEdge ""left"")"
Return
+!j::
   Run, c:\bb_devel\bbcli.exe -c "(SwitchVertexViaEdge ""down"")"
Return
+!k::
   Run, c:\bb_devel\bbcli.exe -c "(SwitchVertexViaEdge ""up"")"
Return
+!l::
   Run, c:\bb_devel\bbcli.exe -c "(SwitchVertexViaEdge ""right"")"
Return

!F1::
   Run, c:\bb_devel\bbcli.exe -c "(SetCurrentVertexId ""Desktop 1"")"
Return
!F2::
   Run, c:\bb_devel\bbcli.exe -c "(SetCurrentVertexId ""Desktop 2"")"
Return

+!Left::
   Run, c:\bb_devel\bbcli.exe -c "(MoveTopWindowToVertexViaEdge ""left"")"
Return
+!Down::
   Run, c:\bb_devel\bbcli.exe -c "(MoveTopWindowToVertexViaEdge ""down"")"
Return
+!Up::
   Run, c:\bb_devel\bbcli.exe -c "(MoveTopWindowToVertexViaEdge ""up"")"
Return
+!Right::
   Run, c:\bb_devel\bbcli.exe -c "(MoveTopWindowToVertexViaEdge ""right"")"
Return

^!h::
   Run, c:\bb_devel\bbcli.exe -c "(MaximizeTopWindow ""horizontal"")"
Return
^!j::
   Run, c:\bb_devel\bbcli.exe -c "(MaximizeTopWindow ""vertical"")"
Return
^!m::
   Run, c:\bb_devel\bbcli.exe -c "(MaximizeTopWindow ""both"")"
Return
^!i::
   Run, c:\bb_devel\bbcli.exe -c "(SetTaskManIgnored ""toggle"")"
Return

; ---------------------------------------------------------------------------------------

+!e::
   Run, Explorer.exe
Return

+!t::
   Run, c:\totalcmd\totalcmd64.exe
Return

+!d::
   Run, C:\cygwin\bin\mintty.exe -i /Cygwin-Terminal.ico /bin/bash -
Return

+!r::
	shell:=ComObjCreate("Shell.Application")
	#R::shell.FileRun()
Return

; # = Win  ! = Alt  ^ = Control  + = Shift

+!h::
   Run, c:\bb_devel\bbcli.exe -c "(SwitchVertexViaEdge ""left"")"
Return
+!j::
   Run, c:\bb_devel\bbcli.exe -c "(SwitchVertexViaEdge ""down"")"
Return
+!k::
   Run, c:\bb_devel\bbcli.exe -c "(SwitchVertexViaEdge ""up"")"
Return
+!l::
   Run, c:\bb_devel\bbcli.exe -c "(SwitchVertexViaEdge ""right"")"
Return

!F1::
   Run, c:\bb_devel\bbcli.exe -c "(SetCurrentVertexId ""Desktop 1"")"
Return
!F2::
   Run, c:\bb_devel\bbcli.exe -c "(SetCurrentVertexId ""Desktop 2"")"
Return

+!Left::
   Run, c:\bb_devel\bbcli.exe -c "(MoveTopWindowToVertexViaEdge ""left"")"
Return
+!Down::
   Run, c:\bb_devel\bbcli.exe -c "(MoveTopWindowToVertexViaEdge ""down"")"
Return
+!Up::
   Run, c:\bb_devel\bbcli.exe -c "(MoveTopWindowToVertexViaEdge ""up"")"
Return
+!Right::
   Run, c:\bb_devel\bbcli.exe -c "(MoveTopWindowToVertexViaEdge ""right"")"
Return

^!h::
   Run, c:\bb_devel\bbcli.exe -c "(MaximizeTopWindow ""horizontal"")"
Return
^!j::
   Run, c:\bb_devel\bbcli.exe -c "(MaximizeTopWindow ""vertical"")"
Return
^!m::
   Run, c:\bb_devel\bbcli.exe -c "(MaximizeTopWindow ""both"")"
Return
^!i::
   Run, c:\bb_devel\bbcli.exe -c "(SetTaskManIgnored ""toggle"")"
Return

; ---------------------------------------------------------------------------------------

+!e::
   Run, Explorer.exe
Return

+!t::
   Run, c:\totalcmd\totalcmd64.exe
Return

+!d::
   Run, C:\cygwin\bin\mintty.exe -i /Cygwin-Terminal.ico /bin/bash -
Return

+!r::
	shell:=ComObjCreate("Shell.Application")
	#R::shell.FileRun()
Return


Quote path in icon_string

Quote path in icon_string

I unpacked wsl-terminal 0.5 in C:\Program Files (x86)\WSL Terminal and got this error when I started open-wsl.exe:

> /usr/bin/mintty: could not load icon file 'C:\Program': The system cannot find the file specified.

So, I guess it's only natural to quote path to icon.

#NoTrayIcon
#NoEnv

args = %1%
IniRead, title, %A_ScriptDir%\etc\wsl-terminal.conf, config, title, "        "
IniRead, shell, %A_ScriptDir%\etc\wsl-terminal.conf, config, shell, "bash"
IniRead, use_cbwin, %A_ScriptDir%\etc\wsl-terminal.conf, config, use_cbwin, 0
IniRead, use_tmux, %A_ScriptDir%\etc\wsl-terminal.conf, config, use_tmux, 0
IniRead, attach_tmux_locally, %A_ScriptDir%\etc\wsl-terminal.conf, config, attach_tmux_locally, 0
IniRead, icon, %A_ScriptDir%\etc\wsl-terminal.conf, config, icon, ""

icon_string = -i "%A_ScriptFullPath%"
if (icon != "" && FileExist(icon))
{
    icon_string = -i "%icon%"
}

if (args = "-a" && WinExist(title))
{
    WinActivate, %title%
}
else if (!use_tmux)
{
    Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -t %shell%
}
else
{
    if (args = "-a" && !WinExist(title))
    {
        if (attach_tmux_locally)
        {
            Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -e USE_TMUX=1 -e ATTACH_ONLY=1 -t %shell%
        }
        else
        {
            Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -t %shell% -c "tmux a 2>/dev/null || tmux"
        }
    }
    else
    {
        if (WinExist(title))
        {
            Run, c:\windows\sysnative\bash -c 'tmux new-window -c "$PWD"', , Hide
            WinActivate, %title%
        }
        else
        {
            if (attach_tmux_locally)
            {
                Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -e USE_TMUX=1 -t %shell%
            }
            else
            {
                Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -t %shell% -c 'tmux new-window -c "$PWD" \; a 2>/dev/null || tmux'
            }
        }
    }
}

Loop, 5
{
    WinActivate, %title%
    if (WinActive(title))
    {
        break
    }

    Sleep, 50
}

if (use_cbwin)
{
    Process, Exist, outbash.exe

    if (ErrorLevel = 0)
    {
        Run, %A_ScriptDir%\bin\outbash --outbash-session -c 'exec sleep 10000000d', , Hide
    }
}
else if (use_tmux)
{
    ; Run a sleep to avoid tmux being killed.
    Process, Exist, sleep

    if (ErrorLevel = 0)
    {
        Run, c:\windows\sysnative\bash -c 'exec sleep 10000000d', , Hide
    }
}

#NoTrayIcon
#NoEnv

args = %1%
IniRead, title, %A_ScriptDir%\etc\wsl-terminal.conf, config, title, "        "
IniRead, shell, %A_ScriptDir%\etc\wsl-terminal.conf, config, shell, "bash"
IniRead, use_cbwin, %A_ScriptDir%\etc\wsl-terminal.conf, config, use_cbwin, 0
IniRead, use_tmux, %A_ScriptDir%\etc\wsl-terminal.conf, config, use_tmux, 0
IniRead, attach_tmux_locally, %A_ScriptDir%\etc\wsl-terminal.conf, config, attach_tmux_locally, 0
IniRead, icon, %A_ScriptDir%\etc\wsl-terminal.conf, config, icon, ""

icon_string := "-i " A_ScriptFullPath
if (icon != "" && FileExist(icon))
{
    icon_string := "-i " icon
}

if (args = "-a" && WinExist(title))
{
    WinActivate, %title%
}
else if (!use_tmux)
{
    Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -t %shell%
}
else
{
    if (args = "-a" && !WinExist(title))
    {
        if (attach_tmux_locally)
        {
            Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -e USE_TMUX=1 -e ATTACH_ONLY=1 -t %shell%
        }
        else
        {
            Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -t %shell% -c "tmux a 2>/dev/null || tmux"
        }
    }
    else
    {
        if (WinExist(title))
        {
            Run, c:\windows\sysnative\bash -c 'tmux new-window -c "$PWD"', , Hide
            WinActivate, %title%
        }
        else
        {
            if (attach_tmux_locally)
            {
                Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -e USE_TMUX=1 -t %shell%
            }
            else
            {
                Run, %A_ScriptDir%\bin\mintty %icon_string% -t "%title%" -e /bin/wslbridge -t %shell% -c 'tmux new-window -c "$PWD" \; a 2>/dev/null || tmux'
            }
        }
    }
}

Loop, 5
{
    WinActivate, %title%
    if (WinActive(title))
    {
        break
    }

    Sleep, 50
}

if (use_cbwin)
{
    Process, Exist, outbash.exe

    if (ErrorLevel = 0)
    {
        Run, %A_ScriptDir%\bin\outbash --outbash-session -c 'exec sleep 10000000d', , Hide
    }
}
else if (use_tmux)
{
    ; Run a sleep to avoid tmux being killed.
    Process, Exist, sleep

    if (ErrorLevel = 0)
    {
        Run, c:\windows\sysnative\bash -c 'exec sleep 10000000d', , Hide
    }
}


tweak some setting

tweak some setting

^Tab::
Send #{Tab}
return

^`::
IfWinActive, ahk_exe WindowsTerminal.exe
    Send !{Tab}
else
    WinActivate ahk_exe WindowsTerminal.exe
return

^!t::
IfWinActive, ahk_exe alacritty.exe
    Send !{Tab}
else
    WinActivate ahk_exe alacritty.exe
return

^!g::
IfWinActive, ahk_exe msedge.exe
    Send !{Tab}
else
    WinActivate ahk_exe msedge.exe
return

^!m::
IfWinActive, ahk_exe chrome.exe
    Send !{Tab}
else
    WinActivate ahk_exe chrome.exe
return

^!r::
IfWinActive, ahk_exe firefox.exe
    Send !{Tab}
else
    WinActivate ahk_exe firefox.exe
return

^!w::
IfWinActive, ahk_exe iridium.exe
    Send !{Tab}
else
    WinActivate ahk_exe iridium.exe
return

^!u::
IfWinActive, ahk_exe Unity.exe
    Send !{Tab}
else
    WinActivate ahk_exe Unity.exe
return

^!a::
IfWinActive, ahk_exe Code - Insiders.exe
    Send !{Tab}
else
    WinActivate ahk_exe Code - Insiders.exe
return

^!v::
IfWinActive, ahk_exe devenv.exe
    Send !{Tab}
else
    WinActivate ahk_exe devenv.exe
return

^!x::
IfWinActive, ahk_exe devenv.exe
    Send !{Tab}
else
    WinActivate ahk_exe devenv.exe
return

^!s::
IfWinActive, ahk_exe ApplicationFrameHost.exe
    Send !{Tab}
else
    WinActivate ahk_exe ApplicationFrameHost.exe
return

^!i::
IfWinActive, ahk_exe idea.exe
    Send !{Tab}
else
    WinActivate ahk_exe idea.exe
return

^!h::
IfWinActive, ahk_exe zeal.exe
    Send !{Tab}
else
    WinActivate ahk_exe zeal.exe
return

^!e::
IfWinActive, ahk_exe Evernote.exe
    Send !{Tab}
else
    WinActivate ahk_exe Evernote.exe
return

^!n::
IfWinActive, ahk_exe MindMaster.exe
    Send !{Tab}
else
    WinActivate ahk_exe MindMaster.exe
return

^!d::
IfWinActive, ahk_exe code.exe
    Send !{Tab}
else
    WinActivate ahk_exe code.exe
return

^!Space::
Process,close,explorer.exe
sleep, 50 ;This sleep 5000 is to let you see what actually happens. Decrease it later
run, explorer.exe
WinWait, ahk_class CabinetWClass
WinClose ;close the new explorer window
return

^Tab::
Send #{Tab}
return

^`::
IfWinActive, ahk_exe WindowsTerminal.exe
    Send !{Tab}
else
    WinActivate ahk_exe WindowsTerminal.exe
return

^!t::
IfWinActive, ahk_exe alacritty.exe
    Send !{Tab}
else
    WinActivate ahk_exe alacritty.exe
return

^!m::
IfWinActive, ahk_exe C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
    Send !{Tab}
else
    WinActivate ahk_exe C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
return

^!w::
IfWinActive, ahk_exe C:\Users\yjpark\AppData\Local\Google\Chrome SxS\Application\chrome.exe
    Send !{Tab}
else
    WinActivate ahk_exe C:\Users\yjpark\AppData\Local\Google\Chrome SxS\Application\chrome.exe
return

^!r::
IfWinActive, ahk_exe firefox.exe
    Send !{Tab}
else
    WinActivate ahk_exe firefox.exe
return

^!u::
IfWinActive, ahk_exe Unity.exe
    Send !{Tab}
else
    WinActivate ahk_exe Unity.exe
return

^!a::
IfWinActive, ahk_exe Code - Insiders.exe
    Send !{Tab}
else
    WinActivate ahk_exe Code - Insiders.exe
return

^!v::
IfWinActive, ahk_exe devenv.exe
    Send !{Tab}
else
    WinActivate ahk_exe devenv.exe
return

^!x::
IfWinActive, ahk_exe devenv.exe
    Send !{Tab}
else
    WinActivate ahk_exe devenv.exe
return

^!s::
IfWinActive, ahk_exe ApplicationFrameHost.exe
    Send !{Tab}
else
    WinActivate ahk_exe ApplicationFrameHost.exe
return

^!i::
IfWinActive, ahk_exe idea.exe
    Send !{Tab}
else
    WinActivate ahk_exe idea.exe
return

^!h::
IfWinActive, ahk_exe zeal.exe
    Send !{Tab}
else
    WinActivate ahk_exe zeal.exe
return

^!e::
IfWinActive, ahk_exe Evernote.exe
    Send !{Tab}
else
    WinActivate ahk_exe Evernote.exe
return

^!n::
IfWinActive, ahk_exe MindMaster.exe
    Send !{Tab}
else
    WinActivate ahk_exe MindMaster.exe
return

^!d::
IfWinActive, ahk_exe code.exe
    Send !{Tab}
else
    WinActivate ahk_exe code.exe
return

^!Space::
Process,close,explorer.exe
sleep, 50 ;This sleep 5000 is to let you see what actually happens. Decrease it later
run, explorer.exe
WinWait, ahk_class CabinetWClass
WinClose ;close the new explorer window
return


[chore] ugh. typo

[chore] ugh. typo

; Autohotkey configuration file
; AHK Version v.1.1.32.00
; Franklin Chou (franklin.chou@nelsonmullins.com)
; 14 Apr. 2020
; Tested to work on Lenovo X1 Yoga, Gen. 4

#SingleInstance Force
#Persistent

GLOBAL_DEBUG_MODE := 0
Return

CapsLock::Ctrl
LCtrl::Return
; LCtrl::CapsLock

; DEBUG TOOLS -----------------------------------------------------------------

#c::
  If(GLOBAL_DEBUG_MODE > 0) {
    ; WinGetClass, title, A
    WinGetActiveTitle, title
    MsgBox %title%
  }
Return

f12::
  If(GLOBAL_DEBUG_MODE > 0) {
    Reload
  }
Return

; SYSTEM ----------------------------------------------------------------------

; Access different windows of the same group
!`::
  WinGet, process_name, ProcessName, A ; get the active window's process name
  process_windows := GetWindowsOfProcess(process_name)

  n_process_windows := process_windows.Length()

  index := 1 ; AHK arrays are 1 indexed
  While(GetKeyState("Alt", "P")) {
    If (GetKeyState("``", "P")) {
      If (index < n_process_windows) {
        index := index + 1
      } Else {
        index := 1
      }
      active_id := process_windows[index]
      WinActivate, ahk_id %active_id%
    }
  }

  index := ""
  process_windows := ""
  n_process_windows := ""
Return

; Get the window ids of all the processes under that process name
GetWindowsOfProcess(process_name) {
  ids := Array()
  WinGet, window_ids, List ; get the IDs for all running windows
  Loop %window_ids% {
    id := window_ids%A_Index%
    WinGetTitle, title, ahk_id %id%
    WinGet, a_process_name, ProcessName, ahk_id %id%
    ; only include windows with visible title
    If (title && a_process_name = process_name) {
      ids.Push(id)
    }
  }
  Return, ids
}

; utility to get selected text (if any)
GetSelectedText() {
  temp := ClipboardAll
  Send ^c
  ClipWait, 0, 1
  selection := Clipboard
  Clipboard := temp
  Return, selection
}

; TIMEKEEPER ------------------------------------------------------------------

; Shift focus to the timekeeper app
#!e::
  timekeeper_app := WinExist("ahk_class WindowsForms10.Window.8.app.0.262fb3d")
  If(timekeeper_app > 0) {
    WinActivate, ahk_id %timekeeper_app%
  } Else {
    Run, DTE.exe, C:\Program Files (x86)\DTEAxiom
  }
Return

; Start the timer on the selected item in the daily view
#IfWinActive ahk_class WindowsForms10.Window.8.app.0.262fb3d
  >+s::
    WinGetActiveTitle, active_title
    selected := GetSelectedText()
    is_releasable := RegExMatch(selected, "Ready to be released")
    ; match monthly view; 2 application windows
    If(is_releaseable && RegExMatch(active_title, "^Entries for") > 0) {
      WinMove, 0, 0
      ; when figuring out how low to get the mouse to move aim for the area
      ; of the menu bar that says "Drag a column header here..."
      MouseMove, 100, 280
      DTEAppContextClick(4)
    ; match weekly view, 1 application window
    } Else If (is_releasable && RegExMatch(active_title, "DTE Axiom") > 0) {
      WinMove, 0, 0
      MouseMove, 100, 440
      DTEAppContextClick(4)
    } Else {
      MsgBox Select releasable entry
      Return
    }
    is_releasable := ""
    selected := ""
Return

; click the item in the DTE context menu that is `position` from the top
DTEAppContextClick(position) {
    ; each item in the dropdown is approximately 25 pixels
    drop_down := 25
    Send {RButton}
    Sleep, 10 ; sleep to allow submenu time to come up
    MouseMove, 170, 300 + drop_down * position
    Send {LButton}
}

; MSOFFICE --------------------------------------------------------------------

; Let the print screen key open the application options key (for spell check)
; Word and Outlook
#If WinActive("ahk_class OpusApp") || WinActive("ahk_class rctrl_renwnd32")
  PrintScreen::AppsKey
Return

; This ridiculous keymapping is care of Lenovo
; which maps F12 to some bloatware keyboard manager utility
#If WinActive("ahk_class OpusApp") || WinActive("ahk_class XLMAIN")
  F12::
    Send {F12}
Return

; WORD ONLY -------------------------------------------------------------------

; Cycle through types of markup
#If WinActive("ahk_class OpusApp")
  >+m::
    Send !r
    Sleep, 10
    Send td
    Send {Down}
    Send {Enter}
Return

; Bring up the tab stop modification dialogue
#If WinActive("ahk_class OpusApp")
  >+t::
    Send !h
    Send pg
    Send !t
Return

; Autohotkey configuration file
; AHK Version v.1.1.32.00
; Franklin Chou (franklin.chou@nelsonmullins.com)
; 14 Apr. 2020
; Tested to work on Lenovo X1 Yoga, Gen. 4

#SingleInstance Force
#Persistent

GLOBAL_DEBUG_MODE := 0
Return

CapsLock::Ctrl
LCtrl::Return
; LCtrl::CapsLock

; DEBUG TOOLS -----------------------------------------------------------------

#c::
  If(GLOBAL_DEBUG_MODE > 0) {
    ; WinGetClass, title, A
    WinGetActiveTitle, title
    MsgBox %title%
  }
Return

f12::
  If(GLOBAL_DEBUG_MODE > 0) {
    Reload
  }
Return

; SYSTEM ----------------------------------------------------------------------

; Access different windows of the same group
!`::
  WinGet, process_name, ProcessName, A ; get the active window's process name
  process_windows := GetWindowsOfProcess(process_name)

  n_process_windows := process_windows.Length()

  index := 1 ; AHK arrays are 1 indexed
  While(GetKeyState("Alt", "P")) {
    If (GetKeyState("``", "P")) {
      If (index < n_process_windows) {
        index := index + 1
      } Else {
        index := 1
      }
      active_id := process_windows[index]
      WinActivate, ahk_id %active_id%
    }
  }

  index := ""
  process_windows := ""
  n_process_windows := ""
Return

; Get the window ids of all the processes under that process name
GetWindowsOfProcess(process_name) {
  ids := Array()
  WinGet, window_ids, List ; get the IDs for all running windows
  Loop %window_ids% {
    id := window_ids%A_Index%
    WinGetTitle, title, ahk_id %id%
    WinGet, a_process_name, ProcessName, ahk_id %id%
    ; only include windows with visible title
    If (title && a_process_name = process_name) {
      ids.Push(id)
    }
  }
  Return, ids
}

; utility to get selected text (if any)
GetSelectedText() {
  temp := ClipboardAll
  Send ^c
  ClipWait, 0, 1
  selection := Clipboard
  Clipboard := temp
  Return, selection
}

; TIMEKEEPER ------------------------------------------------------------------

; Shift focus to the timekeeper app
#!e::
  timekeeper_app := WinExist("ahk_class WindowsForms10.Window.8.app.0.262fb3d")
  If(timekeeper_app > 0) {
    WinActivate, ahk_id %timekeeper_app%
  } Else {
    Run, DTE.exe, C:\Program Files (x86)\DTEAxiom
  }
Return

; Start the timer on the selected item in the daily view
#IfWinActive ahk_class WindowsForms10.Window.8.app.0.262fb3d
  >+s::
    WinGetActiveTitle, active_title
    selected := GetSelectedText()
    is_releasable := RegExMatch(selected, "Ready to be released")
    ; match monthly view; 2 application windows
    If(is_releaseable && RegExMatch(active_title, "^Entries for") > 0) {
      WinMove, 0, 0
      ; when figuring out how low to get the mouse to move aim for the area
      ; of the menu ar that says "Drag a column header here..."
      MouseMove, 100, 280
      DTEAppContextClick(4)
    ; match weekly view, 1 application window
    } Else If (is_releasable && RegExMatch(active_title, "DTE Axiom") > 0) {
      WinMove, 0, 0
      MouseMove, 100, 440
      DTEAppContextClick(4)
    } Else {
      MsgBox Select releasable entry
      Return
    }
    is_releasable := ""
    selected := ""
Return

; click the item in the DTE context menu that is `position` from the top
DTEAppContextClick(position) {
    ; each item in the dropdown is approximately 25 pixels
    drop_down := 25
    Send {RButton}
    Sleep, 10 ; sleep to allow submenu time to come up
    MouseMove, 170, 300 + drop_down * position
    Send {LButton}
}

; MSOFFICE --------------------------------------------------------------------

; Let the print screen key open the application options key (for spell check)
; Word and Outlook
#If WinActive("ahk_class OpusApp") || WinActive("ahk_class rctrl_renwnd32")
  PrintScreen::AppsKey
Return

; This ridiculous keymapping is care of Lenovo
; which maps F12 to some bloatware keyboard manager utility
#If WinActive("ahk_class OpusApp") || WinActive("ahk_class XLMAIN")
  F12::
    Send {F12}
Return

; WORD ONLY -------------------------------------------------------------------

; Cycle through types of markup
#If WinActive("ahk_class OpusApp")
  >+m::
    Send !r
    Sleep, 10
    Send td
    Send {Down}
    Send {Enter}
Return

; Bring up the tab stop modification dialogue
#If WinActive("ahk_class OpusApp")
  >+t::
    Send !h
    Send pg
    Send !t
Return


added xcape-style mapping for CapsLock

added xcape-style mapping for CapsLock

;Replaces the default Win+E shortcut with XYplorer
#e::
run C:\Program Files (x86)\XYplorer\XYplorer.exe
return

;Ctrl + Alt + R -- reloads current script
^!r::Reload

;Alt + Win + E -- Opens this file
!#e::
EnvGet, HOME, HOMEPATH
run "gvim" "%HOME%\.dotfiles\autohotkey-scripts\my_keyboard_shortcuts.ahk"
Return

;shortcuts for Vim

OpenWithVim() ;opens current file in vim if using XYPlorer, else opens vim
{
	EnvGet, DROPBOX, DB_HOME
	oldClipboard = %clipboard%
	IfWinActive, ahk_class ThunderRT6FormDC
	{
		SendInput ^p
		Sleep, 100
		Run, "gvim" "%clipboard%"
		clipboard = %oldClipboard%
	}
	Else
	{
		Run, "gvim" +star, C:\users\nate
	}
}

Pause::
OpenWithVim()
Return

Insert::
OpenWithVim()
Return

Capslock::send {lctrl down}
Capslock up::send % (a_priorkey = "Capslock") ? "{lctrl up}{esc}" : "{lctrl up}"

;Replaces the default Win+E shortcut with XYplorer
#e::
run C:\Program Files (x86)\XYplorer\XYplorer.exe
return

;Ctrl + Alt + R -- reloads current script
^!r::Reload

;Alt + Win + E -- Opens this file
!#e::
EnvGet, HOME, HOMEPATH
run "gvim" "%HOME%\.dotfiles\autohotkey-scripts\my_keyboard_shortcuts.ahk"
Return

;shortcuts for Vim

Capslock::Ctrl

OpenWithVim() ;opens current file in vim if using XYPlorer, else opens vim
{
	EnvGet, DROPBOX, DB_HOME
	oldClipboard = %clipboard%
	IfWinActive, ahk_class ThunderRT6FormDC
	{
		SendInput ^p
		Sleep, 100
		Run, "gvim" "%clipboard%"
		clipboard = %oldClipboard%
	}
	Else
	{
		Run, "gvim" +star, C:\users\nate
	}
}

Pause::
OpenWithVim()
Return

Insert::
OpenWithVim()
Return