All pastes #587755 Raw Edit

Something

public text v1 · immutable
#587755 ·published 2007-06-25 01:52 UTC
rendered paste body
using D2Data;
using D2Onion;
using D2Packets;
using D2Toolkit;
using D2Toolkit.Units;
using ETUtils;
using GameClient;
using GameServer;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace D2Toolkit.Modules
{
    public class GuardianEagle : D2Toolkit.IModule
    {
        private D2Toolkit.D2Instance d2;

        public bool Initialize(D2Toolkit.D2Instance d2)
        {
            this.d2 = d2;

            return true;
        }

        // <usercode> - User code starts here (don't remove this line!)
        public enum GuardianAction
        {
            None = 0,
            Healing = 1,
            Mana = 2,
            Rejuvenation = 3,
            FullRejuvenation = 4,
            TownPortal = 5,
            Chicken = 6,
        }

        private GuardianConfig config;

        public class GuardianConfig
        {
            public GuardConfig Ping = new GuardConfig();
            public GuardConfig Life = new GuardConfig();
            public GuardConfig Mana = new GuardConfig();
            public GuardConfig Merc = new GuardConfig();
            public GuardianHotkeysConfig Hotkeys = new GuardianHotkeysConfig();
            public GuardianDelaysConfig Delays = new GuardianDelaysConfig();
        }


        public class GuardConfig
        {
            public bool Watch;
            public int Healing;
            public int Mana;
            public int Rejuvenation;
            public int FullRejuvenation;
            public int TownPortal;
            public int Chicken;
            public GuardianAction NoHealing;
            public GuardianAction NoMana;
            public GuardianAction NoRejuvenation;
            public GuardianAction NoFullRejuvenation;
            public GuardianAction NoTownPortal;
            public GuardianAction TownPortalTimeout;
            public GuardianAction Death;
            public PotionType HealingPotions = PotionType.AnyHealing;
            public PotionType ManaPotions = PotionType.AnyMana;
            public FindPotionFlags FindPotionFlags;
            public bool IsMerc;
        }

        public class GuardianHotkeysConfig
        {
            public GameSound Healing = GameSound.None;
            public GameSound Mana = GameSound.None;
            public GameSound Rejuvenation = GameSound.None;
            public GameSound FullRejuvenation = GameSound.None;
            public GameSound TownPortal = GameSound.None;
            public GameSound Chicken = GameSound.None;
            public GameSound ToogleActive = GameSound.None;

            public GuardConfig Guard = new GuardConfig();
        }

        public class GuardianDelaysConfig
        {
            public TimeSpan AnyPotion = TimeSpan.FromMilliseconds(100);
            public TimeSpan Healing = TimeSpan.FromMilliseconds(300);
            public TimeSpan Mana = TimeSpan.FromMilliseconds(300);
            public TimeSpan Rejuvenation = TimeSpan.FromMilliseconds(500);
            public TimeSpan TakePortal = TimeSpan.Zero;
            public TimeSpan WaitForPortalTimeout = TimeSpan.FromMilliseconds(5000);
            public TimeSpan TakePortalTimeout = TimeSpan.FromMilliseconds(3000);
        }

        private PotionType ParsePotionType(string value)
        {
            PotionType retVal = PotionType.None;
            if (value == null || value.Length == 0)
                return retVal;

            string[] vals = StringUtils.RemoveWhiteSpace(value).Split(',', '|');
            for (int i = 0; i < vals.Length; i++)
                retVal |= (PotionType)Enum.Parse(typeof(PotionType), vals[i], true);

            return retVal;
        }

        private Keys ParseKeys(string value)
        {
            Keys retVal = Keys.None;
            if (value == null || value.Length == 0)
                return retVal;

            string[] vals = StringUtils.RemoveWhiteSpace(value).Split(',', '|');
            for (int i = 0; i < vals.Length; i++)
                retVal |= (Keys)Enum.Parse(typeof(Keys), vals[i], true);

            return retVal;
        }

        private TimeSpan ParseTimeSpan(string value, TimeSpan def)
        {
            if (value == null || value.Length == 0)
                return def;

            return TimeSpan.FromMilliseconds(Int32.Parse(value));
        }

        private void LoadConfig(string configPath)
        {
            Nini.Config.IniConfigSource source = new Nini.Config.IniConfigSource(configPath);
            source.Alias.AddAlias("Yes", true);
            source.Alias.AddAlias("No", false);
            source.Alias.AddAlias("On", true);
            source.Alias.AddAlias("Off", false);
            source.Alias.AddAlias("True", true);
            source.Alias.AddAlias("False", false);
            source.CaseSensitive = false;

            this.config = new GuardianConfig();
            Nini.Config.IConfig conf;

            if ((conf = source.Configs["Ping"]) != null)
            {
                this.config.Ping.Watch = conf.GetBoolean("Watch", false);
                if (conf.Contains("TownPortal"))
                    this.config.Ping.TownPortal = conf.GetInt("TownPortal");
                if (conf.Contains("Chicken"))
                    this.config.Ping.Chicken = conf.GetInt("Chicken");
                if (conf.Contains("NoTownPortal"))
                    this.config.Ping.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoTownPortal"));
                if (conf.Contains("TownPortalTimeout"))
                    this.config.Ping.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("TownPortalTimeout"));
            }
            else this.config.Ping.Watch = false;

            if ((conf = source.Configs["Life"]) != null)
            {
                this.config.Life.Watch = conf.GetBoolean("Watch", true);
                if (conf.Contains("Healing"))
                    this.config.Life.Healing = conf.GetInt("Healing");
                if (conf.Contains("Rejuvenation"))
                    this.config.Life.Rejuvenation = conf.GetInt("Rejuvenation");
                if (conf.Contains("FullRejuvenation"))
                    this.config.Life.FullRejuvenation = conf.GetInt("FullRejuvenation");
                if (conf.Contains("TownPortal"))
                    this.config.Life.TownPortal = conf.GetInt("TownPortal");
                if (conf.Contains("Chicken"))
                    this.config.Life.Chicken = conf.GetInt("Chicken");
                if (conf.Contains("NoHealing"))
                    this.config.Life.NoHealing = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoHealing"));
                if (conf.Contains("NoRejuvenation"))
                    this.config.Life.NoRejuvenation = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoRejuvenation"));
                if (conf.Contains("NoFullRejuvenation"))
                    this.config.Life.NoFullRejuvenation = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoFullRejuvenation"));
                if (conf.Contains("NoTownPortal"))
                    this.config.Life.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoTownPortal"));
                if (conf.Contains("TownPortalTimeout"))
                    this.config.Life.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("TownPortalTimeout"));
                if (conf.Contains("HealingPotions"))
                    this.config.Life.HealingPotions = (PotionType)StringUtils.ParseEnumFlags<PotionType>(
                        conf.GetString("HealingPotions"), PotionType.AnyHealing);
                if (conf.Contains("SmallestFirst") && conf.GetBoolean("SmallestFirst"))
                    this.config.Life.FindPotionFlags |= FindPotionFlags.SmallestFirst;
                if (!conf.Contains("FromBelt") || conf.GetBoolean("FromBelt"))
                    this.config.Life.FindPotionFlags |= FindPotionFlags.FromBelt;
                if (conf.Contains("FromInventory") && conf.GetBoolean("FromInventory"))
                    this.config.Life.FindPotionFlags |= FindPotionFlags.FromInventory;
                if (conf.Contains("FromBeltFirst") && conf.GetBoolean("FromBeltFirst"))
                    this.config.Life.FindPotionFlags |= FindPotionFlags.FromBeltFirst;
            }
            else this.config.Life.Watch = false;

            if ((conf = source.Configs["Mana"]) != null)
            {
                this.config.Mana.Watch = conf.GetBoolean("Watch", false);
                if (conf.Contains("Mana"))
                    this.config.Mana.Mana = conf.GetInt("Mana");
                if (conf.Contains("Rejuvenation"))
                    this.config.Mana.Rejuvenation = conf.GetInt("Rejuvenation");
                if (conf.Contains("FullRejuvenation"))
                    this.config.Mana.FullRejuvenation = conf.GetInt("FullRejuvenation");
                if (conf.Contains("TownPortal"))
                    this.config.Mana.TownPortal = conf.GetInt("TownPortal");
                if (conf.Contains("Chicken"))
                    this.config.Mana.Chicken = conf.GetInt("Chicken");
                if (conf.Contains("NoMana"))
                    this.config.Mana.NoMana = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoMana"));
                if (conf.Contains("NoRejuvenation"))
                    this.config.Mana.NoRejuvenation = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoRejuvenation"));
                if (conf.Contains("NoFullRejuvenation"))
                    this.config.Mana.NoFullRejuvenation = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoFullRejuvenation"));
                if (conf.Contains("NoTownPortal"))
                    this.config.Mana.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoTownPortal"));
                if (conf.Contains("TownPortalTimeout"))
                    this.config.Mana.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("TownPortalTimeout"));
                if (conf.Contains("ManaPotions"))
                    this.config.Life.ManaPotions = (PotionType)StringUtils.ParseEnumFlags<PotionType>(
                        conf.GetString("ManaPotions"), PotionType.AnyMana);
                if (conf.Contains("SmallestFirst") && conf.GetBoolean("SmallestFirst"))
                    this.config.Mana.FindPotionFlags |= FindPotionFlags.SmallestFirst;
                if (!conf.Contains("FromBelt") || conf.GetBoolean("FromBelt"))
                    this.config.Mana.FindPotionFlags |= FindPotionFlags.FromBelt;
                if (conf.Contains("FromInventory") && conf.GetBoolean("FromInventory"))
                    this.config.Mana.FindPotionFlags |= FindPotionFlags.FromInventory;
                if (conf.Contains("FromBeltFirst") && conf.GetBoolean("FromBeltFirst"))
                    this.config.Mana.FindPotionFlags |= FindPotionFlags.FromBeltFirst;
            }
            else this.config.Mana.Watch = false;

            if ((conf = source.Configs["Merc"]) != null)
            {
                this.config.Merc.Watch = conf.GetBoolean("Watch", false);
                if (conf.Contains("Healing"))
                    this.config.Merc.Healing = conf.GetInt("Healing");
                if (conf.Contains("Rejuvenation"))
                    this.config.Merc.Rejuvenation = conf.GetInt("Rejuvenation");
                if (conf.Contains("FullRejuvenation"))
                    this.config.Merc.FullRejuvenation = conf.GetInt("FullRejuvenation");
                if (conf.Contains("TownPortal"))
                    this.config.Merc.TownPortal = conf.GetInt("TownPortal");
                if (conf.Contains("Chicken"))
                    this.config.Merc.Chicken = conf.GetInt("Chicken");
                if (conf.Contains("NoHealing"))
                    this.config.Merc.NoHealing = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoHealing"));
                if (conf.Contains("NoRejuvenation"))
                    this.config.Merc.NoRejuvenation = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoRejuvenation"));
                if (conf.Contains("NoFullRejuvenation"))
                    this.config.Merc.NoFullRejuvenation = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoFullRejuvenation"));
                if (conf.Contains("NoTownPortal"))
                    this.config.Merc.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoTownPortal"));
                if (conf.Contains("TownPortalTimeout"))
                    this.config.Merc.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("TownPortalTimeout"));
                if (conf.Contains("Death"))
                    this.config.Merc.Death = StringUtils.ParseEnum<GuardianAction>(conf.GetString("Death"));
                if (conf.Contains("SmallestFirst") && conf.GetBoolean("SmallestFirst"))
                    this.config.Merc.FindPotionFlags |= FindPotionFlags.SmallestFirst;

                this.config.Merc.FindPotionFlags |= FindPotionFlags.FromBelt;
                this.config.Merc.IsMerc = true;
            }
            else this.config.Merc.Watch = false;

            if ((conf = source.Configs["Hotkeys"]) != null)
            {
                if (conf.Contains("ToogleActive"))
                    this.config.Hotkeys.ToogleActive =
                        StringUtils.ParseEnum<GameSound>(conf.GetString("ToogleActive"), GameSound.None);
                if (conf.Contains("Chicken"))
                    this.config.Hotkeys.Chicken =
                        StringUtils.ParseEnum<GameSound>(conf.GetString("Chicken"), GameSound.None);
                if (conf.Contains("TownPortal"))
                    this.config.Hotkeys.TownPortal =
                        StringUtils.ParseEnum<GameSound>(conf.GetString("TownPortal"), GameSound.None);
                if (conf.Contains("NoTownPortal"))
                    this.config.Hotkeys.Guard.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("NoTownPortal"));
                if (conf.Contains("TownPortalTimeout"))
                    this.config.Hotkeys.Guard.NoTownPortal = StringUtils.ParseEnum<GuardianAction>(conf.GetString("TownPortalTimeout"));
            }

            if ((conf = source.Configs["Delays"]) != null)
            {
                if (conf.Contains("AnyPotion"))
                    this.config.Delays.AnyPotion = ParseTimeSpan(conf.GetString("AnyPotion"), this.config.Delays.AnyPotion);
                if (conf.Contains("Healing"))
                    this.config.Delays.Healing = ParseTimeSpan(conf.GetString("Healing"), this.config.Delays.Healing);
                if (conf.Contains("Mana"))
                    this.config.Delays.Mana = ParseTimeSpan(conf.GetString("Mana"), this.config.Delays.Mana);
                if (conf.Contains("Rejuvenation"))
                    this.config.Delays.Rejuvenation = ParseTimeSpan(conf.GetString("Rejuvenation"), this.config.Delays.Rejuvenation);
                if (conf.Contains("TakePortal"))
                    this.config.Delays.TakePortal = ParseTimeSpan(conf.GetString("TakePortal"), this.config.Delays.TakePortal);
                if (conf.Contains("WaitForPortalTimeout"))
                    this.config.Delays.WaitForPortalTimeout = ParseTimeSpan(conf.GetString("WaitForPortalTimeout"), this.config.Delays.WaitForPortalTimeout);
                if (conf.Contains("TakePortalTimeout"))
                    this.config.Delays.TakePortalTimeout = ParseTimeSpan(conf.GetString("TakePortalTimeout"), this.config.Delays.TakePortalTimeout);
            }
        }

        private bool active = true;
        private bool tping;
        private DateTime anyPotionTimer;
        private DateTime healingTimer;
        private DateTime manaTimer;
        private DateTime rejuvenationTimer;

        public void Main()
        {
            this.anyPotionTimer = DateTime.Now - TimeSpan.FromDays(1);
            this.healingTimer = this.manaTimer = this.rejuvenationTimer = this.anyPotionTimer;

            string configPath = d2.ConfigPath + Path.DirectorySeparatorChar + "GuardianEagle.ini";
            if (!File.Exists(configPath))
            {
                d2.Output("GuardianEagle: could not find configuration file; aborting...");
                return;
            }
            this.LoadConfig(configPath);

            this.active = this.d2.Game != null;
            if (this.active)
            {
                d2.Game.Me.OnAssignMerc += this.onAssignMerc;
                if (d2.Game.Me.Merc != null)
                    d2.Game.Me.Merc.OnLifeChange += this.onMercLifeChange;
            }

            d2.AddInterceptor(GameServerPacket.GameHandshake, this.onGameHandshake);
            d2.AddInterceptor(GameClientPacket.SendCharacterSpeech, this.onSendCharacterSpeech);
            d2.AddListener(GameServerPacket.LifeManaChange, this.onLifeManaChange);
            d2.OnConnectionStateChange += new ConnectionStateChangeHandler(this.onConnectionStateChange);

            d2.WaitForConnection(ConnectionKind.Bnet, ConnectionState.Disconnected);

        }

        public void Dispose()
        {
            d2.RemoveInterceptor(GameServerPacket.GameHandshake, this.onGameHandshake);
            d2.RemoveInterceptor(GameClientPacket.SendCharacterSpeech, this.onSendCharacterSpeech);
            d2.RemoveListener(GameServerPacket.LifeManaChange, this.onLifeManaChange);
            d2.OnConnectionStateChange -= new ConnectionStateChangeHandler(this.onConnectionStateChange);
        }

        private void onConnectionStateChange(object source, ConnectionStateChangeArgs e)
        {
            if (e.Connection == ConnectionKind.Game && e.State == ConnectionState.Disconnected)
            {
                this.active = false;
            }
        }

        private void onGameHandshake(D2Packet d2p)
        {
            if (!this.active)
                d2.Game.Me.OnAssignMerc += this.onAssignMerc;

            this.active = true;
        }

        private void onAssignMerc(Me me, NPC merc)
        {
            merc.OnLifeChange += this.onMercLifeChange;
        }

        private void onSendCharacterSpeech(D2Packet d2p)
        {
            GameClient.SendCharacterSpeech p = d2p as GameClient.SendCharacterSpeech;

            if (p.Speech == config.Hotkeys.ToogleActive)
            {
                d2.Output(this.active ? "Pausing GuardianEagle..." : "Resuming GuardianEagle...");
                this.active = !this.active;
            }
            else if (p.Speech == config.Hotkeys.Chicken)
            {
                new Thread(this.hotkeyThread).Start(true);
            }
            else if (p.Speech == config.Hotkeys.TownPortal)
            {
                if (d2.Game.InTown)
                    d2.Output("Cannot TP while in town!");
                else
                    new Thread(this.hotkeyThread).Start(false);
            }
            else
                return;

            p.Block();
        }

        private void hotkeyThread(object isChicken)
        {
            this.Fly((bool)isChicken ? GuardianAction.Chicken : GuardianAction.TownPortal, config.Hotkeys.Guard, "Hotkey");
        }

        private void onMercLifeChange(PlayerNPCBase merc)
        {
            if (!this.active || d2.Game.InTown || this.tping)
                return;

            if (!config.Merc.Watch)
                return;

            if (merc.Life < 1)
            {
                this.Fly(config.Merc.Death, config.Merc, "Death");
                return;
            }

            int life = merc.LifePercent;

            if (config.Merc.Chicken > 0 && life < config.Merc.Chicken)
                this.Fly(GuardianAction.Chicken, config.Merc, "Life (" + life + ") < " + config.Merc.Chicken);
            else if (config.Merc.TownPortal > 0 && life < config.Merc.TownPortal)
                this.Fly(GuardianAction.TownPortal, config.Merc, "Life (" + life + ") < " + config.Merc.TownPortal);
            else
            {
                DateTime now = DateTime.Now;
                if (now - anyPotionTimer < config.Delays.AnyPotion)
                    return;

                if (now - rejuvenationTimer > config.Delays.Rejuvenation)
                {
                    if (config.Merc.FullRejuvenation > 0 && life < config.Merc.FullRejuvenation)
                    {
                        this.Fly(GuardianAction.FullRejuvenation, config.Merc, "Life (" + life + ") < " + config.Merc.FullRejuvenation);
                        return;
                    }
                    else if (config.Merc.Rejuvenation > 0 && life < config.Merc.Rejuvenation)
                    {
                        this.Fly(GuardianAction.Rejuvenation, config.Merc, "Life (" + life + ") < " + config.Merc.Rejuvenation);
                        return;
                    }
                }
                if (now - healingTimer > config.Delays.Healing)
                {
                    if (config.Merc.Healing > 0 && life < config.Merc.Healing)
                    {
                        this.Fly(GuardianAction.Healing, config.Merc, "Life (" + life + ") < " + config.Merc.Healing);
                        return;
                    }
                }
            }
        }

        private void onLifeManaChange(D2Packet d2p)
        {
            if (!this.active || d2.Game.InTown || this.tping)
                return;

            int life = d2.Game.Me.LifePercent;
            int mana = d2.Game.Me.ManaPercent;

            if (config.Life.Watch && config.Life.Chicken > 0 && life < config.Life.Chicken)
                this.Fly(GuardianAction.Chicken, config.Life, "Life (" + life + ") < " + config.Life.Chicken);
            else if (config.Mana.Watch && config.Mana.Chicken > 0 && mana < config.Mana.Chicken)
                this.Fly(GuardianAction.Chicken, config.Mana, "Mana (" + mana + ") < " + config.Mana.Chicken);
            else if (config.Life.Watch && config.Life.TownPortal > 0 && life < config.Life.TownPortal)
                this.Fly(GuardianAction.TownPortal, config.Life, "Life (" + life + ") < " + config.Life.TownPortal);
            else if (config.Mana.Watch && config.Mana.TownPortal > 0 && mana < config.Mana.TownPortal)
                this.Fly(GuardianAction.TownPortal, config.Mana, "Mana (" + mana + ") < " + config.Mana.TownPortal);
            else
            {
                DateTime now = DateTime.Now;
                if (now - anyPotionTimer < config.Delays.AnyPotion)
                    return;

                if (now - rejuvenationTimer > config.Delays.Rejuvenation)
                {
                    if (config.Life.Watch && config.Life.FullRejuvenation > 0 && life < config.Life.FullRejuvenation)
                    {
                        this.Fly(GuardianAction.FullRejuvenation, config.Life, "Life (" + life + ") < " + config.Life.FullRejuvenation);
                        return;
                    }
                    else if (config.Mana.Watch && config.Mana.FullRejuvenation > 0 && mana < config.Mana.FullRejuvenation)
                    {
                        this.Fly(GuardianAction.FullRejuvenation, config.Mana, "Mana (" + mana + ") < " + config.Mana.FullRejuvenation);
                        return;
                    }
                    else if (config.Life.Watch && config.Life.Rejuvenation > 0 && life < config.Life.Rejuvenation)
                    {
                        this.Fly(GuardianAction.Rejuvenation, config.Life, "Life (" + life + ") < " + config.Life.Rejuvenation);
                        return;
                    }
                    else if (config.Mana.Watch && config.Mana.Rejuvenation > 0 && mana < config.Mana.Rejuvenation)
                    {
                        this.Fly(GuardianAction.Rejuvenation, config.Mana, "Mana (" + mana + ") < " + config.Mana.Rejuvenation);
                        return;
                    }
                }
                if (now - healingTimer > config.Delays.Healing)
                {
                    if (config.Life.Watch && config.Life.Healing > 0 && life < config.Life.Healing)
                    {
                        this.Fly(GuardianAction.Healing, config.Life, "Life (" + life + ") < " + config.Life.Healing);
                        return;
                    }
                }
                if (now - manaTimer > config.Delays.Mana)
                {
                    if (config.Mana.Watch && config.Mana.Mana > 0 && mana < config.Mana.Mana)
                    {
                        this.Fly(GuardianAction.Mana, config.Mana, "Mana (" + mana + ") < " + config.Mana.Mana);
                        return;
                    }
                }
            }
        }


        private void Fly(GuardianAction action, GuardConfig g, string source)
        {
            if (action == GuardianAction.None)
                return;

            d2.Output("Fly(): ", action, " : ", (g.IsMerc ? "Merc " : ""), source);

            switch (action)
            {
                case GuardianAction.Chicken:
                    d2.Output("Chickening!");
                    d2.Game.Exit();
                    break;
                case GuardianAction.TownPortal:
                    if (!d2.Game.Me.CastTP())
                    {
                        d2.Output("Out of TPs!");
                        this.Fly(g.NoTownPortal, g, "Fallback");
                    }
                    else
                    {
                        d2.Output("Screw you guys, I'm going home...");
                        if (!this.TownTP())
                            this.Fly(g.TownPortalTimeout, g, "Fallback");
                    }
                    break;
                case GuardianAction.FullRejuvenation:
                    if (!this.d2.Game.Me.DrinkPotion(PotionType.FullRejuvenation, g.IsMerc, g.FindPotionFlags))
                        this.Fly(g.NoFullRejuvenation, g, "Fallback");
                    else
                    {
                        anyPotionTimer = rejuvenationTimer = DateTime.Now;
                        d2.Output("Drank a Full Rejuvenation potion.");
                    }
                    break;
                case GuardianAction.Rejuvenation:
                    if (!this.d2.Game.Me.DrinkPotion(PotionType.Rejuvenation, g.IsMerc, g.FindPotionFlags))
                        this.Fly(g.NoRejuvenation, g, "Fallback");
                    else
                    {
                        anyPotionTimer = rejuvenationTimer = DateTime.Now;
                        d2.Output("Drank a Rejuvenation potion.");
                    }
                    break;
                case GuardianAction.Healing:
                    if (!this.d2.Game.Me.DrinkPotion(g.HealingPotions, g.IsMerc, g.FindPotionFlags))
                        this.Fly(g.NoHealing, g, "Fallback");
                    else
                    {
                        anyPotionTimer = healingTimer = DateTime.Now;
                        d2.Output("Drank a Healing potion.");
                    }
                    break;
                case GuardianAction.Mana:
                    if (!this.d2.Game.Me.DrinkPotion(g.ManaPotions, g.IsMerc, g.FindPotionFlags))
                        this.Fly(g.NoMana, g, "Fallback");
                    else
                    {
                        anyPotionTimer = manaTimer = DateTime.Now;
                        d2.Output("Drank a Mana potion.");
                    }
                    break;
            }
        }

        public bool TownTP()
        {
            this.tping = true;

            DateTime start = DateTime.Now;
            while (true)
            {
                if (this.d2.Game.Me.TownPortal != null)
                    break;

                if (DateTime.Now - start > this.config.Delays.WaitForPortalTimeout)
                {
                    d2.Output("Timed out out while waiting for TP...");
                    this.tping = false;
                    return false;
                }

                Thread.Sleep(1);
            }

            if (this.config.Delays.TakePortal > TimeSpan.Zero)
                Thread.Sleep(this.config.Delays.TakePortal);

            d2.SendToGameServer(GameClient.UnitInteract.Build(
                UnitType.GameObject, this.d2.Game.Me.TownPortal.CurrentSide.UID));

            start = DateTime.Now;
            while (true)
            {
                if (d2.Game.Me.States.Contains(StateType.JustPortaled))
                {
                    this.tping = false;
                    return true;
                }

                if (DateTime.Now - start > this.config.Delays.TakePortalTimeout)
                {
                    d2.Output("Timed out out while taking TP...");
                    this.tping = false;
                    return false;
                }

                Thread.Sleep(1);
            }
        }

        // </usercode> - User code ends here (don't remove this line!)

    }
}