• Visit Rebornbuddy
  • Visit Panda Profiles
  • Visit LLamamMagic
  • [Snippet/PoC] Dodge dangerous attacks (Dominus only for now)

    Discussion in 'Archives' started by jyam, Dec 28, 2014.

    1. jyam

      jyam Community Developer

      Joined:
      Dec 27, 2014
      Messages:
      72
      Likes Received:
      1
      Trophy Points:
      0
      [Snippet/PoC] Dodge dangerous attacks (Dominus only for now, working on Atziri!!!)

      Edited, it's included as an attachment, replace the default CR by this one. It's a WIP so don't expect lots of feature atm.
      Supports only dominus for now, Atziri will be possible once pushedx gives us access to id 0 networkobject

      Capturing boss moves (Dev only! If you wanna help me make a complete Evade/Dodge plugin, feel free to use it and give me the results): Put this in Bot/AssistantBot/AssistantBot.cs
      Code:
      using System.Collections.Generic;
      using log4net;
      using Loki.Bot;
      using Loki.Bot.Settings;
      using Loki.Game;
      using Loki.Game.GameData;
      using Loki.Game.Objects;
      using Loki.Utilities;
      using System;
      using System.Windows;
      using System.Windows.Markup;
      using System.IO;
      using System;
      using System.Windows.Data;
      using System.Threading.Tasks;
      using System.Linq;
      using System.Windows.Controls;
      
      //!CompilerOption|AddRef|C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.Speech.dll
      
      namespace AlertBot
      {
          /// <summary> </summary>
          public class AlertBot : IBot
          {
              private static readonly ILog Log = Logger.GetLoggerInstanceForType();
      
              struct Skill
              {
                  public readonly Loki.Game.NativeWrappers.ActionWrapper action;
                  public readonly int createdts;
                  public int timeout;
                  public readonly bool active;
      
                  public Skill(Loki.Game.NativeWrappers.ActionWrapper action)
                  {
                      this.action = action;
                      this.createdts = (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
                      this.timeout = 3;
                      this.active = true;
                  }
                  public override bool Equals(Object obj)
                  {
                      // Check for null values and compare run-time types.
                      if (obj == null || GetType() != obj.GetType())
                          return false;
      
                      Skill s = (Skill)obj;
                      return (s.action.Skill.Name == action.Skill.Name) && (s.action.Destination.Equals(action.Destination)) && (s.createdts - createdts <= 3);
                  }
                  public override int GetHashCode()
                  {
                      return (action.GetHashCode() + action.Destination.GetHashCode() + createdts) % 100000000;
                  }
      
              }
              private readonly List<Skill> _trackedSkills = new List<Skill>();
      
              #region Implementation of IAuthored
      
              /// <summary> The name of this bot. </summary>
              public string Name
              {
                  get { return "AssistantBot"; }
              }
      
              /// <summary> The description of this bot. </summary>
              public string Description
              {
                  get { return "This bot will assist you during manual play."; }
              }
      
              /// <summary>The author of this bot.</summary>
              public string Author
              {
                  get { return "JYam"; }
              }
      
              /// <summary>The version of this bot's implementation.</summary>
              public Version Version
              {
                  get { return new Version(0, 0, 1, 1); }
              }
      
              #endregion
      
              #region Implementation of IBase
      
              /// <summary>Initializes this object. This is called when the object is loaded into the bot.</summary>
              public void Initialize()
              {
              }
      
              #endregion
      
              #region Implementation of IRunnable
      
              /// <summary> The bot start callback. Do any initialization here. </summary>
              public void Start()
              {
                  Log.DebugFormat("[AssistantBot] Start");
      
                  // Reset the default MsBetweenTicks on start.
                  Log.DebugFormat("[Start] MsBetweenTicks: {0}.", MainSettings.Instance.MsBetweenTicks);
                  Log.DebugFormat("[Start] InputEventMsDelay: {0}.", MainSettings.Instance.InputEventMsDelay);
      
                  GameEventManager.Start();
      
                  GameEventManager.AreaChanged += GameEventManagerOnAreaChanged;
              }
      
              /// <summary> The bot tick callback. Do any update logic here. </summary>
              public void Tick()
              {
                  // We don't want to do anything when we're not in game!
                  if (!LokiPoe.IsInGame)
                      return;
      
                  GameEventManager.Tick();
      
                  foreach (Monster obj in LokiPoe.ObjectManager.GetObjectsByType<Monster>())
                  {
      
                      if (obj.IsHostile && obj.Rarity == Rarity.Unique && obj.HasCurrentAction && obj.CurrentAction.Skill != null && obj.CurrentAction.Skill.Name.Length >= 5)
                      {
                          Loki.Game.NativeWrappers.ActionWrapper action = ((Monster)obj).CurrentAction;
                          if (!_trackedSkills.Contains(new Skill(action)))
                          {
                              _trackedSkills.Add(new Skill(action));
                              Log.DebugFormat("Action performed by {0} [X : {1}, Y : {2}]", obj.Name, obj.Position.X, obj.Position.Y);
                              if (action.Destination != null)
                                  Log.DebugFormat("Destination X : {0}, Y : {1}", action.Destination.X, action.Destination.Y);
                              if (action.Target != null)
                                  Log.DebugFormat("Target X : {0}, Y : {1}", action.Target.Position.X, action.Target.Position.Y);
                              if (action.Skill != null)
                                  Log.DebugFormat("{0} [ID : {2} - Addr : {3}] ~ {1}", action.Skill.Name, action.Skill.Description, action.Skill.Id, action.Skill.BaseAddress);
                          }
      
                      }
                      List<Skill> toDelete = new List<Skill>();
      
                      foreach (Skill s in _trackedSkills)
                      {
                          if (s.createdts + s.timeout <= (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds)
                          {
      
                              toDelete.Add(s);
                          }
                      }
                      foreach (Skill s in toDelete)
                      {
                          _trackedSkills.Remove(s);
                      }
                  }
              }
      
              /// <summary> The bot stop callback. Do any pre-dispose cleanup here. </summary>
              public void Stop()
              {
                  Log.DebugFormat("[AssistantBot] OnStop");
      
                  GameEventManager.Stop();
      
                  GameEventManager.AreaChanged -= GameEventManagerOnAreaChanged;
              }
      
              #endregion
      
              #region Implementation of IConfigurable
      
              public JsonSettings Settings
              {
                  get { return null; }
              }
      
              /// <summary> The bot's settings control. This will be added to the Exilebuddy Settings tab.</summary>
              public UserControl Control
              {
                  get { return null; }
              }
      
              #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
      
              #region Coroutine Logic
      
              #endregion
      
              private void GameEventManagerOnAreaChanged(object sender, AreaChangedEventArgs areaChangedEventArgs)
              {
                  _trackedSkills.Clear();
              }
          }
      }
       

      Attached Files:

      Last edited: Jan 6, 2015
    2. cyberbot

      cyberbot Member

      Joined:
      Mar 15, 2014
      Messages:
      220
      Likes Received:
      2
      Trophy Points:
      18
      I think I found a typo?

      Code:
      isInCircle(LokiPoe.Me.Position.X, LokiPoe.Me.Position.Y, dom.Position.X, dom.Position.[B]X[/B], 40)
       
    3. jyam

      jyam Community Developer

      Joined:
      Dec 27, 2014
      Messages:
      72
      Likes Received:
      1
      Trophy Points:
      0
      Woops, editing.
       
    4. WhereIsMyMind

      WhereIsMyMind Member

      Joined:
      Oct 12, 2013
      Messages:
      848
      Likes Received:
      5
      Trophy Points:
      18
      wooo nice work.

      wimm
       
    5. Nepthys

      Nepthys Community Developer

      Joined:
      Oct 13, 2014
      Messages:
      89
      Likes Received:
      1
      Trophy Points:
      0
      from pathofexile.gamepedia.com/Dominus 'damage dealt is calculated when it is initiated, ignoring any resistance gained after the attack has initiated'

      anyone know if this means once he starts winding up the attack, or once it hits?

      ie would it be worthwhile to use a topaz flask (if available) once dom.CurrentAction.Skill.Name.Contains("Touch Of God")


      Thanks!
       
    6. tozededao

      tozededao Community Developer

      Joined:
      Jan 15, 2010
      Messages:
      1,225
      Likes Received:
      5
      Trophy Points:
      38

      I'm pretty sure it means when it hits otherwise it wouldn't make any sense, even though the wiki says :

      There are plenty of people that used to tank vaalsmashes because they would use granites and ruby flasks, and they use it after they see vaal raising his smash. You can find it on videos.

      I'll test it on one of my standard chars and see if it makes any difference using flasks after I see Dominus fist raising or not using at all.
       
    7. jyam

      jyam Community Developer

      Joined:
      Dec 27, 2014
      Messages:
      72
      Likes Received:
      1
      Trophy Points:
      0
      The AoE dodge logic is kinda wrong + it can be made more efficient, what it needs to do is calculate walkable path to 8 positions around dominus bigger than the blast radius then walk to the one furthest to dominus which means it's the safest area to be.

      A more complex and amazing evade would be to iterate through every current skill, make a hitbox of all the skills and go to a safe zone, that way you can dodge dual bosses, multiple dangerous skills, etc.

      Anyone interested in working on thsi with me? I'm making a plugin especially for evading to make bosses way easier.
       
    8. jyam

      jyam Community Developer

      Joined:
      Dec 27, 2014
      Messages:
      72
      Likes Received:
      1
      Trophy Points:
      0
      This is how multiple "skillshots" should be handled :
      [​IMG] any area outside of the skillshot path/blast radius is safe to walk to during that framee
       
    9. jyam

      jyam Community Developer

      Joined:
      Dec 27, 2014
      Messages:
      72
      Likes Received:
      1
      Trophy Points:
      0
      I finally got the to test it a few time vs dominus, the touch of god isn't dodging and i already figured out why. Btw the windup and the actual attack are two different skill, so if you /oos & flask during the windup the damage reduction is going to apply. Skill : "Touch of God" is the actual attack, the windup has some sort of internal name like 858B or something, going to log a bit to make sure. Will release the updated code once i'm done.

      Edit: Ok perfect it's working, btw may i ask someone who has lots of sets for atziri to contact me so i can make an AI to fight atziri?
       
      Last edited: Dec 29, 2014
    10. j19

      j19 Member

      Joined:
      Mar 13, 2014
      Messages:
      59
      Likes Received:
      1
      Trophy Points:
      8
      This looks amazing. Is it possible to use the logic for dodging Fist of God to dodge the explosion from the Bloodline Frost/Flame/Lightning-Bearer magic mob pack affix orbs? I would imagine the radius to be quite similar to that on the Fist of God skill. Maybe the fact that there usually are several orbs spawning at once make things more complicated?

      The orbs are created after the monster with the affix dies and the orb is listed under Object Explorer as a monster with the name "Daemon". It explodes a few seconds after spawning.

      Looking up "Daemon" it has the following info:
      [HIDE]Level: 1, Category: MonsterNecromancerRaisable, InternalName: MonsterNecromancerRaisable, DisplayName: , IsHidden: True, IsPrefix: False, IsSuffix: False, Stats: Min: 1, Max: 1, Stat: 923, Min: 0, Max: 0, Stat: 0, Min: 0, Max: 0, Stat: 0, Min: 0, Max: 0, Stat: 0[/HIDE]
       
      Last edited: Dec 29, 2014
    11. jyam

      jyam Community Developer

      Joined:
      Dec 27, 2014
      Messages:
      72
      Likes Received:
      1
      Trophy Points:
      0
      do the explosion overlap? if yes the logic will be implemented when i finish the plugin itself otherwise it is easy but i have never played a hardcore league so you'll have to guide me through
       
    12. j19

      j19 Member

      Joined:
      Mar 13, 2014
      Messages:
      59
      Likes Received:
      1
      Trophy Points:
      8
      Yes, they do unfortunately overlap. That's the danger of them when you kill a pack of small monsters with the affix. Taking 1 explosion to the face is fine but 5 of them at the same time could mean death. In that case I'll look forward to the finished plugin. Seems like it could be a potential life-saver for hardcore.
       
    13. tozededao

      tozededao Community Developer

      Joined:
      Jan 15, 2010
      Messages:
      1,225
      Likes Received:
      5
      Trophy Points:
      38
      I have some sets on standard I guess PM me.

      Btw would be really nice to have those additions to other boss fights aswell such as Merveil, Brutus and Vaal :)
       
      Last edited: Dec 29, 2014
    14. judge001

      judge001 Member

      Joined:
      Mar 25, 2012
      Messages:
      97
      Likes Received:
      1
      Trophy Points:
      8
      jyam,

      Thank you for your work on this addition. I am likely at fault for the following error; however, I believe I entered to code at the correct location before the flameblast logic, yet I am receiving the following error:

      Compiler Error: \ExampleRoutine\ExampleRoutine.cs(1041,33) : error CS0103: The name 'isInCircle' does not exist in the current context

      Help resolving this error would be greatly appreciated.
       
    15. WhereIsMyMind

      WhereIsMyMind Member

      Joined:
      Oct 12, 2013
      Messages:
      848
      Likes Received:
      5
      Trophy Points:
      18
      >Compiler Error: \ExampleRoutine\ExampleRoutine.cs(1041,33) : error CS0103: The name 'isInCircle' does not exist in the current context

      chk the cr for 'isInCircle', make sure it is declared 'var isInCircle', declared outside of any 'try/catch' code.

      wimm
       
    16. jyam

      jyam Community Developer

      Joined:
      Dec 27, 2014
      Messages:
      72
      Likes Received:
      1
      Trophy Points:
      0
      Check the end of my post, i posted the extra geometric function i use.
      Botted 6h of dominus, died 0 time and I got some sweet loot =D
       
      Last edited: Dec 30, 2014
    17. judge001

      judge001 Member

      Joined:
      Mar 25, 2012
      Messages:
      97
      Likes Received:
      1
      Trophy Points:
      8
      Thank you. I added the geometric function and I am able to get it running; however, it appears as if it is unable to dodge consistently. I will disable CustomPlayerMover and other plugins in the hopes that this may resolve the issue.

      You need to register and have one post to see spoilers!
      After disabling a few plugins, it appears to dodge now (Thank you!). I am hoping the conflict is not 'CustomPlayerMover' as Leap Slam increases by efficiency. I will continue to test. Thank you again for your work on this.
       
    18. jyam

      jyam Community Developer

      Joined:
      Dec 27, 2014
      Messages:
      72
      Likes Received:
      1
      Trophy Points:
      0
      I'm using coroutine to force the move, maybe customplayermover overrides that, i'll let you know.
       
    19. jyam

      jyam Community Developer

      Joined:
      Dec 27, 2014
      Messages:
      72
      Likes Received:
      1
      Trophy Points:
      0
      What is a build that can literally let you AFK in atziri room without dying? If i want to implement atziri logic i need to be able to afk in that room....
       
    20. darkbluefirefly

      darkbluefirefly Community Developer

      Joined:
      Nov 8, 2013
      Messages:
      1,927
      Likes Received:
      18
      Trophy Points:
      38
      Hey jyam,
      Awesome Work!.
      For the optimization, I would think using Circular collision, on overlapping objects would be more optimized? I might have to ask pushedx for this, I was doing something similar with Mervail, using this as my math calculations.
      Circle-Circle Intersection -- from Wolfram MathWorld
      Thinking about Atziri, there was an afk build a while back, I'll have to search for it when I get home.
      But yea, I'll check this out when I get home, I still have to fix my other 2 plugins but extra time will be spent on testing this, instead of playing Hearthstone lol.

      Edit, Don't have Visual in front of me atm, but I think.
      Code:
      public class CircleBody
      {
          public Vector2 position {get;set;} // top left corner
          public float CenterX;
          public float CenterY;
          public int Width { get; set; }
          public int Height { get; set; }
      }
      Code:
      public static bool CirclesIntersect(Circle c1, Circle c2, out float depth)
          {
              float distance = (c1.Position - c2.Position).Length();
              float sumOfRadii = c1.Radius + c2.Radius;
      
              depth = sumOfRadii - distance;
              if (depth < 0)
              {
                  return false;
              }
              return true;
          }
      The depth float that is passed out will give you the smallest distance you need to separate the circles. You can use the depth value like this :

      Code:
      float depth;
      if (CirclesIntersect(dynamicCircle, staticCircle, out depth))
      {
           Vector2 direction = dynamicCircle - staticCircle;
           direction.Normalize();
      
           dynamicCircle.CenterPosition += direction * depth;
      }
      We can do a sort of collision detection if inside and move the opposite direction
      Code:
      float depth;
      if (CirclesIntersect(dynamicCircleOne, dynamicCircleTwo, out depth))
      {
           Vector2 direction_One = dynamicCircleOne - dynamicCircleTwo;
           direction_One.Normalize();
      
           Vector2 direction_Two = dynamicCircleTwo - dynamicCircleOne;
           direction_Two.Normalize();
      
           dynamicCircleOne.CenterPosition += direction_One * (depth / 2);
           dynamicCircleTwo.CenterPosition += direction_Two * (depth / 2);
      }
      This of course if for when moving towards Dominus, it will move away, you have to add some extra to make the bot move away from Dominus when inside the circle.
      This can be changed to skill based movement as well, as you have a direction to move in, therefore you can cast a ray point and choose that point X,Y distance from the collided circle.
      Ok i'll test it tonight lol, got ideas, now to implement it on code, tonight.
       
      Last edited: Dec 30, 2014

    Share This Page