gamestate = 0x2578 > 0x2678
there is no command like this in both .ahk files
Where is it?
gamestate = 0x2578 > 0x2678
there is no command like this in both .ahk files
Where is it?
Look for SetGameStateMenu and find the number there. What he posted was just that it was changed from 0x2578 to 0x2678 and not the actual code.
It should look something like this:
Code:SetGameStateMenu(hwnd) { if (hwnd=0 || hwnd="") return false GetWindowBasics(hwnd,mBase,pH) if (mBase="" || mBase=0 || pH="" || pH=-1) return false fBase:=GetFrameBase(hwnd) if (fBase="" || fBase=0) return false localConnection:=ReadMemUInt(pH,fBase+0xc0) if (localConnection!="" && localConnection!=0) { WriteMemUInt(pH,localConnection+0x2678,1) }
Hey, you guys asked and i updated the script for steam:
PoE_AutoFlasks (Steam).ahk
Also attached is the Cheat table i made while updating this.Code:SetBatchLines, -1 DetectHiddenWindows, On cliname=Path of Exile cliexe=PathOfExileSteam.exe trayNotifications:=true ;display tray notifications about script actions : drinking potions, autoquitting autoPotionsWatchdogPeriod:=10 ;milliseconds, decrease this value to have script recheck life/mana/flasks availability more often/increase chances of getting saved from death in time lagCompensation:=50 autoQuitMode:=1 ; default autoQuit method : 0 =winKill, 1 = exit to login screen autoQuitPauseBeforeClick:=100 autoQuitSoftToleranceBeforeKill:=2000 ; try to quit to loginscreen at most milliseconds before killing game window(in case we can't quit by clicking menu option for some reason) PlayerConfig:={} PlayerConfig["Default"]:={minLifeRatioToDrink: 0.80, minManaRatioToDrink: 0.30, minManaToDrink: 15, minLifeRatioToPopGranite: 0.65, minLifeRatioToQuit: 0.40} ; disableAutoPotions:true, minLifeRatioToQuit:, minNShieldRatioToQuit: , HasZealotsOath: false, } PlayerConfig["Default"].FlaskConfig:=[] PlayerConfig["Default"].FlaskConfig[1]:={Hotkey:"{1 Down 1 UP}"} ; ,OverrideFlaskDuration:70, instantRecoveryOnLowLife:true, } ;specify override recovery time in deciseconds, e.g. 7 seconds = 70 PlayerConfig["Default"].FlaskConfig[2]:={Hotkey:"{2 Down 2 UP}"} PlayerConfig["Default"].FlaskConfig[3]:={Hotkey:"{3 Down 3 UP}"} PlayerConfig["Default"].FlaskConfig[4]:={Hotkey:"{4 Down 4 UP}"} PlayerConfig["Default"].FlaskConfig[5]:={Hotkey:"{5 Down 5 UP}"} PlayerConfig["YourHardcorePlayerName"]:={minLifeRatioToDrink: 0.7, minManaRatioToDrink: 0.35, minManaToDrink: 70, minLifeRatioToQuit: 0.4} PlayerConfig["YourHardcorePlayerName"].FlaskConfig:=[] PlayerConfig["YourHardcorePlayerName"].FlaskConfig[1]:={Hotkey:"{1 Down 1 UP}"} PlayerConfig["YourHardcorePlayerName"].FlaskConfig[2]:={Hotkey:"{2 Down 2 UP}"} PlayerConfig["YourHardcorePlayerName"].FlaskConfig[3]:={Hotkey:"{3 Down 3 UP}"} PlayerConfig["YourHardcorePlayerName"].FlaskConfig[4]:={Hotkey:"{4 Down 4 UP}"} PlayerConfig["YourHardcorePlayerName"].FlaskConfig[5]:={Hotkey:"{5 Down 5 UP}"} autoPotionsState:=true WindowQueuedFlaskEffects:=[] ;keyed by "%hwnd%%CurrPid%", hpQueueEndtime, manaQueueEndtime baseMgrPtr:=0x793dd8 ; 0.11.3b delete for script to try to auto-scan for it in newer versions, scan takes 4-5 seconds basePtrAoBArray:=[0x6A,0xFF,0x68,"?","?","?","?",0x50,0x64,"?","?","?","?","?","?",0xA1,"?","?","?","?",0x81,0xEC,"?","?","?","?",0x53,0x55,0x56,0x57,0x33,0xFF,0x3B,0xC7] basePtrAobOffset:=0x10 WindowBasicsCache:=[] ; keyed by "%hwnd%%CurrPid%", entries are objects with properties processHandle, moduleBase, moduleSize, baseFramePtr #Include AutoHotkeyMemoryLib.ahk Loop { AutoPotions() } GetWindowBasics(hwnd, byref mB="", byref pH="", byref mS="") { global WindowBasicsCache global cliexe WinGet, CurrPid, PID, ahk_id %hwnd% k="%hwnd%%CurrPid%" mB:=WindowBasicsCache[k].mBase mS:=WindowBasicsCache[k].mSize if mB= { WindowBasicsCache[k]:=Object() GetModuleInfo(cliexe, CurrPid, mB, mS) if (mB="" || mS="") { MsgBox, Failed to obtain moduleBase or moduleSize for PID %CurrPid%, script will now terminate ExitApp } WindowBasicsCache[k].mBase:=mB WindowBasicsCache[k].mSize:=mS } pH:=WindowBasicsCache[k].ProcessHandle if pH= { pH:=GetProcessHandle(CurrPid) if (pH="" || pH=-1) { MsgBox, Invalid process handle obtained for PID %CurrPid%, script will now terminate ExitApp } WindowBasicsCache[k].ProcessHandle:=pH } } ScanBaseMgrPtr(mBase,pH,moduleSize) { global basePtrAoBArray global basePtrAobOffset global baseMgrPtr aobResult:=AobScan(pH,mBase,moduleSize,basePtrAoBArray) if aobResult { SetFormat, IntegerFast, hex baseMgrPtr:=ReadMemUInt(pH,mBase+aobResult+basePtrAobOffset)-mBase MsgBox, PoE Base ptr found with AoB Scan baseMgrPtr = %baseMgrPtr%, save this value to script for quick startup SetFormat, IntegerFast, dec } else { MsgBox, baseMgrPtr not found with AoBScan, script will now terminate ExitApp } } GetFrameBase(hwnd) { global baseMgrPtr global WindowBasicsCache WinGet, CurrPid, PID, ahk_id %hwnd% k="%hwnd%%CurrPid%" fB:=WindowBasicsCache[k].fBase if fB= { GetWindowBasics(hwnd, mBase, pH, mSize) if baseMgrPtr= { ScanBaseMgrPtr(mBase, pH, mSize) } fB:=GetMultilevelPointer(pH,[mBase+baseMgrPtr,4,0x7C,0x94]) WindowBasicsCache[k].fBase:=fB } return fB } GetUiBase(hwnd) { global baseMgrPtr GetWindowBasics(hwnd, mBase, pH, mSize) if baseMgrPtr= { ScanBaseMgrPtr(mBase, pH, mSize) } FrameBase:=GetFrameBase(hwnd) if (FrameBase="" || FrameBase=0) return uiBase:=GetMultilevelPointer(pH,[FrameBase+0xD8,0xA4,0x50]) return uiBase } ReadClientResolution(hwnd, ByRef w, ByRef h) { GetWindowBasics(hwnd,mBase,pH) if (mBase!=0 && pH && pH!=-1) { FrameBase:=GetFrameBase(hwnd) w:=ReadMemUInt(pH,FrameBase+0x1340) h:=ReadMemUInt(pH,FrameBase+0x1344) return true } } ReadPlayerStats(hwnd, byRef PlayerStats) { GetWindowBasics(hwnd, mBase, pH) fBase:=GetFrameBase(hwnd) PlayerBase:=GetMultilevelPointer(pH,[fBase+0xD8,0x59C]) PlayerMain:=ReadMemUInt(pH,PlayerBase+4) PlayerStatsOffset:=ReadMemUInt(pH,PlayerMain+0xC) PlayerStats.MaxHP:=ReadMemUInt(pH,PlayerStatsOffset+0x50) PlayerStats.CurrHP:=ReadMemUInt(pH,PlayerStatsOffset+0x54) PlayerStats.ReservedHPFlat:=ReadMemUInt(pH,PlayerStatsOffset+0x5C) PlayerStats.ReservedHPPercent:=ReadMemUInt(pH,PlayerStatsOffset+0x60) PlayerStats.MaxMana:=ReadMemUInt(pH,PlayerStatsOffset+0x74) PlayerStats.ReservedManaFlat:=ReadMemUInt(pH,PlayerStatsOffset+0x80) PlayerStats.ReservedManaPercent:=ReadMemUInt(pH,PlayerStatsOffset+0x84) PlayerStats.CurrMana:=ReadMemUInt(pH,PlayerStatsOffset+0x78) PlayerStats.MaxNShield:=ReadMemUInt(pH,PlayerStatsOffset+0x98) PlayerStats.CurrNShield:=ReadMemUInt(pH,PlayerStatsOffset+0x9C) if (ReadMemUInt(pH, ReadMemUInt(pH,PlayerMain+0x14)+0x24)<8) ;names shorter than 7 chars are stored immediately in component PlayerStats.Name:=ReadMemStr(pH, ReadMemUint(pH,PlayerMain+0x14)+0x10,100,"UTF-16") ;immediate name in component else PlayerStats.Name:=ReadMemStr(pH, GetMultilevelPointer(pH,[PlayerMain+0x14,0x10]),100,"UTF-16") ; otherwise pointer to name is stored } ReadFlasksData(hwnd, byRef FlasksData) { GetWindowBasics(hwnd, mBase, pH) UiBase:=GetUiBase(hwnd) if (!UiBase) ;not InGame return FlaskInvBase:=GetMultilevelPointer(pH,[UiBase+0x968,0x980,0x20]) Loop, 5 { currFlaskPtr:=ReadMemUInt(pH,FlaskInvBase+(A_Index-1)*4) if (currFlaskPtr!=0) ; there's a flask in said slot { FlasksData[A_Index]:={} FlaskChargesPtr:=GetMultilevelPointer(ph,[currFlaskPtr,4,0x1C,4,4,0xC]) FlasksData[A_Index].ChargesCurrent:=ReadMemUInt(pH,FlaskChargesPtr+0xC) FlasksData[A_Index].ChargesPerUse:=ReadMemUInt(pH,ReadMemUInt(pH,FlaskChargesPtr+8)+0xC) if (FlasksData[A_Index].ChargesCurrent < FlasksData[A_Index].ChargesPerUse) ; not enough charges in this flask to use it, don't bother continue FlaskMetadataPtr:=GetMultilevelPointer(ph,[currFlaskPtr,0,8]) FlaskMetadataStr:=ReadMemStr(ph,FlaskMetadataPtr,70,"UTF-16") FlaskTypeStr:=SubStr(FlaskMetadataStr,23) FlasksData[A_Index].type:=FlaskTypeStr FlaskLocalstatsPtr:=GetMultilevelPointer(ph,[currFlaskPtr,4,0x18,0x20,0xC]) if InStr(FlaskTypeStr, "FlaskLife") { FlasksData[A_Index].HPRegAmount:=ReadMemUInt(pH,FlaskLocalstatsPtr+4) FlasksData[A_Index].EffectDuration:=ReadMemUInt(pH,FlaskLocalstatsPtr+0xC) } if InStr(FlaskTypeStr, "FlaskMana") { FlasksData[A_Index].ManaRegAmount:=ReadMemUInt(pH,FlaskLocalstatsPtr+4) FlasksData[A_Index].EffectDuration:=ReadMemUInt(pH,FlaskLocalstatsPtr+0xC) } if InStr(FlaskTypeStr, "FlaskHybrid") { FlasksData[A_Index].HPRegAmount:=ReadMemUInt(pH,FlaskLocalstatsPtr+4) FlasksData[A_Index].ManaRegAmount:=ReadMemUInt(pH,FlaskLocalstatsPtr+0xC) FlasksData[A_Index].EffectDuration:=ReadMemUInt(pH,FlaskLocalstatsPtr+0x14) } if InStr(FlaskTypeStr, "FlaskUtility") { FlasksData[A_Index].EffectDuration:=ReadMemUInt(pH,FlaskLocalstatsPtr+0x4) } } } } IsInGame(hwnd) { if (hwnd=0 || hwnd="") return false GetWindowBasics(hwnd,mBase,pH) if (mBase="" || mBase=0 || pH="" || pH=-1) return false fBase:=GetFrameBase(hwnd) if (fBase="" || fBase=0) return false localConnection:=ReadMemUInt(pH,fBase+0xc0) if (localConnection=0 || localConnection="") return false else return true } SetGameStateMenu(hwnd) { if (hwnd=0 || hwnd="") return false GetWindowBasics(hwnd,mBase,pH) if (mBase="" || mBase=0 || pH="" || pH=-1) return false fBase:=GetFrameBase(hwnd) if (fBase="" || fBase=0) return false localConnection:=GetMultilevelPointer(pH,[fBase+0xd8,0x598]) if (localConnection!="" && localConnection!=0) { WriteMemUInt(pH,localConnection+0x2678,1) } } ReadCursorScreenPosition(hwnd,ByRef cX, ByRef cY) { GetWindowBasics(hwnd,mBase,pH) if (mBase!=0 && pH && pH!=-1) { FrameBase:=GetFrameBase(hwnd) cX:=ReadMemSInt(pH,FrameBase+0x155c) cY:=ReadMemSInt(pH,FrameBase+0x1560) return true } } ScreenToClient(hwnd, ByRef x, ByRef y) { VarSetCapacity(pt, 8) NumPut(x, pt, 0) NumPut(y, pt, 4) DllCall("ScreenToClient", "uint", hwnd, "uint", &pt) x := NumGet(pt, 0, "int") y := NumGet(pt, 4, "int") VarSetCapacity(pt, 0) } GetClientCoords(byRef mx, byRef my) { hwnd:=WinActive("A") CoordMode, Mouse, Screen MouseGetPos, mx, my ScreenToClient(hwnd,mx,my) ;get mouse pos relative to window client rect } GetFractionalCoords(ByRef fX, ByRef fY) { hwnd:=WinActive("A") if (!IsInGame(hwnd)) GetClientCoords(mx,my) else ReadCursorScreenPosition(hwnd,mx,my) ReadClientResolution(hwnd,w,h) fX:=mx/w fY:=my/h } GetClientCoordsFromFractional(hwnd, fX,fY, ByRef cX, ByRef cY) { ReadClientResolution(hwnd,w,h) cX:=fX*w cY:=fY*h } QuitToLoginScreen(hwnd) { if (!IsInGame(hwnd)) { return } SetGameStateMenu(hwnd) } GetMaxChargesFlaskOfType(ByRef FlasksData,TypeStr) { currMaxCharges:=0 Loop, 5 if (InStr(FlasksData[A_Index].type,TypeStr)) { if FlasksData[A_Index].ChargesCurrent>currMaxCharges { currMaxI:=A_Index currMaxCharges:=FlasksData[A_Index].ChargesCurrent } } return currMaxI } AutoPotions() { global autoPotionsWatchdogPeriod global lagCompensation global PlayerConfig global WindowQueuedFlaskEffects global cliname global cliexe global trayNotifications global autoQuitMode if (autoPotionsState!=true) return WinGet, WinID, List, %cliname% Loop, %WinID% { WinGet, ProcModuleName, ProcessName, % "ahk_id" WinID%A_Index% If(ProcModuleName!=cliexe) ; got a window with title "Path of Exile" but exe is not Client.exe, perhaps we have browser window open with PoE site, ignore it continue if (!IsInGame(WinID%A_Index%)) ;not ingame continue if (WinID%A_Index%=WinActive("A")) ThisID:=WinActive("A") PlayerStats:={} ReadPlayerStats(WinID%A_Index%, PlayerStats) if (PlayerStats.MaxHP<1 || PlayerStats.CurrHP=0) ;dead, don't bother continue if (PlayerConfig.HasKey(PlayerStats.Name)) CurrentConfig:=PlayerConfig[PlayerStats.Name] else CurrentConfig:=PlayerConfig["Default"] if PlayerStats.MaxNShield>0 { currNShieldRatio:=PlayerStats.CurrNShield/PlayerStats.MaxNShield } if (PlayerStats.MaxHP>1) { currLifeRatio:=PlayerStats.CurrHP/(PlayerStats.MaxHP-PlayerStats.ReservedHPFlat-PlayerStats.MaxHP*PlayerStats.ReservedHPPercent/100) } if CurrentConfig.HasZealotsOath { currLifeRatio:=currNShieldRatio } if (PlayerStats.MaxMana>0) { currManaRatio:=PlayerStats.CurrMana/(PlayerStats.MaxMana-PlayerStats.ReservedManaFlat-PlayerStats.MaxMana*PlayerStats.ReservedManaPercent/100) } if (currLifeRatio<CurrentConfig.minLifeRatioToQuit || currNShieldRatio<CurrentConfig.minNShieldRatioToQuit) { if (autoQuitMode=0) { TrayTip, PoE autoPotions AutoQuit by closing window, specified min life reached, %A_Space% , 2 WinKill, % "ahk_id" WinID%A_Index% } else if (autoQuitMode=1) { QuitToLoginScreen(WinID%A_Index%) } autoQuit:=1 continue } if (CurrentConfig.disableAutoPotions) continue FlasksData:=[] ReadFlasksData(WinID%A_Index%,FlasksData) WinGet, CurrPID, PID, % "ahk_id" WinID%A_Index% hwnd:=WinID%A_Index% k="%hwnd%%CurrPid%" if (!WindowQueuedFlaskEffects.HasKey(k)) { WindowQueuedFlaskEffects[k]:={} } if (currLifeRatio<CurrentConfig.minLifeRatioToPopGranite || currNShieldRatio<CurrentConfig.minNShieldRatioToPopGranite) if ((!WindowQueuedFlaskEffects[k].HasKey("graniteQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].graniteQueueEndtime-lagCompensation))) { flaskNum:=GetMaxChargesFlaskOfType(FlasksData,"FlaskUtility5") ; granite flask if (flaskNum!="") { if CurrentConfig.FlaskConfig[flaskNum].HasKey("OverrideFlaskDuration") EffectDuration:=CurrentConfig.FlaskConfig[flaskNum].OverrideFlaskDuration else EffectDuration:=FlasksData[flaskNum].EffectDuration WindowQueuedFlaskEffects[k].graniteQueueEndtime:=A_TickCount+EffectDuration*100 if (trayNotifications) { pname:=PlayerStats.Name TrayTip, PoE autoPotions popping Granite flask %flaskNum% on %pname%, %A_Space% , 2 } hKey:=CurrentConfig.FlaskConfig[flaskNum].Hotkey ControlSend,,%hkey%, % "ahk_id" hwnd break } } if (currLifeRatio=1) WindowQueuedFlaskEffects[k].hpQueueEndtime:=A_TickCount if (currManaRatio=1) WindowQueuedFlaskEffects[k].ManaQueueEndtime:=A_TickCount if (currLifeRatio<CurrentConfig.minLifeRatioToDrink || (PlayerStats.CurrHP<CurrentConfig.minLifeToDrink)) if ((!WindowQueuedFlaskEffects[k].HasKey("hpQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].hpQueueEndtime-lagCompensation))) { tflaskNum1:=GetMaxChargesFlaskOfType(FlasksData,"FlaskLife") tflaskNum2:=GetMaxChargesFlaskOfType(FlasksData,"FlaskHybrid") if ((tflaskNum1!=) && (tflaskNum2!=)) flaskNum:=(FlasksData[tflaskNum1].ChargesCurrent>FlasksData[tflaskNum2].ChargesCurrent) ? tflaskNum1 : tflaskNum2 else { if (tflaskNum1!="") flaskNum:=tflaskNum1 if (tflaskNum2!="") flaskNum:=tflaskNum2 } if (flaskNum!="") { if CurrentConfig.FlaskConfig[flaskNum].HasKey("OverrideFlaskDuration") EffectDuration:=CurrentConfig.FlaskConfig[flaskNum].OverrideFlaskDuration else EffectDuration:=FlasksData[flaskNum].EffectDuration if ((CurrentConfig.FlaskConfig[flaskNum].instantRecoveryOnLowLife) && ((PlayerStats.CurrHP/PlayerStats.MaxHP)<=0.35)) ; "Low life" can be caused by auras hp reservation from blood magic EffectDuration:=lagCompensation WindowQueuedFlaskEffects[k].hpQueueEndtime:=A_TickCount+EffectDuration*100 if (FlasksData[flaskNum].HasKey("ManaRegAmount")) ; hybrid flask WindowQueuedFlaskEffects[k].ManaQueueEndtime:=A_TickCount+EffectDuration*100 if (trayNotifications) { pname:=PlayerStats.Name TrayTip, PoE autoPotions sipping HP flask %flaskNum% on %pname%, %A_Space% , 2 } hKey:=CurrentConfig.FlaskConfig[flaskNum].Hotkey ControlSend,,%hkey%, % "ahk_id" hwnd break } } if (PlayerStats.MaxMana>0 && (currManaRatio<CurrentConfig.minManaRatioToDrink || PlayerStats.CurrMana<CurrentConfig.minManaToDrink)) if ((!WindowQueuedFlaskEffects[k].HasKey("ManaQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].ManaQueueEndtime-lagCompensation))) { tflaskNum1:=GetMaxChargesFlaskOfType(FlasksData,"FlaskMana") tflaskNum2:=GetMaxChargesFlaskOfType(FlasksData,"FlaskHybrid") if ((tflaskNum1!=) && (tflaskNum2!=)) flaskNum:=(FlasksData[tflaskNum1].ChargesCurrent>FlasksData[tflaskNum2].ChargesCurrent) ? tflaskNum1 : tflaskNum2 else { if (tflaskNum1!="") flaskNum:=tflaskNum1 if (tflaskNum2!="") flaskNum:=tflaskNum2 } if (flaskNum!="") { if CurrentConfig.FlaskConfig[flaskNum].HasKey("OverrideFlaskDuration") { EffectDuration:=CurrentConfig.FlaskConfig[flaskNum].OverrideFlaskDuration } else EffectDuration:=FlasksData[flaskNum].EffectDuration if ((CurrentConfig.FlaskConfig[flaskNum].instantRecoveryOnLowLife) && ((PlayerStats.CurrHP/PlayerStats.MaxHP)<=0.35)) EffectDuration:=lagCompensation WindowQueuedFlaskEffects[k].ManaQueueEndtime:=A_TickCount+EffectDuration*100 if (FlasksData[flaskNum].HasKey("HPRegAmount")) ; hybrid flask WindowQueuedFlaskEffects[k].hpQueueEndtime:=A_TickCount+EffectDuration*100 hKey:=CurrentConfig.FlaskConfig[flaskNum].Hotkey if (trayNotifications) { pname:=PlayerStats.Name TrayTip, PoE autoPotions sipping mana flask %flaskNum% on %pname%, %A_Space% , 2 } ControlSend,,%hkey%, % "ahk_id" hwnd break } } } if ((autoQuit=1) && (ThisID!="") && (ThisID!=WinActive("A"))) WinActivate, % "ahk_id" ThisID Sleep, %autoPotionsWatchdogPeriod% } F1:: global autoPotionsState global trayNotifications autoPotionsState:=not autoPotionsState if (trayNotifications) { if (autoPotionsState=true) TrayTip, PoE autoPotions is on, %A_Space% , 2 else TrayTip, PoE autoPotions is off, %A_Space% , 2 } return F2:: GetClientCoords(mx,my) GetFractionalCoords(fx,fy) msgbox, mx=%mx% my=%my% fx=%fx% fy=%fy% return F4:: QuitToLoginScreen(WinActive("A")) return
Learn from it since i'm not gonna keep updating so frequently.
Enjoy.
Last edited by gurud; 11-21-2013 at 05:45 PM.
Thank Gurud for the steam update![]()
which one for non steam? sorry can't get any to work.
Gurud thank-you Sir for doing an maintaining this for old stupid farts like me. I downloaded this file looked at it am my previous comment applies well ... I'm an old stupid fart that doesn't know what I'm looking at an how to use this so I can keep this working when changes / updates occur with POE.
I would like to learn how to do this can you help me with this at all Sir (privately or publicly)
Many Thanks, Mark
THANK you Gurud! Testing now,
Last edited by rolandxcalibur8; 11-23-2013 at 06:58 PM.
script not work anymore :/ Used that code below:
Code:SetBatchLines, -1 DetectHiddenWindows, On cliname=Path of Exile cliexe=PathOfExile.exe trayNotifications:=true ;display tray notifications about script actions : drinking potions, autoquitting autoPotionsWatchdogPeriod:=100 ;milliseconds, decrease this value to have script recheck life/mana/flasks availability more often/increase chances of getting saved from death in time lagCompensation:=50 autoQuitMode:=1 ; default autoQuit method : 0 =winKill, 1 = exit to login screen autoQuitPauseBeforeClick:=100 autoQuitSoftToleranceBeforeKill:=2000 ; try to quit to loginscreen at most milliseconds before killing game window(in case we can't quit by clicking menu option for some reason) PlayerConfig:={} PlayerConfig["Default"]:={minLifeRatioToDrink: 0.75, minManaRatioToDrink: 0.25, minManaToDrink: 10, minLifeRatioToPopGranite: 0.80, minLifeRatioToPopJade: 0.80, minLifeRatioToQuit: 0.} ; disableAutoPotions:true, minNShieldRatioToPopGranite: , minLifeRatioToPopJade: , minNShieldRatioToPopJade: , minNShieldRatioToQuit: , HasZealotsOath: false, } PlayerConfig["Default"].FlaskConfig:=[] PlayerConfig["Default"].FlaskConfig[1]:={Hotkey:"{1 Down 1 UP}"} ; ,OverrideFlaskDuration: 70, instantRecoveryOnLowLife:true, } ;specify override recovery time in deciseconds, e.g. 7 seconds = 70 PlayerConfig["Default"].FlaskConfig[2]:={Hotkey:"{2 Down 2 UP}"} PlayerConfig["Default"].FlaskConfig[3]:={Hotkey:"{3 Down 3 UP}"} PlayerConfig["Default"].FlaskConfig[4]:={Hotkey:"{4 Down 4 UP}"} PlayerConfig["Default"].FlaskConfig[5]:={Hotkey:"{5 Down 5 UP}"} PlayerConfig["YourHardcorePlayerName"]:={minLifeRatioToDrink: 0.75, minManaRatioToDrink: 0.25, minManaToDrink: 10, minLifeRatioToPopGranite: 0.80, minLifeRatioToPopJade: 0.80, minLifeRatioToQuit: 0.35} PlayerConfig["YourHardcorePlayerName"].FlaskConfig:=[] PlayerConfig["YourHardcorePlayerName"].FlaskConfig[1]:={Hotkey:"{1 Down 1 UP}"} PlayerConfig["YourHardcorePlayerName"].FlaskConfig[2]:={Hotkey:"{2 Down 2 UP}"} PlayerConfig["YourHardcorePlayerName"].FlaskConfig[3]:={Hotkey:"{3 Down 3 UP}"} PlayerConfig["YourHardcorePlayerName"].FlaskConfig[4]:={Hotkey:"{4 Down 4 UP}"} PlayerConfig["YourHardcorePlayerName"].FlaskConfig[5]:={Hotkey:"{5 Down 5 UP}"} autoPotionsState:=true WindowQueuedFlaskEffects:=[] ;keyed by "%hwnd%%CurrPid%", hpQueueEndtime, manaQueueEndtime baseMgrPtr:=0x78fd54 ; 1.0.1b delete for script to try to auto-scan for it in newer versions, scan takes 4-5 seconds basePtrAoBArray:=[0x6A,0xFF,0x68,"?","?","?","?",0x50,0x64,"?","?","?","?","?","?",0xA1,"?","?","?","?",0x81,0xEC,"?","?","?","?",0x53,0x55,0x56,0x57,0x33,0xFF,0x3B,0xC7] basePtrAobOffset:=0x10 WindowBasicsCache:=[] ; keyed by "%hwnd%%CurrPid%", entries are objects with properties processHandle, moduleBase, moduleSize, baseFramePtr #Include AutoHotkeyMemoryLib.ahk Loop { AutoPotions() } GetWindowBasics(hwnd, byref mB="", byref pH="", byref mS="") { global WindowBasicsCache global cliexe WinGet, CurrPid, PID, ahk_id %hwnd% k="%hwnd%%CurrPid%" mB:=WindowBasicsCache[k].mBase mS:=WindowBasicsCache[k].mSize if mB= { WindowBasicsCache[k]:=Object() GetModuleInfo(cliexe, CurrPid, mB, mS) if (mB="" || mS="") { MsgBox, Failed to obtain moduleBase or moduleSize for PID %CurrPid%, script will now terminate ExitApp } WindowBasicsCache[k].mBase:=mB WindowBasicsCache[k].mSize:=mS } pH:=WindowBasicsCache[k].ProcessHandle if pH= { pH:=GetProcessHandle(CurrPid) if (pH="" || pH=-1) { MsgBox, Invalid process handle obtained for PID %CurrPid%, script will now terminate ExitApp } WindowBasicsCache[k].ProcessHandle:=pH } } ScanBaseMgrPtr(mBase,pH,moduleSize) { global basePtrAoBArray global basePtrAobOffset global baseMgrPtr aobResult:=AobScan(pH,mBase,moduleSize,basePtrAoBArray) if aobResult { SetFormat, IntegerFast, hex baseMgrPtr:=ReadMemUInt(pH,mBase+aobResult+basePtrAobOffset)-mBase MsgBox, PoE Base ptr found with AoB Scan baseMgrPtr = %baseMgrPtr%, save this value to script for quick startup SetFormat, IntegerFast, dec } else { MsgBox, baseMgrPtr not found with AoBScan, script will now terminate ExitApp } } GetFrameBase(hwnd) { global baseMgrPtr global WindowBasicsCache WinGet, CurrPid, PID, ahk_id %hwnd% k="%hwnd%%CurrPid%" fB:=WindowBasicsCache[k].fBase if fB= { GetWindowBasics(hwnd, mBase, pH, mSize) if baseMgrPtr= { ScanBaseMgrPtr(mBase, pH, mSize) } fB:=GetMultilevelPointer(pH,[mBase+baseMgrPtr,4,0x7C,0x94]) WindowBasicsCache[k].fBase:=fB } return fB } GetUiBase(hwnd) { global baseMgrPtr GetWindowBasics(hwnd, mBase, pH, mSize) if baseMgrPtr= { ScanBaseMgrPtr(mBase, pH, mSize) } FrameBase:=GetFrameBase(hwnd) if (FrameBase="" || FrameBase=0) return uiBase:=GetMultilevelPointer(pH,[FrameBase+0xBC,0xA4,0x50]) return uiBase } ReadClientResolution(hwnd, ByRef w, ByRef h) { GetWindowBasics(hwnd,mBase,pH) if (mBase!=0 && pH && pH!=-1) { FrameBase:=GetFrameBase(hwnd) w:=ReadMemUInt(pH,FrameBase+0x1340) h:=ReadMemUInt(pH,FrameBase+0x1344) return true } } ReadPlayerStats(hwnd, byRef PlayerStats) { GetWindowBasics(hwnd, mBase, pH) fBase:=GetFrameBase(hwnd) PlayerBase:=GetMultilevelPointer(pH,[fBase+0xBC,0x59C]) PlayerMain:=ReadMemUInt(pH,PlayerBase+4) PlayerStatsOffset:=ReadMemUInt(pH,PlayerMain+0xC) PlayerStats.MaxHP:=ReadMemUInt(pH,PlayerStatsOffset+0x50) PlayerStats.CurrHP:=ReadMemUInt(pH,PlayerStatsOffset+0x54) PlayerStats.ReservedHPFlat:=ReadMemUInt(pH,PlayerStatsOffset+0x5C) PlayerStats.ReservedHPPercent:=ReadMemUInt(pH,PlayerStatsOffset+0x60) PlayerStats.MaxMana:=ReadMemUInt(pH,PlayerStatsOffset+0x74) PlayerStats.ReservedManaFlat:=ReadMemUInt(pH,PlayerStatsOffset+0x80) PlayerStats.ReservedManaPercent:=ReadMemUInt(pH,PlayerStatsOffset+0x84) PlayerStats.CurrMana:=ReadMemUInt(pH,PlayerStatsOffset+0x78) PlayerStats.MaxNShield:=ReadMemUInt(pH,PlayerStatsOffset+0x98) PlayerStats.CurrNShield:=ReadMemUInt(pH,PlayerStatsOffset+0x9C) if (ReadMemUInt(pH, ReadMemUInt(pH,PlayerMain+0x14)+0x24)<8) ;names shorter than 7 chars are stored immediately in component PlayerStats.Name:=ReadMemStr(pH, ReadMemUint(pH,PlayerMain+0x14)+0x10,100,"UTF-16") ;immediate name in component else PlayerStats.Name:=ReadMemStr(pH, GetMultilevelPointer(pH,[PlayerMain+0x14,0x10]),100,"UTF-16") ; otherwise pointer to name is stored } ReadFlasksData(hwnd, byRef FlasksData) { GetWindowBasics(hwnd, mBase, pH) UiBase:=GetUiBase(hwnd) if (!UiBase) ;not InGame return FlaskInvBase:=GetMultilevelPointer(pH,[UiBase+0x968,0x980,0x20]) Loop, 5 { currFlaskPtr:=ReadMemUInt(pH,FlaskInvBase+(A_Index-1)*4) if (currFlaskPtr!=0) ; there's a flask in said slot { FlasksData[A_Index]:={} FlaskChargesPtr:=GetMultilevelPointer(ph,[currFlaskPtr,4,0x1C,4,4,0xC]) FlasksData[A_Index].ChargesCurrent:=ReadMemUInt(pH,FlaskChargesPtr+0xC) FlasksData[A_Index].ChargesPerUse:=ReadMemUInt(pH,ReadMemUInt(pH,FlaskChargesPtr+8)+0xC) if (FlasksData[A_Index].ChargesCurrent < FlasksData[A_Index].ChargesPerUse) ; not enough charges in this flask to use it, don't bother continue FlaskMetadataPtr:=GetMultilevelPointer(ph,[currFlaskPtr,0,8]) FlaskMetadataStr:=ReadMemStr(ph,FlaskMetadataPtr,70,"UTF-16") FlaskTypeStr:=SubStr(FlaskMetadataStr,23) FlasksData[A_Index].type:=FlaskTypeStr FlaskLocalstatsPtr:=GetMultilevelPointer(ph,[currFlaskPtr,4,0x18,0x20,0xC]) if InStr(FlaskTypeStr, "Life") { FlasksData[A_Index].HPRegAmount:=ReadMemUInt(pH,FlaskLocalstatsPtr+4) FlasksData[A_Index].EffectDuration:=ReadMemUInt(pH,FlaskLocalstatsPtr+0xC) } if InStr(FlaskTypeStr, "Mana") { FlasksData[A_Index].ManaRegAmount:=ReadMemUInt(pH,FlaskLocalstatsPtr+4) FlasksData[A_Index].EffectDuration:=ReadMemUInt(pH,FlaskLocalstatsPtr+0xC) } if InStr(FlaskTypeStr, "Hybrid") { FlasksData[A_Index].HPRegAmount:=ReadMemUInt(pH,FlaskLocalstatsPtr+4) FlasksData[A_Index].ManaRegAmount:=ReadMemUInt(pH,FlaskLocalstatsPtr+0xC) FlasksData[A_Index].EffectDuration:=ReadMemUInt(pH,FlaskLocalstatsPtr+0x14) } if InStr(FlaskTypeStr, "FlaskUtility") { FlasksData[A_Index].EffectDuration:=ReadMemUInt(pH,FlaskLocalstatsPtr+0x4) } } } } IsInGame(hwnd) { if (hwnd=0 || hwnd="") return false GetWindowBasics(hwnd,mBase,pH) if (mBase="" || mBase=0 || pH="" || pH=-1) return false fBase:=GetFrameBase(hwnd) if (fBase="" || fBase=0) return false localConnection:=ReadMemUInt(pH,fBase+0xc0) if (localConnection=0 || localConnection="") return false else return true } SetGameStateMenu(hwnd) { if (hwnd=0 || hwnd="") return false GetWindowBasics(hwnd,mBase,pH) if (mBase="" || mBase=0 || pH="" || pH=-1) return false fBase:=GetFrameBase(hwnd) if (fBase="" || fBase=0) return false localConnection:=ReadMemUInt(pH,fBase+0xc0) if (localConnection!="" && localConnection!=0) { WriteMemUInt(pH,localConnection+0x2578,1) } } ReadCursorScreenPosition(hwnd,ByRef cX, ByRef cY) { GetWindowBasics(hwnd,mBase,pH) if (mBase!=0 && pH && pH!=-1) { FrameBase:=GetFrameBase(hwnd) cX:=ReadMemSInt(pH,FrameBase+0x155c) cY:=ReadMemSInt(pH,FrameBase+0x1560) return true } } ScreenToClient(hwnd, ByRef x, ByRef y) { VarSetCapacity(pt, 8) NumPut(x, pt, 0) NumPut(y, pt, 4) DllCall("ScreenToClient", "uint", hwnd, "uint", &pt) x := NumGet(pt, 0, "int") y := NumGet(pt, 4, "int") VarSetCapacity(pt, 0) } GetClientCoords(byRef mx, byRef my) { hwnd:=WinActive("A") CoordMode, Mouse, Screen MouseGetPos, mx, my ScreenToClient(hwnd,mx,my) ;get mouse pos relative to window client rect } GetFractionalCoords(ByRef fX, ByRef fY) { hwnd:=WinActive("A") if (!IsInGame(hwnd)) GetClientCoords(mx,my) else ReadCursorScreenPosition(hwnd,mx,my) ReadClientResolution(hwnd,w,h) fX:=mx/w fY:=my/h } GetClientCoordsFromFractional(hwnd, fX,fY, ByRef cX, ByRef cY) { ReadClientResolution(hwnd,w,h) cX:=fX*w cY:=fY*h } QuitToLoginScreen(hwnd) { if (!IsInGame(hwnd)) { return } SetGameStateMenu(hwnd) } GetMaxChargesFlaskOfType(ByRef FlasksData,TypeStr) { currMaxCharges:=0 Loop, 5 if (InStr(FlasksData[A_Index].type,TypeStr)) { if FlasksData[A_Index].ChargesCurrent>currMaxCharges { currMaxI:=A_Index currMaxCharges:=FlasksData[A_Index].ChargesCurrent } } return currMaxI } AutoPotions() { global autoPotionsWatchdogPeriod global lagCompensation global PlayerConfig global WindowQueuedFlaskEffects global cliname global cliexe global trayNotifications global autoQuitMode if (autoPotionsState!=true) return WinGet, WinID, List, %cliname% Loop, %WinID% { WinGet, ProcModuleName, ProcessName, % "ahk_id" WinID%A_Index% If(ProcModuleName!=cliexe) ; got a window with title "Path of Exile" but exe is not Client.exe, perhaps we have browser window open with PoE site, ignore it continue if (!IsInGame(WinID%A_Index%)) ;not ingame continue if (WinID%A_Index%=WinActive("A")) ThisID:=WinActive("A") PlayerStats:={} ReadPlayerStats(WinID%A_Index%, PlayerStats) if (PlayerStats.MaxHP<1 || PlayerStats.CurrHP=0) ;dead, don't bother continue if (PlayerConfig.HasKey(PlayerStats.Name)) CurrentConfig:=PlayerConfig[PlayerStats.Name] else CurrentConfig:=PlayerConfig["Default"] if PlayerStats.MaxNShield>0 { currNShieldRatio:=PlayerStats.CurrNShield/PlayerStats.MaxNShield } if (PlayerStats.MaxHP>1) { currLifeRatio:=PlayerStats.CurrHP/(PlayerStats.MaxHP-PlayerStats.ReservedHPFlat-PlayerStats.MaxHP*PlayerStats.ReservedHPPercent/100) } if CurrentConfig.HasZealotsOath { currLifeRatio:=currNShieldRatio } if (PlayerStats.MaxMana>0) { currManaRatio:=PlayerStats.CurrMana/(PlayerStats.MaxMana-PlayerStats.ReservedManaFlat-PlayerStats.MaxMana*PlayerStats.ReservedManaPercent/100) } if (currLifeRatio<CurrentConfig.minLifeRatioToQuit || currNShieldRatio<CurrentConfig.minNShieldRatioToQuit) { if (autoQuitMode=0) { TrayTip, PoE autoPotions AutoQuit by closing window, specified min life reached, %A_Space% , 2 WinKill, % "ahk_id" WinID%A_Index% } else if (autoQuitMode=1) { QuitToLoginScreen(WinID%A_Index%) } autoQuit:=0 continue } if (CurrentConfig.disableAutoPotions) continue FlasksData:=[] ReadFlasksData(WinID%A_Index%,FlasksData) WinGet, CurrPID, PID, % "ahk_id" WinID%A_Index% hwnd:=WinID%A_Index% k="%hwnd%%CurrPid%" if (!WindowQueuedFlaskEffects.HasKey(k)) { WindowQueuedFlaskEffects[k]:={} } if (currLifeRatio<CurrentConfig.minLifeRatioToPopGranite || currNShieldRatio<CurrentConfig.minNShieldRatioToPopGranite) if ((!WindowQueuedFlaskEffects[k].HasKey("graniteQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].graniteQueueEndtime-lagCompensation))) { flaskNum:=GetMaxChargesFlaskOfType(FlasksData,"FlaskUtility5") ; granite flask if (flaskNum!="") { if CurrentConfig.FlaskConfig[flaskNum].HasKey("OverrideFlaskDuration") EffectDuration:=CurrentConfig.FlaskConfig[flaskNum].OverrideFlaskDuration else EffectDuration:=FlasksData[flaskNum].EffectDuration WindowQueuedFlaskEffects[k].graniteQueueEndtime:=A_TickCount+EffectDuration*100 if (trayNotifications) { pname:=PlayerStats.Name TrayTip, PoE autoPotions popping Granite flask %flaskNum% on %pname%, %A_Space% , 2 } hKey:=CurrentConfig.FlaskConfig[flaskNum].Hotkey ControlSend,,%hkey%, % "ahk_id" hwnd break } } if (currLifeRatio<CurrentConfig.minLifeRatioToPopJade || currNShieldRatio<CurrentConfig.minNShieldRatioToPopJade) if ((!WindowQueuedFlaskEffects[k].HasKey("jadeQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].jadeQueueEndtime-lagCompensation))) { flaskNum:=GetMaxChargesFlaskOfType(FlasksData,"FlaskUtility9") ; jade flask if (flaskNum!="") { if CurrentConfig.FlaskConfig[flaskNum].HasKey("OverrideFlaskDuration") EffectDuration:=CurrentConfig.FlaskConfig[flaskNum].OverrideFlaskDuration else EffectDuration:=FlasksData[flaskNum].EffectDuration WindowQueuedFlaskEffects[k].jadeQueueEndtime:=A_TickCount+EffectDuration*100 if (trayNotifications) { pname:=PlayerStats.Name TrayTip, PoE autoPotions popping Jade flask %flaskNum% on %pname%, %A_Space% , 2 } hKey:=CurrentConfig.FlaskConfig[flaskNum].Hotkey ControlSend,,%hkey%, % "ahk_id" hwnd break } } if (currLifeRatio=1) WindowQueuedFlaskEffects[k].hpQueueEndtime:=A_TickCount if (currManaRatio=1) WindowQueuedFlaskEffects[k].ManaQueueEndtime:=A_TickCount if (currLifeRatio<CurrentConfig.minLifeRatioToDrink || (PlayerStats.CurrHP<CurrentConfig.minLifeToDrink)) if ((!WindowQueuedFlaskEffects[k].HasKey("hpQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].hpQueueEndtime-lagCompensation))) { tflaskNum1:=GetMaxChargesFlaskOfType(FlasksData,"FlaskLife") tflaskNum2:=GetMaxChargesFlaskOfType(FlasksData,"FlaskHybrid") if ((tflaskNum1!=) && (tflaskNum2!=)) flaskNum:=(FlasksData[tflaskNum1].ChargesCurrent>FlasksData[tflaskNum2].ChargesCurrent) ? tflaskNum1 : tflaskNum2 else { if (tflaskNum1!="") flaskNum:=tflaskNum1 if (tflaskNum2!="") flaskNum:=tflaskNum2 } if (flaskNum!="") { if CurrentConfig.FlaskConfig[flaskNum].HasKey("OverrideFlaskDuration") EffectDuration:=CurrentConfig.FlaskConfig[flaskNum].OverrideFlaskDuration else EffectDuration:=FlasksData[flaskNum].EffectDuration if ((CurrentConfig.FlaskConfig[flaskNum].instantRecoveryOnLowLife) && ((PlayerStats.CurrHP/PlayerStats.MaxHP)<=0.35)) ; "Low life" can be caused by auras hp reservation from blood magic EffectDuration:=lagCompensation WindowQueuedFlaskEffects[k].hpQueueEndtime:=A_TickCount+EffectDuration*100 if (FlasksData[flaskNum].HasKey("ManaRegAmount")) ; hybrid flask WindowQueuedFlaskEffects[k].ManaQueueEndtime:=A_TickCount+EffectDuration*100 if (trayNotifications) { pname:=PlayerStats.Name TrayTip, PoE autoPotions sipping HP flask %flaskNum% on %pname%, %A_Space% , 2 } hKey:=CurrentConfig.FlaskConfig[flaskNum].Hotkey ControlSend,,%hkey%, % "ahk_id" hwnd break } } if (PlayerStats.MaxMana>0 && (currManaRatio<CurrentConfig.minManaRatioToDrink || PlayerStats.CurrMana<CurrentConfig.minManaToDrink)) if ((!WindowQueuedFlaskEffects[k].HasKey("ManaQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].ManaQueueEndtime-lagCompensation))) { tflaskNum1:=GetMaxChargesFlaskOfType(FlasksData,"FlaskMana") tflaskNum2:=GetMaxChargesFlaskOfType(FlasksData,"FlaskHybrid") if ((tflaskNum1!=) && (tflaskNum2!=)) flaskNum:=(FlasksData[tflaskNum1].ChargesCurrent>FlasksData[tflaskNum2].ChargesCurrent) ? tflaskNum1 : tflaskNum2 else { if (tflaskNum1!="") flaskNum:=tflaskNum1 if (tflaskNum2!="") flaskNum:=tflaskNum2 } if (flaskNum!="") { if CurrentConfig.FlaskConfig[flaskNum].HasKey("OverrideFlaskDuration") { EffectDuration:=CurrentConfig.FlaskConfig[flaskNum].OverrideFlaskDuration } else EffectDuration:=FlasksData[flaskNum].EffectDuration if ((CurrentConfig.FlaskConfig[flaskNum].instantRecoveryOnLowLife) && ((PlayerStats.CurrHP/PlayerStats.MaxHP)<=0.35)) EffectDuration:=lagCompensation WindowQueuedFlaskEffects[k].ManaQueueEndtime:=A_TickCount+EffectDuration*100 if (FlasksData[flaskNum].HasKey("HPRegAmount")) ; hybrid flask WindowQueuedFlaskEffects[k].hpQueueEndtime:=A_TickCount+EffectDuration*100 hKey:=CurrentConfig.FlaskConfig[flaskNum].Hotkey if (trayNotifications) { pname:=PlayerStats.Name TrayTip, PoE autoPotions sipping mana flask %flaskNum% on %pname%, %A_Space% , 2 } ControlSend,,%hkey%, % "ahk_id" hwnd break } } } if ((autoQuit=0) && (ThisID!="") && (ThisID!=WinActive("A"))) WinActivate, % "ahk_id" ThisID Sleep, %autoPotionsWatchdogPeriod% } F1:: global autoPotionsState global trayNotifications autoPotionsState:=not autoPotionsState if (trayNotifications) { if (autoPotionsState=true) TrayTip, PoE autoPotions is on, %A_Space% , 2 else TrayTip, PoE autoPotions is off, %A_Space% , 2 } return F2:: GetClientCoords(mx,my) GetFractionalCoords(fx,fy) msgbox, mx=%mx% my=%my% fx=%fx% fy=%fy% return F4:: QuitToLoginScreen(WinActive("A")) return
Last edited by kamil10; 11-24-2013 at 02:30 PM.
--deleted--
Last edited by MrJetLee; 11-25-2013 at 12:48 AM.
Anyone get this working to logout to character selection screen? I've been digging to see where I could change mouse pointer positions but it doesn't look like it works that way.
1.0.2
baseMgrPtr:=0x79bfc4
baseMgrPtr:=0x7a1090
STEAM 1.0.2