Jump to content

Join our Slack

Talk to other users and have a great time
Slack Server

Welcome to our Community

Click here to get your Exiled Bot license
Donation Store
alkpone

Wrongusername's Autoflask script updated (1.0.0d)

Recommended Posts

I used to look forward to game updates...now I dread them. Quit breaking our shit GGG! lol

you should suggest they make their software more botter friendly. I'm sure they will listen to you :P

Share this post


Link to post
Share on other sites

SORRY THIS LOGIC IS A WAIST and has been dropped

If you use 1920, 1080 resolution then this addon could enable pixel chicken for you.

Pots are not yet active, I'm considering how I want to write this to work on any resolution.

I'm just starting autohotkey.

Paist this code right after the AutoPotions() in the main loop located around line 47.

   ;Pixel Chicken addon
   ;roughly half life chicken, on 1920, 1080
   if(WinActive("Path of Exile")) {
      PixelGetColor pixelcolor, 118, 979
      red:= SubStr(pixelcolor, 7, 2)
      if (red< 141) { ;if life not extream red
         ;SoundBeep
         if(red<> 0) { ;if NOT zone hopping
            QuitToLoginScreen(WinActive("A"))
            ;SoundBeep
         } ;red NOT true black
      } ;red< 141
   } ;pixel chicken winactive()

Main Loop should now look like this:

Loop
{
   AutoPotions()
   ;Pixel Chicken addon
   ;roughly half life chicken, on 1920, 1080
   if(WinActive("Path of Exile")) {
      PixelGetColor pixelcolor, 118, 979
      red:= SubStr(pixelcolor, 7, 2)
      if (red< 141) { ;if life not extream red
         ;SoundBeep
         if(red<> 0) { ;if NOT zone hopping
            QuitToLoginScreen(WinActive("A"))
            ;SoundBeep
         } ;red NOT true black
      } ;red< 141
   } ;pixel chicken winactive()
}

SORRY THIS LOGIC IS A WAIST

This code should be dropped until we lose the HP, MP values in some future patch.

Then I'll revive the pixel sections.

Share this post


Link to post
Share on other sites

You may need to select 'Fullscreen WINDOW mode', from the options, graphics menu in game in order for pixel chicken addon to function correctly.

If you use 1920, 1080, resolution and this addon does not work for you, please let me know.

IGNORE b/c, Xandy dropped the code: Pixel Chicken Addon

Thank you Wrongusername, alkpone, and everyone else for your time.

Share this post


Link to post
Share on other sites

This code will use pots. I didn't test the mana section or implement any delay.

See the config section to preset the hotkey flask buttons to your flask type hotkeys

My example is from a 1life, 2life, 3granite, 4r/w, 5r/w

; - - - Modified by: Xandy
global life_pot:= object()
global granite_pot:= object()
global mana_pot:= object()
;config life potions
life_pot[0]:= 2		;life potion max
life_pot[1]:= 1		;life potion 1 hotkey value
life_pot[2]:= 2		;life potion 2 hotkey value

;config granite potions
granite_pot[0]:= 1	;granite potion max
granite_pot[1]:= 3	;granite potion 1 hotkey value

;config mana potions
mana_pot[0]:= 0	;mana potion max
mana_pot[1]:= 3	;mana potion 1 hotkey value

global life_potcur= 1 ; the potion to use cursor and index [0] holds the max
global granite_potcur= 1 ; the potion to use cursor and index [0] holds the max
global mana_potcur= 1 ; the potion to use cursor and index [0] holds the max
global life_potdelay= 200
global granite_potdelay= 200
global mana_potdelay= 200 ; 99 cents, bag it
; - - - END modified
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.85, minManaRatioToDrink: 0.55, minManaToDrink: 40, minLifeRatioToPopGranite: 0.79, minLifeRatioToQuit: 0.45} ;  disableAutoPotions:true, minLifeRatioToQuit:, minNShieldRatioToQuit: , HasZealotsOath: false, }
;PlayerConfig["Default"]:={minLifeRatioToDrink: 0.75, minManaRatioToDrink: 0.45, minManaToDrink: 0, minLifeRatioToPopGranite: 0.75, minLifeRatioToQuit: 0.10} ;  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:=0x785BB4 ; 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+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+0x8e8,0x900,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:=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)))
            {
               ; modified by: Xandy
               if(granite_pot[0]> 0) {
                  send % granite_pot[granite_potcur]
                  granite_potcur+= 1
                  if(granite_potcur> granite_pot[0])
                     granite_potcur= 1
               }
               ;end modified
               
               flaskNum:=GetMaxChargesFlaskOfType(FlasksData,"FlaskUtility5") ; granite flask
               ; rem'd next line, Xandy
               ;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)))
         {
            ;modified by: Xandy
            if(life_pot[0]> 0) {
               send % life_pot[life_potcur]
               life_potcur+= 1
               if(life_potcur> life_pot[0])
                  life_potcur= 1
            }
            ; END modified
                  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
                  }
                  ; rem'd next line, Xandy
                  ;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)))
         {
            ; modified by: Xandy
            if(mana_pot[0]> 0) {
               send % mana_pot[mana_potcur]
               mana_potcur+= 1
               if(mana_potcur> mana_pot[0])
                  mana_potcur= 1
            }
            ; END modified
               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
               }
               ; rem'd next line, Xandy
               ;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%   
}

F14::
   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

F15::
   GetClientCoords(mx,my)
   GetFractionalCoords(fx,fy)
   msgbox, mx=%mx% my=%my% fx=%fx% fy=%fy%
return

F4::
   QuitToLoginScreen(WinActive("A"))
return

Fixed my own updates a bit: 2

Share this post


Link to post
Share on other sites

works with my granite flask set to belt hotkey 3

;config granite

granite_pot[0]:= 1 ;how many granite potions in belt

granite_pot[1]:= 3 ; the key to send to trigger the granite flask from belt belt bel

EDIT: was missing the ':=' and it is required for the correct assignment !!!

Share this post


Link to post
Share on other sites

I just spliced some reasonable arrays and counters into somebody else's beautiful memory activated code.

My implementation is helpful to me b/c the correct offsets regarding the flasks are not being used and I don't have the skillz to sniff them out.

The timers are messed up and I'm working on releasing a better version. Thing is I'm doing a LAN party at my homies for the rest of the weekend, so this really isn't a good programming environment for me to learn AutoHotkey.

My example above works pretty well for me, but my lifers are instant heals, so idk how it'll work out for everyone.

EDIT: http://exiled-bot.net/forum/viewtopic.php?p=7504#p7504

I gave an example of granite flask config. It was wrong and has been corrected.

Note:

A friend of mine changes his belt hotkeys in game to Numpad0 and shit. If you changed your belt hotkeys to a key that cannot be represented by a single char string, then I'm not sure how to do that yet. If you use the default belt hotkeys (1, 2, 3, 4, 5) this should work fine.

Share this post


Link to post
Share on other sites

ok i got the granite flasks to work, but the granite flask delay is wayyyyy too high

i even set it for 4000ms and it uses both granite flasks and both charges in each in about 2 seconds

Share this post


Link to post
Share on other sites

Here it is working very nice with delays.

Sorry you'll need to re-config the script for your belt and make sure you use numeric hotkeys for flasks such as the default (1, 2, 3, 4, 5)

See: life_potdelay, granite_potdelay, mana_potdelay and feed the values milliseconds yum

; - - - Modified by: Xandy
global life_pot:= object()
global granite_pot:= object()
global mana_pot:= object()
;config life potions
life_pot[0]:= 2      ;life potion max
life_pot[1]:= 1      ;life potion 1 hotkey value
life_pot[2]:= 2      ;life potion 2 hotkey value

;config granite potions 
granite_pot[0]:= 0   ;granite potion max
granite_pot[1]:= 3   ;granite potion 1 hotkey value

;config mana potions
mana_pot[0]:= 2   ;mana potion max
mana_pot[1]:= 4   ;mana potion 1 hotkey value
mana_pot[2]:= 5   ;mana potion 1 hotkey value
global life_potdelay:= 200
global granite_potdelay:= 4000
global mana_potdelay:= 400 ; 99 cents, bag it

global life_potcur:= 1 ; the potion to use cursor and index [0] holds the max
global granite_potcur:= 1 ; the potion to use cursor and index [0] holds the max
global mana_potcur:= 1 ; the potion to use cursor and index [0] holds the max
global life_pottimer:= 0, granite_pottimer:= 0, mana_pottimer:= 0
; - - - END modified
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.85, minManaRatioToDrink: 0.55, minManaToDrink: 40, minLifeRatioToPopGranite: 0.79, minLifeRatioToQuit: 0.45} ;  disableAutoPotions:true, minLifeRatioToQuit:, minNShieldRatioToQuit: , HasZealotsOath: false, }
;PlayerConfig["Default"]:={minLifeRatioToDrink: 0.75, minManaRatioToDrink: 0.45, minManaToDrink: 0, minLifeRatioToPopGranite: 0.75, minLifeRatioToQuit: 0.10} ;  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:=0x785BB4 ; 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+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+0x8e8,0x900,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:=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)
       ;rem'd next line Xandy
         ;if ((!WindowQueuedFlaskEffects[k].HasKey("graniteQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].graniteQueueEndtime-lagCompensation)))
            {
            ; modified by: Xandy
            if(granite_pot[0]> 0) {
               if(granite_pottimer<= A_TickCount) {
                  send % granite_pot[granite_potcur]
                  granite_potcur+= 1
                  if(granite_potcur> granite_pot[0])
                     granite_potcur= 1
                  granite_pottimer:= A_TickCount+granite_potdelay
               }
               }
               ;end modified
               
               flaskNum:=GetMaxChargesFlaskOfType(FlasksData,"FlaskUtility5") ; granite flask
               ; rem'd next line, Xandy
               ;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))
      ; rem'd next line, Xandy
         ;if ((!WindowQueuedFlaskEffects[k].HasKey("hpQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].hpQueueEndtime-lagCompensation)))
         {
            ;modified by: Xandy
            if(life_pot[0]> 0) {
            if(life_pottimer<= A_TickCount) {
               send % life_pot[life_potcur]
               life_potcur+= 1
               if(life_potcur> life_pot[0])
                  life_potcur= 1
               life_pottimer:= A_TickCount+life_potdelay
            }
            }
            ; END modified
                  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
                  }
                  ; rem'd next line, Xandy
                  ;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
                  }
            }
      ; modified example inserted below remared line rem'd next line Xandy
      ;if (PlayerStats.MaxMana>0 && (currManaRatio<CurrentConfig.minManaRatioToDrink || PlayerStats.CurrMana<CurrentConfig.minManaToDrink))
      if (PlayerStats.MaxMana>0 && (currManaRatio<CurrentConfig.minManaRatioToDrink))      
      ; rem'd next line, Xandy
         ;if ((!WindowQueuedFlaskEffects[k].HasKey("ManaQueueEndtime")) || (A_TickCount>=(WindowQueuedFlaskEffects[k].ManaQueueEndtime-lagCompensation)))
         {
            ; modified by: Xandy
            if(mana_pot[0]> 0) {
            if(mana_pottimer<= A_TickCount) {
               send % mana_pot[mana_potcur]
               mana_potcur+= 1
               if(mana_potcur> mana_pot[0])
                  mana_potcur= 1
               mana_pottimer:= A_TickCount+mana_potdelay
            }
            }
            ; END modified
               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
               }
               ; rem'd next line, Xandy
               ;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%   
}

F14::
   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

F15::
   GetClientCoords(mx,my)
   GetFractionalCoords(fx,fy)
   msgbox, mx=%mx% my=%my% fx=%fx% fy=%fy%
return

F4::
   QuitToLoginScreen(WinActive("A"))
return
EDITED: Edited to function with reserved mana

EDITED: Edited back to low life, mana delays

Share this post


Link to post
Share on other sites

Works fine for me. Not sure. I re-copied the script to my post above.

To setup the config for your belt:

Open the script for editing, Notepad or whatever you do.

I'll be using this example belt: 1 HP pot, 2 HP, 3 GRANITE, 4 (run / walk unused), 5 (run / walk unused) ZERO MANAs

Find this code area under Xandy near the top of script.

;config life potions

life_pot[0]:= 2 ; <---<< I have 2 LIFE pots in my belt

life_pot[1]:= 1 ; The button to fire is 1 and

life_pot[2]:= 2 ; fire 2 after firing 1 then cycle back to 1

;config granite potions

granite_pot[0]:= 1 ; <---<< I have 1 GRANITE pot in my belt

granite_pot[1]:= 3 ; the button to fire is 3

;config mana potions

mana_pot[0]:= 0 ; <---<< I have zero mana pots in my belt

mana_pot[1]:= 1 ; this value should make no difference, but it is set to 1 and idc and left for example copy

mana_pot[2]:= 2 ; the following shows how you could have a belt of 5 mana pots

mana_pot[3]:= 3 ; ..

mana_pot[4]:= 4 ; ..

mana_pot[5]:= 5 ; but in the case of 5 mana pots index [0] would be 5

global life_potdelay= 2000 ; my pots are instant so this is only 200 for me

global granite_potdelay= 4000 ; Duration before re-drink granite

global mana_potdelay= 400 ; Duration before re-drink mana

Share this post


Link to post
Share on other sites

Modified my example above to (hopefully) work with reserved mana.

I tested it once it seemed to work, so I posted my changes.

I also changed some of the assignments to ':=" in the delay times, I didn't notice a difference, but maybe it will work MonsterHYS granite flasks idk.

Good luck.

Share this post


Link to post
Share on other sites

The auto chicken worked before any of my changes. What I tried to do was use the still working chicken to throw the hotkeys for flasks.

(If chicken still works then the memory for life must still be correct, eh?)

I made an array for life flasks, granite flasks, and mana. The first index stores the amount of flask type, while the following indexes store the button to activate the flask in game.

You can read how to configure the script (set the arrays) for your belt from my post above.

You can also tell me your flasks in belt, and I'll send you a personalized script tailored for you belt. If it still dosen't work though then idk.

I just started AutoHotkey like a week ago and partied for most of the week. I have been using this script everyday.

Also the script doesn't seem to work well on my low level chars, that doesn't make sense to me. Try it with higher level chars and remember each char needs to have the script tailored to his belt.

Share this post


Link to post
Share on other sites

My belt: Life, Life, Life, Mana, Mana

 

Real-life party? Cool! :D I only have Magic the Gathering tournaments :P.

 

About the low-level problem. Probably it is connected to the level of mana/life? The higher the level, the higher life/mana values - under some threshold script seems to not see the values properly.

 

I have other problem - sometimes script doesn't work, and sometimes it spams flasks like crazy.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...