155 lines
4.0 KiB
AutoHotkey
155 lines
4.0 KiB
AutoHotkey
#Requires AutoHotkey v2.0
|
|
#SingleInstance Force
|
|
SetTitleMatchMode 2
|
|
CoordMode "Mouse", "Client"
|
|
|
|
; === CONFIGURATION ===
|
|
global targetWindow := "DirtyLeague"
|
|
global isRunning := false
|
|
global actionQueue := []
|
|
global timerStates := Map()
|
|
global timerFunctions := [] ; PROPERLY INITIALIZED ARRAY
|
|
global startupDelay := 5000 ; 5-second global delay (ms)
|
|
|
|
; Timer configurations
|
|
timers := [
|
|
[25, "Common", [1850, 1150]],
|
|
[50, "Rare", [1300, 450]],
|
|
[90, "Epic", [2520, 450]]
|
|
]
|
|
|
|
; Common click sequence
|
|
CommonSequence := [{ action: "Start Battle", pos: [1945, 1780], delay: 30000 }, { action: "Close Results", pos: [980,
|
|
1630], delay: 4000 }, { action: "Close Shop", pos: [3700, 120], delay: 4000 }
|
|
]
|
|
|
|
; === INITIALIZATION ===
|
|
Sleep startupDelay ; GLOBAL STARTUP DELAY
|
|
SetupTimers()
|
|
SetTimer ProcessQueue, 1000
|
|
SetTimer UpdateStatusTooltip, 1000
|
|
|
|
; === HOTKEYS ===
|
|
^!s:: {
|
|
global timerFunctions
|
|
; Kill all timers
|
|
for fn in timerFunctions {
|
|
SetTimer fn, 0
|
|
}
|
|
SetTimer ProcessQueue, 0
|
|
SetTimer UpdateStatusTooltip, 0
|
|
ToolTip
|
|
ExitApp
|
|
}
|
|
|
|
; === TIMER SETUP ===
|
|
SetupTimers() {
|
|
global timers, timerStates, timerFunctions, startupDelay
|
|
|
|
for i, timer in timers {
|
|
timerName := "Timer" i
|
|
ms := timer[1] * 60000
|
|
|
|
timerStates[timerName] := {
|
|
interval: ms,
|
|
nextRun: A_TickCount + startupDelay + (1000 * i),
|
|
opponent: timer[2],
|
|
position: timer[3]
|
|
}
|
|
|
|
fn := ObjBindMethod(MyTimer, "Trigger", timerName)
|
|
timerFunctions.Push(fn)
|
|
SetTimer fn, ms
|
|
SetTimer fn, -(startupDelay + (1000 * i))
|
|
}
|
|
}
|
|
|
|
class MyTimer {
|
|
static Trigger(name) {
|
|
global actionQueue, timerStates
|
|
|
|
; Update next run time
|
|
timerStates[name].nextRun := A_TickCount + timerStates[name].interval
|
|
|
|
; Add to queue
|
|
actionQueue.Push({
|
|
name: name,
|
|
opponent: timerStates[name].opponent,
|
|
opponentPos: timerStates[name].position,
|
|
time: FormatTime(, "HH:mm:ss")
|
|
})
|
|
}
|
|
}
|
|
|
|
ProcessQueue() {
|
|
global isRunning, actionQueue, CommonSequence, targetWindow
|
|
|
|
if (!isRunning && actionQueue.Length > 0) {
|
|
isRunning := true
|
|
current := actionQueue.RemoveAt(1)
|
|
|
|
if WinExist(targetWindow) {
|
|
WinActivate
|
|
WinWaitActive
|
|
|
|
; Opponent-specific step
|
|
ToolTip "Attacking: " current.opponent, 10, 10
|
|
MouseMove current.opponentPos[1], current.opponentPos[2]
|
|
Click
|
|
Sleep 4000
|
|
|
|
; Common sequence
|
|
for step in CommonSequence {
|
|
ToolTip step.action "...", 10, 10
|
|
MouseMove step.pos[1], step.pos[2]
|
|
Click
|
|
Sleep step.delay
|
|
}
|
|
} else {
|
|
ToolTip "ERROR: Window not found", 10, 10
|
|
Sleep 2000
|
|
}
|
|
|
|
ToolTip
|
|
isRunning := false
|
|
}
|
|
}
|
|
|
|
UpdateStatusTooltip() {
|
|
global isRunning, timerStates, actionQueue
|
|
|
|
if (isRunning) {
|
|
return
|
|
}
|
|
|
|
statusText := "Next Battles:`n`n"
|
|
totalWidth := 300
|
|
|
|
for name, timer in timerStates {
|
|
remaining := timer.nextRun - A_TickCount
|
|
if (remaining < 0) {
|
|
statusText .= name ": READY NOW`n"
|
|
} else {
|
|
mins := Floor(remaining / 60000)
|
|
secs := Mod(Floor(remaining / 1000), 60)
|
|
progress := 100 - (remaining * 100 / timer.interval)
|
|
progress := Min(Max(progress, 0), 100)
|
|
|
|
barWidth := Floor(totalWidth * (progress / 100))
|
|
progressBar := "[" . Format("{:-" barWidth "}", "")
|
|
. Format("{:" (totalWidth - barWidth) "}", "") . "]"
|
|
|
|
statusText .= name ": " Format("{1:02}:{2:02}", mins, secs)
|
|
. " (" progress "%)`n" progressBar "`n"
|
|
}
|
|
}
|
|
|
|
if (actionQueue.Length > 0) {
|
|
statusText .= "`nQueued: " actionQueue.Length " battles"
|
|
}
|
|
|
|
ToolTip statusText, 10, 10, 1
|
|
}
|
|
|
|
; Clear tooltips when script exits
|
|
OnExit(ObjBindMethod(ToolTip, , , , 1)) |