I added quicksilver support to the autoflask plugin
Copy this over the corresponding files in {your Exilebuddy folder}/plugins/autoflask.
AutoFlask.cs
AutoFlaskSettings.cs
SettingsGui.xaml
I might add support for other flasks later.

Copy this over the corresponding files in {your Exilebuddy folder}/plugins/autoflask.
AutoFlask.cs
Code:
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
using log4net;
using System;
using Loki.Bot;
using Loki.Game;
using Loki.Game.GameData;
using Loki.Game.Objects;
using Loki.Game.Objects.Items;
using Loki.Utilities;
namespace AutoFlask
{
internal class AutoFlask : IPlugin
{
private static readonly ILog Log = Logger.GetLoggerInstanceForType();
private readonly Stopwatch _lifeFlaskCd = new Stopwatch();
private readonly Stopwatch _manaFlaskCd = new Stopwatch();
private readonly Stopwatch _quicksilverFlaskCd = new Stopwatch();
#region Implementation of IPlugin
/// <summary> The name of the plugin. </summary>
public string Name
{
get { return "AutoFlask"; }
}
/// <summary> The description of the plugin. </summary>
public string Description
{
get { return "A plugin that provides auto-flask use."; }
}
/// <summary>The author of the plugin.</summary>
public string Author
{
get { return "Bossland GmbH"; }
}
/// <summary>The version of the plugin.</summary>
public Version Version
{
get { return new Version(0, 0, 1, 2); }
}
/// <summary>Initializes this plugin.</summary>
public void Initialize()
{
Log.DebugFormat("[AutoFlask] Initialize");
}
/// <summary> The plugin start callback. Do any initialization here. </summary>
public void Start()
{
Log.DebugFormat("[AutoFlask] Start");
}
private bool FlaskHelper(Stopwatch sw, int flaskCdMs, IEnumerable<Item> flasks)
{
var useFlask = false;
if (!sw.IsRunning)
{
sw.Start();
useFlask = true;
}
else if (sw.ElapsedMilliseconds > Utility.LatencySafeValue(flaskCdMs))
{
sw.Restart();
useFlask = true;
}
if (useFlask)
{
var flask = flasks.FirstOrDefault();
if (flask != null)
{
var err = LokiPoe.InGameState.QuickFlaskPanel.UseFlask(flask);
if (err != LokiPoe.InGameState.UseFlaskError.None)
{
Log.ErrorFormat("[FlaskHelper] QuickFlaskPanel.UseFlask returned {0}.", err);
}
return true;
}
}
return false;
}
/// <summary> The plugin tick callback. Do any update logic here. </summary>
public void Tick()
{
if (!LokiPoe.IsInGame || LokiPoe.Me.IsInTown || LokiPoe.Me.IsDead)
return;
// Life
if (LokiPoe.Me.HealthPercent < AutoFlaskSettings.Instance.HpFlaskPercentTrigger &&
!LokiPoe.Me.IsUsingHealthFlask)
{
if (FlaskHelper(_lifeFlaskCd, AutoFlaskSettings.Instance.HpFlaskCooldownMs, LifeFlasks))
{
return;
}
}
// Mana
if (LokiPoe.Me.ManaPercent < AutoFlaskSettings.Instance.MpFlaskPercentTrigger &&
!LokiPoe.Me.IsUsingManaFlask)
{
if (FlaskHelper(_manaFlaskCd, AutoFlaskSettings.Instance.MpFlaskCooldownMs, ManaFlasks))
{
// ReSharper disable once RedundantJumpStatement
return;
}
}
// Quicksilver
var monsters =
LokiPoe.ObjectManager.GetObjectsByType<Monster>()
.Where(m => m.IsActive)
.OrderBy(m => m.Distance).ToList();
if (!LokiPoe.Me.IsUsingQuicksilverFlask &&
!monsters.Any(m => m.IsActive && m.Distance < AutoFlaskSettings.Instance.QuicksilverMinimumMonsterDistance))
{
if (FlaskHelper(_quicksilverFlaskCd, AutoFlaskSettings.Instance.QuicksilverFlaskCooldownMs, QuicksilverFlasks))
{
return;
}
}
}
/// <summary> The plugin stop callback. Do any pre-dispose cleanup here. </summary>
public void Stop()
{
Log.DebugFormat("[AutoFlask] Stop");
}
public JsonSettings Settings
{
get { return AutoFlaskSettings.Instance; }
}
/// <summary> The routine's settings control. This will be added to the Exilebuddy Settings tab.</summary>
public UserControl Control
{
get
{
using (var fs = new FileStream(@"Plugins\AutoFlask\SettingsGui.xaml", FileMode.Open))
{
var root = (UserControl) XamlReader.Load(fs);
// Your settings binding here.
if (
!Wpf.SetupTextBoxBinding(root, "HpFlaskPercentTriggerTextBox", "HpFlaskPercentTrigger",
BindingMode.TwoWay, AutoFlaskSettings.Instance))
{
Log.DebugFormat(
"[SettingsControl] SetupTextBoxBinding failed for 'HpFlaskPercentTriggerTextBox'.");
throw new Exception("The SettingsControl could not be created.");
}
if (
!Wpf.SetupTextBoxBinding(root, "MpFlaskPercentTriggerTextBox", "MpFlaskPercentTrigger",
BindingMode.TwoWay, AutoFlaskSettings.Instance))
{
Log.DebugFormat(
"[SettingsControl] SetupTextBoxBinding failed for 'MpFlaskPercentTriggerTextBox'.");
throw new Exception("The SettingsControl could not be created.");
}
if (!Wpf.SetupTextBoxBinding(root, "HpFlaskCooldownMsTextBox", "HpFlaskCooldownMs",
BindingMode.TwoWay, AutoFlaskSettings.Instance))
{
Log.DebugFormat("[SettingsControl] SetupTextBoxBinding failed for 'HpFlaskCooldownMsTextBox'.");
throw new Exception("The SettingsControl could not be created.");
}
if (!Wpf.SetupTextBoxBinding(root, "MpFlaskCooldownMsTextBox", "MpFlaskCooldownMs",
BindingMode.TwoWay, AutoFlaskSettings.Instance))
{
Log.DebugFormat("[SettingsControl] SetupTextBoxBinding failed for 'MpFlaskCooldownMsTextBox'.");
throw new Exception("The SettingsControl could not be created.");
}
//quicksilver bindings
if (!Wpf.SetupTextBoxBinding(root, "QuicksilverFlaskCooldownMsTextBox", "QuicksilverFlaskCooldownMs",
BindingMode.TwoWay, AutoFlaskSettings.Instance))
{
Log.DebugFormat("[SettingsControl] SetupTextBoxBinding failed for 'QuicksilverFlaskCooldownMsTextBox'.");
throw new Exception("The SettingsControl could not be created.");
}
if (!Wpf.SetupTextBoxBinding(root, "QuicksilverMinimumMonsterDistanceTextBox", "QuicksilverMinimumMonsterDistance",
BindingMode.TwoWay, AutoFlaskSettings.Instance))
{
Log.DebugFormat("[SettingsControl] SetupTextBoxBinding failed for 'QuicksilverMinimumMonsterDistanceTextBox'.");
throw new Exception("The SettingsControl could not be created.");
}
// Your settings event handlers here.
return root;
}
}
}
/// <summary> The plugin is being enabled.</summary>
public void OnEnable()
{
Log.DebugFormat("[AutoFlask] OnEnable");
}
/// <summary> The plugin is being disabled.</summary>
public void OnDisable()
{
Log.DebugFormat("[AutoFlask] OnDisable");
}
#endregion
#region Implementation of IDisposable
/// <summary> </summary>
public void Dispose()
{
}
#endregion
#region Override of Object
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Name + ": " + Description;
}
#endregion
/// <summary>All life restoring flasks that are non-unique.</summary>
public static IEnumerable<Item> LifeFlasks
{
get
{
var inv = LokiPoe.InGameState.QuickFlaskPanel.Flasks;
return from item in inv
let flask = item as Flask
where flask != null && flask.Rarity != Rarity.Unique && flask.HealthRecover > 0 && flask.CanUse
orderby flask.CurrentCharges descending
select item;
}
}
/// <summary>All mana restoring flasks that are non-unique.</summary>
public static IEnumerable<Item> ManaFlasks
{
get
{
var inv = LokiPoe.InGameState.QuickFlaskPanel.Flasks;
return from item in inv
let flask = item as Flask
where flask != null && flask.Rarity != Rarity.Unique && flask.ManaRecover > 0 && flask.CanUse
orderby flask.CurrentCharges descending
select item;
}
}
/// <summary>All quicksilver flasks that are non-unique.</summary>
public static IEnumerable<Item> QuicksilverFlasks
{
get
{
var inv = LokiPoe.InGameState.QuickFlaskPanel.Flasks;
return from item in inv
let flask = item as Flask
where flask != null && flask.Rarity != Rarity.Unique && flask.Name == "Quicksilver Flask" && flask.CanUse
orderby flask.CurrentCharges descending
select item;
}
}
}
}
AutoFlaskSettings.cs
Code:
using System.ComponentModel;
using Loki.Bot.Settings;
using Loki.Utilities;
namespace AutoFlask
{
/// <summary>Settings for the AutoFlask. </summary>
public class AutoFlaskSettings : JsonSettings
{
private static AutoFlaskSettings _instance;
/// <summary>The current instance for this class. </summary>
public static AutoFlaskSettings Instance
{
get { return _instance ?? (_instance = new AutoFlaskSettings()); }
}
/// <summary>The default ctor. Will use the settings path "AutoFlask".</summary>
public AutoFlaskSettings()
: base(GetSettingsFilePath(Configuration.Instance.Name, string.Format("{0}.json", "AutoFlask")))
{
// Setup defaults here if needed for properties that don't support DefaultValue.
}
private int _hpFlaskPercentTrigger;
private int _mpFlaskPercentTrigger;
private int _quicksilverMinimumMonsterDistance;
private int _hpFlaskCooldownMs;
private int _mpFlaskCooldownMs;
private int _quicksilverFlaskCooldownMs;
private bool _useFrozenFlasks;
private bool _useBleedingFlasks;
private bool _useShockedFlasks;
private bool _useBurningFlasks;
private int _frozenFlaskCooldownMs;
private int _bleedingFlaskCooldownMs;
private int _shockedFlaskCooldownMs;
private int _burningFlaskCooldownMs;
/// <summary>Should the bot use this type of flask under a status effect?</summary>
[DefaultValue(false)]
public bool UseFrozenFlasks
{
get { return _useFrozenFlasks; }
set
{
if (value.Equals(_useFrozenFlasks))
{
return;
}
_useFrozenFlasks = value;
NotifyPropertyChanged(() => UseFrozenFlasks);
}
}
/// <summary>Should the bot use this type of flask under a status effect?</summary>
[DefaultValue(true)]
public bool UseBleedingFlasks
{
get { return _useBleedingFlasks; }
set
{
if (value.Equals(_useBleedingFlasks))
{
return;
}
_useBleedingFlasks = value;
NotifyPropertyChanged(() => UseBleedingFlasks);
}
}
/// <summary>Should the bot use this type of flask under a status effect?</summary>
[DefaultValue(false)]
public bool UseShockedFlasks
{
get { return _useShockedFlasks; }
set
{
if (value.Equals(_useShockedFlasks))
{
return;
}
_useShockedFlasks = value;
NotifyPropertyChanged(() => UseShockedFlasks);
}
}
/// <summary>Should the bot use this type of flask under a status effect?</summary>
[DefaultValue(false)]
public bool UseBurningFlasks
{
get { return _useBurningFlasks; }
set
{
if (value.Equals(_useBurningFlasks))
{
return;
}
_useBurningFlasks = value;
NotifyPropertyChanged(() => UseBurningFlasks);
}
}
/// <summary>The hard cooldown the bot will wait before using another flask.</summary>
[DefaultValue(250)]
public int HpFlaskCooldownMs
{
get { return _hpFlaskCooldownMs; }
set
{
if (value.Equals(_hpFlaskCooldownMs))
{
return;
}
_hpFlaskCooldownMs = value;
NotifyPropertyChanged(() => HpFlaskCooldownMs);
}
}
/// <summary>The hard cooldown the bot will wait before using another flask.</summary>
[DefaultValue(250)]
public int MpFlaskCooldownMs
{
get { return _mpFlaskCooldownMs; }
set
{
if (value.Equals(_mpFlaskCooldownMs))
{
return;
}
_mpFlaskCooldownMs = value;
NotifyPropertyChanged(() => MpFlaskCooldownMs);
}
}
/// <summary>The hard cooldown the bot will wait before using another flask.</summary>
[DefaultValue(5000)]
public int QuicksilverFlaskCooldownMs
{
get { return _quicksilverFlaskCooldownMs; }
set
{
if (value.Equals(_quicksilverFlaskCooldownMs))
{
return;
}
_quicksilverFlaskCooldownMs = value;
NotifyPropertyChanged(() => QuicksilverFlaskCooldownMs);
}
}
/// <summary>The hard cooldown the bot will wait before using another flask.</summary>
[DefaultValue(250)]
public int FrozenFlaskCooldownMs
{
get { return _frozenFlaskCooldownMs; }
set
{
if (value.Equals(_frozenFlaskCooldownMs))
{
return;
}
_frozenFlaskCooldownMs = value;
NotifyPropertyChanged(() => FrozenFlaskCooldownMs);
}
}
/// <summary>The hard cooldown the bot will wait before using another flask.</summary>
[DefaultValue(250)]
public int BleedingFlaskCooldownMs
{
get { return _bleedingFlaskCooldownMs; }
set
{
if (value.Equals(_bleedingFlaskCooldownMs))
{
return;
}
_bleedingFlaskCooldownMs = value;
NotifyPropertyChanged(() => BleedingFlaskCooldownMs);
}
}
/// <summary>The hard cooldown the bot will wait before using another flask.</summary>
[DefaultValue(250)]
public int ShockedFlaskCooldownMs
{
get { return _shockedFlaskCooldownMs; }
set
{
if (value.Equals(_shockedFlaskCooldownMs))
{
return;
}
_shockedFlaskCooldownMs = value;
NotifyPropertyChanged(() => ShockedFlaskCooldownMs);
}
}
/// <summary>The hard cooldown the bot will wait before using another flask.</summary>
[DefaultValue(250)]
public int BurningFlaskCooldownMs
{
get { return _burningFlaskCooldownMs; }
set
{
if (value.Equals(_burningFlaskCooldownMs))
{
return;
}
_burningFlaskCooldownMs = value;
NotifyPropertyChanged(() => BurningFlaskCooldownMs);
}
}
/// <summary>The % to trigger hp flasks.</summary>
[DefaultValue(90)]
public int HpFlaskPercentTrigger
{
get { return _hpFlaskPercentTrigger; }
set
{
if (value.Equals(_hpFlaskPercentTrigger))
{
return;
}
_hpFlaskPercentTrigger = value;
NotifyPropertyChanged(() => HpFlaskPercentTrigger);
}
}
/// <summary>The % to trigger mp flasks.</summary>
[DefaultValue(75)]
public int MpFlaskPercentTrigger
{
get { return _mpFlaskPercentTrigger; }
set
{
if (value.Equals(_mpFlaskPercentTrigger))
{
return;
}
_mpFlaskPercentTrigger = value;
NotifyPropertyChanged(() => MpFlaskPercentTrigger);
}
}
/// <summary>The % to trigger mp flasks.</summary>
[DefaultValue(100)]
public int QuicksilverMinimumMonsterDistance
{
get { return _quicksilverMinimumMonsterDistance; }
set
{
if (value.Equals(_quicksilverMinimumMonsterDistance))
{
return;
}
_quicksilverMinimumMonsterDistance = value;
NotifyPropertyChanged(() => QuicksilverMinimumMonsterDistance);
}
}
}
}
SettingsGui.xaml
Code:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="440" d:DesignWidth="627">
<Grid x:Name="Root">
<Grid.Resources>
<Style TargetType="Label" x:Key="TitleLabel">
<Setter Property="Margin" Value="15,0,0,0"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<Style TargetType="Label" x:Key="Label">
<Setter Property="Margin" Value="15,0,0,0"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<Style TargetType="TextBox" x:Key="TextBox">
<Setter Property="Margin" Value="3"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#333333"/>
<Setter Property="BorderBrush" Value="black"/>
</Style>
</Grid.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="30"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" MinWidth="50" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" MinWidth="50" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" MinWidth="50" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- life flask support -->
<Label Grid.Row="0" Grid.Column="0" Style="{StaticResource TitleLabel}" Content="Life Flask"/>
<Label Grid.Row="1" Grid.Column="0" Style="{StaticResource Label}" Content="Trigger (%): " ToolTipService.ToolTip="The % life your character has to be at to trigger health flasks."/>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="HpFlaskPercentTriggerTextBox" Style="{StaticResource TextBox}"/>
<Label Grid.Row="2" Grid.Column="0" Style="{StaticResource Label}" Content="Cooldown (ms): " ToolTipService.ToolTip="The hard cooldown the bot will wait before using another flask."/>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="HpFlaskCooldownMsTextBox" Style="{StaticResource TextBox}"/>
<!-- mana flask support -->
<Label Grid.Row="0" Grid.Column="2" Style="{StaticResource TitleLabel}" Content="Mana Flask"/>
<Label Grid.Row="1" Grid.Column="2" Style="{StaticResource Label}" Content="Trigger (%): " ToolTipService.ToolTip="The % mana your character has to be at to trigger mana flasks."/>
<TextBox Grid.Row="1" Grid.Column="3" x:Name="MpFlaskPercentTriggerTextBox" Style="{StaticResource TextBox}"/>
<Label Grid.Row="2" Grid.Column="2" Style="{StaticResource Label}" Content="Cooldown (ms): " ToolTipService.ToolTip="The hard cooldown the bot will wait before using another flask."/>
<TextBox Grid.Row="2" Grid.Column="3" x:Name="MpFlaskCooldownMsTextBox" Style="{StaticResource TextBox}"/>
<!-- quicksilver support -->
<Label Grid.Row="0" Grid.Column="4" Style="{StaticResource TitleLabel}" Content="Quicksilver Flask"/>
<Label Grid.Row="1" Grid.Column="4" Style="{StaticResource Label}" Content="Min. monster distance: " ToolTipService.ToolTip="The minimum distance between the character and a monster to trigger the use of a quicksilver flask."/>
<TextBox Grid.Row="1" Grid.Column="5" x:Name="QuicksilverMinimumMonsterDistanceTextBox" Style="{StaticResource TextBox}"/>
<Label Grid.Row="2" Grid.Column="4" Style="{StaticResource Label}" Content="Cooldown (ms): " ToolTipService.ToolTip="The hard cooldown the bot will wait before using another flask."/>
<TextBox Grid.Row="2" Grid.Column="5" x:Name="QuicksilverFlaskCooldownMsTextBox" Style="{StaticResource TextBox}"/>
</Grid>
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
I might add support for other flasks later.