• Visit Rebornbuddy
  • Visit Panda Profiles
  • Visit LLamamMagic
  • CR access to pathing s during combatend ranged skill -> direction of travel

    Discussion in 'Archives' started by WhereIsMyMind, Oct 24, 2014.

    1. WhereIsMyMind

      WhereIsMyMind Member

      Joined:
      Oct 12, 2013
      Messages:
      848
      Likes Received:
      5
      Trophy Points:
      18
      Hi,

      So i'm writting a CR that will use tornado shot as primary attack. Thus it will be cool:
      1) at combatend fire ranged aoe in direction of next travel (myposition ray to nextposition + full range.To flush out anything 'hiding' as I'd prefer to engage at MAX range
      2) also, as I am already asking something like this, I'd like to fire a shot through a doorway if the besttarget is detected 'behind' an open door, before PlayerMover.MoveTowards is triggered.

      thnx,
      WIMM
       
    2. pushedx

      pushedx Moderator Moderator Buddy Core Dev

      Joined:
      Sep 24, 2013
      Messages:
      4,252
      Likes Received:
      290
      Trophy Points:
      83
      To do this, you'll want to implement a custom PlayerMover class that casts the skill in the direction you want to move. See the CustomPlayerMover plugin provided with the bot. It simply casts Leap Slam to move, but with minor modifications you can make it use a skill before moving normally.

      To solve the issue of figuring out where to cast at max range, as you mentioned, you'd have to use ExilePather.Raycast in the direction along which to move to know the point before the skill most likely would be uncastable. It won't be perfect though, since dynamic objects are not part of the game's pathfinding information, but you can either just cast along some points in the direction. The Utility class has functions such as CalculatePointAtDistanceBeforeStart, and other similarly named ones that you can use to get a point along the line from your current position to the movement position.

      So, if you want to find a point to cast that is within 40 units along the direction you want to move, you'd have:
      var extPoint = Utility.CalculatePointAtDistanceAfterStart(LokiPoe.Me.Position, point, 40);

      where point was the final point calculated to move towards originally in the PlayerMover class. Once you raycast to extPoint, you then can use ExilePather.GetPointsOnSegment to get a list of points that should be castable to along the ray between your current position and the last walkable position in the direction you want to move. Now that you have a bunch of points you can cast towards, you can now try to cast along various points until you get the cast off.

      You'll have to work in ways to make this more smooth, as it's a lot of calculations and checking when it comes to trying to cast, but it should be doable with what's there. To avoid doing this while in combat, you'll have to do something along the lines of setting a flag that you're in combat when the task starts for combat, and then clear the flag when you're out of combat for your player mover to process, or, replace all the PlayerMover.MoveTowards in ExampleRoutine to pass an object to signal you're moving for combat reasons, and shouldn't execute your new casting logic. That's why the user param is there.

      In the case where there was a door, you can:
      1. detect the open door being between you and the mob.
      2. cast the spell towards the door itself before going in.

      In the case where there was no door, you can't know you're in a doorway. The client only has 2d pathfinding data with no association as to what is around you, which is why the wall hugging issues in City of Sarn is not solvable, and why stairs will always be an issue. At best, you can do an insane amount of pathfinding data processing to determine the layout of terrain you're in, but there's no way to process models due to the way the game works. Think about trying to put together a 2d puzzle of a maze, and then being able to figure out the maze walls knowing only the shape of the puzzle pieces.

      The logic for ClosedDoorBetween, which you can see in the CR is simply this:
      You need to register and have one post to see spoilers! You can modify that a bit to try and figure out if there's an open door between you and a mob.
       
    3. Nixon233

      Nixon233 New Member

      Joined:
      Sep 30, 2013
      Messages:
      320
      Likes Received:
      2
      Trophy Points:
      0
      So, for getting into range and to stop moving towards the target would you do something like
      " Loki.Bot.Pathfinding.ExilePather.Raycast" ?

      return false;
      }

      var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(1, false, cachedPosition);
      if (err1 != LokiPoe.InGameState.UseError.None)
      {
      Log.ErrorFormat("[Logic] Use returned {0} for {1}.", err1, 1);
      }

      Or is there a lot more behind it like targeting ?
       
    4. WhereIsMyMind

      WhereIsMyMind Member

      Joined:
      Oct 12, 2013
      Messages:
      848
      Likes Received:
      5
      Trophy Points:
      18
      Hi Nixon,

      Well, that is already done in someways in the Example Routine. I note that you have set the attack in place (aip) variable in the below (bolded by me) to false:
      var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(1, false, cachedPosition);

      The other way is with cansee:
      var canSee = ExilePather.CanObjectSee(LokiPoe.Me, bestTarget);

      So if you cannot see the target then try some things, perhaps try a leap near the target, or some other movement skill. In my CR's case I fire a AOE skill (tornado shot) in the general direction and them call the MoveTowards function.

      Hope that helps

      WIMM
       
    5. Nixon233

      Nixon233 New Member

      Joined:
      Sep 30, 2013
      Messages:
      320
      Likes Received:
      2
      Trophy Points:
      0
      Somewhat, I'd really like to just move until the target is in sight. I find that with the current example routine, regardless of ranged, trap or totem it casts the spell and ends up moving almost ontop of the mobs
       
    6. WhereIsMyMind

      WhereIsMyMind Member

      Joined:
      Oct 12, 2013
      Messages:
      848
      Likes Received:
      5
      Trophy Points:
      18
      Ok, did you try setting the Always Attack In Place setting on the Example Routine? It is one of the GUI settings.
      Otherwise you can edit the CR directly, replacing any instance of:
      var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(1, aip, cachedPosition);
      or
      var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(1, false, cachedPosition);
      with
      var err1 = LokiPoe.InGameState.SkillBarPanel.UseAt(1, true, cachedPosition);

      WIMM
       
    7. pushedx

      pushedx Moderator Moderator Buddy Core Dev

      Joined:
      Sep 24, 2013
      Messages:
      4,252
      Likes Received:
      290
      Trophy Points:
      83
      In terms of how it handles combat, it will move towards the best target when it's not in range or out of LoS, but the best target can change every tick. As a result, the routine doesn't engage one enemy and wait for it to die then move on to the next. It starts combat for a mob, and then keeps on doing combat things until there are no more targets, so under certain cases, the bot will appear to be moving to it's target, but it's really moving towards a different target which is now the new best target.

      I wouldn't try taking the approach ExampleRoutine does for a specialized CR though. ExampleRoutine does fallbacks to melee range, which is most likely the issue you're seeing when it can't use a ranged skill.

      Consider the following bare bones routine, that simply casts slot 6 in place (which should be a projectile spell that can be used at any range): https://gist.github.com/anonymous/7f746e8ab4372a8cba41 I was using Lightning Arrow as the skill.

      Targeting simply orders mobs by distance, and the CR only moves towards the target if it can't see the mob or it's blocked by a door. If you run that routine in a simple area, you should see a very basic behavior of your character standing in place, and firing off at mobs in the distance. The logic doesn't handle desync or when your projectiles get clipped or eaten by the terrain, but the core behavior should be pretty obvious.

      That routine would probably work better for you than ExampleRoutine, because of the assumptions being made in the implementation (which can't be made for ExampleRoutine). That logic works in most cases, but there's some game specific things that you start to have to add logic to handle. The first would be giving Necros more weight, so the CR won't kill the raised mobs over and over. That's shown in ExampleRoutine by detecting the necro and adding weight to make it more important. The same is true of any summoned minions that affect combat, but are not a huge threat. That's pretty much the idea behind setting up targeting. You adjust the priority in which the CR determines the best target.

      However, that routine just uses one skill, all the time. It doesn't try to determine AoE or Single Target, because LA works great for both pretty much. However, if you were using a skill that wasn't so good all around for both cases, like Burning Arrow, you'd undoubtedly want logic to use a different skill for AoE, such as Rain of Arrows.

      The whole design of the CR revolves around being given a target, determined from targeting, and then performing logic to kill that target, using a skill that is more favorable based on information about it. E.g., if it's rare or unique, you might use a single target, higher DPS skill, or if it's surrounded by a bunch of other mobs, use an AoE skill instead.

      An example of that can be seen with this simple CR: https://gist.github.com/anonymous/c7e410a4f82fbc2908b0

      The logic simply checks to see the number of mobs around the bestTarget. If it's more than 2, it'll use Slot 7 instead, which is assumed to be an AoE skill, like Rain of Arrows. If you run that routine, you'll see the expected behavior; casts Slot 6 on single target mobs, then Slot 7 on groups of mobs.

      Continuing on with this pattern, you could support any number of various hard coded logic this way. Let's say you wanted to cast Slot 3 on Rare/Unique mobs. You'd just check the mob rarity before those two other checks, to give it more priority. The CR would then use that skill on those mobs rather than your other skills.

      Now, this aspect of the CR development is pretty simple. You're just coding around specific skills, and can make specific assumptions on how they should be used, because you know exactly what will be used. The problem though, is trying to find a way to make this process more flexible to cover more generic cases, and still be able to handle proper melee/ranged skill usages. E.g., Fireball can be a melee or ranged skill, as it's just a projectile. A skill being projectile based doesn't mean it has to be used at range. Conversely, some projectile based skills, such as Freezing Pulse, should be used at melee range, but not at a range due to the way the skill works.

      The actual issue with ExampleRoutine, which is what you're most likely seeing, as it's always been an issue with the routines we provide, is the need to differentiate between skills that you should use only if the target is in range, and skills that you need to move into range to use. This depends on the user's build, and is not something that can be generically coded for without the user configuring it. For example, if you're only using Freezing Pulse, you obviously want the CR to move into range to use the skill. However, if you have a build where you only use FP if the mob is in melee range, you don't want to move into range to use FP, since you have other skills that you can use from afar. When you no longer use FP, after moving into melee range, you're now attacking a lot closer than you have to be.

      The biggest obstacle has always been, how to create a CR where users can configure the CR, in a way that isn't too complex, or require a ton of coding, yet still have enough flexibility to do meaningful things without having to rewrite everything. Exile had no gui, and had a lot more flexibility for things, but required pure code modifications and manual changes to get skills to be used in a different priority. In addition, it didn't support distinguishing between skills that you should move into range, and just use from where you were at, without requiring more a complicated BT design. ExilebuddyRoutine attempted to solve the GUI issue better, but as it turns out, trying to keep track of skills by their ids did not work well due to how they were only valid in game. As a result, trying to configure the CR by skill name presented a lot of problems when you weren't in game, and were trying to change things in the GUI itself. ExampleRoutine solved that issue by using skill slots instead, which also solved the issue of multiple skills with the same name, but the user only wanting to use a specific one. However, the current design, while is a lot simpler to configure, is the most inflexible out of all three, because it attempts to handle combat using a set of specific skill slots under really specific conditions, which the user can't change.

      For the "next routine", I would do roughly the following to try and advanced what's there based on how the previous 3 have been. The idea is to use a system similar to what is done for Profiles, just not quite a profile system:
      * Use IronPython for logic execution. This removes the need to manually change the CR, and it would now be changeable at runtime without recompiling.
      * The new logic system is based on Exile's design of a large if/else chain of dynamic conditions and actions, except it's tied to the GUI so users can add/remove/rearrange without changing the underlying code.
      * The routine would act as a template, so users that need to add custom logic to expose though Python to use in their code, would simply take the routine, rename it, then add in their custom logic to the appropriate provided class. For example, let's say you needed specific logic to determine the best location to place a totem. You'd add a function to do that to the special class, then you'd simply call it from the action portion of the skill entry. Or, if you needed something special for conditional logic, such as CanCurrentlyKite, you would do the exact same.

      A setup like this would provide the flexibility that Exile did, without being constrained to actual C# CR changes and reloading the bot to test changes (unless you need to change the logic exposed to Python, whihc would). It would not be as user friendly as the current GUI is though, since the API and some basic coding (scripting) is needed, but that's the trade off compared to having no customization and a really easy configuration like ExampleRoutine does. Being able to use the GUI to reorder things or add/remove new logic entries, will make things easier to manage for slight changes people need in different builds, without having to do a ton of extra work.

      Looking at how this setup would solve existing and past problems, let's say you had a build where you always wanted to be within a certain distance before starting combat. Your first logic entry would be a condition that is simply the best target's distance is greater than your range, (pathDistance > 20). The action would simply be to move towards the target, (PlayerMover.MoveTowards(cachedPosition)). Now, the routine would always move into range before executing anything below that. For a user who didn't want that, they would either delete that entry, or, move it down in the priority list, so the CR would move into that range, before using the next skill, which would be some melee ranged skill.

      For them, their first entry would be to check if the current target is within some skill's range (pathDistance > 5 && pathDistance < 15), and if so, use some skill (LokiPoe.InGameState.SkillBarPanel.Use(2, true)). That'd be an example of something for Shock Nova, for example.

      The immediate downside to this system would be that there are no meaningful defaults, other than providing some examples to configure, so there would be an initial learning curve for users to get the CR working right away with their build. That could be somewhat remedied with a new guide for that routine, and cover more API specific stuff that might be used. However, there's no real way to make everything super user friendly and still provide enough flexibility/functionality. I do think it would be a good trade-off though, and would still be pretty manageable from a generic routine standpoint.
       
    8. WhereIsMyMind

      WhereIsMyMind Member

      Joined:
      Oct 12, 2013
      Messages:
      848
      Likes Received:
      5
      Trophy Points:
      18
      awesome stuff.
       

    Share This Page