What's new
  • Visit Rebornbuddy
  • Visit Resources
  • Visit API Documentation
  • Visit Downloads
  • Visit Portal
  • Visit Panda Profiles
  • Visit LLamamMagic

Any way to get bot to use granite flask? I would stay alive sooo much more.

juicypoonany

New Member
Joined
Aug 15, 2012
Messages
18
Reaction score
0
2 things,

1. If I can set bot to use my granite flask when it is vs 6 or more mobs...
And
2. If I can get my bot to use my instant heal health potions more.. It uses them fine for a bit during the combat, then I just watch it use them slowly and die, even though they are instant heal, can I have it so it continuously spams them when he goes under 20 % life or something?

If someone can make this for me, I will give them a big tip on the game, 5 exalted! TY!
 
The problem I have with using Granites right now, is that I have no solid way to tell *when* we should be using them. Sure, low life. But sometimes we get hit once, and then pop a life flask, making the granite basically wasteful if we use it. (Think on Piety, getting hit by 1 ice spear, and then hiding, you wouldn't pop a granite for that)

If you guys want to give me a decent list of alternative conditions, I'd be happy to add it to Exile.
 
By taking a quick look at an unedited version of Apoc's Ranger Routine we can do some really quick psudo coding and figure out what exactly we need to do.

1. Getting Granite Flasks to be Used
First off, let's look at the IEnum that defines Granite Flasks and how the routine checks to see if a flask is in use or not.
Code:
private IEnumerable<InventoryItem> GraniteFlasks
        {
            get
            {
                IEnumerable<InventoryItem> inv = LokiPoe.Me.Inventory.Flasks.Items;
                return from item in inv
                    let flask = item.Flask
                    where flask != null && item.Name == "Granite Flask" && flask.CanUse
                    select item;
            }
        }
Code:
private Player Me { get { return LokiPoe.Me; } }

private Player Me { get { return LokiPoe.Me; } }

        private Composite CreateFlaskLogic()
        {
            return new PrioritySelector(
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 80 && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_life"),
                    new Action(ret =>
                    {
                        LifeFlasks.First().Use();
                        _flaskCd.Reset();
                    })),
                new Decorator(ret => _flaskCd.IsFinished && Me.ManaPercent < 50 && ManaFlasks.Count() != 0 && !Me.HasAura("flask_effect_mana"),
                    new Action(ret =>
                    {
                        ManaFlasks.First().Use();
                        _flaskCd.Reset();
                    }))
                );
        }

As you may or may not have noticed popping granite flasks is not implemented in the combat routine. So let's do a bit of quick copypasta.
Code:
private Composite CreateFlaskLogic()
        {
            return new PrioritySelector(
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 80 && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_life"),
                    new Action(ret =>
                    {
                        LifeFlasks.First().Use();
                        _flaskCd.Reset();
                    })),
                new Decorator(ret => _flaskCd.IsFinished && Me.ManaPercent < 50 && ManaFlasks.Count() != 0 && !Me.HasAura("flask_effect_mana"),
                    new Action(ret =>
                    {
                        ManaFlasks.First().Use();
                        _flaskCd.Reset();
                    }))
                );
        }
Looking within the function we can assume that the following is psudo plausible:
Code:
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 80 && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_granite"),
                    new Action(ret =>
                    {
                        GraniteFlasks.First().Use();
                        _flaskCd.Reset();
                    })),
This portion determines when the flask is viable;
Code:
_flaskCd.IsFinished && Me.HealthPercent < 80 && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_granite")
  • Is current flask finished
  • Is the character's HP less than 80%
  • Does the character NOT have the granite flask effect applied?
There are two conditions that we can choose to apply, one which are; how many mobs are nearby and how far away they are.
Code:
&& NumberOfMobsNear(STRING, INT, INT)
Code:
&& MainTarget.Distance [comparer] INT)

So let's say that we want to be semi-paranoid about ranged monsters but that our focus should go to melee mobs.
Code:
&& NumberOfMobsNear(MainTarget, 20, 1) && MainTarget.Distance < 5)
These two conditions will only trigger if BOTH of them are true, so there are several monsters nearby that are within the range of 5 units.

So now we can go back up to our psudo granite flask logic and add our new conditions to the existing ones
Code:
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 80 && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_granite") && NumberOfMobsNear(MainTarget, 20, 1) && MainTarget.Distance < 5),
                    new Action(ret =>
                    {
                        GraniteFlasks.First().Use();
                        _flaskCd.Reset();
                    })),

2. Establishing a panic condition for low life situations.
The code provided by the flask logic function:
Code:
        private Composite CreateFlaskLogic()
        {
            return new PrioritySelector(
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 80 && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_life"),
                    new Action(ret =>
                    {
                        LifeFlasks.First().Use();
                        _flaskCd.Reset();
                    })),
                new Decorator(ret => _flaskCd.IsFinished && Me.ManaPercent < 50 && ManaFlasks.Count() != 0 && !Me.HasAura("flask_effect_mana"),
                    new Action(ret =>
                    {
                        ManaFlasks.First().Use();
                        _flaskCd.Reset();
                    }))
                );
        }
As before we're going to look at the code within the decorator pattern...
Code:
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 80 && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_life"),
                    new Action(ret =>
                    {
                        LifeFlasks.First().Use();
                        _flaskCd.Reset();
                    })),
Lets just remove the condition to check if we have already used a health pot and also add the condition to not use the panic routine if the bot has more than the "normal" decanter routine is.
Code:
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 20 && LifeFlasks.Count() != 0,
                    new Action(ret =>
                    {
                        LifeFlasks.First().Use();
                        _flaskCd.Reset();
                    })),
Seems reasonable. In psudo terms.

Surviving More Easily
Now what else can we do to help with survivability, taking a look at the exile.cs routine that Apoc is updating gradually we can do a quick mishmash and have enduring cry, molten shell and immortal call utilized by the bot.
Code:
				Cast("Enduring Cry", ret => !Me.HasAura("Endurance Charges")&& NumberOfMobsNear(MainTarget, 20, 1) && MainTarget.Distance > 5),
				Cast("Molten Shell", ret => !Me.HasAura("Molten Shell")),
				Cast("Immortal Call", ret => !Me.HasAura("Immortal Call")) && NumberOfMobsNear(MainTarget, 20, 1) && Me.HealthPercent < 10),

Implementing all of the modifications
  1. Open up your routine in notepad (or notepad++ or MSVS, whatever you have).
  2. Find "private Composite CreateFlaskLogic()"
  3. Replace the decantor code with our edited version:
Code:
private Composite CreateFlaskLogic()
        {
            return new PrioritySelector(
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 80 && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_life"),
                    new Action(ret =>
                    {
                        LifeFlasks.First().Use();
                        _flaskCd.Reset();
                    })),
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 80 && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_granite") && NumberOfMobsNear(MainTarget, 20, 1) && MainTarget.Distance < 5),
                    new Action(ret =>
                    {
                        GraniteFlasks.First().Use();
                        _flaskCd.Reset();
                    })),
                new Decorator(ret => _flaskCd.IsFinished && Me.HealthPercent < 20 && LifeFlasks.Count() != 0,
                    new Action(ret =>
                    {
                        LifeFlasks.First().Use();
                        _flaskCd.Reset();
                    })),
                new Decorator(ret => _flaskCd.IsFinished && Me.ManaPercent < 50 && ManaFlasks.Count() != 0 && !Me.HasAura("flask_effect_mana"),
                    new Action(ret =>
                    {
                        ManaFlasks.First().Use();
                        _flaskCd.Reset();
                    }))
                );
        }
4. Find the combat portion of the code that prioritizes what skills to use, it's initialized always at the end.
5. Add in our survivability spells
Code:
        private Composite CreateProjectileLogic()
        {
            return new PrioritySelector(
                Cast("Frenzy", ret => FrenzyTimeLeft.TotalSeconds <= 1.5 || FrenzyCharges < MaxFrenzyCharges),
		Cast("Enduring Cry", ret => !Me.HasAura("Endurance Charges")&& NumberOfMobsNear(MainTarget, 20, 1) && MainTarget.Distance > 5),
		Cast("Molten Shell", ret => !Me.HasAura("Molten Shell")),
		Cast("Warlord's Mark", ret=> !MainTarget.HasAura("Warlord's Mark") && NumberOfMobsNear(MainTarget, 40, 2 && MainTarget.IsCursable && MainTarget.Distance > 5),
		Cast("Enfeeble", ret=> !MainTarget.HasAura("Enfeeble") && MainTarget.IsCursable && MainTarget.Distance < 5),
                Cast("Lightning Arrow", ret => NumberOfMobsNear(MainTarget, 40, 1)),
                Cast("Frenzy"),
                Cast("Default Attack")
                );
        }
 
Wow thank you so much very impressive!
So quick question then - is this saying:

NumberOfMobsNear(MainTarget, 20, 1) && MainTarget.Distance > 5),

that it needs to have 20 minions near target? Also what is the 5 - the distance or the number of ranged mobs that are in the distance?

Lastly - would there be a way to activate the flask when fighting a certain boss by name? - There is this boss before piety that 2 shots me and I almost ahve enough time to kill him - if the flask can be used even after the first hit it would be great.
 
Wow thank you so much very impressive!
So quick question then - is this saying:

NumberOfMobsNear(MainTarget, 20, 1) && MainTarget.Distance > 5),

that it needs to have 20 minions near target? Also what is the 5 - the distance or the number of ranged mobs that are in the distance?

Lastly - would there be a way to activate the flask when fighting a certain boss by name? - There is this boss before piety that 2 shots me and I almost ahve enough time to kill him - if the flask can be used even after the first hit it would be great.

Looking at exile.cs
Code:
        private bool NumberOfMobsNear(PoEObject monster, float distance, int count, bool dead = false)
        {
            if (monster == null)
            {
                return false;
            }

            Vector2i mpos = monster.Position;

            int curCount = 0;
            foreach (Monster mob in Targeting.Combat.Targets.OfType<Monster>())
            {
                if (mob.ID == monster.ID)
                {
                    continue;
                }

                // If we're only checking for dead mobs... then... yeah...
                if (dead && !mob.IsDead)
                {
                    continue;
                }

                if (mob.Position.Distance(mpos) < distance)
                {
                    curCount++;
                }

                if (curCount >= count)
                {
                    return true;
                }
            }

            return false;
        }

        #endregion
    }
Distance is less than 20 feet and there is at least one mob present. The condition for the distance be greater than five ensures that we don't cast enduring cry if they're in melee range, otherwise we might get stunned and go into a loop.

In regards to dealing with monster string recognition... I don't believe it is possible to do without xtenshisanx's http://www.thebuddyforum.com/exilebuddy-forum/exilebuddy-combat-routines/137601-allrounder.html routine.

Edit:
Looking through xtenshisan's code it appears that there is a built into Buddy? I wish Apoc would make a list of what we can use.
Code:
Variables.MainTarget.Rarity >= Rarity.Rare && OnlyBosses
I'm guessing that we can do MainTarget.Rarity... I'm not sure, you'll have to test it out.

This will only trigger if there is a rare or unique monster nearby.
Code:
MainTarget.Rarirty >= Rarity.Rare

So for rare and unique monsters we can do...
Code:
                new Decorator(ret => _flaskCd.IsFinished && MainTarget.Rarirty >= Rarity.Rare && LifeFlasks.Count() != 0 && !Me.HasAura("flask_effect_granite") && NumberOfMobsNear(MainTarget, 20, 1) && MainTarget.Distance < 5),
                    new Action(ret =>
                    {
                        GraniteFlasks.First().Use();
                        _flaskCd.Reset();
                    })),

There are much more efficient ways to have all of our code checked, we could use if then statements to streamline it but I'm not really in the mood to put in any effort more than the bare minimum.
 
Back
Top