Try hhkb/macOS style

Try hhkb/macOS style

FileEncoding, UTF-8 ; This file needs to be saved/encoded with "UTF-8 with BOM"

; Use Swedish characters on US-English keyboard
![:: Send, å
!+{:: Send, Å
!':: Send, ä
!+':: Send, Ä
!;:: Send, ö
!+;:: Send, Ö  ; does not work

; HHKB settings to mimic macOS behavior on Windows
; Leave righ hand side modifier keys at their defaults

LWin::LControl

LWin & Tab:: Send {LAlt down}{Tab}
LWin Up:: Send {Alt up}

LWin & Up:: Send, {PgUp}
LWin & Down:: Send, {PgDn}
LWin & Left:: Send, {Home}
LWin & Right:: Send, {End}

FileEncoding, UTF-8 ; This file needs to be saved/encoded with "UTF-8 with BOM"
![:: Send, å
!+{:: Send, Å
!':: Send, ä
!+':: Send, Ä
!;:: Send, ö
!+;:: Send, Ö  ; does not work


mod-ahk: disable left Win key

mod-ahk: disable left Win key

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

#Persistent
#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

;detect cygwin
global CygPath
CygPath = C:\Program Files (x86)\cygwin
IfNotExist %CygPath%
    CygPath = C:\Cygwin
IfNotExist %CygPath%
    CygPath = C:\Cygwin64

;detect browser
global BrowserPath
BrowserPath = C:\Program Files (x86)\Mozilla Firefox\firefox.exe
IfNotExist %BrowserPath%
    BrowserPath = "C:\Users\rr-\AppData\Local\Google\Chrome\Application\chrome.exe"

;detect im
global IMClass
global IMPath
IMClass := "Buddy List"
IMPath := "C:\Program Files (x86)\pidgin\pidgin.exe"
If !FileExist(IMPath) {
    ;wtw
    IMClass := "ahk_class {B993D471-D465-43f2-BBA5-DEEA18A1789E}"
    IMPath := "C:\Program Files\WTW\WTW.exe"
    If !FileExist(IMPath) {
        IMPath := "C:\Program Files\K2T\WTW\WTW.exe"
    }
}

;disable windows+l
RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Policies\System, DisableLockWorkstation, 1

;detect screen resolution
global MonitorWorkAreaLeft
global MonitorWorkAreaRight
global MonitorWorkAreaTop
global MonitorWorkAreaBottom
SysGet, MonitorPrimary, MonitorPrimary
SysGet, MonitorWorkArea, MonitorWorkArea, %MonitorPrimary%
;...and set terminal position basing on this
TermX := MonitorWorkAreaRight - 920
TermY := 45
RemoteTermX := 45
RemoteTermY := 45

;activate/run a program
FRun(window, path, folder)
{
    if (!window or !WinExist(window))
    {
        Run, %path%, %folder%
    }
    else
    {
        WinShow
        WinActivate
    }
    return
}

return

;replace stuff in clipboard when it changes
OnClipboardChange:
{
    if (A_EventInfo == 1) and (SubStr(clipboard, 1, 7) == "http://")
    {
        StringReplace, clipboard, clipboard, [, `%5b, All
        StringReplace, clipboard, clipboard, \, `%5c, All
        StringReplace, clipboard, clipboard, ], `%5d, All
    }
    return
}

#If FileExist(CygPath)
    ;cygwin - activate/run
    #Enter::
    {
        Run, %CygPath%\bin\mintty.exe --title "Terminal" --size "110`,35" --position "%TermX%`,%TermY%" --class "mintty_thetty" --exec /bin/zsh -l, %CygPath%
        return
    }
    +^![::
    {
        Run, %CygPath%\bin\mintty.exe --title "Terminal" --size "110`,35" --position "%TermX%`,%TermY%" --class "mintty_thetty" --exec /bin/zsh -l, %CygPath%
        return
    }
    ^![::
    {
        if (!WinExist("ahk_class mintty_thetty"))
        {
            Run, %CygPath%\bin\mintty.exe --title "Terminal" --size "110`,35" --position "%TermX%`,%TermY%" --class "mintty_thetty" --exec /bin/zsh -c 'while /bin/true`; do /bin/zsh -l`; cygstart "%A_AhkPath%" "%A_ScriptDir%\hide.ahk"`; clear; done', %CygPath%
            WinWait ahk_class mintty_thetty
        }
        else
        {
            WinShow
            WinActivate
        }
        return
    }

    ;ssh to burza - activate/run
    +^!]::
    {
        Run, %CygPath%\bin\mintty.exe --title "Remote terminal" --size "190`,65" --position "%RemoteTermX%`,%RemoteTermY%" --class mintty_ssh --exec /bin/ssh burza, %CygPath%/bin
        return
    }
    ^!]::
    {
        if (!WinExist("ahk_class mintty_ssh"))
        {
            Run, %CygPath%\bin\mintty.exe --title "Remote terminal" --size "190`,65" --position "%RemoteTermX%`,%RemoteTermY%" --class mintty_ssh --exec /bin/ssh burza, %CygPath%/bin
            WinWait ahk_class mintty_ssh
        }
        else
        {
            WinShow
            WinActivate
        }
        return
    }

    ;text editor - activate/run + fix screen position
    +^!N::
    {
        IfWinExist, ahk_class Vim
        {
            WinShow
            WinActivate
        }
        else
        {
            Run, %CygPath%\bin\mintty.exe --size "180`,60" --position "100`,100" --class "Vim" --exec /bin/zsh -l -i -c /bin/vim, %CygPath%/bin
            WinWait, ahk_class Vim
        }
        return
    }

    ;vifm - activate/run
    #E::
    {
        IfWinExist, ahk_class Vifm
        {
            WinShow
            WinActivate
        }
        else
        {
            Run, %CygPath%\bin\mintty.exe --window max --class "Vifm" --exec /bin/zsh -l -i -c vifm, %CygPath%/bin
            WinWait, ahk_class Vifm
        }
        return
    }

    ;vifm - just run
    +#E::
    {
        Run, %CygPath%\bin\mintty.exe --window max --class "Vifm" --exec /bin/zsh -l -i -c vifm, %CygPath%/bin
        return
    }

;im
#If FileExist(IMPath)
    ;im - activate/run
    +^!M::
        if (!WinExist(IMClass))
        {
            Run, %IMPath% -x
        }
        else
        {
            WinShow
            WinActivate
        }
        return

;browser
#If FileExist(BrowserPath)
    ;web browser - activate/run
    ^!;::
        if WinExist("Mozilla Firefox")
        {
            WinShow
            WinActivate
            Send, !d
        }
        else if WinExist("Vimperator")
        {
            WinShow
            WinActivate
            Send, !d
        }
        else if WinExist("ahk_class Chrome_WidgetWin_1")
        {
            WinActivate
            ControlFocus, Chrome_OmniboxView1
            SendInput, {Home}+{End}
        }
        else
        {
            IfExist %BrowserPath%
                Run, %BrowserPath%
        }
        return

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

;close active window
#Q::
    ActiveHwnd := WinExist("A")
    WinClose
    return

;fullscreen
#F::
    WinGet MX, MinMax, A
    if MX
        WinRestore A
    else
        WinMaximize A
    return

;restore active window
#S::
    ActiveHwnd := WinExist("A")
    PostMessage 0x112, 0xf120 ;WM_SYSCOMMAND, SC_RESTORE
    return

;minimize active window
#W::
    if WinActive("WTW$")
    {
        WinHide
    }
    else if WinActive("Buddy List")
    {
        WinHide
    }
    else
    {
        ActiveHwnd := WinExist("A")
        PostMessage 0x112, 0xF020 ;WM_SYSCOMMAND, SC_MINIMIZE
    }
    return

;set active window as always on top
#A::WinSet, AlwaysOnTop, Toggle, A

;transparency
AddTransparency(delta)
{
    WinGet, Transparency, Transparent, A
    if ! Transparency
        Transparency = 255
    Transparency := Transparency + delta
    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
}
#WheelUp::AddTransparency(12)
#WheelDown::AddTransparency(-12)
#Z::AddTransparency(-12)
+#Z::AddTransparency(12)

;directional focus
DirectionalFocus(direction)
{
    DetectHiddenWindows, Off
    ActiveHwnd := WinExist("A")
    WinGetPos bx, by, _, _, ahk_id %ActiveHwnd%
    WinGet windows, List
    Loop %windows%
    {
        id := windows%A_Index%
        WinGetPos wx, wy, _, _, ahk_id %id%
        if (direction == "left")
            condition := wx < bx
        else if (direction == "right")
            condition := wx > bx
        else if (direction == "up")
            condition := wy < by
        else if (direction == "down")
            condition := wy > by
        else
        {
            MsgBox % "Bad direction"
            return
        }
        if (condition)
        {
            WinGetTitle, wtitle, ahk_id %id%
            if (wtitle != "")
            {
                WinActivate, ahk_id %id%
                break
            }
        }
    }
    DetectHiddenWindows, On
    return
}
#H::DirectionalFocus("left")
#J::DirectionalFocus("down")
#K::DirectionalFocus("up")
#L::DirectionalFocus("right")
+#H::SendInput, {LWin down}{LShift down}{Left}{LShift up}{LWin up}
+#L::SendInput, {LWin down}{LShift down}{Right}{LShift up}{LWin up}

;music
#X::Send {Volume_Up}
+#X::Volume_Down
#C::Send {Media_Next}
+#C::Media_Prev
#V::Send {Media_Play_Pause}

;screenshots
+#I::Run, shot -w -i --output=Z:/
#I::Run, shot -i --output=Z:/

;reload autohotkey
!F12::Reload

;prevent pressing win key from opening start menu (can use right win key)
~LWin Up:: Return


Continuous noSleep mode

Continuous noSleep mode

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

; #Warn All
#Persistent
#NoEnv
#InstallKeybdHook

#Include %A_ScriptDir%
#Include ch_bot_lib.ahk

SetControlDelay, -1

scriptName=CH Sw1ft Bot
scriptVersion=4.x
minLibVersion=4.0

script := scriptName . " v" . scriptVersion

clickerScript := "monster_clicker.ahk"
clickerName := clickerScript . " - AutoHotkey"

scheduleReload := false
scheduleStop := false
manualProgression := false

elapsedTime := 0.0

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

#Include system\wm_messages.ahk

; Load system default settings
#Include system\ch_bot_default_settings.ahk

IfNotExist, ch_bot_settings.ahk
{
	FileCopy, system\ch_bot_default_settings.ahk, ch_bot_settings.ahk
}

; Load user settings
#Include *i ch_bot_settings.ahk

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

SysGet, VirtualScreenWidth, 78
SysGet, VirtualScreenHeight, 79

logVariable("A_AhkVersion", A_AhkVersion)
logVariable("A_OSVersion", A_OSVersion)
logVariable("A_ScreenWidth", A_ScreenWidth)
logVariable("A_ScreenHeight", A_ScreenHeight)
if (VirtualScreenWidth > A_ScreenHeight) {
	logVariable("VirtualScreenWidth", VirtualScreenWidth)
	logVariable("VirtualScreenHeight", VirtualScreenHeight)
}
logVariable("A_ScreenDPI", A_ScreenDPI )
logVariable("script", script)

clientCheck()

Run, "%A_ScriptDir%\%clickerScript%",, UseErrorLevel
if (ErrorLevel != 0) {
	playWarningSound()
	msgbox,,% script,% "Failed to auto-start " . clickerScript . " (system error code = " . A_LastError . ")!"
}

handleAutorun()

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

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

; Top margin calculation when clicking in the center of the ancient tab eye
^mbutton::
	mousegetpos, xpos, ypos
	msgbox,,% script,% "Set browserTopMargin to: " . ypos-102
return

; -- Main Hotkeys -------------------------------------------------------------------------

; Start a Vision Run loop with Ctrl+F1
^F1::
	loopVisionRun()
return

; Reload and restart Vision Run loop with Ctrl+F3
^F3::
	global scheduleReload := true
	handleScheduledReload("loopVisionRun")
return

; Pause/unpause the script
~Pause::Pause
return

; Abort any active run or initiated ascension with Alt+Pause
!Pause::
	showUserSplash("Aborting...")
	exitThread := true
return
Hotkey, !Pause, , P10

; Schedule a stop after finishing the current run with Shift+Pause
+Pause::
	toggleFlag("scheduleStop", scheduleStop)
return

; Reload the script (needed after configuration changes)
!F5::
	global scheduleReload := true
	handleScheduledReload()
return
Hotkey, !F5, , P10

; Schedule a script reload after finishing the current run, then restart it
+^F5::
	toggleFlag("scheduleReload", scheduleReload)
return

; Re-initialize coordinates (needed after moving or re-sizing the client window)
!F6::
	showUserSplash("Re-initialize coordinates... ")
	clientCheck()
	clickerInitialize()
return
Hotkey, !F6, , P10

; -- Supplementary Hotkeys ----------------------------------------------------------------

; Suspend/Unsuspend all other Hotkeys with Ctrl+Esc
~^Esc::Suspend, Toggle
return

; Autosave the game
^F11::
	save()
return
Hotkey, ^F11, , P5

; Raid once for free with Win+F6
#F6::
	raid()
return
Hotkey, #F6, , P5

; One paid raid
#F7::
	raid(1)
return
Hotkey, #F7, , P5

; Paid raids
#F8::
	raid(1, raidAttempts)
return
Hotkey, #F8, , P5

; Toggle boolean (true/false) flags with Shift+Ctrl+Fx

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

+^F6::
	toggleFlag("playNotificationSounds", playNotificationSounds)
return
Hotkey, +^F6, , P5

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

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

; -- Test Hotkeys -------------------------------------------------------------------------

; Ctrl+Alt+F1 should scroll down to the bottom, then back up
^!F1::
	scrollToBottom()
	scrollToTop()
return

; Ctrl+Alt+F2 should switch between all used tabs
^!F2::
	switchToAncientTab()
	switchToRelicTab()
	switchToClanTab()
	switchToCombatTab()
return

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

getClickable(active:=1) {
	global
	local xPos, yPos
	if (active = 1) {
		clickPos(524, 487)
		clickPos(747, 431)
		clickPos(760, 380)
		clickPos(873, 512)
		clickPos(1005, 453)
		clickPos(1053, 443)
	} else {
		loop % clickableImageFiles.Length()
		{
			imgClickable.file := clickableImageFiles[A_Index]
			if (locateImage(imgClickable, xPos, yPos)) {
				clickPos(xPos, yPos, 1, 1) ; absolute pos
				break
			}
		}
	}
}

; Level up and upgrade all heroes
initRun(initMode:=0) {
	global
	local hasAscendButton := false
	local hasSkillBar := false
	local hasNoSkillLocked := false

	showDebugSplash("Init Run @ Lvl " . getCurrentZone())

	switchToCombatTab()
	scrollToTop()
	reFocus()

	local foundDK := false
	local xButton, yButton, xDK, yDK, x
	local clickCount := initMode = 1 ? 1 : 2

	locateImage(imgCoin, xButton, yButton) ; get a x coordinate for the hire/lvl up buttons

	loop 10 ; pages
	{
		if (locateImage(imgDK, xDK, yDK) or locateImage(imgDKG, xDK, yDK)) {
			foundDK := true
		}
		loop 5 ; attempts per page
		{
			if (locateImage(imgDimmedSkill, x, yButton)
					or locateImage(imgHire, x, yButton)) {
				if (foundDK and yButton > yDK) {
					; Don't level anything below Frostleaf
					continue
				}
				ctrlClick(xButton, yButton, clickCount, 1, 1)
			} else {
				break
			}
		}
		if (foundDK) {
			if (locateImage(imgAscend)) {
				hasAscendButton := true
			}
			break
		}
		scrollDown(5)
	}
	scrollToBottom()
	buyAvailableUpgrades()

	if (initMode = 0) {
		if (locateImage(imgSkillBar)) {
			hasSkillBar := true
		}
		if (!locateImage(imgSkillLocked)) {
			hasNoSkillLocked := true
		}
		logVariable("hasAscendButton", hasAscendButton, true, "TRACE")
		logVariable("hasSkillBar", hasSkillBar, true, "TRACE")
		logVariable("hasNoSkillLocked", hasNoSkillLocked, true, "TRACE")
	}

	return hasAscendButton and hasSkillBar and hasNoSkillLocked
}

getEndZone() {
	global
	return endLvlActive > endLvlIdle ? endLvlActive : endLvlIdle
}

getState() {
	global

	if (!WinExist(winName)) {
		return -2 ; no ch window
	}
	if (getCurrentZone() = 0) {
		return -1 ; vision, but not in browser
	}
	if (!locateImage(imgSmile)) {
		return 0 ; vision, but not finding anything
	}
	if (getCurrentZone() < getEndZone() and !readyToAscend) {
		return 1 ; ready for progression
	} else {
		return 2 ; ready to ascend
	}
}

loopVisionRun() {
	global
	readyToAscend := false

	local state := 0

	showUserSplash("Starting Vision Runs!")

	logVariable("browser", browser)
	logVariable("browserTopMargin", browserTopMargin)
	logVariable("gildedRanger", rangers[gildedRanger])
	logVariable("endLvlIdle", endLvlIdle)
	logVariable("endLvlActive", endLvlActive)
	logVariable("maxMonsterKillTime", maxMonsterKillTime)
	logVariable("chronos", chronos)
	logVariable("kumawakamaru", kumawakamaru)
	logVariable("vaagur", vaagur)
	if (endLvlActive > 0) {
		logArray("skillCombo", skillCombo)
	}
	logVariable("clickableHuntDelay", clickableHuntDelay)
	logVariable("saveBeforeAscending", saveBeforeAscending, true)
	logVariable("autoAscend", autoAscend, true)
	logVariable("levelSolomon", levelSolomon, true)

	loop
	{
		state := getState()
		if (state < 1) {
			showWarningSplash("Start failed (state = " . state . ")! Trying again...")
			clientCheck()
			clickerInitialize()
			continue
		}
		if (getState() = 1) {
			visionRun()
		}
		if (getState() = 2) {
			if (saveBeforeAscending) {
				save()
			}
			ascend(autoAscend)
			readyToAscend := false
			if (levelSolomon) {
				solomonLeveler(solomonLevels)
			}
			handleScheduledStop()
			handleScheduledReload("loopVisionRun")
		}
	}
}

visionRun() {
	global
	exitThread := false
	isResuming := false

	local startRunTime := A_TickCount

	local isInitiated := false
	local isClickerRunning := false
	local isComboActive := false
	local hasActivatedSkills := false
	local hasBomberBuff := gildedRanger = 12 ? true : false
	local hasGogBuff := gildedRanger = 13 ? true : false
	local foundTheHero := false

	local xBtn := 0, yBtn := 0, isNew := 0, startAt := 0
	local xSkill := 0, ySkill := 0, skillSearch := false

	local locateGildedDelay := gildedRanger ? 60 : 4
	local locateBuyUpgradesDelay := 20
	local progressCheckDelay := 10

	local t := 0
	local elapsedRunTime := 0

	local comboDelay := skillCombo[1]
	comboIndex := 2

	manualProgression := false
	switchToCombatTab()
	setProgressionMode()
	if (!locateImage(imgProgression)) {
		showTraceSplash("Manual progression: On")
		manualProgression := true
		SetTimer, nextZoneTimer, 500
	}

	local previousZone := 0

	local secPerMonster := 0
	local farmMonsterKillTime := 2.0 ; stop and farm before boss when exceeded

	farmTime := 60
	bossFightTimer := 30 + chronos + 1
	bossFailCounter := 0

	local startZone := getCurrentZone()
	local zone := startZone
	zoneTime := {}
	local initiatedZone := 0
	local earliestAscendZone := 140
	local estimatedAscendLevel := gildedRanger ? abs(gildedRanger) * 250 - 75 : earliestAscendZone
	local initZone := 146
	local earlyGameZone := 175

	local tr1 := -1 ; Samurai
	local tr2 := ""

	if (gildedCheck(tr1, tr2, earlyGameZone)) {
		showSplash("Recommended transitional hero(es): " . rangers[tr1] . " > " . rangers[tr2])
	}

	local earlyGameMode := true
	gameMode := "INIT"

	showSplash("Starting Vision Run")

	showDebugSplash("Early game mode ends @ Lvl " . earlyGameZone)
	if (estimatedAscendLevel > earliestAscendZone) {
		showDebugSplash("Estimated ascension @ Lvl " . estimatedAscendLevel + 400 . " (idle), " . estimatedAscendLevel + 800 . " (active)")
	}

	startMonitoring()
	startTimer()
	reFocus()

	SetTimer, zoneTimer, 500

	loop
	{
		if (exitThread) {
			zoneTime := ""
			SetTimer, nextZoneTimer, off
			SetTimer, zoneTimer, off
			SetTimer, comboTimer, off
			clickerStop()
			stopTimer()
			stopMonitoring()
			showUserSplash("Vision Run aborted!")
			exit
		}

		; Gief moar rubies plox!
		if (mod(t, clickableHuntDelay) = 0) {
			getClickable(isClickerRunning)
		}

		; Active zone?
		if (isActiveZone(zone)) {
			if (!isClickerRunning) {
				; Yup, start hammering!
				clickerStart() ; ~38 CPS
				isClickerRunning := true
			}
			if (isInitiated and isClickerRunning and !isComboActive) {
				; Save combos till we have all skills
				Gosub, comboTimer
				SetTimer, comboTimer, % comboDelay * 1000 + 250
				isComboActive := true
			}
		} else if (isClickerRunning) {
			clickerStop()
			isClickerRunning := false
		}

		; Early progression
		if (zone < earlyGameZone) {
			if (manualProgression) {
				if (zone > 100) {
					showTraceSplash("Manual progression: Off")
					manualProgression := false
					SetTimer, nextZoneTimer, off
				}
			}
			if (mod(t, locateBuyUpgradesDelay) = 0 or isResuming) {
				; Scroll down when loosing track of the upgrades button
				if (!locateImage(imgBuyUpgrades)) {
					scrollToBottom()
					sleep % coinPickUpDelay * 1000
					buyAvailableUpgrades()
				}
				skillSearch := true
				isResuming := false
			}
			if (mod(t, lvlUpDelay) = 0) {
				; Level heroes bottom up
				if (locateImageUp(imgCoin, xBtn, yBtn)) {
					ctrlClick(xBtn, yBtn, 2, 1, 1)
				}
			}
			if (zone > 30 and zone > initiatedZone and mod(zone-6, 30) = 0 and zone < initZone) {
				; Lvl earlier heroes at zones 36, 66, 96 and 126
				initRun(1) ; x 100
				initiatedZone := zone
			}
		} else if (earlyGameMode) {
			showTraceSplash("Ending early game mode @ Lvl " . zone)
			earlyGameMode := false
		}

		if (!isInitiated and zone >= initZone) {
			; If enough gold, run init
			isInitiated := initRun()
			isResuming := true
		}

		; Normal progression
		if (!earlyGameMode and ((!foundTheHero and mod(t, locateGildedDelay) = 0) or isResuming)) {
			; Traverse bottom up till we find the first gilded hero/ranger we can lvl up
			if (locateGilded(xBtn, yBtn, isNew, startAt, !gildedRanger, foundTheHero)) {
				maxClick(xBtn, yBtn, 2, 1)
				if (!gildedRanger) {
					; "Power 5" mode, moving between gilded heroes
					startAt := yBtn + yWinPos - 56
				} else {
					if (isNew) {
						showDebugSplash("New gilded hero found @ Lvl " . zone)
						buyAvailableUpgrades()
					}
					skillSearch := true
				}
				isResuming := false
			} else {
				scrollToBottom()
				earlyGameZone := zone + 25
				earlyGameMode := true
				showTraceSplash("No gilded hero found yet! Early game mode extended to Lvl " . earlyGameZone)
			}
		}

		zone := getCurrentZone()

		; Ascend or keep farming?
		if (zone > 10 and zone > previousZone and mod(zone-4, 5) = 0 and gameMode = "PROGRESSING") {
			; Progressing @ zone before boss?
			previousZone := zone

			; Calculate average monster kill time for the previous zone
			secPerMonster := timeBetweenZones(zone-1, zone) / (10.0 + kumawakamaru)
			; Fast enough to kill next boss easily?
			if (secPerMonster >= farmMonsterKillTime) {
				showDebugSplash("Lvl " . zone-1 . " -> " . zone . " - Avg monster kill time: " . round(secPerMonster, 2))
				; No! Time to ascend?
				if (secPerMonster >= maxMonsterKillTime and zone > estimatedAscendLevel) {
					; Yeah, we are done here
					triggerAscension("End of run")
					break
				}
				if (gameMode = "PROGRESSING") {
					; Farm a bit before next boss
					farmTime := ceil(secPerMonster * 25)
					startFarming()
				}
			}
		}

		; Progressing?
		if (mod(t, progressCheckDelay) = 0) {
			if (!locateImage(imgProgression) and gameMode != "FARMING") {
				if (++bossFailCounter < 2) {
					showDebugSplash("Try boss one more time...")
					setProgressionMode()
				} else {
					if (zone > estimatedAscendLevel) {
						triggerAscension("Stuck at high level boss")
						break
					} else {
						startFarming()
					}
				}
			}
		}

		; Level up...
		if (!earlyGameMode and mod(t, lvlUpDelay) = 0 and !isResuming) {
			if (matchPixelColor(blueColor, xBtn+xWinPos, yBtn+yWinPos)) {
				if (!foundTheHero) {
					; Get Bomber Max and Gog global gold and dps buffs when we can
					if (!hasBomberBuff and zone > 2930) {
						getBuff(imgMax, hasBomberBuff, skillSearch)
					} else if (!hasGogBuff and zone > 3210) {
						getBuff(imgGog, hasGogBuff, skillSearch)
					}
				}
				; ... when we can afford to do so
				ctrlClick(xBtn, yBtn, 2, 1, 1)
			} else if (gildedRanger and !matchPixelColor(goldColor, xBtn-51+xWinPos, yBtn+yWinPos)) {
				if (!matchPixelColor(brightGoldColor, xBtn-51+xWinPos, yBtn+yWinPos)) {
					; ... or not, lost sight of our gilded hero
					showTraceSplash("Trigger gilded hero locator")
					clickAwayImage(imgCombatTab)
					isResuming := true
				}
			}
		}

		if (skillSearch) {
			; Aquire possible new skills
			while (locateImage(imgSkill, xSkill, ySkill)) {
				clickPos(xSkill, ySkill, 1, 1)
				sleep 500
			}
			if (!locateImage(imgDimmedSkill)) {
				skillSearch := false
			}
		}

		zone := getCurrentZone()
		t += 1
		sleep 1000

	} until zone > getEndZone() or readyToAscend

	if (earlyGameMode) {
		maxLevels() ; get some extra souls from levels
	}

	SetTimer, nextZoneTimer, off
	SetTimer, zoneTimer, off

	if (useZoneDataLogger) {
		logZoneData(zdlStart, zone, zdlInterval)
	}
	zoneTime := ""

	SetTimer, comboTimer, off
	clickerStop()
	stopTimer()
	stopMonitoring()

	elapsedRunTime := (A_TickCount - startRunTime) / 1000
	showSplash("Vision Run duration: " . formatSeconds(elapsedRunTime))
}

gildedCheck(byref tr1, byref tr2, byref earlyGameZone) {
	global
	if (gildedRanger > 0) {
		if (gildedRanger > 3) {
			if (gildedRanger > 14) {
				; Use Wepwawet as last transitional hero for gilded Betty or Midas
				tr2 := 14
			} else {
				tr2 := gildedRanger - 3
			}
			if (gildedRanger > 6) {
				tr1 := tr2 - 3
				earlyGameZone := tr1 * 250 - 75
			}
		}
		return 1
	}
	return 0
}

triggerAscension(msg, delay:=0) {
	global
	if (!readyToAscend) {
		if (delay > 0) {
			showDebugSplash("Trigger ascension in " . floor(delay) . " seconds (" . msg . ")")
			SetTimer, ascendTimer, % -delay * 1000
		} else {
			showDebugSplash("Ascension triggered! (" . msg . ")")
			readyToAscend := true
		}
	}
}

setGameMode(newGameMode) {
	global
	showTraceSplash(gameMode . " --> " . newGameMode . " @ Lvl " . getCurrentZone())
	gameMode := newGameMode
}

isActiveZone(zone) {
	global
	if (zone < 10) {
		return true
	}
	if (zone < endLvlActive) {
		if (endLvlIdle < endLvlActive and zone < endLvlIdle) {
			return false
		}
		return true
	}
	return false
}

getBuff(image, byref hasBuff, byref skillSearch) {
	global
	local who := image = imgMax ? "Bomber Max" : "Gog"
	scrollToBottom()
	if (upLocator(image, image.file, xImg, yImg)) {
		showDebugSplash("Get buff from " . who . " @ Lvl " . getCurrentZone())
		ctrlClick(xImg-320, yImg+43, 2, 1, 1) ; hire
		skillSearch := true
	}
	hasBuff := true
}

; Max levels early game for some extra souls
maxLevels() {
	global

	showDebugSplash("Max levels for souls")

	scrollToTop()
	reFocus()

	local xButton, yButton
	loop 9 ; pages
	{
		ControlSend,, {vk51 down}, ahk_id %chWinId% ; {q}, {vk51} or {sc010}
		sleep 500
		if (locateImage(imgMaxLvl, xButton, yButton)) {
			loop 4
			{
				clickPos(xButton, yButton, 1, 1)
				sleep % zzz
				yButton += oLvl
			}
		}
		scrollDown(5)
	}
	ControlSend,, {vk51 up}, ahk_id %chWinId%
}

clickerStart(duration := 0) {
	sendClickerMsg(WM_CLICKER_START)
	if (duration > 0) {
		SetTimer, clickerStopTimer, % -duration * 1000
	}
}

clickerPause() {
	sendClickerMsg(WM_CLICKER_PAUSE)
}

clickerStop() {
	sendClickerMsg(WM_CLICKER_STOP)
	sleep 1000
}

clickerReload() {
	sendClickerMsg(WM_CLICKER_RELOAD)
}

clickerInitialize() {
	sendClickerMsg(WM_CLICKER_INITIALIZE)
}

clickerModeFast() {
	sendClickerMsg(WM_CLICKER_MODE_FAST)
}

clickerModeSlow() {
	sendClickerMsg(WM_CLICKER_MODE_SLOW)
}

getClickerStatus() {
	return sendClickerMsg(WM_CLICKER_STATUS, 1)
}

sendClickerMsg(msg, wait:=0) {
	global
	local reply := 0
	local tmm := A_TitleMatchMode
	local dhw := A_DetectHiddenWindows
	SetTitleMatchMode, 2
	DetectHiddenWindows, on
	if (!wait) {
		PostMessage, %msg%,,,,% clickerName
	} else {
		SendMessage, %msg%,,,,% clickerName
		if (ErrorLevel != "FAIL") {
			reply := ErrorLevel
		} else {
			showWarningSplash("SendMessage failed! " . clickerScript . " started?")
		}
	}
	DetectHiddenWindows,% dhw
	SetTitleMatchMode,% tmm
	return reply
}

openSaveDialog() {
	global

	clickPos(xSettings, ySettings)
	sleep % zzz * 3
	clickPos(xSave, ySave)
	sleep % zzz * 4
}

save() {
	global
	local fileName := "ch" . A_NowUTC . ".txt"
	local newFileName := ""

	showDebugSplash("Save to " . fileName)

	; Close possible other dialog box
	ControlSend,, {esc}, ahk_class %dialogBoxClass%

	clickerPause()
	openSaveDialog()

	; Change the file name...
	if (saveMode = 1) {
		ControlSetText, Edit1, %fileName%, ahk_class %dialogBoxClass%
	} else {
		ControlSend, Edit1, %fileName%, ahk_class %dialogBoxClass%
	}
	sleep % zzz * 4
	; ... and double-check that it's correct
	ControlGetText, newFileName, Edit1, ahk_class %dialogBoxClass%
	if (newFileName = fileName) {
		ControlClick, %saveButtonClassNN%, ahk_class %dialogBoxClass%,,,, NA
	} else {
		ControlSend,, {esc}, ahk_class %dialogBoxClass%
	}

	sleep % zzz * 3
	clickPos(xSettingsClose, ySettingsClose)
	sleep % zzz
}

ascend(autoYes:=false) {
	global
	exitThread := false

	local x, y

	startMonitoring()

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

	salvageJunkPile() ; must salvage junk relics before ascending
	setFarmMode()

	showDebugSplash("Ascend @ Lvl " . getCurrentZone())

	clickPos(xAscend, yAscend) ; 0.23 ascend button
	sleep % zzz * 4
	clickPos(xYes, yYes)
	sleep % zzz * 2

	stopMonitoring()
	sleep 1000 ; wait a sec
}

salvageJunkPile() {
	global

	switchToRelicTab()

	if (autoAscend) {
		if (displayRelicsDuration > 0) {
			clickPos(xRelic, yRelic) ; focus (will show the upgrade screen in 0.23)
		}

		if (displayRelicsDuration > 0) {
			showWarningSplash("Salvaging junk in " . displayRelicsDuration . " seconds! (Abort with Alt+Pause)", displayRelicsDuration)
			if (exitThread) {
				exitThread := false
				showUserSplash("Salvage aborted!")
				exit
			}
		}

		if (displayRelicsDuration > 0) {
			clickPos(xUpgradeNo, yUpgradeNo) ; don't upgrade
			sleep % zzz
			clickPos(xRelic+100, yRelic) ; remove focus
		}
	}

	showDebugSplash("Salvage Junk Pile")

	clickPos(xSalvageJunk, ySalvageJunk)
	sleep % zzz * 4
	clickPos(xDestroyYes, yDestroyYes)
	sleep % zzz * 2
}

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

raid(doSpend:=0, attempts:=1) {
	global
	exitThread := false

	local xBtn := 0, yBtn := 0, raidDuration := 34 * 1000
	local wasClickerRunning := getClickerStatus()

	local mode := doSpend ? "Paid" : "Free"
	showUserSplash(mode . " Raid x " . attempts)

	Thread, NoTimers ; block timers if mid run

	switchToClanTab()
	sleep 1000
	clickAwayImage(imgClanRaid)

	if (!wasClickerRunning) {
		clickerStart()
		sleep 2500
	}
	loop % attempts
	{
		if (exitThread) {
			exitThread := false
			showUserSplash("Raid aborted!")
			break
		}
		if (clickAwayImage(imgClanCollect)) {
			break
		}
		if (doSpend) {
			showSplash(mode . " Raid (" . A_Index . "/" . attempts . ")")
			if (locateImage(imgClanFightAgain, xBtn, yBtn)) {
				while (!locateImage(imgYes)) {
					clickPos(xBtn, yBtn, 1, 1)
					sleep 250
				}
				clickAwayImage(imgYes)
				clickAwayImage(imgClanFight)
				sleep % raidDuration
			}
		} else {
			if (clickAwayImage(imgClanFight)) {
				sleep % raidDuration
			}
		}
		getClickable()
	}
	if (!wasClickerRunning) {
		clickerStop()
	}

	clickAwayImage(imgCombatTab)
	isResuming := true
}

; Toggle between farm and progression modes
toggleMode(toggle:=1) {
	global
	if (toggle) {
		; ControlSend,, {vk41}, ahk_id %chWinId% ; {a}, {vk41} or {sc01E}
		clickPos(xMode, yMode)
		sleep % zzz
	}
}

setFarmMode() {
	global
	if (!manualProgression and locateImage(imgProgression)) {
		clickAwayImage(imgProgression)
		showTraceSplash("Set Farm Mode")
	}
}

setProgressionMode() {
	global
	if (!manualProgression and locateImage(imgFarm)) {
		clickAwayImage(imgFarm)
		showTraceSplash("Set Progression Mode")
	}
}

activateSkills(skills) {
	global
	reFocus()
	loop,parse,skills,-
	{
		ControlSend,,% A_LoopField, ahk_id %chWinId%
		sleep 25
	}
}

startMonitoring() {
	global
	setTimer, checkMousePosition, 250
	setTimer, checkWindowVisibility, 20000
	if (noSleep) {
		DllCall( "SetThreadExecutionState", UInt, 0x80000003) ; ES_CONTINUOUS + ES_DISPLAY_REQUIRED + ES_SYSTEM_REQUIRED
	}
}

stopMonitoring() {
	global
	setTimer, checkMousePosition, off
	setTimer, checkWindowVisibility, off
	if (noSleep) {
		DllCall( "SetThreadExecutionState", UInt, 0x80000000) ; ES_CONTINUOUS
	}
}

handleScheduledReload(function := "") {
	global
	local params := function != "" ? "/autorun " . function : ""
	if (scheduleReload) {
		showUserSplash("Script Reload " . params, 3)
		Run "%A_AhkPath%" /restart "%A_ScriptFullPath%" %params%
	}
}

handleScheduledStop() {
	global
	if (scheduleStop) {
		showUserSplash("Scheduled stop. Exiting...")
		scheduleStop := false
		exit
	}
}

handleAutorun() {
	global
	option = %1%
	function = %2%
	if (option = "/autorun") {
		loopVisionRun()
	}
}

hasClickable() {
	global
	return locateImage(imgClickable)
}

; Try to find the first gilded hero/ranger we can lvl up
locateGilded(byref xPos, byref yPos, byref isNew, startAt:=0, silent:=0, byref foundTheHero:=0) {
	global
	isNew := 0
	local xAbs, yAbs
	local retries := 1

	if (startAt = 0 and !locateImage(imgBuyUpgrades)) {
		if (locateImage(imgCombatTab)) {
			clickAwayImage(imgCombatTab)
		}
		scrollToBottom()
	}

	if (gildedRanger = -1 and locateImage(imgBuyUpgrades)) {
		scrollUp(30) ; Locate Samurai
		foundTheHero := true
	} else if (gildedRanger = 15 and locateImage(imgBuyUpgrades) and locateImage(imgChefBuff)) {
		scrollUp(35) ; Locate Betty
		foundTheHero := true
	} else if (gildedRanger = 16 and locateImage(imgBuyUpgrades) and locateImage(imgKingsBuff)) {
		scrollUp(22) ; Locate Midas
		foundTheHero := true
	}

	while (upLocator(imgGilded, "Gilded hero", xAbs, yAbs, retries, 5, 1, startAt, silent)) {
		local xPixel := xAbs + 83 ; HI[R]E
		local yPixel := yAbs + 38
		if (matchPixelColor(dimmedYellowColor, xPixel, yPixel)) {
			startAt := yAbs
			continue
		} else if (matchPixelColor(yellowColor, xPixel, yPixel)) {
			isNew := 1
		}
		; Transform to screen relative and offset coordinates to the lvl up button
		xPos := xAbs - xWinPos + 57
		yPos := yAbs - yWinPos + 56
		return 1
	}
	return 0
}

solomonLeveler(levels) {
	global
	local x, y

	showSplash("Level Solomon x " . levels)

	switchToAncientTab()
	if (locator(imgSolomon, "Solomon", x, y)) {
		; Offset coordinates to the lvl up button
		x -= 365
		y += 28
		clickPos(x, y, levels, 1)
		sleep % zzz * 2
	}
}

checkSafetyZones() {
	global
	local window, x, y
	local i, sz
	local xL, yT, xR, yB

	MouseGetPos,,, window
	if (window = WinExist(winName)) {

		WinActivate
		MouseGetPos, x, y

		for i, sz in safetyZones
		{
			xL := getAdjustedX(sz.x1)
			yT := getAdjustedY(sz.y1)
			xR := getAdjustedX(sz.x2)
			yB := getAdjustedY(sz.y2)

			if (x > xL && y > yT && x < xR && y < yB) {
				if (sz.zone = "gilded" && !locateImage(imgGildedButton)) {
					return
				}
				Thread, NoTimers ; block timers
				playNotificationSound()
				clickerModeSlow()
				if (locateImage(imgSmile)) {
					msgbox,,% script,Click safety pause engaged. Resume?
					clickAwayImage(imgCombatTab)
					isResuming := true
					reFocus()
				} else {
					msgbox,,% script,Click safety pause engaged. Continue?
				}
				clickerModeFast()
			}
		}
	}
}

zoneMovedWithin(zone, sec) {
	loop % sec * 10 {
		sleep 100
		zoneMoved := getCurrentZone() - zone
		if (zoneMoved) {
			return zoneMoved
		}
	}
	return 0
}

nextZone() {
	global
	if (gameMode != "FARMING") {
		clickPos(xPlusOneZone, yZone)
		sleep % zzz
	}
}

timeBetweenZones(z1, z2) {
	global
	local currentTime := getTime()
	local z1time := zoneTime.HasKey(z1) ? zoneTime[z1] : currentTime
	local z2time := zoneTime.HasKey(z2) ? zoneTime[z2] : currentTime
	return abs(z1time - z2time)
}

storeZoneTime() {
	global
	local cz := getCurrentZone()
	if (cz > 0) {
		local pz := cz - 1
		local currentTime := getTime()

		if (!zoneTime.HasKey(pz)) {
			zoneTime[pz] := currentTime
		}
		if (!zoneTime.HasKey(cz)) {
			zoneTime[cz] := currentTime
			; Reached a new non-boss zone?
			if (gameMode != "PROGRESSING" and mod(cz, 5) > 0 and zoneTime.MaxIndex() > 1) {
				; Yup!
				setGameMode("PROGRESSING")
			}
			bossFailCounter := 0
		}
	}
}

logZoneData(zStart, zEnd, zInterval) {
	global
	local startZone := zStart < zoneTime.MinIndex() ? zoneTime.MinIndex() : zStart
	local endZone := zEnd > zoneTime.MaxIndex() ? zoneTime.MaxIndex() : zEnd
	local intervals := ceil((endZone - startZone) / zInterval)

	local zone := startZone
	local prevZone := zone - zInterval

	local totalTime := 0
	local intervalTime := 0

	local t := "`t" ; tab
	local nl := "`n" ; new line
	local zoneData := "Zones: " . startZone . " -> " . endZone . ", Interval: " . zInterval
	zoneData .= nl . "Zone" . t . "Time" . t . "Diff (s)"
	zoneData .= nl . zone . t . "00:00:00" . t . "0"

	loop % intervals {
		zone += zInterval
		if (zone > endZone) {
			zone := endZone
		}
		prevZone += zInterval

		totalTime := timeBetweenZones(startZone, zone)
		intervalTime := timeBetweenZones(prevZone, zone)

		zoneData .= nl . zone . t . formatSeconds(totalTime) . t . round(intervalTime, 1)
	}

	logger(zoneData, "INFO", "_zone_data")
}

startFarming() {
	global
	if (gameMode != "FARMING") {
		setGameMode("FARMING")
		setFarmMode()
		scrollToZone(zoneTime.MaxIndex())
		local farmZone := getCurrentZone()
		if (mod(farmZone, 5) = 0) {
			scrollToZone(--farmZone)
		}
		; Farm on highest recorded non-boss zone
		showDebugSplash("Farm @ Lvl " . farmZone . " for " . farmTime . "s")
		SetTimer, farmTimer, % -farmTime * 1000
	}
}

bossFight() {
	global
	if (gameMode != "FIGHTING") {
		setGameMode("FIGHTING")
		setProgressionMode()
		SetTimer, bossTimer, % -bossFightTimer * 1000
	}
}

startTimer() {
	global
	SetTimer, timeTick, 250, 4 ; prio 4
}

stopTimer() {
	global
	SetTimer, timeTick, off
}

getTime() {
	global
	return elapsedTime
}

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

timeTick:
	elapsedTime += 0.25
return

; Safety zone around the in-game tabs (that triggers an automatic script pause when breached)
checkMousePosition:
	checkSafetyZones()
return

checkWindowVisibility:
	if (!locateImage(imgSmile)) {
		WinActivate, ahk_id %chWinId%
	}
return

comboTimer:
	activateSkills(skillCombo[comboIndex])
	comboIndex := comboIndex < skillCombo.MaxIndex() ? comboIndex+1 : 2
return

clickerStopTimer:
	clickerStop()
return

farmTimer:
	if (gameMode != "PROGRESSING") {
		bossFight()
	}
return

bossTimer:
	if (!locateImage(imgProgression)) {
		; Failed the boss, back to farming...
		showDebugSplash("Failed boss!")
		startFarming()
	}
return

ascendTimer:
	readyToAscend := true
return

zoneTimer:
	storeZoneTime()
return

nextZoneTimer:
	nextZone()
return

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

; #Warn All
#Persistent
#NoEnv
#InstallKeybdHook

#Include %A_ScriptDir%
#Include ch_bot_lib.ahk

SetControlDelay, -1

scriptName=CH Sw1ft Bot
scriptVersion=4.x
minLibVersion=4.0

script := scriptName . " v" . scriptVersion

clickerScript := "monster_clicker.ahk"
clickerName := clickerScript . " - AutoHotkey"

scheduleReload := false
scheduleStop := false
manualProgression := false

elapsedTime := 0.0

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

#Include system\wm_messages.ahk

; Load system default settings
#Include system\ch_bot_default_settings.ahk

IfNotExist, ch_bot_settings.ahk
{
	FileCopy, system\ch_bot_default_settings.ahk, ch_bot_settings.ahk
}

; Load user settings
#Include *i ch_bot_settings.ahk

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

SysGet, VirtualScreenWidth, 78
SysGet, VirtualScreenHeight, 79

logVariable("A_AhkVersion", A_AhkVersion)
logVariable("A_OSVersion", A_OSVersion)
logVariable("A_ScreenWidth", A_ScreenWidth)
logVariable("A_ScreenHeight", A_ScreenHeight)
if (VirtualScreenWidth > A_ScreenHeight) {
	logVariable("VirtualScreenWidth", VirtualScreenWidth)
	logVariable("VirtualScreenHeight", VirtualScreenHeight)
}
logVariable("A_ScreenDPI", A_ScreenDPI )
logVariable("script", script)

clientCheck()

Run, "%A_ScriptDir%\%clickerScript%",, UseErrorLevel
if (ErrorLevel != 0) {
	playWarningSound()
	msgbox,,% script,% "Failed to auto-start " . clickerScript . " (system error code = " . A_LastError . ")!"
}

handleAutorun()

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

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

; Top margin calculation when clicking in the center of the ancient tab eye
^mbutton::
	mousegetpos, xpos, ypos
	msgbox,,% script,% "Set browserTopMargin to: " . ypos-102
return

; -- Main Hotkeys -------------------------------------------------------------------------

; Start a Vision Run loop with Ctrl+F1
^F1::
	loopVisionRun()
return

; Reload and restart Vision Run loop with Ctrl+F3
^F3::
	global scheduleReload := true
	handleScheduledReload("loopVisionRun")
return

; Pause/unpause the script
~Pause::Pause
return

; Abort any active run or initiated ascension with Alt+Pause
!Pause::
	showUserSplash("Aborting...")
	exitThread := true
return
Hotkey, !Pause, , P10

; Schedule a stop after finishing the current run with Shift+Pause
+Pause::
	toggleFlag("scheduleStop", scheduleStop)
return

; Reload the script (needed after configuration changes)
!F5::
	global scheduleReload := true
	handleScheduledReload()
return
Hotkey, !F5, , P10

; Schedule a script reload after finishing the current run, then restart it
+^F5::
	toggleFlag("scheduleReload", scheduleReload)
return

; Re-initialize coordinates (needed after moving or re-sizing the client window)
!F6::
	showUserSplash("Re-initialize coordinates... ")
	clientCheck()
	clickerInitialize()
return
Hotkey, !F6, , P10

; -- Supplementary Hotkeys ----------------------------------------------------------------

; Suspend/Unsuspend all other Hotkeys with Ctrl+Esc
~^Esc::Suspend, Toggle
return

; Autosave the game
^F11::
	save()
return
Hotkey, ^F11, , P5

; Raid once for free with Win+F6
#F6::
	raid()
return
Hotkey, #F6, , P5

; One paid raid
#F7::
	raid(1)
return
Hotkey, #F7, , P5

; Paid raids
#F8::
	raid(1, raidAttempts)
return
Hotkey, #F8, , P5

; Toggle boolean (true/false) flags with Shift+Ctrl+Fx

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

+^F6::
	toggleFlag("playNotificationSounds", playNotificationSounds)
return
Hotkey, +^F6, , P5

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

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

; -- Test Hotkeys -------------------------------------------------------------------------

; Ctrl+Alt+F1 should scroll down to the bottom, then back up
^!F1::
	scrollToBottom()
	scrollToTop()
return

; Ctrl+Alt+F2 should switch between all used tabs
^!F2::
	switchToAncientTab()
	switchToRelicTab()
	switchToClanTab()
	switchToCombatTab()
return

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

getClickable(active:=1) {
	global
	local xPos, yPos
	if (active = 1) {
		clickPos(524, 487)
		clickPos(747, 431)
		clickPos(760, 380)
		clickPos(873, 512)
		clickPos(1005, 453)
		clickPos(1053, 443)
	} else {
		loop % clickableImageFiles.Length()
		{
			imgClickable.file := clickableImageFiles[A_Index]
			if (locateImage(imgClickable, xPos, yPos)) {
				clickPos(xPos, yPos, 1, 1) ; absolute pos
				break
			}
		}
	}
}

; Level up and upgrade all heroes
initRun(initMode:=0) {
	global
	local hasAscendButton := false
	local hasSkillBar := false
	local hasNoSkillLocked := false

	showDebugSplash("Init Run @ Lvl " . getCurrentZone())

	switchToCombatTab()
	scrollToTop()
	reFocus()

	local foundDK := false
	local xButton, yButton, xDK, yDK, x
	local clickCount := initMode = 1 ? 1 : 2

	locateImage(imgCoin, xButton, yButton) ; get a x coordinate for the hire/lvl up buttons

	loop 10 ; pages
	{
		if (locateImage(imgDK, xDK, yDK) or locateImage(imgDKG, xDK, yDK)) {
			foundDK := true
		}
		loop 5 ; attempts per page
		{
			if (locateImage(imgDimmedSkill, x, yButton)
					or locateImage(imgHire, x, yButton)) {
				if (foundDK and yButton > yDK) {
					; Don't level anything below Frostleaf
					continue
				}
				ctrlClick(xButton, yButton, clickCount, 1, 1)
			} else {
				break
			}
		}
		if (foundDK) {
			if (locateImage(imgAscend)) {
				hasAscendButton := true
			}
			break
		}
		scrollDown(5)
	}
	scrollToBottom()
	buyAvailableUpgrades()

	if (initMode = 0) {
		if (locateImage(imgSkillBar)) {
			hasSkillBar := true
		}
		if (!locateImage(imgSkillLocked)) {
			hasNoSkillLocked := true
		}
		logVariable("hasAscendButton", hasAscendButton, true, "TRACE")
		logVariable("hasSkillBar", hasSkillBar, true, "TRACE")
		logVariable("hasNoSkillLocked", hasNoSkillLocked, true, "TRACE")
	}

	return hasAscendButton and hasSkillBar and hasNoSkillLocked
}

getEndZone() {
	global
	return endLvlActive > endLvlIdle ? endLvlActive : endLvlIdle
}

getState() {
	global

	if (!WinExist(winName)) {
		return -2 ; no ch window
	}
	if (getCurrentZone() = 0) {
		return -1 ; vision, but not in browser
	}
	if (!locateImage(imgSmile)) {
		return 0 ; vision, but not finding anything
	}
	if (getCurrentZone() < getEndZone() and !readyToAscend) {
		return 1 ; ready for progression
	} else {
		return 2 ; ready to ascend
	}
}

loopVisionRun() {
	global
	readyToAscend := false

	local state := 0

	showUserSplash("Starting Vision Runs!")

	logVariable("browser", browser)
	logVariable("browserTopMargin", browserTopMargin)
	logVariable("gildedRanger", rangers[gildedRanger])
	logVariable("endLvlIdle", endLvlIdle)
	logVariable("endLvlActive", endLvlActive)
	logVariable("maxMonsterKillTime", maxMonsterKillTime)
	logVariable("chronos", chronos)
	logVariable("kumawakamaru", kumawakamaru)
	logVariable("vaagur", vaagur)
	if (endLvlActive > 0) {
		logArray("skillCombo", skillCombo)
	}
	logVariable("clickableHuntDelay", clickableHuntDelay)
	logVariable("saveBeforeAscending", saveBeforeAscending, true)
	logVariable("autoAscend", autoAscend, true)
	logVariable("levelSolomon", levelSolomon, true)

	loop
	{
		state := getState()
		if (state < 1) {
			showWarningSplash("Start failed (state = " . state . ")! Trying again...")
			clientCheck()
			clickerInitialize()
			continue
		}
		if (getState() = 1) {
			visionRun()
		}
		if (getState() = 2) {
			if (saveBeforeAscending) {
				save()
			}
			ascend(autoAscend)
			readyToAscend := false
			if (levelSolomon) {
				solomonLeveler(solomonLevels)
			}
			handleScheduledStop()
			handleScheduledReload("loopVisionRun")
		}
	}
}

visionRun() {
	global
	exitThread := false
	isResuming := false

	local startRunTime := A_TickCount

	local isInitiated := false
	local isClickerRunning := false
	local isComboActive := false
	local hasActivatedSkills := false
	local hasBomberBuff := gildedRanger = 12 ? true : false
	local hasGogBuff := gildedRanger = 13 ? true : false
	local foundTheHero := false

	local xBtn := 0, yBtn := 0, isNew := 0, startAt := 0
	local xSkill := 0, ySkill := 0, skillSearch := false

	local locateGildedDelay := gildedRanger ? 60 : 4
	local locateBuyUpgradesDelay := 20
	local progressCheckDelay := 10

	local t := 0
	local elapsedRunTime := 0

	local comboDelay := skillCombo[1]
	comboIndex := 2

	manualProgression := false
	switchToCombatTab()
	setProgressionMode()
	if (!locateImage(imgProgression)) {
		showTraceSplash("Manual progression: On")
		manualProgression := true
		SetTimer, nextZoneTimer, 500
	}

	local previousZone := 0

	local secPerMonster := 0
	local farmMonsterKillTime := 2.0 ; stop and farm before boss when exceeded

	farmTime := 60
	bossFightTimer := 30 + chronos + 1
	bossFailCounter := 0

	local startZone := getCurrentZone()
	local zone := startZone
	zoneTime := {}
	local initiatedZone := 0
	local earliestAscendZone := 140
	local estimatedAscendLevel := gildedRanger ? abs(gildedRanger) * 250 - 75 : earliestAscendZone
	local initZone := 146
	local earlyGameZone := 175

	local tr1 := -1 ; Samurai
	local tr2 := ""

	if (gildedCheck(tr1, tr2, earlyGameZone)) {
		showSplash("Recommended transitional hero(es): " . rangers[tr1] . " > " . rangers[tr2])
	}

	local earlyGameMode := true
	gameMode := "INIT"

	showSplash("Starting Vision Run")

	showDebugSplash("Early game mode ends @ Lvl " . earlyGameZone)
	if (estimatedAscendLevel > earliestAscendZone) {
		showDebugSplash("Estimated ascension @ Lvl " . estimatedAscendLevel + 400 . " (idle), " . estimatedAscendLevel + 800 . " (active)")
	}

	startMonitoring()
	startTimer()
	reFocus()

	SetTimer, zoneTimer, 500

	loop
	{
		if (exitThread) {
			zoneTime := ""
			SetTimer, nextZoneTimer, off
			SetTimer, zoneTimer, off
			SetTimer, comboTimer, off
			clickerStop()
			stopTimer()
			stopMonitoring()
			showUserSplash("Vision Run aborted!")
			exit
		}

		; Gief moar rubies plox!
		if (mod(t, clickableHuntDelay) = 0) {
			getClickable(isClickerRunning)
		}

		; Active zone?
		if (isActiveZone(zone)) {
			if (!isClickerRunning) {
				; Yup, start hammering!
				clickerStart() ; ~38 CPS
				isClickerRunning := true
			}
			if (isInitiated and isClickerRunning and !isComboActive) {
				; Save combos till we have all skills
				Gosub, comboTimer
				SetTimer, comboTimer, % comboDelay * 1000 + 250
				isComboActive := true
			}
		} else if (isClickerRunning) {
			clickerStop()
			isClickerRunning := false
		}

		; Early progression
		if (zone < earlyGameZone) {
			if (manualProgression) {
				if (zone > 100) {
					showTraceSplash("Manual progression: Off")
					manualProgression := false
					SetTimer, nextZoneTimer, off
				}
			}
			if (mod(t, locateBuyUpgradesDelay) = 0 or isResuming) {
				; Scroll down when loosing track of the upgrades button
				if (!locateImage(imgBuyUpgrades)) {
					scrollToBottom()
					sleep % coinPickUpDelay * 1000
					buyAvailableUpgrades()
				}
				skillSearch := true
				isResuming := false
			}
			if (mod(t, lvlUpDelay) = 0) {
				; Level heroes bottom up
				if (locateImageUp(imgCoin, xBtn, yBtn)) {
					ctrlClick(xBtn, yBtn, 2, 1, 1)
				}
			}
			if (zone > 30 and zone > initiatedZone and mod(zone-6, 30) = 0 and zone < initZone) {
				; Lvl earlier heroes at zones 36, 66, 96 and 126
				initRun(1) ; x 100
				initiatedZone := zone
			}
		} else if (earlyGameMode) {
			showTraceSplash("Ending early game mode @ Lvl " . zone)
			earlyGameMode := false
		}

		if (!isInitiated and zone >= initZone) {
			; If enough gold, run init
			isInitiated := initRun()
			isResuming := true
		}

		; Normal progression
		if (!earlyGameMode and ((!foundTheHero and mod(t, locateGildedDelay) = 0) or isResuming)) {
			; Traverse bottom up till we find the first gilded hero/ranger we can lvl up
			if (locateGilded(xBtn, yBtn, isNew, startAt, !gildedRanger, foundTheHero)) {
				maxClick(xBtn, yBtn, 2, 1)
				if (!gildedRanger) {
					; "Power 5" mode, moving between gilded heroes
					startAt := yBtn + yWinPos - 56
				} else {
					if (isNew) {
						showDebugSplash("New gilded hero found @ Lvl " . zone)
						buyAvailableUpgrades()
					}
					skillSearch := true
				}
				isResuming := false
			} else {
				scrollToBottom()
				earlyGameZone := zone + 25
				earlyGameMode := true
				showTraceSplash("No gilded hero found yet! Early game mode extended to Lvl " . earlyGameZone)
			}
		}

		zone := getCurrentZone()

		; Ascend or keep farming?
		if (zone > 10 and zone > previousZone and mod(zone-4, 5) = 0 and gameMode = "PROGRESSING") {
			; Progressing @ zone before boss?
			previousZone := zone

			; Calculate average monster kill time for the previous zone
			secPerMonster := timeBetweenZones(zone-1, zone) / (10.0 + kumawakamaru)
			; Fast enough to kill next boss easily?
			if (secPerMonster >= farmMonsterKillTime) {
				showDebugSplash("Lvl " . zone-1 . " -> " . zone . " - Avg monster kill time: " . round(secPerMonster, 2))
				; No! Time to ascend?
				if (secPerMonster >= maxMonsterKillTime and zone > estimatedAscendLevel) {
					; Yeah, we are done here
					triggerAscension("End of run")
					break
				}
				if (gameMode = "PROGRESSING") {
					; Farm a bit before next boss
					farmTime := ceil(secPerMonster * 25)
					startFarming()
				}
			}
		}

		; Progressing?
		if (mod(t, progressCheckDelay) = 0) {
			if (!locateImage(imgProgression) and gameMode != "FARMING") {
				if (++bossFailCounter < 2) {
					showDebugSplash("Try boss one more time...")
					setProgressionMode()
				} else {
					if (zone > estimatedAscendLevel) {
						triggerAscension("Stuck at high level boss")
						break
					} else {
						startFarming()
					}
				}
			}
		}

		; Level up...
		if (!earlyGameMode and mod(t, lvlUpDelay) = 0 and !isResuming) {
			if (matchPixelColor(blueColor, xBtn+xWinPos, yBtn+yWinPos)) {
				if (!foundTheHero) {
					; Get Bomber Max and Gog global gold and dps buffs when we can
					if (!hasBomberBuff and zone > 2930) {
						getBuff(imgMax, hasBomberBuff, skillSearch)
					} else if (!hasGogBuff and zone > 3210) {
						getBuff(imgGog, hasGogBuff, skillSearch)
					}
				}
				; ... when we can afford to do so
				ctrlClick(xBtn, yBtn, 2, 1, 1)
			} else if (gildedRanger and !matchPixelColor(goldColor, xBtn-51+xWinPos, yBtn+yWinPos)) {
				if (!matchPixelColor(brightGoldColor, xBtn-51+xWinPos, yBtn+yWinPos)) {
					; ... or not, lost sight of our gilded hero
					showTraceSplash("Trigger gilded hero locator")
					clickAwayImage(imgCombatTab)
					isResuming := true
				}
			}
		}

		if (skillSearch) {
			; Aquire possible new skills
			while (locateImage(imgSkill, xSkill, ySkill)) {
				clickPos(xSkill, ySkill, 1, 1)
				sleep 500
			}
			if (!locateImage(imgDimmedSkill)) {
				skillSearch := false
			}
		}

		zone := getCurrentZone()
		t += 1
		sleep 1000

	} until zone > getEndZone() or readyToAscend

	if (earlyGameMode) {
		maxLevels() ; get some extra souls from levels
	}

	SetTimer, nextZoneTimer, off
	SetTimer, zoneTimer, off

	if (useZoneDataLogger) {
		logZoneData(zdlStart, zone, zdlInterval)
	}
	zoneTime := ""

	SetTimer, comboTimer, off
	clickerStop()
	stopTimer()
	stopMonitoring()

	elapsedRunTime := (A_TickCount - startRunTime) / 1000
	showSplash("Vision Run duration: " . formatSeconds(elapsedRunTime))
}

gildedCheck(byref tr1, byref tr2, byref earlyGameZone) {
	global
	if (gildedRanger > 0) {
		if (gildedRanger > 3) {
			if (gildedRanger > 14) {
				; Use Wepwawet as last transitional hero for gilded Betty or Midas
				tr2 := 14
			} else {
				tr2 := gildedRanger - 3
			}
			if (gildedRanger > 6) {
				tr1 := tr2 - 3
				earlyGameZone := tr1 * 250 - 75
			}
		}
		return 1
	}
	return 0
}

triggerAscension(msg, delay:=0) {
	global
	if (!readyToAscend) {
		if (delay > 0) {
			showDebugSplash("Trigger ascension in " . floor(delay) . " seconds (" . msg . ")")
			SetTimer, ascendTimer, % -delay * 1000
		} else {
			showDebugSplash("Ascension triggered! (" . msg . ")")
			readyToAscend := true
		}
	}
}

setGameMode(newGameMode) {
	global
	showTraceSplash(gameMode . " --> " . newGameMode . " @ Lvl " . getCurrentZone())
	gameMode := newGameMode
}

isActiveZone(zone) {
	global
	if (zone < 10) {
		return true
	}
	if (zone < endLvlActive) {
		if (endLvlIdle < endLvlActive and zone < endLvlIdle) {
			return false
		}
		return true
	}
	return false
}

getBuff(image, byref hasBuff, byref skillSearch) {
	global
	local who := image = imgMax ? "Bomber Max" : "Gog"
	scrollToBottom()
	if (upLocator(image, image.file, xImg, yImg)) {
		showDebugSplash("Get buff from " . who . " @ Lvl " . getCurrentZone())
		ctrlClick(xImg-320, yImg+43, 2, 1, 1) ; hire
		skillSearch := true
	}
	hasBuff := true
}

; Max levels early game for some extra souls
maxLevels() {
	global

	showDebugSplash("Max levels for souls")

	scrollToTop()
	reFocus()

	local xButton, yButton
	loop 9 ; pages
	{
		ControlSend,, {vk51 down}, ahk_id %chWinId% ; {q}, {vk51} or {sc010}
		sleep 500
		if (locateImage(imgMaxLvl, xButton, yButton)) {
			loop 4
			{
				clickPos(xButton, yButton, 1, 1)
				sleep % zzz
				yButton += oLvl
			}
		}
		scrollDown(5)
	}
	ControlSend,, {vk51 up}, ahk_id %chWinId%
}

clickerStart(duration := 0) {
	sendClickerMsg(WM_CLICKER_START)
	if (duration > 0) {
		SetTimer, clickerStopTimer, % -duration * 1000
	}
}

clickerPause() {
	sendClickerMsg(WM_CLICKER_PAUSE)
}

clickerStop() {
	sendClickerMsg(WM_CLICKER_STOP)
	sleep 1000
}

clickerReload() {
	sendClickerMsg(WM_CLICKER_RELOAD)
}

clickerInitialize() {
	sendClickerMsg(WM_CLICKER_INITIALIZE)
}

clickerModeFast() {
	sendClickerMsg(WM_CLICKER_MODE_FAST)
}

clickerModeSlow() {
	sendClickerMsg(WM_CLICKER_MODE_SLOW)
}

getClickerStatus() {
	return sendClickerMsg(WM_CLICKER_STATUS, 1)
}

sendClickerMsg(msg, wait:=0) {
	global
	local reply := 0
	local tmm := A_TitleMatchMode
	local dhw := A_DetectHiddenWindows
	SetTitleMatchMode, 2
	DetectHiddenWindows, on
	if (!wait) {
		PostMessage, %msg%,,,,% clickerName
	} else {
		SendMessage, %msg%,,,,% clickerName
		if (ErrorLevel != "FAIL") {
			reply := ErrorLevel
		} else {
			showWarningSplash("SendMessage failed! " . clickerScript . " started?")
		}
	}
	DetectHiddenWindows,% dhw
	SetTitleMatchMode,% tmm
	return reply
}

openSaveDialog() {
	global

	clickPos(xSettings, ySettings)
	sleep % zzz * 3
	clickPos(xSave, ySave)
	sleep % zzz * 4
}

save() {
	global
	local fileName := "ch" . A_NowUTC . ".txt"
	local newFileName := ""

	showDebugSplash("Save to " . fileName)

	; Close possible other dialog box
	ControlSend,, {esc}, ahk_class %dialogBoxClass%

	clickerPause()
	openSaveDialog()

	; Change the file name...
	if (saveMode = 1) {
		ControlSetText, Edit1, %fileName%, ahk_class %dialogBoxClass%
	} else {
		ControlSend, Edit1, %fileName%, ahk_class %dialogBoxClass%
	}
	sleep % zzz * 4
	; ... and double-check that it's correct
	ControlGetText, newFileName, Edit1, ahk_class %dialogBoxClass%
	if (newFileName = fileName) {
		ControlClick, %saveButtonClassNN%, ahk_class %dialogBoxClass%,,,, NA
	} else {
		ControlSend,, {esc}, ahk_class %dialogBoxClass%
	}

	sleep % zzz * 3
	clickPos(xSettingsClose, ySettingsClose)
	sleep % zzz
}

ascend(autoYes:=false) {
	global
	exitThread := false

	local x, y

	startMonitoring()

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

	salvageJunkPile() ; must salvage junk relics before ascending
	setFarmMode()

	showDebugSplash("Ascend @ Lvl " . getCurrentZone())

	clickPos(xAscend, yAscend) ; 0.23 ascend button
	sleep % zzz * 4
	clickPos(xYes, yYes)
	sleep % zzz * 2

	stopMonitoring()
	sleep 1000 ; wait a sec
}

salvageJunkPile() {
	global

	switchToRelicTab()

	if (autoAscend) {
		if (displayRelicsDuration > 0) {
			clickPos(xRelic, yRelic) ; focus (will show the upgrade screen in 0.23)
		}

		if (displayRelicsDuration > 0) {
			showWarningSplash("Salvaging junk in " . displayRelicsDuration . " seconds! (Abort with Alt+Pause)", displayRelicsDuration)
			if (exitThread) {
				exitThread := false
				showUserSplash("Salvage aborted!")
				exit
			}
		}

		if (displayRelicsDuration > 0) {
			clickPos(xUpgradeNo, yUpgradeNo) ; don't upgrade
			sleep % zzz
			clickPos(xRelic+100, yRelic) ; remove focus
		}
	}

	showDebugSplash("Salvage Junk Pile")

	clickPos(xSalvageJunk, ySalvageJunk)
	sleep % zzz * 4
	clickPos(xDestroyYes, yDestroyYes)
	sleep % zzz * 2
}

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

raid(doSpend:=0, attempts:=1) {
	global
	exitThread := false

	local xBtn := 0, yBtn := 0, raidDuration := 34 * 1000
	local wasClickerRunning := getClickerStatus()

	local mode := doSpend ? "Paid" : "Free"
	showUserSplash(mode . " Raid x " . attempts)

	Thread, NoTimers ; block timers if mid run

	switchToClanTab()
	sleep 1000
	clickAwayImage(imgClanRaid)

	if (!wasClickerRunning) {
		clickerStart()
		sleep 2500
	}
	loop % attempts
	{
		if (exitThread) {
			exitThread := false
			showUserSplash("Raid aborted!")
			break
		}
		if (clickAwayImage(imgClanCollect)) {
			break
		}
		if (doSpend) {
			showSplash(mode . " Raid (" . A_Index . "/" . attempts . ")")
			if (locateImage(imgClanFightAgain, xBtn, yBtn)) {
				while (!locateImage(imgYes)) {
					clickPos(xBtn, yBtn, 1, 1)
					sleep 250
				}
				clickAwayImage(imgYes)
				clickAwayImage(imgClanFight)
				sleep % raidDuration
			}
		} else {
			if (clickAwayImage(imgClanFight)) {
				sleep % raidDuration
			}
		}
		getClickable()
	}
	if (!wasClickerRunning) {
		clickerStop()
	}

	clickAwayImage(imgCombatTab)
	isResuming := true
}

; Toggle between farm and progression modes
toggleMode(toggle:=1) {
	global
	if (toggle) {
		; ControlSend,, {vk41}, ahk_id %chWinId% ; {a}, {vk41} or {sc01E}
		clickPos(xMode, yMode)
		sleep % zzz
	}
}

setFarmMode() {
	global
	if (!manualProgression and locateImage(imgProgression)) {
		clickAwayImage(imgProgression)
		showTraceSplash("Set Farm Mode")
	}
}

setProgressionMode() {
	global
	if (!manualProgression and locateImage(imgFarm)) {
		clickAwayImage(imgFarm)
		showTraceSplash("Set Progression Mode")
	}
}

activateSkills(skills) {
	global
	reFocus()
	loop,parse,skills,-
	{
		ControlSend,,% A_LoopField, ahk_id %chWinId%
		sleep 25
	}
}

startMonitoring() {
	global
	setTimer, checkMousePosition, 250
	setTimer, checkWindowVisibility, 20000
	if (noSleep) {
		setTimer, noSleepTimer, 5000
	}
}

stopMonitoring() {
	global
	setTimer, checkMousePosition, off
	setTimer, checkWindowVisibility, off
	if (noSleep) {
		setTimer, noSleepTimer, off
	}
}

handleScheduledReload(function := "") {
	global
	local params := function != "" ? "/autorun " . function : ""
	if (scheduleReload) {
		showUserSplash("Script Reload " . params, 3)
		Run "%A_AhkPath%" /restart "%A_ScriptFullPath%" %params%
	}
}

handleScheduledStop() {
	global
	if (scheduleStop) {
		showUserSplash("Scheduled stop. Exiting...")
		scheduleStop := false
		exit
	}
}

handleAutorun() {
	global
	option = %1%
	function = %2%
	if (option = "/autorun") {
		loopVisionRun()
	}
}

hasClickable() {
	global
	return locateImage(imgClickable)
}

; Try to find the first gilded hero/ranger we can lvl up
locateGilded(byref xPos, byref yPos, byref isNew, startAt:=0, silent:=0, byref foundTheHero:=0) {
	global
	isNew := 0
	local xAbs, yAbs
	local retries := 1

	if (startAt = 0 and !locateImage(imgBuyUpgrades)) {
		if (locateImage(imgCombatTab)) {
			clickAwayImage(imgCombatTab)
		}
		scrollToBottom()
	}

	if (gildedRanger = -1 and locateImage(imgBuyUpgrades)) {
		scrollUp(30) ; Locate Samurai
		foundTheHero := true
	} else if (gildedRanger = 15 and locateImage(imgBuyUpgrades) and locateImage(imgChefBuff)) {
		scrollUp(35) ; Locate Betty
		foundTheHero := true
	} else if (gildedRanger = 16 and locateImage(imgBuyUpgrades) and locateImage(imgKingsBuff)) {
		scrollUp(22) ; Locate Midas
		foundTheHero := true
	}

	while (upLocator(imgGilded, "Gilded hero", xAbs, yAbs, retries, 5, 1, startAt, silent)) {
		local xPixel := xAbs + 83 ; HI[R]E
		local yPixel := yAbs + 38
		if (matchPixelColor(dimmedYellowColor, xPixel, yPixel)) {
			startAt := yAbs
			continue
		} else if (matchPixelColor(yellowColor, xPixel, yPixel)) {
			isNew := 1
		}
		; Transform to screen relative and offset coordinates to the lvl up button
		xPos := xAbs - xWinPos + 57
		yPos := yAbs - yWinPos + 56
		return 1
	}
	return 0
}

solomonLeveler(levels) {
	global
	local x, y

	showSplash("Level Solomon x " . levels)

	switchToAncientTab()
	if (locator(imgSolomon, "Solomon", x, y)) {
		; Offset coordinates to the lvl up button
		x -= 365
		y += 28
		clickPos(x, y, levels, 1)
		sleep % zzz * 2
	}
}

checkSafetyZones() {
	global
	local window, x, y
	local i, sz
	local xL, yT, xR, yB

	MouseGetPos,,, window
	if (window = WinExist(winName)) {

		WinActivate
		MouseGetPos, x, y

		for i, sz in safetyZones
		{
			xL := getAdjustedX(sz.x1)
			yT := getAdjustedY(sz.y1)
			xR := getAdjustedX(sz.x2)
			yB := getAdjustedY(sz.y2)

			if (x > xL && y > yT && x < xR && y < yB) {
				if (sz.zone = "gilded" && !locateImage(imgGildedButton)) {
					return
				}
				Thread, NoTimers ; block timers
				playNotificationSound()
				clickerModeSlow()
				if (locateImage(imgSmile)) {
					msgbox,,% script,Click safety pause engaged. Resume?
					clickAwayImage(imgCombatTab)
					isResuming := true
					reFocus()
				} else {
					msgbox,,% script,Click safety pause engaged. Continue?
				}
				clickerModeFast()
			}
		}
	}
}

zoneMovedWithin(zone, sec) {
	loop % sec * 10 {
		sleep 100
		zoneMoved := getCurrentZone() - zone
		if (zoneMoved) {
			return zoneMoved
		}
	}
	return 0
}

nextZone() {
	global
	if (gameMode != "FARMING") {
		clickPos(xPlusOneZone, yZone)
		sleep % zzz
	}
}

timeBetweenZones(z1, z2) {
	global
	local currentTime := getTime()
	local z1time := zoneTime.HasKey(z1) ? zoneTime[z1] : currentTime
	local z2time := zoneTime.HasKey(z2) ? zoneTime[z2] : currentTime
	return abs(z1time - z2time)
}

storeZoneTime() {
	global
	local cz := getCurrentZone()
	if (cz > 0) {
		local pz := cz - 1
		local currentTime := getTime()

		if (!zoneTime.HasKey(pz)) {
			zoneTime[pz] := currentTime
		}
		if (!zoneTime.HasKey(cz)) {
			zoneTime[cz] := currentTime
			; Reached a new non-boss zone?
			if (gameMode != "PROGRESSING" and mod(cz, 5) > 0 and zoneTime.MaxIndex() > 1) {
				; Yup!
				setGameMode("PROGRESSING")
			}
			bossFailCounter := 0
		}
	}
}

logZoneData(zStart, zEnd, zInterval) {
	global
	local startZone := zStart < zoneTime.MinIndex() ? zoneTime.MinIndex() : zStart
	local endZone := zEnd > zoneTime.MaxIndex() ? zoneTime.MaxIndex() : zEnd
	local intervals := ceil((endZone - startZone) / zInterval)

	local zone := startZone
	local prevZone := zone - zInterval

	local totalTime := 0
	local intervalTime := 0

	local t := "`t" ; tab
	local nl := "`n" ; new line
	local zoneData := "Zones: " . startZone . " -> " . endZone . ", Interval: " . zInterval
	zoneData .= nl . "Zone" . t . "Time" . t . "Diff (s)"
	zoneData .= nl . zone . t . "00:00:00" . t . "0"

	loop % intervals {
		zone += zInterval
		if (zone > endZone) {
			zone := endZone
		}
		prevZone += zInterval

		totalTime := timeBetweenZones(startZone, zone)
		intervalTime := timeBetweenZones(prevZone, zone)

		zoneData .= nl . zone . t . formatSeconds(totalTime) . t . round(intervalTime, 1)
	}

	logger(zoneData, "INFO", "_zone_data")
}

startFarming() {
	global
	if (gameMode != "FARMING") {
		setGameMode("FARMING")
		setFarmMode()
		scrollToZone(zoneTime.MaxIndex())
		local farmZone := getCurrentZone()
		if (mod(farmZone, 5) = 0) {
			scrollToZone(--farmZone)
		}
		; Farm on highest recorded non-boss zone
		showDebugSplash("Farm @ Lvl " . farmZone . " for " . farmTime . "s")
		SetTimer, farmTimer, % -farmTime * 1000
	}
}

bossFight() {
	global
	if (gameMode != "FIGHTING") {
		setGameMode("FIGHTING")
		setProgressionMode()
		SetTimer, bossTimer, % -bossFightTimer * 1000
	}
}

startTimer() {
	global
	SetTimer, timeTick, 250, 4 ; prio 4
}

stopTimer() {
	global
	SetTimer, timeTick, off
}

getTime() {
	global
	return elapsedTime
}

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

timeTick:
	elapsedTime += 0.25
return

; Safety zone around the in-game tabs (that triggers an automatic script pause when breached)
checkMousePosition:
	checkSafetyZones()
return

checkWindowVisibility:
	if (!locateImage(imgSmile)) {
		WinActivate, ahk_id %chWinId%
	}
return

comboTimer:
	activateSkills(skillCombo[comboIndex])
	comboIndex := comboIndex < skillCombo.MaxIndex() ? comboIndex+1 : 2
return

clickerStopTimer:
	clickerStop()
return

farmTimer:
	if (gameMode != "PROGRESSING") {
		bossFight()
	}
return

bossTimer:
	if (!locateImage(imgProgression)) {
		; Failed the boss, back to farming...
		showDebugSplash("Failed boss!")
		startFarming()
	}
return

ascendTimer:
	readyToAscend := true
return

zoneTimer:
	storeZoneTime()
return

nextZoneTimer:
	nextZone()
return

noSleepTimer:
	DllCall( "SetThreadExecutionState", UInt, 0x80000003) ; ES_DISPLAY_REQUIRED + ES_SYSTEM_REQUIRED
return


set up google earth on work computer

set up google earth on work computer

#NoEnv
#Persistent
if FileExist("C:/Users/Chris") != ""
{
    Home = 1
    WordProcessor = C:\Program Files (x86)\LibreOffice 4\program\swriter.exe
    Spreadsheet = C:\Program Files (x86)\LibreOffice 4\program\scalc.exe
    VisualStudio = C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe
    VisualStudioProjects = Explorer C:\Users\chris\Documents\Visual Studio 2012\Projects
    GoogleEarth = C:\Program Files (x86)\Google\Google Earth\client\googleearth.exe
}
if FileExist("C:/Users/IBM_ADMIN") != ""
{
    Work = 1
    WordProcessor = C:\Program Files (x86)\OpenOffice 4\program\swriter.exe
    Spreadsheet = C:\Program Files (x86)\OpenOffice 4\program\scalc.exe
    GoogleEarth = C:\Program Files (x86)\Google\Google Earth Pro\client\googleearth.exe
}
Return

^Capslock::Capslock
Capslock::LCtrl

!#a::Run "C:\Program Files (x86)\Vim\vim74\gvim.exe" %A_MyDocuments%/AutoHotkey.ahk
^#a::Run AutoHotkey

;#a::Run
#c::Run Chrome
#g::Run %GoogleEarth%
#h::Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico -
#+h::Run %A_MyDocuments%/../Program Files/Cygwin-setup-x86_64.exe
#j::RemoteLogin1()
#+j::RemoteLogin2()
#^j::RemoteLogin3()
#n::Run Notepad
#o::StartOctave()
#q::Run Explorer %A_MyDocuments%\stuff
#s::Run acrord32
#v::Run C:\Program Files (x86)\JetBrains\PyCharm Community Edition 4.5.1\bin\pycharm.exe
#w::Run %WordProcessor%
#x::Run %Spreadsheet%
#y::Run powershell
#^y::Run cmd
#+y::Run "C:\Program Files (x86)\Vim\vim74\gvim.exe" C:\Users\Chris\Documents\WindowsPowerShell\profile.ps1
#z::Run Firefox
#]::WinMinimize A

+Space::_

; Unused Keys Win+Key combinations
;#Escape
;#k
;#`
;#,
;#i
;#.
;#;
;#/
;#[
;#'
;#]
;#\
;#Backspace
;#Enter
;#Insert
;#Delete
;#Home
;#End
;#PageDown
;#PageUp

; Don't use these key combinations
;#e opens explorer
;#d shows desktop
;#r opens run dialog
;#f opens windows search
;#t focuses task bar
;#b focuses notification area
;#u opens ease of use control panel
;#m opens start menu along with program
;#l locks workstation when regular windows key is used
;#p opens some kind of screen management menu
;win + top row numberkeys, selects programs from the task bar
;#- windows magnifier zoom out
;#= windows magnifier zoom in
;#Space
;win + arrow keys, manipulates windows

#Numpad0::PlaceActiveWindow(0, 0, 1, 1)

#Numpad1::PlacePattern1()
PlacePattern1()
{
    global LastPattern
    global Spot
    if (LastPattern != 1)
        Spot := -1
    LastPattern := 1
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 1/2)
    if (Spot == 1)
        PlaceActiveWindow(0, 1/2, 1, 1/2)
}

#Numpad2::PlacePattern2()
PlacePattern2()
{
    global LastPattern
    global Spot
    if (LastPattern != 2)
        Spot := -1
    LastPattern := 2
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1/2, 1)
    if (Spot == 1)
        PlaceActiveWindow(1/2, 0, 1/2, 1)
}

#Numpad3::PlacePattern3()
PlacePattern3()
{
    global LastPattern
    global Spot
    if (LastPattern != 3)
        Spot := -1
    LastPattern := 3
    Spot := mod(Spot + 1, 4)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1/2, 1/2)
    if (Spot == 1)
        PlaceActiveWindow(1/2, 0, 1/2, 1/2)
    if (Spot == 2)
        PlaceActiveWindow(0, 1/2, 1/2, 1/2)
    if (Spot == 3)
        PlaceActiveWindow(1/2, 1/2, 1/2, 1/2)
}

#Numpad4::PlacePattern4()
PlacePattern4()
{
    global LastPattern
    global Spot
    if (LastPattern != 4)
        Spot := -1
    LastPattern := 4
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 2/3)
    if (Spot == 1)
        PlaceActiveWindow(0, 2/3, 1, 1/3)
}

#Numpad5::PlacePattern5()
PlacePattern5()
{
    global LastPattern
    global Spot
    if (LastPattern != 5)
        Spot := -1
    LastPattern := 5
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 3/4)
    if (Spot == 1)
        PlaceActiveWindow(0, 3/4, 1, 1/4)
}

#`::ToggleWindowBorder()
#\::ToggleWindowBorder()
ToggleWindowBorder()
{
    SetWinDelay 10
    WinGet state, MinMax, A
    if (state == 1)
        PlaceActiveWindow(0, 0, 1, 1)
    WinSet Style, ^0x840000, A
    WinGetPos X, Y, Width, Height, A
    WinMove A, , X, Y, Width, Height + 1
    WinMove A, , X, Y, Width, Height
}

;#^f::ToggleFocusFollow()
;FocusFollow = 0
;ToggleFocusFollow()
;{
;    global FocusFollow
;    FocusFollow := !FocusFollow
;    SetFocusFollow(FocusFollow)
;}
;SetFocusFollow(enabled)
;{
;    SPI_SETACTIVEWINDOWTRACKING = 0x1001
;    SPIF_UPDATEINIFILE = 1
;    SPIF_SENDCHANGE = 2
;    DllCall("SystemParametersInfo",UInt,SPI_SETACTIVEWINDOWTRACKING,UInt,0,UInt,enabled,UInt,SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)
;}

RemoteLogin1()
{
    global Home, Work
    if Home
    {
        Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico /usr/bin/ssh chris@192.168.1.101
    }
    if Work
    {
        WorkLogin("t14hstbuild01")
    }
}

RemoteLogin2()
{
    global Work
    if Work
    {
        WorkLogin("t14hstbuild04")
    }
}

RemoteLogin3()
{
    global Work
    if Work
    {
        WorkLogin("peologin06")
    }
}

WorkLogin(server)
{
    SetWinDelay 10
    Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico --title mintty /usr/bin/ssh cwatrous@%server%
    WinWait mintty
    SendInput . .bashrc{Enter}
}

StartOctave()
{
    Run C:\cygwin64\bin\mintty.exe --title mintty -w max -i /Cygwin-Terminal.ico -
    WinWait mintty
    SendInput octave -q{Enter}
}

#NoEnv
#Persistent
if FileExist("C:/Users/Chris") != ""
{
    Home = 1
    WordProcessor = C:\Program Files (x86)\LibreOffice 4\program\swriter.exe
    Spreadsheet = C:\Program Files (x86)\LibreOffice 4\program\scalc.exe
    VisualStudio = C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe
    VisualStudioProjects = Explorer C:\Users\chris\Documents\Visual Studio 2012\Projects
    GoogleEarth = C:\Program Files (x86)\Google\Google Earth\client\googleearth.exe
}
if FileExist("C:/Users/IBM_ADMIN") != ""
{
    Work = 1
    WordProcessor = C:\Program Files (x86)\OpenOffice 4\program\swriter.exe
    Spreadsheet = C:\Program Files (x86)\OpenOffice 4\program\scalc.exe
}
Return

^Capslock::Capslock
Capslock::LCtrl

!#a::Run "C:\Program Files (x86)\Vim\vim74\gvim.exe" %A_MyDocuments%/AutoHotkey.ahk
^#a::Run AutoHotkey

;#a::Run
#c::Run Chrome
#g::Run %GoogleEarth%
#h::Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico -
#+h::Run %A_MyDocuments%/../Program Files/Cygwin-setup-x86_64.exe
#j::RemoteLogin1()
#+j::RemoteLogin2()
#^j::RemoteLogin3()
#n::Run Notepad
#o::StartOctave()
#q::Run Explorer %A_MyDocuments%\stuff
#s::Run acrord32
#v::Run C:\Program Files (x86)\JetBrains\PyCharm Community Edition 4.5.1\bin\pycharm.exe
#w::Run %WordProcessor%
#x::Run %Spreadsheet%
#y::Run powershell
#^y::Run cmd
#+y::Run "C:\Program Files (x86)\Vim\vim74\gvim.exe" C:\Users\Chris\Documents\WindowsPowerShell\profile.ps1
#z::Run Firefox
#]::WinMinimize A

+Space::_

; Unused Keys Win+Key combinations
;#Escape
;#k
;#`
;#,
;#i
;#.
;#;
;#/
;#[
;#'
;#]
;#\
;#Backspace
;#Enter
;#Insert
;#Delete
;#Home
;#End
;#PageDown
;#PageUp

; Don't use these key combinations
;#e opens explorer
;#d shows desktop
;#r opens run dialog
;#f opens windows search
;#t focuses task bar
;#b focuses notification area
;#u opens ease of use control panel
;#m opens start menu along with program
;#l locks workstation when regular windows key is used
;#p opens some kind of screen management menu
;win + top row numberkeys, selects programs from the task bar
;#- windows magnifier zoom out
;#= windows magnifier zoom in
;#Space
;win + arrow keys, manipulates windows

#Numpad0::PlaceActiveWindow(0, 0, 1, 1)

#Numpad1::PlacePattern1()
PlacePattern1()
{
    global LastPattern
    global Spot
    if (LastPattern != 1)
        Spot := -1
    LastPattern := 1
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 1/2)
    if (Spot == 1)
        PlaceActiveWindow(0, 1/2, 1, 1/2)
}

#Numpad2::PlacePattern2()
PlacePattern2()
{
    global LastPattern
    global Spot
    if (LastPattern != 2)
        Spot := -1
    LastPattern := 2
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1/2, 1)
    if (Spot == 1)
        PlaceActiveWindow(1/2, 0, 1/2, 1)
}

#Numpad3::PlacePattern3()
PlacePattern3()
{
    global LastPattern
    global Spot
    if (LastPattern != 3)
        Spot := -1
    LastPattern := 3
    Spot := mod(Spot + 1, 4)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1/2, 1/2)
    if (Spot == 1)
        PlaceActiveWindow(1/2, 0, 1/2, 1/2)
    if (Spot == 2)
        PlaceActiveWindow(0, 1/2, 1/2, 1/2)
    if (Spot == 3)
        PlaceActiveWindow(1/2, 1/2, 1/2, 1/2)
}

#Numpad4::PlacePattern4()
PlacePattern4()
{
    global LastPattern
    global Spot
    if (LastPattern != 4)
        Spot := -1
    LastPattern := 4
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 2/3)
    if (Spot == 1)
        PlaceActiveWindow(0, 2/3, 1, 1/3)
}

#Numpad5::PlacePattern5()
PlacePattern5()
{
    global LastPattern
    global Spot
    if (LastPattern != 5)
        Spot := -1
    LastPattern := 5
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 3/4)
    if (Spot == 1)
        PlaceActiveWindow(0, 3/4, 1, 1/4)
}

#`::ToggleWindowBorder()
#\::ToggleWindowBorder()
ToggleWindowBorder()
{
    SetWinDelay 10
    WinGet state, MinMax, A
    if (state == 1)
        PlaceActiveWindow(0, 0, 1, 1)
    WinSet Style, ^0x840000, A
    WinGetPos X, Y, Width, Height, A
    WinMove A, , X, Y, Width, Height + 1
    WinMove A, , X, Y, Width, Height
}

;#^f::ToggleFocusFollow()
;FocusFollow = 0
;ToggleFocusFollow()
;{
;    global FocusFollow
;    FocusFollow := !FocusFollow
;    SetFocusFollow(FocusFollow)
;}
;SetFocusFollow(enabled)
;{
;    SPI_SETACTIVEWINDOWTRACKING = 0x1001
;    SPIF_UPDATEINIFILE = 1
;    SPIF_SENDCHANGE = 2
;    DllCall("SystemParametersInfo",UInt,SPI_SETACTIVEWINDOWTRACKING,UInt,0,UInt,enabled,UInt,SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)
;}

RemoteLogin1()
{
    global Home, Work
    if Home
    {
        Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico /usr/bin/ssh chris@192.168.1.101
    }
    if Work
    {
        WorkLogin("t14hstbuild01")
    }
}

RemoteLogin2()
{
    global Work
    if Work
    {
        WorkLogin("t14hstbuild04")
    }
}

RemoteLogin3()
{
    global Work
    if Work
    {
        WorkLogin("peologin06")
    }
}

WorkLogin(server)
{
    SetWinDelay 10
    Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico --title mintty /usr/bin/ssh cwatrous@%server%
    WinWait mintty
    SendInput . .bashrc{Enter}
}

StartOctave()
{
    Run C:\cygwin64\bin\mintty.exe --title mintty -w max -i /Cygwin-Terminal.ico -
    WinWait mintty
    SendInput octave -q{Enter}
}


update remote logins

update remote logins

#NoEnv
#Persistent
if FileExist("C:/Users/Chris") != ""
{
    Home = 1
    WordProcessor = C:\Program Files (x86)\LibreOffice 4\program\swriter.exe
    Spreadsheet = C:\Program Files (x86)\LibreOffice 4\program\scalc.exe
    VisualStudio = C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe
    VisualStudioProjects = Explorer C:\Users\chris\Documents\Visual Studio 2012\Projects
    GoogleEarth = C:\Program Files (x86)\Google\Google Earth\client\googleearth.exe
}
if FileExist("C:/Users/IBM_ADMIN") != ""
{
    Work = 1
    WordProcessor = C:\Program Files (x86)\OpenOffice 4\program\swriter.exe
    Spreadsheet = C:\Program Files (x86)\OpenOffice 4\program\scalc.exe
    GoogleEarth = C:\Program Files (x86)\Google\Google Earth Pro\client\googleearth.exe
}
Return

^Capslock::Capslock
Capslock::LCtrl

!#a::Run "C:\Program Files (x86)\Vim\vim74\gvim.exe" %A_MyDocuments%/AutoHotkey.ahk
^#a::Run AutoHotkey

;#a::Run
#c::Run Chrome
#g::Run %GoogleEarth%
#h::Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico -
#+h::Run %A_MyDocuments%/../Program Files/Cygwin-setup-x86_64.exe
#j::RemoteLogin1()
#+j::RemoteLogin2()
#^j::RemoteLogin3()
#n::Run Notepad
#o::StartOctave()
#q::Run Explorer %A_MyDocuments%\stuff
#s::Run acrord32
#v::Run C:\Program Files (x86)\JetBrains\PyCharm Community Edition 4.5.1\bin\pycharm.exe
#w::Run %WordProcessor%
#x::Run %Spreadsheet%
#y::Run powershell
#^y::Run cmd
#+y::Run "C:\Program Files (x86)\Vim\vim74\gvim.exe" C:\Users\Chris\Documents\WindowsPowerShell\profile.ps1
#z::Run Firefox
#]::WinMinimize A

+Space::_

; Unused Keys Win+Key combinations
;#Escape
;#k
;#`
;#,
;#i
;#.
;#;
;#/
;#[
;#'
;#]
;#\
;#Backspace
;#Enter
;#Insert
;#Delete
;#Home
;#End
;#PageDown
;#PageUp

; Don't use these key combinations
;#e opens explorer
;#d shows desktop
;#r opens run dialog
;#f opens windows search
;#t focuses task bar
;#b focuses notification area
;#u opens ease of use control panel
;#m opens start menu along with program
;#l locks workstation when regular windows key is used
;#p opens some kind of screen management menu
;win + top row numberkeys, selects programs from the task bar
;#- windows magnifier zoom out
;#= windows magnifier zoom in
;#Space
;win + arrow keys, manipulates windows

#Numpad0::PlaceActiveWindow(0, 0, 1, 1)

#Numpad1::PlacePattern1()
PlacePattern1()
{
    global LastPattern
    global Spot
    if (LastPattern != 1)
        Spot := -1
    LastPattern := 1
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 1/2)
    if (Spot == 1)
        PlaceActiveWindow(0, 1/2, 1, 1/2)
}

#Numpad2::PlacePattern2()
PlacePattern2()
{
    global LastPattern
    global Spot
    if (LastPattern != 2)
        Spot := -1
    LastPattern := 2
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1/2, 1)
    if (Spot == 1)
        PlaceActiveWindow(1/2, 0, 1/2, 1)
}

#Numpad3::PlacePattern3()
PlacePattern3()
{
    global LastPattern
    global Spot
    if (LastPattern != 3)
        Spot := -1
    LastPattern := 3
    Spot := mod(Spot + 1, 4)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1/2, 1/2)
    if (Spot == 1)
        PlaceActiveWindow(1/2, 0, 1/2, 1/2)
    if (Spot == 2)
        PlaceActiveWindow(0, 1/2, 1/2, 1/2)
    if (Spot == 3)
        PlaceActiveWindow(1/2, 1/2, 1/2, 1/2)
}

#Numpad4::PlacePattern4()
PlacePattern4()
{
    global LastPattern
    global Spot
    if (LastPattern != 4)
        Spot := -1
    LastPattern := 4
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 2/3)
    if (Spot == 1)
        PlaceActiveWindow(0, 2/3, 1, 1/3)
}

#Numpad5::PlacePattern5()
PlacePattern5()
{
    global LastPattern
    global Spot
    if (LastPattern != 5)
        Spot := -1
    LastPattern := 5
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 3/4)
    if (Spot == 1)
        PlaceActiveWindow(0, 3/4, 1, 1/4)
}

#`::ToggleWindowBorder()
#\::ToggleWindowBorder()
ToggleWindowBorder()
{
    SetWinDelay 10
    WinGet state, MinMax, A
    if (state == 1)
        PlaceActiveWindow(0, 0, 1, 1)
    WinSet Style, ^0x840000, A
    WinGetPos X, Y, Width, Height, A
    WinMove A, , X, Y, Width, Height + 1
    WinMove A, , X, Y, Width, Height
}

;#^f::ToggleFocusFollow()
;FocusFollow = 0
;ToggleFocusFollow()
;{
;    global FocusFollow
;    FocusFollow := !FocusFollow
;    SetFocusFollow(FocusFollow)
;}
;SetFocusFollow(enabled)
;{
;    SPI_SETACTIVEWINDOWTRACKING = 0x1001
;    SPIF_UPDATEINIFILE = 1
;    SPIF_SENDCHANGE = 2
;    DllCall("SystemParametersInfo",UInt,SPI_SETACTIVEWINDOWTRACKING,UInt,0,UInt,enabled,UInt,SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)
;}

RemoteLogin1()
{
    global Home, Work
    if Home
    {
        ;Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico /usr/bin/ssh chris@192.168.1.101
        Run C:\cygwin64\bin\mintty.exe -w max /usr/bin/ssh chris@192.168.1.101
    }
    if Work
    {
        ;WorkLogin("t14hstbuild01")
        ;Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico /usr/bin/ssh chris@192.168.56.101
        Run C:\cygwin64\bin\mintty.exe -w max /usr/bin/ssh chris@192.168.56.101
    }
}

RemoteLogin2()
{
    global Work
    if Home
    {
        Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico /usr/bin/ssh chris@192.168.56.101
    }
    if Work
    {
        WorkLogin("t14hstbuild04")
    }
}

RemoteLogin3()
{
    global Work
    if Work
    {
        WorkLogin("peologin06")
    }
}

WorkLogin(server)
{
    SetWinDelay 10
    Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico --title mintty /usr/bin/ssh cwatrous@%server%
    WinWait mintty
    SendInput . .bashrc{Enter}
}

StartOctave()
{
    Run C:\cygwin64\bin\mintty.exe --title mintty -w max -i /Cygwin-Terminal.ico -
    WinWait mintty
    SendInput octave -q{Enter}
}

#NoEnv
#Persistent
if FileExist("C:/Users/Chris") != ""
{
    Home = 1
    WordProcessor = C:\Program Files (x86)\LibreOffice 4\program\swriter.exe
    Spreadsheet = C:\Program Files (x86)\LibreOffice 4\program\scalc.exe
    VisualStudio = C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe
    VisualStudioProjects = Explorer C:\Users\chris\Documents\Visual Studio 2012\Projects
    GoogleEarth = C:\Program Files (x86)\Google\Google Earth\client\googleearth.exe
}
if FileExist("C:/Users/IBM_ADMIN") != ""
{
    Work = 1
    WordProcessor = C:\Program Files (x86)\OpenOffice 4\program\swriter.exe
    Spreadsheet = C:\Program Files (x86)\OpenOffice 4\program\scalc.exe
    GoogleEarth = C:\Program Files (x86)\Google\Google Earth Pro\client\googleearth.exe
}
Return

^Capslock::Capslock
Capslock::LCtrl

!#a::Run "C:\Program Files (x86)\Vim\vim74\gvim.exe" %A_MyDocuments%/AutoHotkey.ahk
^#a::Run AutoHotkey

;#a::Run
#c::Run Chrome
#g::Run %GoogleEarth%
#h::Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico -
#+h::Run %A_MyDocuments%/../Program Files/Cygwin-setup-x86_64.exe
#j::RemoteLogin1()
#+j::RemoteLogin2()
#^j::RemoteLogin3()
#n::Run Notepad
#o::StartOctave()
#q::Run Explorer %A_MyDocuments%\stuff
#s::Run acrord32
#v::Run C:\Program Files (x86)\JetBrains\PyCharm Community Edition 4.5.1\bin\pycharm.exe
#w::Run %WordProcessor%
#x::Run %Spreadsheet%
#y::Run powershell
#^y::Run cmd
#+y::Run "C:\Program Files (x86)\Vim\vim74\gvim.exe" C:\Users\Chris\Documents\WindowsPowerShell\profile.ps1
#z::Run Firefox
#]::WinMinimize A

+Space::_

; Unused Keys Win+Key combinations
;#Escape
;#k
;#`
;#,
;#i
;#.
;#;
;#/
;#[
;#'
;#]
;#\
;#Backspace
;#Enter
;#Insert
;#Delete
;#Home
;#End
;#PageDown
;#PageUp

; Don't use these key combinations
;#e opens explorer
;#d shows desktop
;#r opens run dialog
;#f opens windows search
;#t focuses task bar
;#b focuses notification area
;#u opens ease of use control panel
;#m opens start menu along with program
;#l locks workstation when regular windows key is used
;#p opens some kind of screen management menu
;win + top row numberkeys, selects programs from the task bar
;#- windows magnifier zoom out
;#= windows magnifier zoom in
;#Space
;win + arrow keys, manipulates windows

#Numpad0::PlaceActiveWindow(0, 0, 1, 1)

#Numpad1::PlacePattern1()
PlacePattern1()
{
    global LastPattern
    global Spot
    if (LastPattern != 1)
        Spot := -1
    LastPattern := 1
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 1/2)
    if (Spot == 1)
        PlaceActiveWindow(0, 1/2, 1, 1/2)
}

#Numpad2::PlacePattern2()
PlacePattern2()
{
    global LastPattern
    global Spot
    if (LastPattern != 2)
        Spot := -1
    LastPattern := 2
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1/2, 1)
    if (Spot == 1)
        PlaceActiveWindow(1/2, 0, 1/2, 1)
}

#Numpad3::PlacePattern3()
PlacePattern3()
{
    global LastPattern
    global Spot
    if (LastPattern != 3)
        Spot := -1
    LastPattern := 3
    Spot := mod(Spot + 1, 4)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1/2, 1/2)
    if (Spot == 1)
        PlaceActiveWindow(1/2, 0, 1/2, 1/2)
    if (Spot == 2)
        PlaceActiveWindow(0, 1/2, 1/2, 1/2)
    if (Spot == 3)
        PlaceActiveWindow(1/2, 1/2, 1/2, 1/2)
}

#Numpad4::PlacePattern4()
PlacePattern4()
{
    global LastPattern
    global Spot
    if (LastPattern != 4)
        Spot := -1
    LastPattern := 4
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 2/3)
    if (Spot == 1)
        PlaceActiveWindow(0, 2/3, 1, 1/3)
}

#Numpad5::PlacePattern5()
PlacePattern5()
{
    global LastPattern
    global Spot
    if (LastPattern != 5)
        Spot := -1
    LastPattern := 5
    Spot := mod(Spot + 1, 2)
    if (Spot == 0)
        PlaceActiveWindow(0, 0, 1, 3/4)
    if (Spot == 1)
        PlaceActiveWindow(0, 3/4, 1, 1/4)
}

#`::ToggleWindowBorder()
#\::ToggleWindowBorder()
ToggleWindowBorder()
{
    SetWinDelay 10
    WinGet state, MinMax, A
    if (state == 1)
        PlaceActiveWindow(0, 0, 1, 1)
    WinSet Style, ^0x840000, A
    WinGetPos X, Y, Width, Height, A
    WinMove A, , X, Y, Width, Height + 1
    WinMove A, , X, Y, Width, Height
}

;#^f::ToggleFocusFollow()
;FocusFollow = 0
;ToggleFocusFollow()
;{
;    global FocusFollow
;    FocusFollow := !FocusFollow
;    SetFocusFollow(FocusFollow)
;}
;SetFocusFollow(enabled)
;{
;    SPI_SETACTIVEWINDOWTRACKING = 0x1001
;    SPIF_UPDATEINIFILE = 1
;    SPIF_SENDCHANGE = 2
;    DllCall("SystemParametersInfo",UInt,SPI_SETACTIVEWINDOWTRACKING,UInt,0,UInt,enabled,UInt,SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)
;}

RemoteLogin1()
{
    global Home, Work
    if Home
    {
        Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico /usr/bin/ssh chris@192.168.1.101
    }
    if Work
    {
        ;WorkLogin("t14hstbuild01")
        Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico /usr/bin/ssh chris@192.168.56.101
    }
}

RemoteLogin2()
{
    global Work
    if Home
    {
        Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico /usr/bin/ssh chris@192.168.56.101
    }
    if Work
    {
        WorkLogin("t14hstbuild04")
    }
}

RemoteLogin3()
{
    global Work
    if Work
    {
        WorkLogin("peologin06")
    }
}

WorkLogin(server)
{
    SetWinDelay 10
    Run C:\cygwin64\bin\mintty.exe -w max -i /Cygwin-Terminal.ico --title mintty /usr/bin/ssh cwatrous@%server%
    WinWait mintty
    SendInput . .bashrc{Enter}
}

StartOctave()
{
    Run C:\cygwin64\bin\mintty.exe --title mintty -w max -i /Cygwin-Terminal.ico -
    WinWait mintty
    SendInput octave -q{Enter}
}