Hey guys, i got this script that i was using for POE 1 and modified it for POE 2. ALT+F12 to activate, I use mouse4 for my skill, make sure to edit script and look at the notes and keybinds and modify to whatever you use. You need to update the coordiantes for inventory management and gem swap tho, it uses those from POE 1. It should be easy to do, just use ALT+G to get the coordiantes of where is your mouse and edit script with updated coordinates. Just install AutoHotKey v1.1 Just a moment... then Right Click on your Desktop and go to New-AutoHotKey Script , name it whatever you want, after just Right Click on it and Edit, delete any text inside and copy paste this script, edit keybinds for your needs. If you don't figure out how to replace keybinds just paste the script or upload the file into Just a moment... , select DeepThink (R1) in chat window and then ask it to change/add whatever you want.
Code:
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
#IfWinActive Path of Exile 2
#SingleInstance force
#Persistent
DebugMode := false ; Set to false to disable debug messages
;----------------------------------------------------------------------
; PoE 2 Flasks macro for AutoHotKey (2 Flask Slots)
; NOTE: Run this script as Administrator if the game is running as Administrator.
;----------------------------------------------------------------------
;----------------------------------------------------------------------
; Flask and Buff Configuration
;----------------------------------------------------------------------
FlaskDurationInit := []
FlaskDurationInit[1] := 3000 ; Flask 1 duration (3 seconds)
FlaskDurationInit[2] := 9000 ; Flask 2 duration (9 seconds)
FlaskDurationInit["q"] := 1000 ; Buff "q" duration (1 second)
FlaskDurationInit["e"] := 1000 ; Buff "e" duration (1 second)
FlaskDurationInit["r"] := 1000 ; Buff "r" duration (1 second)
FlaskDurationInit["t"] := 1000 ; Buff "t" duration (1 second)
FlaskDuration := []
FlaskLastUsed := []
UseFlasks := true
HoldMouse4 := true
LastMouse4 := 0
;----------------------------------------------------------------------
; The following are used for fast ctrl-click from the Inventory screen
; using alt-c. The coordinates for ix,iy come from MouseGetPos (Alt+g)
; of the top left location in the inventory screen. The delta is the
; pixel change to the next box, either down or right.
;
; To get the correct values for use below, do the following:
; 1. Load the macro into AutoHotKey
; 2. open Inventory screen (I) and place the mouse cursor in the
; middle of the top left inventory box.
; 3. Press Alt+g and note the coordinates displayed by the mouse.
; 4. Replace the coordinates below.
; 5. To get the "delta", do the same for the next inventory box down
; and note the difference
;----------------------------------------------------------------------
; UI Coordinates (Update via Alt+g)
;----------------------------------------------------------------------
ix := 1730 ; Inventory top-left X
iy := 818 ; Inventory top-left Y
delta := 70 ; Inventory slot spacing
;----------------------------------------------------------------------
; The following are used for fast ctrl-click from Stash tabs into the
; inventory screen, using alt-m.
; Stash top left and delta for 12x12 and 24x24 stash are defined here.
; As above, you'll use Alt+g to determine the actual values needed.
;
; To get these values, follow the instructions for the Inventory screen
; except use the stash tab boxes, instead. Note, the first COLUMN is
; for the 12x12 stash and the second COLUMN is for the 24x24 "Quad" stash.
;----------------------------------------------------------------------
StashX := [60, 40] ; Stash tab X coordinates (12x12, 24x24)
StashY := [253, 234] ; Stash tab Y coordinates
StashD := [70, 35] ; Stash slot spacing
StashSize := [12, 24] ; Stash tab sizes
;----------------------------------------------------------------------
; The following are used for gem swapping. Useful
; when you use one skill for clearing and another for bossing.
; Put the coordinates of your primary attack skill in PrimX, PrimY
; Put the coordinates of alternate attack skill in AltX, AltY
; WeaponSwap determines if alt gem is in inventory or alternate weapon.
;----------------------------------------------------------------------
PrimX := 1403 ; Primary gem X
PrimY := 304 ; Primary gem Y
AltX := 1397 ; Alternate gem X
AltY := 299 ; Alternate gem Y
WeaponSwap := False
;----------------------------------------------------------------------
; Main Program Loop - Auto Flask Logic
;----------------------------------------------------------------------
; Main program loop - basics are that we use flasks whenever flask
; usage is enabled via hotkey (default is F12), and we've attacked
; within the last 0.5 second (or are channeling/continuous attacking.
;----------------------------------------------------------------------
Loop {
if (UseFlasks) {
if ((A_TickCount - LastMouse4) < 500) || (HoldMouse4) {
Gosub, CycleAllFlasksWhenReady
}
}
}
;----------------------------------------------------------------------
; Hotkeys
;----------------------------------------------------------------------
!F12:: ; Toggle Auto-Flasks (Alt+F12)
UseFlasks := not UseFlasks
if UseFlasks {
ToolTip, UseFlasks On
if (DebugMode) {
MsgBox, Auto-Flasks Enabled.
}
; Reset timers
for i in FlaskDurationInit {
FlaskLastUsed[i] := 0
FlaskDuration[i] := FlaskDurationInit[i]
}
} else {
ToolTip, UseFlasks Off
if (DebugMode) {
MsgBox, Auto-Flasks Disabled.
}
}
return
~XButton1:: ; Mouse Button 4 (Attack)
HoldMouse4 := true
LastMouse4 := A_TickCount
if (DebugMode) {
ToolTip, Attacking (Mouse4)
Sleep, 1000
ToolTip
}
return
~XButton1 up:: ; Release Mouse Button 4
HoldMouse4 := false
return
;----------------------------------------------------------------------
; The following 3 hotkeys allow for manual use of flasks while still
; tracking optimal recast times.
;----------------------------------------------------------------------
~1:: ; Manual Flask 1
FlaskLastUsed[1] := A_TickCount
Random, delay, -99, 99
FlaskDuration[1] := FlaskDurationInit[1] + delay
return
~2:: ; Manual Flask 2
FlaskLastUsed[2] := A_TickCount
Random, delay, -99, 99
FlaskDuration[2] := FlaskDurationInit[2] + delay
return
`:: ; Panic Button (Use All Flasks)
if UseFlasks {
Send 1
Random, delay, -99, 99
Sleep, %delay%
Send 2
}
return
;----------------------------------------------------------------------
; Auto Flask Logic
;----------------------------------------------------------------------
CycleAllFlasksWhenReady:
for flask, duration in FlaskDuration {
if (duration > 0) && (A_TickCount - FlaskLastUsed[flask] > duration) {
Send %flask%
FlaskLastUsed[flask] := A_TickCount
Random, delay, -99, 99
FlaskDuration[flask] := FlaskDurationInit[flask] + delay
Sleep, %delay%
if (DebugMode) {
ToolTip, Used: %flask%
Sleep, 500
ToolTip
}
}
}
return
;----------------------------------------------------------------------
; Inventory/Stash Management
;----------------------------------------------------------------------
; Alt+c to Ctrl-Click every location in the (I)nventory screen.
;----------------------------------------------------------------------
!c:: ; Ctrl-Click Inventory (Alt+c)
Loop, 12 {
col := ix + (A_Index - 1) * delta
Loop, 5 {
row := iy + (A_Index - 1) * delta
Send ^{Click, %col%, %row%}
}
}
return
;----------------------------------------------------------------------
; Alt+m - Allow setting stash tab size as normal (12x12) or large (24x24)
;
; vMouseRow := 1 (default) means starting in row 1 of stash tab
; always place mouse pointer in starting box
;
; ItemsToMove := 50 (default) is how many items to move to Inventory
;----------------------------------------------------------------------
!m:: ; Stash Management (Alt+m)
Gui, Add, Radio, vSelStash checked, Norm Stash Tab (12x12)
Gui, Add, Radio,, Quad Stash Tab (24x24)
Gui, Add, Text,, &Clicks:
Gui, Add, Edit, w50
Gui, Add, UpDown, vClicks Range1-50, 50
Gui, Add, Text,, Mouse is in &Row:
Gui, Add, Edit, w50
Gui, Add, UpDown, vStartRow Range1-24, 1
Gui, Add, Button, default, OK
Gui, Show
return
ButtonOK:
GuiClose:
GuiEscape:
Gui, Submit
MouseGetPos, x, y
ClickCt := 0
Loop {
Send ^{Click, %x%, %y%}
if (++ClickCt > StashSize[SelStash] - StartRow) {
StartRow := 1
x := x + StashD[SelStash]
y := StashY[SelStash]
ClickCt := 0
} else {
y := y + StashD[SelStash]
}
} until (--Clicks <= 0)
Gui, Destroy
return
;----------------------------------------------------------------------
; Utility Hotkeys ; Alt+g - Get the current screen coordinates of the mouse pointer.
;----------------------------------------------------------------------
!g:: ; Get Mouse Coordinates (Alt+g)
MouseGetPos, x, y
ToolTip, %x% %y%
return
;----------------------------------------------------------------------
; Alt+s - Swap a skill gem with an alternate. Gems must be same color if alt
; weapon slot is used for holding gems.
;----------------------------------------------------------------------
!s:: ; Swap Skill Gem (Alt+s)
MouseGetPos, x, y
Send i
Sleep 100
Send {Click Right, %PrimX%, %PrimY%}
Sleep 100
if (WeaponSwap) {
Send {x}
Sleep 100
}
Send {Click %AltX%, %AltY%}
Sleep 100
if (WeaponSwap) {
Send {x}
Sleep 100
}
Send {Click %PrimX%, %PrimY%}
Sleep 100
Send i
Sleep 100
MouseMove, x, y
return
;----------------------------------------------------------------------
; Buff Skills (q, e, r, t)
;----------------------------------------------------------------------
~q::
~e::
~r::
~t::
key := SubStr(A_ThisHotkey, 2) ; Extract the pressed key (q/e/r/t)
FlaskLastUsed[key] := A_TickCount
Random, delay, -99, 99
FlaskDuration[key] := FlaskDurationInit[key] + delay
return
;----------------------------------------------------------------------
; Pause/Resume Script (Pause/Break Key)
;----------------------------------------------------------------------
Pause::
Pause, Toggle
if (A_IsPaused) {
ToolTip, Script Paused
} else {
ToolTip, Script Resumed
}
Sleep, 1000
ToolTip
return
Made new specific script for inventory, need to have stash open and probably the exact window opened without affinities if you have different type of items. Could be incorporated in the AutoFlask code eventualy. Now i am focused more on AutoHotKey v2.0, trying to make a script with a GUI.
Code:
; Auto-Admin Reload
if not A_IsAdmin
{
MsgBox, This script requires administrator rights to interact with Path of Exile 2.`nPlease re-run as Administrator.
try RunAsAdmin()
ExitApp
RunAsAdmin() {
full_command_line := DllCall("GetCommandLine", "str")
if not (A_IsAdmin || RegExMatch(full_command_line, " /restart(?!\S)")) {
try Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
ExitApp
}
}
}
#NoEnv
#SingleInstance, Force
#WinActivateForce
SendMode Input
SetWorkingDir, %A_ScriptDir%
; Configuration
global baseX := 0
global baseY := 0
global deltaX := 0
global deltaY := 0
global debugMode := false ; Set to true for testing
; CALIBRATION HOTKEYS
^!1::
MouseGetPos, baseX, baseY
ShowTooltip("CALIBRATED TOP-LEFT SLOT`nX" baseX " Y" baseY)
return
^!2::
MsgBox, 4, Calibration, Hover over BOTTOM-RIGHT slot (12th column, 5th row) then click Yes
IfMsgBox Yes
{
MouseGetPos, endX, endY
deltaX := (endX - baseX)//11 ; Integer division for exact pixels
deltaY := (endY - baseY)//4
ShowTooltip("CALIBRATION COMPLETE`nX-per-slot: " deltaX "`nY-per-slot: " deltaY)
}
return
; MAIN TRANSFER HOTKEY
^!c::
if !ValidateCalibration()
return
originalPID := ActivateGameWindow()
if !originalPID
return
MouseGetPos, origX, origY
successCount := 0
Loop, 5 { ; Rows
currentRow := A_Index - 1
Loop, 12 { ; Columns
currentCol := A_Index - 1
targetX := baseX + (deltaX * currentCol)
targetY := baseY + (deltaY * currentRow)
; Debug visualization
if debugMode {
MouseMove, %targetX%, %targetY%, 0
Sleep, 500
continue
}
; Actual transfer
MouseMove, %targetX%, %targetY%, 0
Sleep, 30
Send, {Ctrl down}
Click
Sleep, 30
Send, {Ctrl up}
Sleep, 50 ; Game response delay
successCount++
}
}
MouseMove, %origX%, %origY%, 0
SoundBeep, 1000, 300 ; Simple success beep
ShowTooltip("Transfer attempted " successCount " slots", 1500)
return
; FUNCTIONS (remain unchanged from previous version)
ActivateGameWindow() {
SetTitleMatchMode, 2
WinGet, pid, PID, Path of Exile 2
if !pid {
MsgBox, Game window not found!`nMake sure Path of Exile 2 is running.
return 0
}
WinActivate, ahk_pid %pid%
WinWaitActive, ahk_pid %pid%,, 2
if ErrorLevel {
MsgBox, Failed to activate game window!`nTry manual click on game window first.
return 0
}
Sleep, 200 ; Mandatory stabilization delay
return pid
}
ValidateCalibration() {
if (baseX = 0 || baseY = 0 || deltaX = 0 || deltaY = 0) {
MsgBox, Calibration required!`n1. Ctrl+Alt+1 on top-left slot`n2. Ctrl+Alt+2 on bottom-right slot
return false
}
return true
}
ShowTooltip(message, duration := 2000) {
ToolTip, %message%
SetTimer, RemoveToolTip, -%duration%
}
RemoveToolTip:
ToolTip
return
*NEW Updated Inventory Transfer script with GUI for AutoHotKey v2.0 , Transfer of items is fast now.
Code:
#Requires AutoHotkey v2.0
#SingleInstance Force
#WinActivateForce
SetWorkingDir(A_ScriptDir)
; ------------------
; CONFIGURATION CLASS
; ------------------
class PoEConfig {
static Calibration := Map(
"baseX", 0,
"baseY", 0,
"deltaX", 0,
"deltaY", 0,
"emptyColor", "",
"valid", false
)
static Settings := Map(
"minDelay", 1, ; Further reduced minimum delay
"maxDelay", 5, ; Further reduced maximum delay
"mouseSpeed", "Fast",
"retryAttempts", 3,
"hotkey", "^!s"
)
}
; ------------------
; GLOBAL VARIABLES
; ------------------
global guiMain := 0
global hwndGame := 0
global txtStatus := 0
global progBar := 0
global isTransferActive := false
global testLog := []
global logFile := "PoE_Stash_Log.txt"
; ------------------
; CORE FUNCTIONS (DEFINED FIRST)
; ------------------
!F12::ActivateGameWindow()
ActivateGameWindow() {
static lastActivation := 0
if (A_TickCount - lastActivation < 1000)
return true
hwndGame := WinExist("Path of Exile 2")
if !hwndGame {
LogMessage("Game window not found!")
MsgBox("Game window not found!", "Error", 0x10)
return false
}
try {
WinActivate(hwndGame)
WinWaitActive(hwndGame,, 2)
lastActivation := A_TickCount
return true
}
catch {
LogMessage("Failed to activate game window!")
MsgBox("Failed to activate game window!", "Error", 0x10)
return false
}
}
CalculateSlotX(col) {
return PoEConfig.Calibration["baseX"] + Round(PoEConfig.Calibration["deltaX"] * col)
}
CalculateSlotY(row) {
return PoEConfig.Calibration["baseY"] + Round(PoEConfig.Calibration["deltaY"] * row)
}
MoveMouseSmooth(x, y) {
MouseGetPos(¤tX, ¤tY)
steps := Random(2, 3) ; Further reduced number of steps for even faster movement
dx := (x - currentX) / steps
dy := (y - currentY) / steps
Loop steps {
try MouseMove(currentX + (dx * A_Index), currentY + (dy * A_Index), 0)
Sleep(Random(1, 3)) ; Further reduced sleep time for even faster movement
}
}
UpdateProgress(step := 0) {
static maxSteps := 60
progBar.Value := step
txtStatus.Text := "Transferring: " Round((step / maxSteps) * 100) "%"
}
CleanupTransfer(count, x, y) {
Send("{Ctrl Up}")
MouseMove(x, y)
MsgBox("Transfer complete!`nItems moved: " count, "Success", 0x40)
UpdateStatus()
progBar.Value := 0
ToolTip()
global isTransferActive
isTransferActive := false
LogMessage("Transfer completed! Items moved: " count)
}
UpdateStatus() {
statusText := "Calibration: "
if PoEConfig.Calibration["valid"] {
statusText .= "VALID"
if (PoEConfig.Calibration["emptyColor"] != "") {
statusText .= " (Color Set)"
} else {
statusText .= " (Color Missing)"
}
} else {
statusText .= "INVALID"
}
txtStatus.Text := statusText
}
LogMessage(message) {
FileAppend(A_Now " - " message "`n", logFile)
}
; ------------------
; TRANSFER SYSTEM
; ------------------
StartTransfer(*) {
global isTransferActive
if isTransferActive || !ValidateCalibration() || !ActivateGameWindow()
return
isTransferActive := true
MouseGetPos(&originalX, &originalY)
totalTransferred := 0
progBar.Value := 0
successColor := PoEConfig.Calibration["emptyColor"]
Send("{Ctrl Down}")
Loop 12 {
currentCol := A_Index - 1
Loop 5 {
currentRow := A_Index - 1
targetX := CalculateSlotX(currentCol)
targetY := CalculateSlotY(currentRow)
if (AttemptTransfer(targetX, targetY, successColor)) {
totalTransferred++
}
UpdateProgress(currentCol * 5 + currentRow + 1)
Sleep(Random(PoEConfig.Settings["minDelay"], PoEConfig.Settings["maxDelay"]))
}
}
; Call CleanupTransfer instead of defining it here
CleanupTransfer(totalTransferred, originalX, originalY)
}
AttemptTransfer(x, y, successColor) {
Loop PoEConfig.Settings["retryAttempts"] {
currentColor := PixelGetColor(x, y)
if (currentColor == successColor)
return false
try {
MoveMouseSmooth(x, y)
Click()
Sleep(5) ; Further reduced sleep time
if (PixelGetColor(x, y) == successColor) {
return true
}
}
catch {
Sleep(5) ; Further reduced sleep time
}
}
return false
}
; ------------------
; CALIBRATION HOTKEYS (MUST BE IN GLOBAL SCOPE)
; ------------------
^!1:: { ; Ctrl+Alt+1 - Set Top-Left slot
if (!ActivateGameWindow())
return
MouseGetPos(&x, &y)
PoEConfig.Calibration["baseX"] := x
PoEConfig.Calibration["baseY"] := y
MsgBox("Top-Left set to X: " x " Y: " y, "Calibration", 0x40)
UpdateStatus()
}
^!2:: { ; Ctrl+Alt+2 - Set Bottom-Right slot
if (!ActivateGameWindow())
return
MouseGetPos(&x, &y)
PoEConfig.Calibration["deltaX"] := (x - PoEConfig.Calibration["baseX"]) / 11
PoEConfig.Calibration["deltaY"] := (y - PoEConfig.Calibration["baseY"]) / 4
PoEConfig.Calibration["valid"] := true
MsgBox("Bottom-Right set to X: " x " Y: " y "`nCalibration complete!", "Calibration", 0x40)
UpdateStatus()
SaveConfig()
}
^!4:: { ; Ctrl+Alt+4 - Set Empty slot color
if (!ActivateGameWindow())
return
MouseGetPos(&x, &y)
color := PixelGetColor(x, y)
PoEConfig.Calibration["emptyColor"] := color
MsgBox("Empty slot color set to: " color, "Calibration", 0x40)
UpdateStatus()
SaveConfig()
}
; Additional hotkey for testing calibration
^!3:: { ; Ctrl+Alt+3 - Test first slot
if (!ValidateCalibration() || !ActivateGameWindow())
return
MoveMouseSmooth(PoEConfig.Calibration["baseX"], PoEConfig.Calibration["baseY"])
ToolTip("First slot: X" PoEConfig.Calibration["baseX"] " Y" PoEConfig.Calibration["baseY"])
Sleep(2000)
ToolTip()
}
; ------------------
; GUI CONSTRUCTION (SEPARATE FROM HOTKEYS)
; ------------------
CreateGUI() {
global guiMain, txtStatus, progBar
guiMain := Gui("+Resize +AlwaysOnTop", "PoE 2 Stash Manager")
guiMain.OnEvent("Close", (*) => ExitApp())
guiMain.SetFont("s10", "Segoe UI")
; Calibration Section
guiMain.Add("GroupBox", "w400 h180", "Calibration")
guiMain.Add("Text", "xp+10 yp+25", "1. Activate game window (Alt+F12)")
guiMain.Add("Text", "yp+25", "2. Ctrl+Alt+1 - Set Top-Left slot")
guiMain.Add("Text", "yp+25", "3. Ctrl+Alt+4 - Set empty slot color")
guiMain.Add("Text", "yp+25", "4. Ctrl+Alt+2 - Set Bottom-Right slot")
guiMain.Add("Text", "yp+25", "5. Ctrl+Alt+3 - Test first slot")
guiMain.Add("Text", "yp+25", "6. Ctrl+Alt+S - Start transfer")
; Status Section
guiMain.Add("GroupBox", "y+20 w400 h100", "Status")
txtStatus := guiMain.Add("Text", "xp+10 yp+25", "Calibration: INVALID")
btnStart := guiMain.Add("Button", "yp+50 w120", "Start Transfer")
btnStart.OnEvent("Click", StartTransfer)
progBar := guiMain.Add("Progress", "x+10 w200 h20 Range0-60", 0)
guiMain.Show("AutoSize")
UpdateStatus()
}
; ------------------
; PERSISTENCE
; ------------------
LoadConfig() {
if FileExist("PoE_Stash.ini") {
try {
PoEConfig.Calibration["baseX"] := IniRead("PoE_Stash.ini", "Calibration", "baseX", 0)
PoEConfig.Calibration["baseY"] := IniRead("PoE_Stash.ini", "Calibration", "baseY", 0)
PoEConfig.Calibration["deltaX"] := IniRead("PoE_Stash.ini", "Calibration", "deltaX", 0)
PoEConfig.Calibration["deltaY"] := IniRead("PoE_Stash.ini", "Calibration", "deltaY", 0)
PoEConfig.Calibration["emptyColor"] := IniRead("PoE_Stash.ini", "Calibration", "emptyColor", "")
PoEConfig.Calibration["valid"] := IniRead("PoE_Stash.ini", "Calibration", "valid", 0) != 0
}
catch {
MsgBox("Invalid configuration file! Resetting settings.", "Error", 0x10)
}
}
}
SaveConfig() {
try {
IniWrite(PoEConfig.Calibration["baseX"], "PoE_Stash.ini", "Calibration", "baseX")
IniWrite(PoEConfig.Calibration["baseY"], "PoE_Stash.ini", "Calibration", "baseY")
IniWrite(PoEConfig.Calibration["deltaX"], "PoE_Stash.ini", "Calibration", "deltaX")
IniWrite(PoEConfig.Calibration["deltaY"], "PoE_Stash.ini", "Calibration", "deltaY")
IniWrite(PoEConfig.Calibration["emptyColor"], "PoE_Stash.ini", "Calibration", "emptyColor")
IniWrite(PoEConfig.Calibration["valid"] ? 1 : 0, "PoE_Stash.ini", "Calibration", "valid")
}
catch {
MsgBox("Failed to save configuration!", "Error", 0x10)
}
}
HandleExit(ExitReason, ExitCode) {
SaveConfig()
ExitApp()
}
; ------------------
; VALIDATION
; ------------------
ValidateCalibration() {
if !PoEConfig.Calibration["valid"] || (PoEConfig.Calibration["emptyColor"] == "") {
MsgBox("Calibration required!`nUse Ctrl+Alt+1/2/4 first", "Error", 0x10)
return false
}
return true
}
; ------------------
; INITIALIZATION
; ------------------
if !A_IsAdmin {
try Run('*RunAs "' A_ScriptFullPath '"')
ExitApp()
}
LoadConfig()
CreateGUI()
OnExit(HandleExit)
Hotkey(PoEConfig.Settings["hotkey"], (*) => StartTransfer())