• Visit Rebornbuddy
  • How to edit Default Routine to Support Dual Totem

    Discussion in 'Archives' started by tozededao, Sep 2, 2014.

    1. tozededao

      tozededao Community Developer

      Joined:
      Jan 15, 2010
      Messages:
      1,225
      Likes Received:
      5
      Trophy Points:
      38
      How to edit Default Routine to Support Dual Totem - .cs added as attachment

      UPDATED FOR #896
      http://pastebin.com/x3QCtLFJ or Attachment


      Important



      If you are using Shockwave Totem and you want it to be cast right on monsters position.

      Code:
      var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(_totemSlot, true, Utility.CalculatePointAtDistanceAfterStart(myPos, cachedPosition,cachedDistance -3));


      If you are using any other totem and you want it to keep some distance from enemies

      Code:
      var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(_totemSlot, true, Utility.CalculatePointAtDistanceAfterStart(myPos, cachedPosition,cachedDistance / 2));


      Credits to Ben's Templar CR and Pushedx.
       

      Attached Files:

      Last edited: Sep 8, 2014
    2. IeU

      IeU Member

      Joined:
      Jul 20, 2010
      Messages:
      830
      Likes Received:
      11
      Trophy Points:
      18
      Thank you for sharing!
       
    3. pushedx

      pushedx Moderator Moderator Buddy Core Dev

      Joined:
      Sep 24, 2013
      Messages:
      4,252
      Likes Received:
      290
      Trophy Points:
      83
      Looks good! I started working on some example logic for a smaller routine for dual totem last night based on what you mentioned, but I ran into a fun client issue with casting totems. In short, it's possible to try and cast a totem too fast, and the client simply doesn't do anything. If you don't use the previous Beta's style of checking for casting, the totems will never cast in the correct place.

      Here's that basic CR, which you should be able to see the casting behavior is correct for sandwiching mobs between totems.

      You need to register and have one post to see spoilers!
      One thing that doesn't account for, is CanCast, as well as having a cast timeout in case the client decides where you want to cast at is not a valid location, which also has to be handled. Combat range has to be lowered some, because if you try casting behind mobs too far, the cursor will be off-screen or overlap the gui itself.
       
    4. tozededao

      tozededao Community Developer

      Joined:
      Jan 15, 2010
      Messages:
      1,225
      Likes Received:
      5
      Trophy Points:
      38
      The bouncing is amazing, I'm gonna use it!

      I'm using it just on monster.Rarity > Rarity.Magic since Magic and White monsters always come in packs and there is no need to sandwich them.

      Tomorrow I'm gonna try to create some logic to kill clusters of monsters in order to position right in the mdidle of the pack so with the Area of Effect reaches the maximum number of monsters.

      I'm curious about monsters.First, does it return the closest monster? the thoughest monster?
       
    5. pushedx

      pushedx Moderator Moderator Buddy Core Dev

      Joined:
      Sep 24, 2013
      Messages:
      4,252
      Likes Received:
      290
      Trophy Points:
      83
      monsters.First returns the first element in the sequence. monsters is generated by:

      Code:
      var monsters =
                          LokiPoe.ObjectManager.GetObjectsByType<Monster>()
                              .Where(
                                  m =>
                                      !AreaStateCache.Current.IsBlacklisted(m.Id) &&
                                      !m.CannotDie &&
                                      m.Distance < (_currentLeashRange != -1 ? _currentLeashRange : 50) &&
                                      m.IsActive)
                              .OrderBy(m => m.Distance).ToList();
      
      So, simply the closest. A targeting weight priority simple we be added back to the CR soon so users can customize weights like before. That way you can do things like, add weight based on # of surrounding mobs, or if it's a necro make it a top priority, etc... CR stuff is just low priority right now as I'm trying to work out some of the larger issues being reported that stem from the API itself.
       
    6. tozededao

      tozededao Community Developer

      Joined:
      Jan 15, 2010
      Messages:
      1,225
      Likes Received:
      5
      Trophy Points:
      38
      Updated the thread and I need help from you pushedx.

      I am trying to add Ice Spear with power charge on crit so I can keep up my power charges in order to deal more damage even though I'm dual totem I can still cast Ice Spear to gain Power Charges.

      I've added

      Code:
      private int _iceSpearSlot = -1;
      
      
      Code:
      _iceSpearSlot = -1;
      
      Code:
      var icespear = LokiPoe.InGameState.SkillBarPanel.Skills.FirstOrDefault(s => s.Name == "Ice Spear");
                      if (IsCastableHelper(icespear))
                                {
                                    _iceSpearSlot = icespear.Slot;
                                }
      
      
      Code:
      private int _maxPowerCharges = -1;
      
      
              private int MaxPowerCharges
              {
                  get
                  {
                      // This is so we avoid looking up this mostly static stat, every time.
                      if (_maxPowerCharges == -1)
                      {
                          _maxPowerCharges = LokiPoe.ObjectManager.Me.GetStat(StatType.MaxPowerCharges);
                      }
                      return _maxPowerCharges;
                  }
              }
      
      
              private int PowerCharges
              {
                  get
                  {
                      Aura aura = LokiPoe.ObjectManager.Me.Auras.FirstOrDefault(a => a.InternalName == "power_charge");
                      if (aura != null)
                      {
                          return aura.Charges;
                      }
                      return 0;
                  }
              }
      
      
              private TimeSpan PowerChargeTimeLeft
              {
                  get
                  {
                      Aura aura = LokiPoe.ObjectManager.Me.Auras.FirstOrDefault(a => a.InternalName == "power_charge");
                      if (aura != null)
                      {
                          return aura.TimeLeft;
                      }
                      return TimeSpan.Zero;
                  }
              }
      
      

      Now here's the logic I want it to execute, it will always drop 1 totem near our target no matter what, if we dont have the max number of Power Charges up, or they are finishing soon we cast Ice Spear so we gain them, and only after we have the previous condition we drop the second totem.


      Here is what I was using:

      Code:
      
      if (_totemSlot != -1)
                      {
                          var skill = LokiPoe.InGameState.SkillBarPanel.Slot(_totemSlot);
                          var currentTotems = skill.DeployedObjects;
                          int minimumTotemDistance = 15;
                          bool targetHasTotemNear = currentTotems.Any(o => o.Position.Distance(bestTarget.Position) < minimumTotemDistance);
                          int numberTotemsNearTarget = currentTotems.Count(o => o.Position.Distance(bestTarget.Position) < minimumTotemDistance);
      [B]                    int numberTotemsThatHaveAnAliveMonsterNear = currentTotems.Count(o => o.Position.Distance(CombatTargeting.Targets<Monster>().Any.Position) < minimumTotemDistance);
                          //Code in bold is wrong
                          //Here's where I need help.  Using numberTotemsNearTarget works, but it makes bot unnefective because we have a totem that is currently damaging monsters, but since                       //it is out of range from our BestTarget it recasts the totem instead of charging up the Power Charges, so instead of using numberTotemsNearTarget I want to know the
                          //number of totems that are actually damaging any momsters, because if they are I won't bother recasting it
      
      
      [/B]
                          
                          
      
      
      
      
      
      
      
      
                          if (skill.CanUse() && numberTotemsNearTarget < 1 )
                          {
                              var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(_totemSlot, true, Utility.CalculatePointAtDistanceAfterStart(myPos, cachedPosition, cachedDistance - 3));
      
      
      
      
      
      
                              //_totemStopwatch.Restart();
      
      
                              if (err1 == LokiPoe.InGameState.UseError.None)
                                  return true;
      
      
                              Log.ErrorFormat("[Logic] UseAt returned {0} for {1}.", err1, skill.Name);
                          }
                          else
                          {
                              // keep powercharges up
                              if (_iceSpearSlot != -1)
                              {
                                  // See if we can use the skill.
                                  var skillTest = LokiPoe.InGameState.SkillBarPanel.Slot(_iceSpearSlot);
                                  if (skillTest.CanUse())
                                  {
                                      if (PowerChargeTimeLeft.TotalSeconds <= 5 || PowerCharges < MaxPowerCharges)
                                      {
                                          var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(_iceSpearSlot, true, cachedPosition);
                                          if (err1 == LokiPoe.InGameState.UseError.None)
                                          {
                                              await Coroutine.Sleep(Utility.LatencySafeValue(500));
      
      
                                              await Coroutines.FinishCurrentAction(false);
      
      
                                              return true;
                                          }
      
      
                                          Log.ErrorFormat("[Logic] Use returned {0} for {1}.", err1, skill.Name);
                                      }
                                  }
                              }
                              
      
      
      
      
                              if (skill.CanUse() && numberTotemsNearTarget < 2)
                              {
                                  var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(_totemSlot, true, Utility.CalculatePointAtDistanceAfterStart(myPos, cachedPosition, cachedDistance - 3));
      
      
      
      
      
      
                                  //_totemStopwatch.Restart();
      
      
                                  if (err1 == LokiPoe.InGameState.UseError.None)
                                      return true;
      
      
                                  Log.ErrorFormat("[Logic] UseAt returned {0} for {1}.", err1, skill.Name);
                              }
      
      
                          }
                      }
      
      
      Without the bold code it is working, I don't know how to count the number of totems who have an alive monster within the minimum distance set by minimumTotemDistance


       
      Last edited: Sep 8, 2014
    7. pushedx

      pushedx Moderator Moderator Buddy Core Dev

      Joined:
      Sep 24, 2013
      Messages:
      4,252
      Likes Received:
      290
      Trophy Points:
      83
      Once you have a Skill, you can access DeployedObjects to get the current objects created from the skill.

      If you look at the code for the DualTotemRoutine, that's this portion of it:
      Code:
      var totemSkill = LokiPoe.InGameState.SkillBarPanel.Slot2;
      var totems = totemSkill.DeployedObjects.ToList();
      
      var oldestTotem = totems.Count > 0 ? totems[0] : null;
      var newestTotem = totems.Count > 1 ? totems[1] : null;
      
      In this case, skill is your totemSkill, so you don't have to use .Slot2.

      Now, you can just check the two totem objects and see how many mobs are around them.
      Code:
      if(oldestTotem != null)
      {
         var mobsAroundTotem = Utility.NumberOfMobsNear(oldestTotem, 20);
         if(mobsAroundTotem == 0)
         {
             // You should recast the totem, since it's most likely not attacking anything.
         }
      }
      
      As I mentioned in the other thread about general dual totem stuff, you have to consider the game's casting mechanics for totems. If you have only one totem up, then the next totem you cast will be where you cast it. If you have two totems up, the oldestTotem, is going to be replaced with the new cast, so you shouldn't care about checking newestTotem, as it'd take two casts to replace it.

      While it is possible to check the CurrentAction of a totem to see if it's casting or not, you should probably use the mobs around check instead, because of the nature of the game and the fact the APi works out of process. Between attacks, there is a time where the Actor doesn't have a current action, so if you processed based on that, then you'd be recasting at times you shouldn't be, depending on when the API actually read the current data from the client.
       
    8. hooplin

      hooplin New Member

      Joined:
      Mar 22, 2014
      Messages:
      41
      Likes Received:
      0
      Trophy Points:
      0
      i dont really see the difference in this routine? still spams totems
       
    9. hooplin

      hooplin New Member

      Joined:
      Mar 22, 2014
      Messages:
      41
      Likes Received:
      0
      Trophy Points:
      0
      Ok this is working fine but all it does is cast totems? Is there anyway i can cast my curses?
       
    10. pushedx

      pushedx Moderator Moderator Buddy Core Dev

      Joined:
      Sep 24, 2013
      Messages:
      4,252
      Likes Received:
      290
      Trophy Points:
      83
      The default behavior of ExampleRoutine is to cast curses that are on your skill bar under this scenario:
      Code:
      // Handle curse logic - curse magic+ and packs of 4+, but only cast within MaxRangeRange.
                      var checkCurses = myPos.Distance(cachedPosition) < ExampleRoutineSettings.Instance.MaxRangeRange &&
                                        (cachedRarity >= Rarity.Magic || Utility.NumberOfMobsNear(bestTarget, 20) >= 3);
      
       

    Share This Page