private static bool RefreshGizmo(bool AddToCache) { if (!Settings.WorldObject.AllowPlayerResurection && CurrentCacheObject.ActorSNO == DataDictionary.PLAYER_HEADSTONE_SNO) { c_IgnoreSubStep = "IgnoreHeadstones"; AddToCache = false; return(AddToCache); } // start as true, then set as false as we go. If nothing matches below, it will return true. AddToCache = true; bool openResplendentChest = CurrentCacheObject.InternalName.ToLower().Contains("chest_rare"); // Ignore it if it's not in range yet, except health wells and resplendent chests if we're opening chests if ((CurrentCacheObject.RadiusDistance > CurrentBotLootRange || CurrentCacheObject.RadiusDistance > 50) && CurrentCacheObject.Type != GObjectType.HealthWell && CurrentCacheObject.Type != GObjectType.Shrine && CurrentCacheObject.RActorGuid != LastTargetRactorGUID) { AddToCache = false; c_IgnoreSubStep = "NotInRange"; } // re-add resplendent chests if (openResplendentChest) { AddToCache = true; c_IgnoreSubStep = ""; } try { CurrentCacheObject.IsBountyObjective = (CurrentCacheObject.CommonData.GetAttribute <int>(ActorAttributeType.BountyObjective) > 0); } catch (Exception) { Logger.LogDebug("Error refreshing IsBountyObjective"); } try { CurrentCacheObject.IsQuestMonster = CurrentCacheObject.Object.CommonData.GetAttribute <int>(ActorAttributeType.QuestMonster) > 1; } catch (Exception ex) { Logger.LogDebug(LogCategory.CacheManagement, "Error reading IsQuestMonster for Unit sno:{0} raGuid:{1} name:{2} ex:{3}", CurrentCacheObject.ActorSNO, CurrentCacheObject.RActorGuid, CurrentCacheObject.InternalName, ex.Message); } try { CurrentCacheObject.IsMinimapActive = CurrentCacheObject.Object.CommonData.GetAttribute <int>(ActorAttributeType.MinimapActive) > 0; } catch (Exception ex) { Logger.LogDebug(LogCategory.CacheManagement, "Error reading MinimapActive for Gizmo sno:{0} raGuid:{1} name:{2} ex:{3}", CurrentCacheObject.ActorSNO, CurrentCacheObject.RActorGuid, CurrentCacheObject.InternalName, ex.Message); } try { CurrentCacheObject.IsQuestMonster = CurrentCacheObject.Object.CommonData.GetAttribute <int>(ActorAttributeType.QuestMonster) > 0; } catch (Exception ex) { Logger.LogDebug(LogCategory.CacheManagement, "Error reading IsQuestMonster for Gizmo sno:{0} raGuid:{1} name:{2} ex:{3}", CurrentCacheObject.ActorSNO, CurrentCacheObject.RActorGuid, CurrentCacheObject.InternalName, ex.Message); } if (CurrentCacheObject.Gizmo != null) { CurrentCacheObject.GizmoType = CurrentCacheObject.Gizmo.ActorInfo.GizmoType; } // Anything that's been disabled by a script bool isGizmoDisabledByScript = false; try { if (CurrentCacheObject.Object is DiaGizmo) { isGizmoDisabledByScript = CurrentCacheObject.Object.CommonData.GetAttribute <int>(ActorAttributeType.GizmoDisabledByScript) > 0; } } catch { CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Safely handled exception getting Gizmo-Disabled-By-Script attribute for object {0} [{1}]", CurrentCacheObject.InternalName, CurrentCacheObject.ActorSNO); c_IgnoreSubStep = "isGizmoDisabledByScriptException"; AddToCache = false; } if (isGizmoDisabledByScript) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "GizmoDisabledByScript"; return(AddToCache); } // Anything that's Untargetable bool untargetable = false; try { if (CurrentCacheObject.Object is DiaGizmo) { untargetable = CurrentCacheObject.Object.CommonData.GetAttribute <int>(ActorAttributeType.Untargetable) > 0; } } catch { } // Anything that's Invulnerable bool invulnerable = false; try { if (CurrentCacheObject.Object is DiaGizmo) { invulnerable = CurrentCacheObject.Object.CommonData.GetAttribute <int>(ActorAttributeType.Invulnerable) > 0; } } catch { } bool noDamage = false; try { if (CurrentCacheObject.Object is DiaGizmo) { noDamage = CurrentCacheObject.Object.CommonData.GetAttribute <int>(ActorAttributeType.NoDamage) > 0; } } catch { CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Safely handled exception getting NoDamage attribute for object {0} [{1}]", CurrentCacheObject.InternalName, CurrentCacheObject.ActorSNO); c_IgnoreSubStep = "NoDamage"; AddToCache = false; } double minDistance; bool gizmoUsed = false; switch (CurrentCacheObject.Type) { case GObjectType.Door: { AddToCache = true; if (c_diaObject is DiaGizmo && ((DiaGizmo)c_diaObject).HasBeenOperated) { AddToCache = false; c_IgnoreSubStep = "Door has been operated"; return(AddToCache); } try { string currentAnimation = CurrentCacheObject.CommonData.CurrentAnimation.ToString().ToLower(); gizmoUsed = currentAnimation.EndsWith("open") || currentAnimation.EndsWith("opening"); // special hax for A3 Iron Gates if (currentAnimation.Contains("irongate") && currentAnimation.Contains("open")) { gizmoUsed = false; } if (currentAnimation.Contains("irongate") && currentAnimation.Contains("idle")) { gizmoUsed = true; } } catch { } if (gizmoUsed) { Blacklist3Seconds.Add(CurrentCacheObject.RActorGuid); AddToCache = false; c_IgnoreSubStep = "Door is Open or Opening"; return(AddToCache); } try { int gizmoState = CurrentCacheObject.CommonData.GetAttribute <int>(ActorAttributeType.GizmoState); if (gizmoState == 1) { AddToCache = false; c_IgnoreSubStep = "GizmoState=1"; return(AddToCache); } } catch { AddToCache = false; c_IgnoreSubStep = "GizmoStateException"; return(AddToCache); } if (untargetable) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "Untargetable"; return(AddToCache); } if (AddToCache) { try { DiaGizmo door = null; if (c_diaObject is DiaGizmo) { door = (DiaGizmo)c_diaObject; if (door != null && door.IsGizmoDisabledByScript) { CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); Blacklist3Seconds.Add(CurrentCacheObject.RActorGuid); AddToCache = false; c_IgnoreSubStep = "DoorDisabledbyScript"; return(AddToCache); } } else { AddToCache = false; c_IgnoreSubStep = "InvalidCastToDoor"; } } catch { } } } break; case GObjectType.Interactable: { AddToCache = true; if (untargetable) { ((MainGridProvider)MainGridProvider).AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject() { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "Untargetable"; return(AddToCache); } int endAnimation; if (DataDictionary.InteractEndAnimations.TryGetValue(CurrentCacheObject.ActorSNO, out endAnimation)) { if (endAnimation == (int)CurrentCacheObject.Gizmo.CommonData.CurrentAnimation) { AddToCache = false; c_IgnoreSubStep = "EndAnimation"; return(AddToCache); } } if (CurrentCacheObject.Gizmo != null && CurrentCacheObject.Gizmo is GizmoLootContainer && CurrentCacheObject.Gizmo.HasBeenOperated) { AddToCache = false; c_IgnoreSubStep = "GizmoHasBeenOperated"; return(AddToCache); } CurrentCacheObject.Radius = c_diaObject.CollisionSphere.Radius; } break; case GObjectType.HealthWell: { AddToCache = true; try { gizmoUsed = (CurrentCacheObject.CommonData.GetAttribute <int>(ActorAttributeType.GizmoCharges) <= 0 && CurrentCacheObject.CommonData.GetAttribute <int>(ActorAttributeType.GizmoCharges) > 0); } catch { Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Safely handled exception getting shrine-been-operated attribute for object {0} [{1}]", CurrentCacheObject.InternalName, CurrentCacheObject.ActorSNO); AddToCache = true; //return bWantThis; } try { int gizmoState = CurrentCacheObject.CommonData.GetAttribute <int>(ActorAttributeType.GizmoState); if (gizmoState == 1) { AddToCache = false; c_IgnoreSubStep = "GizmoState=1"; return(AddToCache); } } catch { AddToCache = false; c_IgnoreSubStep = "GizmoStateException"; return(AddToCache); } if (gizmoUsed) { c_IgnoreSubStep = "GizmoCharges"; AddToCache = false; return(AddToCache); } if (untargetable) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "Untargetable"; return(AddToCache); } } break; case GObjectType.CursedShrine: case GObjectType.Shrine: { AddToCache = true; // Shrines // Check if either we want to ignore all shrines if (!Settings.WorldObject.UseShrine) { // We're ignoring all shrines, so blacklist this one c_IgnoreSubStep = "IgnoreAllShrinesSet"; AddToCache = false; return(AddToCache); } try { int gizmoState = CurrentCacheObject.CommonData.GetAttribute <int>(ActorAttributeType.GizmoState); if (gizmoState == 1) { AddToCache = false; c_IgnoreSubStep = "GizmoState=1"; return(AddToCache); } } catch { AddToCache = false; c_IgnoreSubStep = "GizmoStateException"; return(AddToCache); } if (untargetable) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "Untargetable"; return(AddToCache); } // Determine what shrine type it is, and blacklist if the user has disabled it switch (CurrentCacheObject.ActorSNO) { case 176077: //Frenzy Shrine if (!Settings.WorldObject.UseFrenzyShrine) { Blacklist60Seconds.Add(CurrentCacheObject.RActorGuid); c_IgnoreSubStep = "IgnoreShrineOption"; AddToCache = false; } if (Player.ActorClass == ActorClass.Monk && Settings.Combat.Monk.TROption.HasFlag(TempestRushOption.MovementOnly) && Hotbar.Contains(SNOPower.Monk_TempestRush)) { // Frenzy shrines are a huge time sink for monks using Tempest Rush to move, we should ignore them. AddToCache = false; c_IgnoreSubStep = "IgnoreShrineOption"; return(AddToCache); } break; case 176076: //Fortune Shrine if (!Settings.WorldObject.UseFortuneShrine) { AddToCache = false; c_IgnoreSubStep = "IgnoreShrineOption"; return(AddToCache); } break; case 176074: //Protection Shrine if (!Settings.WorldObject.UseProtectionShrine) { AddToCache = false; c_IgnoreSubStep = "IgnoreShrineOption"; return(AddToCache); } break; case 260330: //Empowered Shrine if (!Settings.WorldObject.UseEmpoweredShrine) { AddToCache = false; c_IgnoreSubStep = "IgnoreShrineOption"; return(AddToCache); } break; case 176075: //Enlightened Shrine if (!Settings.WorldObject.UseEnlightenedShrine) { AddToCache = false; c_IgnoreSubStep = "IgnoreShrineOption"; return(AddToCache); } break; case 260331: //Fleeting Shrine if (!Settings.WorldObject.UseFleetingShrine) { AddToCache = false; c_IgnoreSubStep = "IgnoreShrineOption"; return(AddToCache); } break; } //end switch // Bag it! CurrentCacheObject.Radius = 4f; break; } case GObjectType.Barricade: { AddToCache = true; if (noDamage) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "NoDamage"; return(AddToCache); } if (untargetable) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "Untargetable"; return(AddToCache); } if (invulnerable) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "Invulnerable"; return(AddToCache); } float maxRadiusDistance; if (DataDictionary.DestructableObjectRadius.TryGetValue(CurrentCacheObject.ActorSNO, out maxRadiusDistance)) { if (CurrentCacheObject.RadiusDistance < maxRadiusDistance) { AddToCache = true; c_IgnoreSubStep = ""; } } if (DateTime.UtcNow.Subtract(PlayerMover.LastGeneratedStuckPosition).TotalSeconds <= 1) { AddToCache = true; c_IgnoreSubStep = ""; break; } // Set min distance to user-defined setting minDistance = Settings.WorldObject.DestructibleRange + CurrentCacheObject.Radius; if (_forceCloseRangeTarget) { minDistance += 6f; } // This object isn't yet in our destructible desire range if (minDistance <= 0 || CurrentCacheObject.RadiusDistance > minDistance) { c_IgnoreSubStep = "NotInBarricadeRange"; AddToCache = false; return(AddToCache); } break; } case GObjectType.Destructible: { AddToCache = true; if (noDamage) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "NoDamage"; return(AddToCache); } if (invulnerable) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "Invulnerable"; return(AddToCache); } if (untargetable) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "Untargetable"; return(AddToCache); } if (Player.ActorClass == ActorClass.Monk && Hotbar.Contains(SNOPower.Monk_TempestRush) && TimeSinceUse(SNOPower.Monk_TempestRush) <= 150) { AddToCache = false; c_IgnoreSubStep = "MonkTR"; break; } if (Player.ActorClass == ActorClass.Monk && Hotbar.Contains(SNOPower.Monk_SweepingWind) && GetHasBuff(SNOPower.Monk_SweepingWind)) { AddToCache = false; c_IgnoreSubStep = "MonkSW"; break; } if (CurrentCacheObject.IsQuestMonster || CurrentCacheObject.IsMinimapActive) { AddToCache = true; c_IgnoreSubStep = ""; break; } if (!DataDictionary.ForceDestructibles.Contains(CurrentCacheObject.ActorSNO) && Settings.WorldObject.DestructibleOption == DestructibleIgnoreOption.ForceIgnore) { AddToCache = false; c_IgnoreSubStep = "ForceIgnoreDestructibles"; break; } if (DateTime.UtcNow.Subtract(PlayerMover.LastGeneratedStuckPosition).TotalSeconds <= 1) { AddToCache = true; c_IgnoreSubStep = ""; break; } // Set min distance to user-defined setting minDistance = Settings.WorldObject.DestructibleRange; if (_forceCloseRangeTarget) { minDistance += 6f; } // Only break destructables if we're stuck and using IgnoreNonBlocking if (Settings.WorldObject.DestructibleOption == DestructibleIgnoreOption.DestroyAll) { minDistance += 12f; AddToCache = true; c_IgnoreSubStep = ""; } float maxRadiusDistance; if (DataDictionary.DestructableObjectRadius.TryGetValue(CurrentCacheObject.ActorSNO, out maxRadiusDistance)) { if (CurrentCacheObject.RadiusDistance < maxRadiusDistance) { AddToCache = true; c_IgnoreSubStep = ""; } } // Always add large destructibles within ultra close range if (!AddToCache && CurrentCacheObject.Radius >= 10f && CurrentCacheObject.RadiusDistance <= 5.9f) { AddToCache = true; c_IgnoreSubStep = ""; break; } // This object isn't yet in our destructible desire range if (AddToCache && (minDistance <= 1 || CurrentCacheObject.RadiusDistance > minDistance) && PlayerMover.GetMovementSpeed() >= 1) { AddToCache = false; c_IgnoreSubStep = "NotInDestructableRange"; } if (AddToCache && CurrentCacheObject.RadiusDistance <= 2f && DateTime.UtcNow.Subtract(PlayerMover.LastGeneratedStuckPosition).TotalMilliseconds > 500) { AddToCache = false; c_IgnoreSubStep = "NotStuck2"; } // Add if we're standing still and bumping into it if (CurrentCacheObject.RadiusDistance <= 2f && PlayerMover.GetMovementSpeed() <= 0) { AddToCache = true; c_IgnoreSubStep = ""; } if (CurrentCacheObject.RActorGuid == LastTargetRactorGUID) { AddToCache = true; c_IgnoreSubStep = ""; } break; } case GObjectType.CursedChest: case GObjectType.Container: { AddToCache = false; bool isRareChest = CurrentCacheObject.InternalName.ToLower().Contains("chest_rare") || DataDictionary.ResplendentChestIds.Contains(CurrentCacheObject.ActorSNO); bool isChest = (!isRareChest && CurrentCacheObject.InternalName.ToLower().Contains("chest")) || DataDictionary.ContainerWhiteListIds.Contains(CurrentCacheObject.ActorSNO); // We know it's a container but this is not a known rare chest bool isCorpse = CurrentCacheObject.InternalName.ToLower().Contains("corpse"); bool isWeaponRack = CurrentCacheObject.InternalName.ToLower().Contains("rack"); bool isGroundClicky = CurrentCacheObject.InternalName.ToLower().Contains("ground_clicky"); // We want to do some vendoring, so don't open anything new yet if (ForceVendorRunASAP) { AddToCache = false; c_IgnoreSubStep = "ForceVendorRunASAP"; } // Already open, blacklist it and don't look at it again bool chestOpen; try { chestOpen = (CurrentCacheObject.CommonData.GetAttribute <int>(ActorAttributeType.ChestOpen) > 0); } catch { Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Safely handled exception getting container-been-opened attribute for object {0} [{1}]", CurrentCacheObject.InternalName, CurrentCacheObject.ActorSNO); c_IgnoreSubStep = "ChestOpenException"; AddToCache = false; return(AddToCache); } // Check if chest is open if (chestOpen) { // It's already open! AddToCache = false; c_IgnoreSubStep = "AlreadyOpen"; return(AddToCache); } if (untargetable) { MainGridProvider.AddCellWeightingObstacle(CurrentCacheObject.ActorSNO, CurrentCacheObject.Radius); CacheData.NavigationObstacles.Add(new CacheObstacleObject { ActorSNO = CurrentCacheObject.ActorSNO, Radius = CurrentCacheObject.Radius, Position = CurrentCacheObject.Position, RActorGUID = CurrentCacheObject.RActorGuid, ObjectType = CurrentCacheObject.Type, }); AddToCache = false; c_IgnoreSubStep = "Untargetable"; return(AddToCache); } // Resplendent chests have no range check if (isRareChest && Settings.WorldObject.OpenRareChests) { AddToCache = true; return(AddToCache); } // Regular container, check range if (CurrentCacheObject.RadiusDistance <= Settings.WorldObject.ContainerOpenRange) { if (isChest && Settings.WorldObject.OpenContainers) { return(true); } if (isCorpse && Settings.WorldObject.InspectCorpses) { return(true); } if (isGroundClicky && Settings.WorldObject.InspectGroundClicky) { return(true); } if (isWeaponRack && Settings.WorldObject.InspectWeaponRacks) { return(true); } } if (CurrentCacheObject.IsQuestMonster) { AddToCache = true; return(AddToCache); } if (Settings.WorldObject.OpenAnyContainer) { AddToCache = true; return(AddToCache); } if (!isChest && !isCorpse && !isRareChest) { c_IgnoreSubStep = "InvalidContainer"; } else { c_IgnoreSubStep = "IgnoreContainer"; } break; } } return(AddToCache); }
private static void RefreshDiaGetWeights() { using (new PerformanceLogger("RefreshDiaObjectCache.Weighting")) { double MovementSpeed = PlayerMover.GetMovementSpeed(); // Store if we are ignoring all units this cycle or not bool bIgnoreAllUnits = !AnyElitesPresent && !AnyMobsInRange && ( ( !AnyTreasureGoblinsPresent && Settings.Combat.Misc.GoblinPriority >= GoblinPriority.Prioritize ) || Settings.Combat.Misc.GoblinPriority < GoblinPriority.Prioritize ) && PlayerStatus.CurrentHealthPct >= 0.85d; bool PrioritizeCloseRangeUnits = (ForceCloseRangeTarget || PlayerStatus.IsRooted || MovementSpeed < 1 || GilesObjectCache.Count(u => u.Type == GObjectType.Unit && u.RadiusDistance < 5f) >= 3); bool hasWrathOfTheBerserker = PlayerStatus.ActorClass == ActorClass.Barbarian && GetHasBuff(SNOPower.Barbarian_WrathOfTheBerserker); int TrashMobCount = GilesObjectCache.Count(u => u.Type == GObjectType.Unit && u.IsTrashMob); int EliteCount = Settings.Combat.Misc.IgnoreElites ? 0 : GilesObjectCache.Count(u => u.Type == GObjectType.Unit && u.IsBossOrEliteRareUnique); int AvoidanceCount = Settings.Combat.Misc.AvoidAOE ? 0 : GilesObjectCache.Count(o => o.Type == GObjectType.Avoidance && o.CentreDistance <= 50f); bool profileTagCheck = false; if (ProfileManager.CurrentProfileBehavior != null) { Type behaviorType = ProfileManager.CurrentProfileBehavior.GetType(); if (behaviorType == typeof(WaitTimerTag) || behaviorType == typeof(UseTownPortalTag) || behaviorType == typeof(XmlTags.TrinityTownRun)) { profileTagCheck = true; } } bool ShouldIgnoreTrashMobs = (!TownRun.IsTryingToTownPortal() && !profileTagCheck && !PrioritizeCloseRangeUnits && Settings.Combat.Misc.TrashPackSize > 1 && EliteCount == 0 && AvoidanceCount == 0 && PlayerStatus.Level >= 15 && MovementSpeed >= 1 ); string unitWeightInfo = ""; foreach (GilesObject cacheObject in GilesObjectCache.OrderBy(c => c.CentreDistance)) { unitWeightInfo = ""; // Just to make sure each one starts at 0 weight... cacheObject.Weight = 0d; // Now do different calculations based on the object type switch (cacheObject.Type) { // Weight Units case GObjectType.Unit: { int nearbyMonsterCount = GilesObjectCache.Count(u => u.IsTrashMob && cacheObject.Position.Distance2D(u.Position) <= Settings.Combat.Misc.TrashPackClusterRadius); // Ignore Solitary Trash mobs (no elites present) // Except if has been primary target or if already low on health (<= 20%) if (ShouldIgnoreTrashMobs && cacheObject.IsTrashMob && !cacheObject.HasBeenPrimaryTarget && cacheObject.RadiusDistance >= 2f && !(nearbyMonsterCount >= Settings.Combat.Misc.TrashPackSize)) { unitWeightInfo = String.Format("Ignoring trash mob {0} {1} nearbyCount={2} packSize={3} packRadius={4:0} radiusDistance={5:0} ShouldIgnore={6} ms={7:0.00} Elites={8} Avoid={9} profileTagCheck={10} level={11} prioritize={12}", cacheObject.InternalName, cacheObject.RActorGuid, nearbyMonsterCount, Settings.Combat.Misc.TrashPackSize, Settings.Combat.Misc.TrashPackClusterRadius, cacheObject.RadiusDistance, ShouldIgnoreTrashMobs, MovementSpeed, EliteCount, AvoidanceCount, profileTagCheck, PlayerStatus.Level, PrioritizeCloseRangeUnits); break; } else { unitWeightInfo = String.Format("Adding trash mob {0} {1} nearbyCount={2} packSize={3} packRadius={4:0} radiusDistance={5:0} ShouldIgnore={6} ms={7:0.00} Elites={8} Avoid={9} profileTagCheck={10} level={11} prioritize={12}", cacheObject.InternalName, cacheObject.RActorGuid, nearbyMonsterCount, Settings.Combat.Misc.TrashPackSize, Settings.Combat.Misc.TrashPackClusterRadius, cacheObject.RadiusDistance, ShouldIgnoreTrashMobs, MovementSpeed, EliteCount, AvoidanceCount, profileTagCheck, PlayerStatus.Level, PrioritizeCloseRangeUnits); } // Ignore elite option, except if trying to town portal if (Settings.Combat.Misc.IgnoreElites && (cacheObject.IsEliteRareUnique) && !TownRun.IsTryingToTownPortal()) { break; } // No champions, no mobs nearby, no treasure goblins to prioritize, and not injured, so skip mobs if (bIgnoreAllUnits) { break; } // Monster is in cache but not within kill range if (cacheObject.RadiusDistance > cacheObject.KillRange) { break; } if (cacheObject.HitPoints <= 0) { break; } // Total up monsters at various ranges if (cacheObject.RadiusDistance <= 50f) { bool isElite = (cacheObject.IsEliteRareUnique || cacheObject.IsBoss); bool isRended = cacheObject.HasDotDPS; // Flag up any bosses in range if (cacheObject.IsBoss) { anyBossesInRange = true; } if (cacheObject.RadiusDistance <= 6f) { AnythingWithinRange[RANGE_6]++; if (isElite) { ElitesWithinRange[RANGE_6]++; } } if (cacheObject.RadiusDistance <= 9f && !isRended) { NonRendedTargets_9++; } if (cacheObject.RadiusDistance <= 12f) { AnythingWithinRange[RANGE_12]++; if (isElite) { ElitesWithinRange[RANGE_12]++; } } if (cacheObject.RadiusDistance <= 15f) { AnythingWithinRange[RANGE_15]++; if (isElite) { ElitesWithinRange[RANGE_15]++; } } if (cacheObject.RadiusDistance <= 20f) { AnythingWithinRange[RANGE_20]++; if (isElite) { ElitesWithinRange[RANGE_20]++; } } if (cacheObject.RadiusDistance <= 25f) { if (!bAnyNonWWIgnoreMobsInRange && !hashActorSNOWhirlwindIgnore.Contains(cacheObject.ActorSNO)) { bAnyNonWWIgnoreMobsInRange = true; } AnythingWithinRange[RANGE_25]++; if (isElite) { ElitesWithinRange[RANGE_25]++; } } if (cacheObject.RadiusDistance <= 30f) { AnythingWithinRange[RANGE_30]++; if (isElite) { ElitesWithinRange[RANGE_30]++; } } if (cacheObject.RadiusDistance <= 40f) { AnythingWithinRange[RANGE_40]++; if (isElite) { ElitesWithinRange[RANGE_40]++; } } if (cacheObject.RadiusDistance <= 50f) { AnythingWithinRange[RANGE_50]++; if (isElite) { ElitesWithinRange[RANGE_50]++; } } } // Force a close range target because we seem to be stuck *OR* if not ranged and currently rooted if (PrioritizeCloseRangeUnits) { cacheObject.Weight = (50 - cacheObject.RadiusDistance) / 50 * 20000d; // Goblin priority KAMIKAZEEEEEEEE if (cacheObject.IsTreasureGoblin && Settings.Combat.Misc.GoblinPriority == GoblinPriority.Kamikaze) { cacheObject.Weight += 25000; } } else { // Not attackable, could be shielded, make super low priority if (cacheObject.IsShielded) { // Only 500 weight helps prevent it being prioritized over an unshielded cacheObject.Weight = 500; } // Not forcing close-ranged targets from being stuck, so let's calculate a weight! else { // Elites/Bosses that are killed should have weight erased so we don't keep attacking if ((cacheObject.IsEliteRareUnique || cacheObject.IsBoss) && cacheObject.HitPointsPct <= 0) { cacheObject.Weight = 0; break; } // Starting weight of 5000 if (cacheObject.IsTrashMob) { cacheObject.Weight = (CurrentBotKillRange - cacheObject.RadiusDistance) / CurrentBotKillRange * 5000; } // Starting weight of 8000 for elites if (cacheObject.IsBossOrEliteRareUnique) { cacheObject.Weight = (90f - cacheObject.RadiusDistance) / 90f * 8000; } // Give extra weight to ranged enemies if ((PlayerStatus.ActorClass == ActorClass.Barbarian || PlayerStatus.ActorClass == ActorClass.Monk) && (cacheObject.MonsterStyle == MonsterSize.Ranged || hashActorSNORanged.Contains(c_ActorSNO))) { cacheObject.Weight += 1100; cacheObject.ForceLeapAgainst = true; } // Lower health gives higher weight - health is worth up to 1000ish extra weight if (cacheObject.IsTrashMob && cacheObject.HitPointsPct < 0.20) { cacheObject.Weight += (100 - cacheObject.HitPointsPct) / 100 * 1000; } // Elites on low health get extra priority - up to 2500ish if (cacheObject.IsBossOrEliteRareUnique && cacheObject.HitPointsPct < 0.20) { cacheObject.Weight += (100 - cacheObject.HitPointsPct) / 100 * 2500; } // Goblins on low health get extra priority - up to 4000ish if (Settings.Combat.Misc.GoblinPriority >= GoblinPriority.Prioritize && cacheObject.IsTreasureGoblin && cacheObject.HitPointsPct <= 0.98) { cacheObject.Weight += (100 - cacheObject.HitPointsPct) / 100 * 4000; } // Bonuses to priority type monsters from the dictionary/hashlist set at the top of the code int iExtraPriority; if (dictActorSNOPriority.TryGetValue(cacheObject.ActorSNO, out iExtraPriority)) { cacheObject.Weight += iExtraPriority; } // Close range get higher weights the more of them there are, to prevent body-blocking if (cacheObject.RadiusDistance <= 5f) { cacheObject.Weight += (2000 * cacheObject.Radius); } // Special additional weight for corrupt growths in act 4 ONLY if they are at close range (not a standard priority thing) if ((cacheObject.ActorSNO == 210120 || cacheObject.ActorSNO == 210268) && cacheObject.CentreDistance <= 25f) { cacheObject.Weight += 2000; } // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f) { cacheObject.Weight += 1000; } // Prevent going less than 300 yet to prevent annoyances (should only lose this much weight from priority reductions in priority list?) if (cacheObject.Weight < 300) { cacheObject.Weight = 300; } // If any AoE between us and target, do not attack, for non-ranged attacks only if (!Settings.Combat.Misc.KillMonstersInAoE && PlayerKiteDistance <= 0 && hashAvoidanceObstacleCache.Any(o => MathUtil.IntersectsPath(o.Location, o.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight = 1; } // See if there's any AOE avoidance in that spot, if so reduce the weight to 1, for non-ranged attacks only if (!Settings.Combat.Misc.KillMonstersInAoE && PlayerKiteDistance <= 0 && hashAvoidanceObstacleCache.Any(aoe => cacheObject.Position.Distance2D(aoe.Location) <= aoe.Radius)) { cacheObject.Weight = 1; } if (PlayerKiteDistance > 0) { if (GilesObjectCache.Any(m => m.Type == GObjectType.Unit && MathUtil.IntersectsPath(cacheObject.Position, cacheObject.Radius, PlayerStatus.CurrentPosition, m.Position) && m.RActorGuid != cacheObject.RActorGuid)) { cacheObject.Weight = 0; } } // Deal with treasure goblins - note, of priority is set to "0", then the is-a-goblin flag isn't even set for use here - the monster is ignored if (cacheObject.IsTreasureGoblin && !GilesObjectCache.Any(u => (u.Type == GObjectType.Door || u.Type == GObjectType.Barricade) && u.RadiusDistance <= 40f)) { // Logging goblin sightings if (lastGoblinTime == DateTime.Today) { iTotalNumberGoblins++; lastGoblinTime = DateTime.Now; DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "Goblin #{0} in sight. Distance={1:0}", iTotalNumberGoblins, cacheObject.CentreDistance); } else { if (DateTime.Now.Subtract(lastGoblinTime).TotalMilliseconds > 30000) { lastGoblinTime = DateTime.Today; } } if (hashAvoidanceObstacleCache.Any(aoe => cacheObject.Position.Distance2D(aoe.Location) <= aoe.Radius) && Settings.Combat.Misc.GoblinPriority != GoblinPriority.Kamikaze) { cacheObject.Weight = 1; break; } // Original Trinity stuff for priority handling now switch (Settings.Combat.Misc.GoblinPriority) { case GoblinPriority.Normal: // Treating goblins as "normal monsters". Ok so I lied a little in the config, they get a little extra weight really! ;) cacheObject.Weight += 751; break; case GoblinPriority.Prioritize: // Super-high priority option below... cacheObject.Weight += 20000; break; case GoblinPriority.Kamikaze: // KAMIKAZE SUICIDAL TREASURE GOBLIN RAPE AHOY! cacheObject.Weight += 40000; break; } } } // Forcing close range target or not? } // This is an attackable unit break; } case GObjectType.Item: case GObjectType.Gold: { // Weight Items // We'll weight them based on distance, giving gold less weight and close objects more //if (cacheObject.GoldAmount > 0) // cacheObject.Weight = 5000d - (Math.Floor(cacheObject.CentreDistance) * 2000d); //else // cacheObject.Weight = 8000d - (Math.Floor(cacheObject.CentreDistance) * 1900d); if (cacheObject.GoldAmount > 0) { cacheObject.Weight = (300 - cacheObject.CentreDistance) / 300 * 9000d; } else { cacheObject.Weight = (300 - cacheObject.CentreDistance) / 300 * 9000d; } // Point-blank items get a weight increase if (cacheObject.GoldAmount <= 0 && cacheObject.CentreDistance <= 12f) { cacheObject.Weight += 1000d; } // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets if (cacheObject.RActorGuid == CurrentTargetRactorGUID) { cacheObject.Weight += 800; } // Give yellows more weight if (cacheObject.GoldAmount <= 0 && cacheObject.ItemQuality >= ItemQuality.Rare4) { cacheObject.Weight += 4000d; } // Give legendaries more weight if (cacheObject.GoldAmount <= 0 && cacheObject.ItemQuality >= ItemQuality.Legendary) { cacheObject.Weight += 15000d; } // Are we prioritizing close-range stuff atm? If so limit it at a value 3k lower than monster close-range priority //if (PrioritizeCloseRangeUnits) // cacheObject.Weight = (200f - cacheObject.CentreDistance) / 200f * 18000d; if (PlayerStatus.ActorClass == ActorClass.Monk && TimeSinceUse(SNOPower.Monk_TempestRush) < 1000 && cacheObject.ItemQuality < ItemQuality.Legendary) { cacheObject.Weight = 500; } // If there's a monster in the path-line to the item, reduce the weight to 1, except legendaries if (cacheObject.ItemQuality < ItemQuality.Legendary && hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius * 1.2f, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight = 1; } // ignore any items/gold if there is mobs in kill radius and we aren't combat looting if (CurrentTarget != null && AnyMobsInRange && !Zeta.CommonBot.Settings.CharacterSettings.Instance.CombatLooting && cacheObject.ItemQuality < ItemQuality.Legendary) { cacheObject.Weight = 1; } // See if there's any AOE avoidance in that spot or inbetween us, if so reduce the weight to 1 if (hashAvoidanceObstacleCache.Any(aoe => cacheObject.Position.Distance2D(aoe.Location) <= aoe.Radius)) { cacheObject.Weight = 1; } // ignore non-legendaries and gold near elites if we're ignoring elites // not sure how we should safely determine this distance if (Settings.Combat.Misc.IgnoreElites && cacheObject.ItemQuality < ItemQuality.Legendary && GilesObjectCache.Any(u => u.Type == GObjectType.Unit && u.IsEliteRareUnique && u.Position.Distance2D(cacheObject.Position) <= 40f)) { cacheObject.Weight = 0; } break; } case GObjectType.Globe: { // Weight Health Globes // Give all globes 0 weight (so never gone-to), unless we have low health, then go for them if (PlayerStatus.CurrentHealthPct > PlayerEmergencyHealthGlobeLimit || !Settings.Combat.Misc.CollectHealthGlobe) { cacheObject.Weight = 0; } else { // Ok we have globes enabled, and our health is low...! cacheObject.Weight = (300f - cacheObject.RadiusDistance) / 300f * 17000d; // Point-blank items get a weight increase if (cacheObject.CentreDistance <= 15f) { cacheObject.Weight += 3000d; } // Close items get a weight increase if (cacheObject.CentreDistance <= 60f) { cacheObject.Weight += 1500d; } // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f) { cacheObject.Weight += 800; } // Are we prioritizing close-range stuff atm? If so limit it at a value 3k lower than monster close-range priority //if (bPrioritizeCloseRange) // thisgilesobject.dThisWeight = 22000 - (Math.Floor(thisgilesobject.fCentreDistance) * 200); // If there's a monster in the path-line to the item, reduce the weight by 15% for each Vector3 point = cacheObject.Position; foreach (GilesObstacle tempobstacle in hashMonsterObstacleCache.Where(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, point))) { cacheObject.Weight *= 0.85; } // See if there's any AOE avoidance in that spot, if so reduce the weight by 10% if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight *= 0.9; } // Calculate a spot reaching a little bit further out from the globe, to help globe-movements if (cacheObject.Weight > 0) { cacheObject.Position = MathEx.CalculatePointFrom(cacheObject.Position, PlayerStatus.CurrentPosition, cacheObject.CentreDistance + 3f); } // do not collect health globes if we are kiting and health globe is too close to monster or avoidance if (PlayerKiteDistance > 0) { if (hashMonsterObstacleCache.Any(m => m.Location.Distance(cacheObject.Position) < PlayerKiteDistance)) { cacheObject.Weight = 0; } if (hashAvoidanceObstacleCache.Any(m => m.Location.Distance(cacheObject.Position) < PlayerKiteDistance)) { cacheObject.Weight = 0; } } } break; } case GObjectType.HealthWell: { // Healths Wells get handled correctly ... if (cacheObject.Type == GObjectType.HealthWell && PlayerStatus.CurrentHealthPct <= .75) { cacheObject.Weight += 7500; } if (cacheObject.Type == GObjectType.HealthWell && PlayerStatus.CurrentHealthPct <= .25) { cacheObject.Weight += 20000d; } break; } case GObjectType.Shrine: { // Weight Shrines cacheObject.Weight = (75f - cacheObject.RadiusDistance) / 75f * 14500f; // Very close shrines get a weight increase if (cacheObject.CentreDistance <= 30f) { cacheObject.Weight += 10000d; } if (cacheObject.Weight > 0) { // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f) { cacheObject.Weight += 400; } // If there's a monster in the path-line to the item if (hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight = 1; } // See if there's any AOE avoidance in that spot, if so reduce the weight to 1 if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight = 1; } // if there's any monsters nearby if (TargetUtil.AnyMobsInRange(15f)) { cacheObject.Weight = 1; } if (PrioritizeCloseRangeUnits) { cacheObject.Weight = 1; } } break; } case GObjectType.Door: { if (!GilesObjectCache.Any(u => u.Type == GObjectType.Unit && u.HitPointsPct > 0 && MathUtil.IntersectsPath(u.Position, u.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { if (cacheObject.RadiusDistance <= 20f) { cacheObject.Weight += 15000d; } // We're standing on the damn thing... open it!! if (cacheObject.RadiusDistance <= 12f) { cacheObject.Weight += 30000d; } } break; } case GObjectType.Destructible: case GObjectType.Barricade: { // rrrix added this as a single "weight" source based on the DestructableRange. // Calculate the weight based on distance, where a distance = 1 is 5000, 90 = 0 cacheObject.Weight = (90f - cacheObject.RadiusDistance) / 90f * 5000f; // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f) { cacheObject.Weight += 400; } //// Close destructibles get a weight increase //if (cacheObject.CentreDistance <= 16f) // cacheObject.Weight += 1500d; // If there's a monster in the path-line to the item, reduce the weight by 50% if (hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight *= 0.5; } // See if there's any AOE avoidance in that spot, if so reduce the weight to 1 if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight = 1; } // Are we prioritizing close-range stuff atm? If so limit it at a value 3k lower than monster close-range priority if (PrioritizeCloseRangeUnits) { cacheObject.Weight = (200d - cacheObject.CentreDistance) / 200d * 19200d; } //// We're standing on the damn thing... break it if (cacheObject.RadiusDistance <= 5f) { cacheObject.Weight += 40000d; } //// Fix for WhimsyShire Pinata if (hashSNOContainerResplendant.Contains(cacheObject.ActorSNO)) { cacheObject.Weight = 100 + cacheObject.RadiusDistance; } break; } case GObjectType.Interactable: { // Weight Interactable Specials // Very close interactables get a weight increase cacheObject.Weight = (90d - cacheObject.CentreDistance) / 90d * 15000d; if (cacheObject.CentreDistance <= 12f) { cacheObject.Weight += 1000d; } // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f) { cacheObject.Weight += 400; } // If there's a monster in the path-line to the item, reduce the weight by 50% if (hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight *= 0.5; } // See if there's any AOE avoidance in that spot, if so reduce the weight to 1 if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight = 1; } //if (bAnyMobsInCloseRange || (CurrentTarget != null && CurrentTarget.IsBossOrEliteRareUnique)) // cacheObject.Weight = 1; break; } case GObjectType.Container: { // Weight Containers // Very close containers get a weight increase cacheObject.Weight = (190d - cacheObject.CentreDistance) / 190d * 11000d; if (cacheObject.CentreDistance <= 12f) { cacheObject.Weight += 600d; } // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f) { cacheObject.Weight += 400; } // If there's a monster in the path-line to the item, reduce the weight by 50% if (hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight *= 0.5; } // See if there's any AOE avoidance in that spot, if so reduce the weight to 1 if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position))) { cacheObject.Weight = 1; } break; } } // Switch on object type // Force the character to stay where it is if there is nothing available that is out of avoidance stuff and we aren't already in avoidance stuff if (cacheObject.Weight == 1 && !StandingInAvoidance && GilesObjectCache.Any(o => o.Type == GObjectType.Avoidance)) { cacheObject.Weight = 0; ShouldStayPutDuringAvoidance = true; } DbHelper.Log(TrinityLogLevel.Debug, LogCategory.Weight, "Weight={2:0} target= {0} ({1}) type={3} R-Dist={4:0} IsElite={5} RAGuid={6} {7}", cacheObject.InternalName, cacheObject.ActorSNO, cacheObject.Weight, cacheObject.Type, cacheObject.RadiusDistance, cacheObject.IsElite, cacheObject.RActorGuid, unitWeightInfo); // Prevent current target dynamic ranged weighting flip-flop if (CurrentTargetRactorGUID == cacheObject.RActorGuid && cacheObject.Weight <= 1) { cacheObject.Weight = 100; } // Is the weight of this one higher than the current-highest weight? Then make this the new primary target! if (cacheObject.Weight > w_HighestWeightFound && cacheObject.Weight > 0) { // Clone the current Giles-cache object CurrentTarget = cacheObject.Clone(); w_HighestWeightFound = cacheObject.Weight; // See if we can try attempting kiting later NeedToKite = false; vKitePointAvoid = vNullLocation; // Kiting and Avoidance if (CurrentTarget.Type == GObjectType.Unit) { var AvoidanceList = hashAvoidanceObstacleCache.Where(o => // Distance from avoidance to target is less than avoidance radius o.Location.Distance(CurrentTarget.Position) <= (GetAvoidanceRadius(o.ActorSNO) * 1.2) && // Distance from obstacle to me is <= cacheObject.RadiusDistance o.Location.Distance(PlayerStatus.CurrentPosition) <= (cacheObject.RadiusDistance - 4f) ); // if there's any obstacle within a specified distance of the avoidance radius *1.2 if (AvoidanceList.Any()) { foreach (GilesObstacle o in AvoidanceList) { DbHelper.Log(TrinityLogLevel.Debug, LogCategory.Targetting, "Avoidance: Id={0} Weight={1} Loc={2} Radius={3} Name={4}", o.ActorSNO, o.Weight, o.Location, o.Radius, o.Name); } vKitePointAvoid = CurrentTarget.Position; NeedToKite = true; } } } } // Loop through all the objects and give them a weight if (CurrentTarget != null && CurrentTarget.InternalName != null && CurrentTarget.ActorSNO > 0 && CurrentTarget.RActorGuid != CurrentTargetRactorGUID) { RecordTargetHistory(); DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Targetting, "Target changed to name={2} sno={0} type={1} raGuid={3}", CurrentTarget.InternalName, CurrentTarget.ActorSNO, CurrentTarget.Type, CurrentTarget.RActorGuid); } } }