///<summary> ///Used to recreate from temp into obstacle object. ///</summary> public CacheObject(CacheObject parent) : base(parent) { this.AcdGuid=parent.AcdGuid; this.BlacklistFlag=parent.BlacklistFlag; this.BlacklistLoops_=parent.BlacklistLoops_; this.gprect_=parent.gprect_; this.InteractionAttempts=parent.InteractionAttempts; this.LastLOSCheck=parent.LastLOSCheck; this.LoopsUnseen_=parent.LoopsUnseen_; this.losv3_=parent.losv3_; this.LosSearchRetryMilliseconds_=parent.LosSearchRetryMilliseconds_; this.NeedsRemoved=parent.NeedsRemoved; this.NeedsUpdate=parent.NeedsUpdate; this.PrioritizedDate=parent.PrioritizedDate; this.PriorityCounter=parent.PriorityCounter; this.position_=parent.Position; this.radius_=parent.Radius; this.RAGUID=parent.RAGUID; this.ref_DiaObject=parent.ref_DiaObject; this.removal_=parent.removal_; this.RequiresLOSCheck=parent.RequiresLOSCheck; this.SummonerID=parent.SummonerID; this.weight_=parent.Weight; this.HandleAsAvoidanceObject=parent.HandleAsAvoidanceObject; }
public CacheAvoidance(CacheObject parent, AvoidanceType type, Ray R, double speed) : base(parent) { this.AvoidanceType=type; this.ray_=R; this.Speed=speed; this.projectile_startPosition=base.Position; }
public CacheAvoidance(CacheObject parent, AvoidanceType avoidancetype) : base(parent) { this.AvoidanceType=avoidancetype; //Special avoidances that require additional loops before removal if ((AvoidanceType.TreeSpore|AvoidanceType.GrotesqueExplosion).HasFlag(this.AvoidanceType)) this.RefreshRemovalCounter=30; }
public CacheServerObject(CacheObject parent) : base(parent) { }
///<summary> ///Tests if this intersects with current bot position using CacheObject ///</summary> public virtual bool TestIntersection(CacheObject OBJ, Vector3 BotPosition) { return MathEx.IntersectsPath(base.Position, this.Radius, BotPosition, base.BotMeleeVector); }
///<summary> /// ///</summary> public CacheObstacle(CacheObject fromObj) : base(fromObj) { if (!base.Obstacletype.HasValue) base.Obstacletype=ObstacleType.None; }
public override bool TestIntersection(CacheObject OBJ, Vector3 BotPosition) { if (this.Obstacletype.Value==ObstacleType.MovingAvoidance) { Vector3 ProjectileEndPoint=MathEx.GetPointAt(this.Position, this.ProjectileMaxRange, this.Rotation); return GridPoint.LineIntersectsLine(BotPosition, this.Position, this.PointPosition, ProjectileEndPoint); } return MathEx.IntersectsPath(base.Position, this.Radius, BotPosition, OBJ.Position); }
///<summary> ///Iterates through Usable objects and sets the Bot.CurrentTarget to the highest weighted object found inside the given list. ///</summary> private void WeightEvaluationObjList() { // Store if we are ignoring all units this cycle or not bool bIgnoreAllUnits=!Bot.Combat.bAnyChampionsPresent &&!Bot.Combat.bAnyMobsInCloseRange &&((!Bot.Combat.bAnyTreasureGoblinsPresent&&Bot.SettingsFunky.GoblinPriority>=2)||Bot.SettingsFunky.GoblinPriority<2) &&Bot.Character.dCurrentHealthPct>=0.85d; //clear our last "avoid" list.. ObjectCache.Objects.objectsIgnoredDueToAvoidance.Clear(); double iHighestWeightFound=0; foreach (CacheObject thisobj in Bot.ValidObjects) { thisobj.UpdateWeight(); if (thisobj.Weight==1) { // 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 thisobj.Weight=0; if (!Bot.Combat.RequiresAvoidance) Bot.Combat.bStayPutDuringAvoidance=true; continue; } // Is the weight of this one higher than the current-highest weight? Then make this the new primary target! if (thisobj.Weight>iHighestWeightFound&&thisobj.Weight>0) { //Check combat looting (Demonbuddy Setting) if (iHighestWeightFound>0 &&thisobj.targetType.Value==TargetType.Item &&!Zeta.CommonBot.Settings.CharacterSettings.Instance.CombatLooting &&CurrentTarget.targetType.Value==TargetType.Unit) continue; //cache RAGUID so we can switch back if we need to int CurrentTargetRAGUID=CurrentTarget!=null?CurrentTarget.RAGUID:-1; //Set our current target to this object! CurrentTarget=ObjectCache.Objects[thisobj.RAGUID]; bool resetTarget=false; //Check for Range Classes and Unit Targets if (!Bot.Class.IsMeleeClass&&CurrentTarget.targetType.Value==TargetType.Unit&&Bot.Combat.NearbyAvoidances.Count>0) { //set unit target (for Ability selector). CurrentUnitTarget=(CacheUnit)CurrentTarget; //Generate next Ability.. Ability nextAbility=Bot.Class.AbilitySelector(); //reset unit target CurrentUnitTarget=null; //Check if we are already within interaction range. if (!thisobj.WithinInteractionRange()) { Vector3 destinationV3=nextAbility.DestinationVector; //Check if the estimated destination will also be inside avoidance zone.. if (ObjectCache.Obstacles.IsPositionWithinAvoidanceArea(destinationV3) ||ObjectCache.Obstacles.TestVectorAgainstAvoidanceZones(destinationV3)) { //Only wait if the object is special and we are not avoiding.. if (thisobj.ObjectIsSpecial) { if (!Bot.Combat.RequiresAvoidance) { Bot.Combat.bStayPutDuringAvoidance=true; resetTarget=true; } else if (!nextAbility.IsRanged&&nextAbility.Range>0) { //Non-Ranged Ability.. act like melee.. //Try to find a spot ObjectCache.Objects.objectsIgnoredDueToAvoidance.Add(thisobj); } } else resetTarget=true; } } } //Avoidance Attempt to find a location where we can attack! if (ObjectCache.Objects.objectsIgnoredDueToAvoidance.Contains(thisobj)) { //Wait if no valid target found yet.. and no avoidance movement required. if (!Bot.Combat.RequiresAvoidance) Bot.Combat.bStayPutDuringAvoidance=true; //Check Bot Navigationally blocked Bot.NavigationCache.RefreshNavigationBlocked(); if (!Bot.NavigationCache.BotIsNavigationallyBlocked) { Vector3 SafeLOSMovement; if (thisobj.GPRect.TryFindSafeSpot(Bot.Character.Position, out SafeLOSMovement, Vector3.Zero, Bot.Character.ShouldFlee, true)) { CurrentTarget=new CacheObject(SafeLOSMovement, TargetType.Avoidance, 20000, "SafetyMovement", 2.5f, -1); //Reset Avoidance Timer so we don't trigger it while moving towards the target! Bot.Combat.timeCancelledEmergencyMove=DateTime.Now; Bot.Combat.iMillisecondsCancelledEmergencyMoveFor=1000+((int)(Bot.Target.CurrentTarget.CentreDistance/25f)*1000); } else { resetTarget=true; } } } if (resetTarget) { CurrentTarget=CurrentTargetRAGUID!=-1?ObjectCache.Objects[CurrentTargetRAGUID]:null; continue; } iHighestWeightFound=thisobj.Weight; } } // Loop through all the objects and give them a weight }
public CacheDestructable(CacheObject baseobj) : base(baseobj) { }
public CacheGizmo(CacheObject baseobj) : base(baseobj) { }
//internal bool UsedAutoMovementCommand=false; internal static RunStatus TargetMoveTo(CacheObject obj) { #region DebugInfo if (Bot.SettingsFunky.DebugStatusBar) { string Action="[Move-"; switch (obj.targetType.Value) { case TargetType.Avoidance: Action+="Avoid] "; break; case TargetType.Unit: if (obj.LOSV3!=Vector3.Zero) Action+="LOS] "; else if (Bot.NavigationCache.groupRunningBehavior&&Bot.NavigationCache.groupingCurrentUnit!=null&&Bot.NavigationCache.groupingCurrentUnit==obj) Action+="Grouping] "; else Action+="Combat] "; break; case TargetType.Item: case TargetType.Gold: case TargetType.Globe: Action+="Pickup] "; break; case TargetType.Interactable: Action+="Interact] "; break; case TargetType.Container: Action+="Open] "; break; case TargetType.Destructible: case TargetType.Barricade: Action+="Destroy] "; break; case TargetType.Shrine: Action+="Click] "; break; } Bot.Target.UpdateStatusText(Action); } #endregion // Are we currently incapacitated? If so then wait... if (Bot.Character.bIsIncapacitated||Bot.Character.bIsRooted) return RunStatus.Running; if (Bot.SettingsFunky.SkipAhead) SkipAheadCache.RecordSkipAheadCachePoint(); // Some stuff to avoid spamming usepower EVERY loop, and also to detect stucks/staying in one place for too long bool bForceNewMovement=false; //Herbfunk: Added this to prevent stucks attempting to move to a target blocked. (Case: 3 champs behind a wall, within range but could not engage due to being on the other side.) if (NonMovementCounter>50) { Logging.WriteVerbose("{0}: Ignoring obj {1} due to no movement counter reaching {2}", "[Funky]", obj.InternalName+" _ SNO:"+obj.SNOID, NonMovementCounter); obj.BlacklistLoops=50; obj.RequiresLOSCheck=true; Bot.Combat.bForceTargetUpdate=true; NonMovementCounter=0; // Reset the emergency loop counter and return success return RunStatus.Running; } Bot.NavigationCache.RefreshMovementCache(); Bot.NavigationCache.ObstaclePrioritizeCheck(); #region DistanceChecks // Count how long we have failed to move - body block stuff etc. if (!Bot.NavigationCache.IsMoving||Bot.NavigationCache.currentMovementState.Equals(MovementState.WalkingInPlace)||Bot.NavigationCache.currentMovementState.Equals(MovementState.None)) { bForceNewMovement=true; if (DateTime.Now.Subtract(LastMovementDuringCombat).TotalMilliseconds>=250) { LastMovementDuringCombat=DateTime.Now; // We've been stuck at least 250 ms, let's go and pick new targets etc. BlockedMovementCounter++; Bot.Combat.bForceCloseRangeTarget=true; Bot.Combat.lastForcedKeepCloseRange=DateTime.Now; // Tell target finder to prioritize close-combat targets incase we were bodyblocked #region TargetingPriortize switch (BlockedMovementCounter) { case 2: case 3: //Than check our movement state //If we are moving to a LOS location.. nullify it! if (obj.LOSV3!=Vector3.Zero) { Logging.WriteVerbose("Blockcounter Reseting LOS Movement Vector"); obj.LOSV3=Vector3.Zero; } var intersectingObstacles=Bot.Combat.NearbyObstacleObjects //ObjectCache.Obstacles.Values.OfType<CacheServerObject>() .Where(obstacle => !Bot.Combat.PrioritizedRAGUIDs.Contains(obstacle.RAGUID)//Only objects not already prioritized &&obstacle.Obstacletype.HasValue &&ObstacleType.Navigation.HasFlag(obstacle.Obstacletype.Value)//only navigation/intersection blocking objects! &&obstacle.RadiusDistance<=10f); if (intersectingObstacles.Any()) { var intersectingObjectRAGUIDs=(from objs in intersectingObstacles select objs.RAGUID); Bot.Combat.PrioritizedRAGUIDs.AddRange(intersectingObjectRAGUIDs); } if (Bot.NavigationCache.groupRunningBehavior) { Logging.WriteVerbose("Grouping Behavior stopped due to blocking counter"); Bot.NavigationCache.GroupingFinishBehavior(); Bot.NavigationCache.groupingSuspendedDate=DateTime.Now.AddMilliseconds(2500); Bot.Combat.bForceTargetUpdate=true; return RunStatus.Running; } if (obj.targetType.Value==TargetType.Avoidance) {//Avoidance Movement.. Bot.Combat.timeCancelledFleeMove=DateTime.Now; Bot.Combat.timeCancelledEmergencyMove=DateTime.Now; Bot.NavigationCache.BlacklistLastSafespot(); Bot.UpdateAvoidKiteRates(); Bot.Combat.bForceTargetUpdate=true; return RunStatus.Running; } break; default: if (obj.targetType.Value!=TargetType.Avoidance) { //Finally try raycasting to see if navigation is possible.. if (obj.Actortype.HasValue&& (obj.Actortype.Value==ActorType.Gizmo||obj.Actortype.Value==ActorType.Unit)) { Vector3 hitTest; // No raycast available, try and force-ignore this for a little while, and blacklist for a few seconds if (Zeta.Navigation.Navigator.Raycast(Bot.Character.Position, obj.Position, out hitTest)) { if (hitTest!=Vector3.Zero) { obj.RequiresLOSCheck=true; obj.BlacklistLoops=10; Logging.WriteDiagnostic("Ignoring object "+obj.InternalName+" due to not moving and raycast failure!", true); Bot.Combat.bForceTargetUpdate=true; return RunStatus.Running; } } } else if (obj.Actortype.HasValue&&obj.Actortype.Value.HasFlag(ActorType.Item)) { Bot.Combat.timeCancelledEmergencyMove=DateTime.Now; Bot.Combat.timeCancelledFleeMove=DateTime.Now; //Check if we can walk to this location from current location.. if (!Navigation.CanRayCast(Bot.Character.Position, CurrentTargetLocation, NavCellFlags.AllowWalk)) { obj.BlacklistLoops=10; obj.RequiresLOSCheck=true; Logging.WriteDiagnostic("Ignoring Item {0} -- due to AllowWalk RayCast Failure!", obj.InternalName); Bot.Combat.bForceTargetUpdate=true; return RunStatus.Running; } } } else { if (!Navigation.CanRayCast(Bot.Character.Position, CurrentTargetLocation, NavCellFlags.AllowWalk)) { Logging.WriteVerbose("Cannot continue with avoidance movement due to raycast failure!"); BlockedMovementCounter=0; Bot.Combat.iMillisecondsCancelledEmergencyMoveFor/=2; Bot.Combat.timeCancelledEmergencyMove=DateTime.Now; //Ignore avoidance movements. Bot.Combat.iMillisecondsCancelledFleeMoveFor/=2; Bot.Combat.timeCancelledFleeMove=DateTime.Now; Bot.NavigationCache.BlacklistLastSafespot(); Bot.Combat.bForceTargetUpdate=true; return RunStatus.Running; } } break; } #endregion if (obj.targetType.Value==TargetType.Item) { obj.BlacklistLoops=1; Bot.Combat.bForceTargetUpdate=true; } return RunStatus.Running; } // Been 250 milliseconds of non-movement? } else { // Movement has been made, so count the time last moved! LastMovementDuringCombat=DateTime.Now; } #endregion // Update the last distance stored LastDistanceFromTarget=obj.DistanceFromTarget; // See if we want to ACTUALLY move, or are just waiting for the last move command... if (!bForceNewMovement&&IsAlreadyMoving&&CurrentTargetLocation==LastTargetLocation&&DateTime.Now.Subtract(LastMovementCommand).TotalMilliseconds<=100) { return RunStatus.Running; } float currentDistance=Vector3.Distance(LastTargetLocation, CurrentTargetLocation); // If we're doing avoidance, globes or backtracking, try to use special abilities to move quicker #region SpecialMovementChecks if ((TargetType.Avoidance|TargetType.Gold|TargetType.Globe).HasFlag(obj.targetType.Value)) { bool bTooMuchZChange=((Bot.Character.Position.Z-CurrentTargetLocation.Z)>=4f); Ability MovementPower; if (Bot.Class.FindMovementPower(out MovementPower)) { double lastUsedAbilityMS=MovementPower.LastUsedMilliseconds; bool foundMovementPower=false; float pointDistance=0f; Vector3 vTargetAimPoint=CurrentTargetLocation; bool ignoreLOSTest=false; switch (MovementPower.Power) { case SNOPower.Monk_TempestRush: vTargetAimPoint=MathEx.CalculatePointFrom(CurrentTargetLocation, Bot.Character.Position, 10f); Bot.Character.UpdateAnimationState(false, true); bool isHobbling=Bot.Character.CurrentSNOAnim.HasFlag(SNOAnim.Monk_Female_Hobble_Run|SNOAnim.Monk_Male_HTH_Hobble_Run); foundMovementPower=(!bTooMuchZChange&&!Bot.Class.bWaitingForSpecial&¤tDistance<15f&&((isHobbling||lastUsedAbilityMS<300)&&Bot.Character.dCurrentEnergy>15) &&!ObjectCache.Obstacles.DoesPositionIntersectAny(vTargetAimPoint, ObstacleType.ServerObject)); break; case SNOPower.DemonHunter_Vault: foundMovementPower=(obj.targetType.Value!=TargetType.Destructible&&!bTooMuchZChange&¤tDistance>=18f&& (lastUsedAbilityMS>=Bot.SettingsFunky.Class.iDHVaultMovementDelay)); pointDistance=35f; if (currentDistance>pointDistance) vTargetAimPoint=MathEx.CalculatePointFrom(CurrentTargetLocation, Bot.Character.Position, pointDistance); break; case SNOPower.Barbarian_FuriousCharge: foundMovementPower=(obj.targetType.Value!=TargetType.Destructible&&!bTooMuchZChange &&(currentDistance>20f||obj.targetType.Value.HasFlag(TargetType.Avoidance)&&(NonMovementCounter>0||BlockedMovementCounter>0))); pointDistance=35f; if (currentDistance>pointDistance) vTargetAimPoint=MathEx.CalculatePointFrom(CurrentTargetLocation, Bot.Character.Position, pointDistance); break; case SNOPower.Barbarian_Leap: case SNOPower.Wizard_Archon_Teleport: case SNOPower.Wizard_Teleport: foundMovementPower=(obj.targetType.Value!=TargetType.Destructible&&!bTooMuchZChange &&(currentDistance>20f||obj.targetType.Value.HasFlag(TargetType.Avoidance)&&(NonMovementCounter>0||BlockedMovementCounter>0))); pointDistance=35f; if (currentDistance>pointDistance) vTargetAimPoint=MathEx.CalculatePointFrom(CurrentTargetLocation, Bot.Character.Position, pointDistance); //Teleport and Leap ignores raycast testing below! ignoreLOSTest=true; break; case SNOPower.Barbarian_Whirlwind: break; default: Bot.Character.WaitWhileAnimating(3, true); ZetaDia.Me.UsePower(MovementPower.Power, CurrentTargetLocation, Bot.Character.iCurrentWorldID, -1); MovementPower.LastUsed=DateTime.Now; Bot.Character.WaitWhileAnimating(6, true); // Store the current destination for comparison incase of changes next loop LastTargetLocation=CurrentTargetLocation; // Reset total body-block count, since we should have moved if (DateTime.Now.Subtract(Bot.Combat.lastForcedKeepCloseRange).TotalMilliseconds>=2000) BlockedMovementCounter=0; return RunStatus.Running; } if (foundMovementPower) { if ((MovementPower.Power==SNOPower.Monk_TempestRush&&lastUsedAbilityMS>500)|| (ignoreLOSTest||ZetaDia.Physics.Raycast(Bot.Character.Position, vTargetAimPoint, NavCellFlags.AllowWalk))) { ZetaDia.Me.UsePower(MovementPower.Power, vTargetAimPoint, Bot.Character.iCurrentWorldID, -1); MovementPower.LastUsed=DateTime.Now; // Store the current destination for comparison incase of changes next loop LastTargetLocation=CurrentTargetLocation; // Reset total body-block count, since we should have moved if (DateTime.Now.Subtract(Bot.Combat.lastForcedKeepCloseRange).TotalMilliseconds>=2000) BlockedMovementCounter=0; return RunStatus.Running; } } } //Special Whirlwind Code if (Bot.Class.AC==Zeta.Internals.Actors.ActorClass.Barbarian&&Bot.Class.HotbarPowers.Contains(SNOPower.Barbarian_Whirlwind)) { // Whirlwind against everything within range (except backtrack points) if (Bot.Character.dCurrentEnergy>=10 &&Bot.Combat.iAnythingWithinRange[(int)RangeIntervals.Range_20]>=1 &&obj.DistanceFromTarget<=12f &&(!Bot.Class.HotbarPowers.Contains(SNOPower.Barbarian_Sprint)||Bot.Class.HasBuff(SNOPower.Barbarian_Sprint)) &&(!(TargetType.Avoidance|TargetType.Gold|TargetType.Globe).HasFlag(obj.targetType.Value)&obj.DistanceFromTarget>=6f) &&(obj.targetType.Value!=TargetType.Unit ||(obj.targetType.Value==TargetType.Unit&&!obj.IsTreasureGoblin &&(!Bot.SettingsFunky.Class.bSelectiveWhirlwind ||Bot.Combat.bAnyNonWWIgnoreMobsInRange ||!CacheIDLookup.hashActorSNOWhirlwindIgnore.Contains(obj.SNOID))))) { // Special code to prevent whirlwind double-spam, this helps save fury bool bUseThisLoop=SNOPower.Barbarian_Whirlwind!=Bot.Combat.powerLastSnoPowerUsed; if (!bUseThisLoop) { Bot.Combat.powerLastSnoPowerUsed=SNOPower.None; if (DateTime.Now.Subtract(PowerCacheLookup.dictAbilityLastUse[SNOPower.Barbarian_Whirlwind]).TotalMilliseconds>=200) bUseThisLoop=true; } if (bUseThisLoop) { ZetaDia.Me.UsePower(SNOPower.Barbarian_Whirlwind, CurrentTargetLocation, Bot.Character.iCurrentWorldID, -1); Bot.Combat.powerLastSnoPowerUsed=SNOPower.Barbarian_Whirlwind; PowerCacheLookup.dictAbilityLastUse[SNOPower.Barbarian_Whirlwind]=DateTime.Now; } // Store the current destination for comparison incase of changes next loop LastTargetLocation=CurrentTargetLocation; // Reset total body-block count if ((!Bot.Combat.bForceCloseRangeTarget||DateTime.Now.Subtract(Bot.Combat.lastForcedKeepCloseRange).TotalMilliseconds>Bot.Combat.iMillisecondsForceCloseRange)&& DateTime.Now.Subtract(Bot.Combat.lastForcedKeepCloseRange).TotalMilliseconds>=2000) BlockedMovementCounter=0; return RunStatus.Running; } } } #endregion // Now for the actual movement request stuff IsAlreadyMoving=true; LastMovementCommand=DateTime.Now; if (DateTime.Now.Subtract(LastMovementAttempted).TotalMilliseconds>=250||currentDistance>=2f||bForceNewMovement) { if (obj.targetType.Value.Equals(TargetType.Avoidance)) { if (NonMovementCounter<10) ZetaDia.Me.Movement.MoveActor(CurrentTargetLocation); else ZetaDia.Me.UsePower(SNOPower.Walk, CurrentTargetLocation, Bot.Character.iCurrentWorldID, -1); } else { //Use Walk Power when not using LOS Movement, target is not an item and target does not ignore LOS. bool UsePower=(NonMovementCounter<10&&!obj.UsingLOSV3&&obj.targetType.Value!=TargetType.Item&&!obj.IgnoresLOSCheck); if (UsePower) { ZetaDia.Me.UsePower(SNOPower.Walk, CurrentTargetLocation, Bot.Character.iCurrentWorldID, -1); } else ZetaDia.Me.Movement.MoveActor(CurrentTargetLocation); } LastMovementAttempted=DateTime.Now; // Store the current destination for comparison incase of changes next loop LastTargetLocation=CurrentTargetLocation; // Reset total body-block count, since we should have moved if (DateTime.Now.Subtract(Bot.Combat.lastForcedKeepCloseRange).TotalMilliseconds>=2000) BlockedMovementCounter=0; //Herbfunk: Quick fix for stuck occuring on above average mob who is damaged.. if (LastPlayerLocation==Bot.Character.Position) NonMovementCounter++; else NonMovementCounter=0; LastPlayerLocation=Bot.Character.Position; } return RunStatus.Running; }
///<summary> ///Adds/Updates CacheObjects inside collection by Iteration of RactorList ///This is the method that caches all live data about an object! ///</summary> public static bool UpdateCacheObjectCollection() { if (!ZetaDia.IsInGame) return false; HashSet<int> hashDoneThisRactor=new HashSet<int>(); foreach (Actor thisActor in ZetaDia.Actors.RActorList) { int tmp_raGUID; DiaObject thisObj; if (!thisActor.IsValid) continue; //Convert to DiaObject thisObj=(DiaObject)thisActor; tmp_raGUID=thisObj.RActorGuid; // See if we've already checked this ractor, this loop if (hashDoneThisRactor.Contains(tmp_raGUID)) continue; hashDoneThisRactor.Add(tmp_raGUID); //Update RactorGUID and check blacklisting.. if (ObjectCache.IsRAGUIDBlacklisted(tmp_raGUID)) continue; CacheObject tmp_CachedObj; using (ZetaDia.Memory.AcquireFrame()) { if (!ObjectCache.Objects.TryGetValue(tmp_raGUID, out tmp_CachedObj)) { Vector3 tmp_position; int tmp_acdguid; int tmp_SNOID; #region SNO //Lookup SNO try { tmp_SNOID=thisObj.ActorSNO; } catch (NullReferenceException) { Logging.WriteVerbose("Failure to get SNO from object! RaGUID: {0}", tmp_raGUID); continue; } #endregion //check our SNO blacklist if (ObjectCache.IsSNOIDBlacklisted(tmp_SNOID)&&!CacheIDLookup.hashSummonedPets.Contains(tmp_SNOID)) continue; #region Position try { tmp_position=thisObj.Position; } catch (NullReferenceException) { Logging.WriteVerbose("Failure to get position vector for RAGUID {0}", tmp_raGUID); continue; } #endregion #region AcdGUID try { tmp_acdguid=thisObj.ACDGuid; } catch (NullReferenceException) { Logging.WriteVerbose("Failure to get ACDGUID for RAGUID {0}", tmp_raGUID); continue; } #endregion tmp_CachedObj=new CacheObject(tmp_SNOID, tmp_raGUID, tmp_acdguid, tmp_position); } else //Reset unseen var tmp_CachedObj.LoopsUnseen=0; //Validate try { if (thisObj.CommonData==null||thisObj.CommonData.ACDGuid!=thisObj.ACDGuid) continue; } catch (NullReferenceException) { continue; } //Check if this object is a summoned unit by a player... #region SummonedUnits if (tmp_CachedObj.IsSummonedPet) { // Get the summoned-by info, cached if possible if (!tmp_CachedObj.SummonerID.HasValue) { try { tmp_CachedObj.SummonerID=thisObj.CommonData.GetAttribute<int>(ActorAttributeType.SummonedByACDID); } catch (Exception ex) { Logging.WriteVerbose("[Funky] Safely handled exception getting summoned-by info ["+tmp_CachedObj.SNOID.ToString()+"]"); Logging.WriteDiagnostic(ex.ToString()); continue; } } //See if this summoned unit was summoned by the bot. if (Bot.Character.iMyDynamicID==tmp_CachedObj.SummonerID.Value) { //Now modify the player data pets count.. if (Bot.Class.AC==ActorClass.Monk) Bot.Character.PetData.MysticAlly++; else if (Bot.Class.AC==ActorClass.DemonHunter&&CacheIDLookup.hashDHPets.Contains(tmp_CachedObj.SNOID)) Bot.Character.PetData.DemonHunterPet++; else if (Bot.Class.AC==ActorClass.WitchDoctor) { if (CacheIDLookup.hashZombie.Contains(tmp_CachedObj.SNOID)) Bot.Character.PetData.ZombieDogs++; else if (CacheIDLookup.hashGargantuan.Contains(tmp_CachedObj.SNOID)) Bot.Character.PetData.Gargantuan++; } else if (Bot.Class.AC==Zeta.Internals.Actors.ActorClass.Wizard) { //only count when range is within 45f (so we can summon a new one) if (CacheIDLookup.hashWizHydras.Contains(tmp_CachedObj.SNOID)&&tmp_CachedObj.CentreDistance<=45f) Bot.Character.PetData.WizardHydra++; } } //We return regardless if it was summoned by us or not since this object is not anything we want to deal with.. tmp_CachedObj.NeedsRemoved=true; continue; } #endregion //Update any SNO Data. #region SNO_Cache_Update if (tmp_CachedObj.ref_DiaObject==null||tmp_CachedObj.ContainsNullValues()) { if (!tmp_CachedObj.UpdateData(thisObj, tmp_CachedObj.RAGUID)) continue; } else if (!tmp_CachedObj.IsFinalized) {//Finalize this data by recreating it and updating the Sno cache with a new finalized entry, this also clears our all Sno cache dictionaries since we no longer need them! ObjectCache.cacheSnoCollection.FinalizeEntry(tmp_CachedObj.SNOID); } #endregion //Objects with static positions already cached don't need to be updated here. if (!tmp_CachedObj.NeedsUpdate) continue; //Obstacles -- (Not an actual object we add to targeting.) if (tmp_CachedObj.targetType.Value==TargetType.Avoidance||tmp_CachedObj.IsObstacle||tmp_CachedObj.HandleAsAvoidanceObject) { #region Obstacles bool bRequireAvoidance=false; bool bTravellingAvoidance=false; CacheObstacle thisObstacle; //Do we have this cached? if (!ObjectCache.Obstacles.TryGetValue(tmp_CachedObj.RAGUID, out thisObstacle)) { AvoidanceType AvoidanceType=AvoidanceType.Unknown; if (tmp_CachedObj.IsAvoidance) { AvoidanceType=CacheIDLookup.FindAvoidanceUsingSNOID(tmp_CachedObj.SNOID); if (AvoidanceType==AvoidanceType.Unknown) { AvoidanceType=CacheIDLookup.FindAvoidanceUsingName(tmp_CachedObj.InternalName); if (AvoidanceType==AvoidanceType.Unknown) continue; } } if (tmp_CachedObj.IsAvoidance&&tmp_CachedObj.IsProjectileAvoidance) {//Ranged Projectiles require more than simple bounding points.. so we create it as avoidance zone to cache it with properties. //Check for intersection.. ActorMovement thisMovement=thisObj.Movement; Vector2 Direction=thisMovement.DirectionVector; Ray R=new Ray(tmp_CachedObj.Position, Direction.ToVector3()); double Speed; //Lookup Cached Speed, or add new entry. if (!ObjectCache.dictProjectileSpeed.TryGetValue(tmp_CachedObj.SNOID, out Speed)) { Speed=thisMovement.DesiredSpeed; ObjectCache.dictProjectileSpeed.Add(tmp_CachedObj.SNOID, Speed); } thisObstacle=new CacheAvoidance(tmp_CachedObj, AvoidanceType, R, Speed); ObjectCache.Obstacles.Add(thisObstacle); } else if (tmp_CachedObj.IsAvoidance) { thisObstacle=new CacheAvoidance(tmp_CachedObj, AvoidanceType); ObjectCache.Obstacles.Add(thisObstacle); } else { //Obstacles. thisObstacle=new CacheServerObject(tmp_CachedObj); ObjectCache.Obstacles.Add(thisObstacle); continue; } } //Test if this avoidance requires movement now. if (thisObstacle is CacheAvoidance) { //Check last time we attempted avoidance movement (Only if its been at least a second since last time we required it..) //if (DateTime.Now.Subtract(Bot.Combat.LastAvoidanceMovement).TotalMilliseconds<1000) //continue; CacheAvoidance thisAvoidance=thisObstacle as CacheAvoidance; if (Bot.IgnoreAvoidance(thisAvoidance.AvoidanceType)) continue; //Only update position of Movement Avoidances! if (thisAvoidance.Obstacletype.Value==ObstacleType.MovingAvoidance) { //Blacklisted updates if (thisAvoidance.BlacklistRefreshCounter>0&& !thisAvoidance.CheckUpdateForProjectile) { thisAvoidance.BlacklistRefreshCounter--; } bRequireAvoidance=thisAvoidance.UpdateProjectileRayTest(tmp_CachedObj.Position); //If we need to avoid, than enable travel avoidance flag also. if (bRequireAvoidance) bTravellingAvoidance=true; } else { if (thisObstacle.CentreDistance<50f) Bot.Combat.NearbyAvoidances.Add(thisObstacle.RAGUID); if (thisAvoidance.Position.Distance(Bot.Character.Position)<=thisAvoidance.Radius) bRequireAvoidance=true; } Bot.Combat.RequiresAvoidance=bRequireAvoidance; Bot.Combat.TravellingAvoidance=bTravellingAvoidance; if (bRequireAvoidance) Bot.Combat.TriggeringAvoidances.Add((CacheAvoidance)thisObstacle); } else { //Add this server object to cell weighting in MGP //MGP.AddCellWeightingObstacle(thisObstacle.SNOID, thisObstacle.CollisionRadius.Value); //Add nearby objects to our collection (used in navblock/obstaclecheck methods to reduce queries) if (thisObstacle.CentreDistance<25f) Bot.Combat.NearbyObstacleObjects.Add((CacheServerObject)thisObstacle); } continue; #endregion } if (tmp_CachedObj.ObjectShouldBeRecreated) { //Specific updates if (tmp_CachedObj.Actortype.Value==ActorType.Item) { tmp_CachedObj=new CacheItem(tmp_CachedObj); } else if (tmp_CachedObj.Actortype.Value==ActorType.Unit) { tmp_CachedObj=new CacheUnit(tmp_CachedObj); } else if (tmp_CachedObj.Actortype.Value==ActorType.Gizmo) { if (TargetType.Interactables.HasFlag(tmp_CachedObj.targetType.Value)) tmp_CachedObj=new CacheInteractable(tmp_CachedObj); else tmp_CachedObj=new CacheDestructable(tmp_CachedObj); } } if (!tmp_CachedObj.UpdateData()) continue; //Obstacle cache if (tmp_CachedObj.Obstacletype.Value!=ObstacleType.None &&(TargetType.ServerObjects.HasFlag(tmp_CachedObj.targetType.Value))) { CacheObstacle thisObstacleObj; if (!ObjectCache.Obstacles.TryGetValue(tmp_CachedObj.RAGUID, out thisObstacleObj)) { ObjectCache.Obstacles.Add(tmp_CachedObj.RAGUID, new CacheServerObject(tmp_CachedObj)); } else { if (thisObstacleObj.targetType.Value==TargetType.Unit) { //Since units position requires updating, we update using the CacheObject thisObstacleObj.Position=tmp_CachedObj.Position; ObjectCache.Obstacles[tmp_CachedObj.RAGUID]=thisObstacleObj; } if (thisObstacleObj.CentreDistance<=25f) Bot.Combat.NearbyObstacleObjects.Add((CacheServerObject)thisObstacleObj); } //Add nearby objects to our collection (used in navblock/obstaclecheck methods to reduce queries) } //cache it if (ObjectCache.Objects.ContainsKey(tmp_CachedObj.RAGUID)) ObjectCache.Objects[tmp_CachedObj.RAGUID]=tmp_CachedObj; else ObjectCache.Objects.Add(tmp_CachedObj.RAGUID, tmp_CachedObj); } } //End of Loop //Tally up unseen objects. var UnseenObjects=ObjectCache.Objects.Keys.Where<int>(O => !hashDoneThisRactor.Contains(O)).ToList(); if (UnseenObjects.Count()>0) { for (int i=0; i<UnseenObjects.Count(); i++) { ObjectCache.Objects[UnseenObjects[i]].LoopsUnseen++; } } //Trim our collection every 5th refresh. UpdateLoopCounter++; if (UpdateLoopCounter>4) { UpdateLoopCounter=0; //Now flag any objects not seen for 5 loops. Gold/Globe only 1 loop. foreach (var item in ObjectCache.Objects.Values.Where<CacheObject>(CO => CO.LoopsUnseen>=5|| (CO.targetType.HasValue&&(CO.targetType.Value==TargetType.Gold||CO.targetType.Value==TargetType.Globe)&&CO.LoopsUnseen>0))) { item.NeedsRemoved=true; } } return true; }
///<summary> ///Update our current object data ("Current Target") ///</summary> public bool UpdateTarget() { //Generate a vaild object list using our cached collection! Bot.ValidObjects=ObjectCache.Objects.Values.Where(obj => obj.ObjectIsValidForTargeting).ToList(); //Check avoidance requirement still valid if (Bot.Combat.RequiresAvoidance&& Bot.Combat.TriggeringAvoidances.Count==0&& (!Bot.SettingsFunky.EnableFleeingBehavior||Bot.Character.dCurrentHealthPct>0.25d)) Bot.Combat.RequiresAvoidance=false; #region Grouping Behavior Resume if (Bot.NavigationCache.groupRunningBehavior) { if (!Bot.NavigationCache.groupReturningToOrgin) { Bot.Combat.UpdateGroupClusteringVariables(); bool EndBehavior=false; if (!Bot.NavigationCache.groupingCurrentUnit.ObjectIsValidForTargeting) { if (Bot.SettingsFunky.LogGroupingOutput) Logging.WriteVerbose("[Grouping] Target is no longer valid. Starting return to Orgin."); EndBehavior=true; } else if (Bot.NavigationCache.groupingCurrentUnit.CurrentHealthPct.Value<1d &&Bot.NavigationCache.groupingCurrentUnit.IsMoving) { if (Bot.SettingsFunky.LogGroupingOutput) Logging.WriteVerbose("[Grouping] Target has been engaged. Starting return to Orgin."); EndBehavior=true; } if (!EndBehavior) { CurrentTarget=Bot.NavigationCache.groupingCurrentUnit; return true; } else { Bot.NavigationCache.groupingCurrentUnit=null; Bot.NavigationCache.groupReturningToOrgin=true; CurrentTarget=Bot.NavigationCache.groupingOrginUnit; return true; } } else { bool endBehavior=false; //Returning to Orgin Unit.. if (!Bot.NavigationCache.groupingOrginUnit.ObjectIsValidForTargeting) { endBehavior=true; if (Bot.SettingsFunky.LogGroupingOutput) Logging.WriteVerbose("[Grouping] Orgin Target is no longer valid for targeting."); } else if (Bot.NavigationCache.groupingOrginUnit.CentreDistance<(Bot.Class.IsMeleeClass?25f:45f)) { if (Bot.SettingsFunky.LogGroupingOutput) Logging.WriteVerbose("[Grouping] Orgin Target is within {0}f of the bot.", (Bot.Class.IsMeleeClass?25f:45f).ToString()); endBehavior=true; } if (!endBehavior) { CurrentTarget=Bot.NavigationCache.groupingOrginUnit; return true; } else Bot.NavigationCache.GroupingFinishBehavior(); } } #endregion Vector3 LOS=Vector3.Zero; //Check if we require avoidance movement. #region AvodianceMovementCheck if (Bot.Combat.RequiresAvoidance&&(!Bot.Combat.bAnyTreasureGoblinsPresent||Bot.SettingsFunky.GoblinPriority<2) &&(DateTime.Now.Subtract(Bot.Combat.timeCancelledEmergencyMove).TotalMilliseconds>Bot.Combat.iMillisecondsCancelledEmergencyMoveFor)) { //Reuse the last generated safe spot... if (DateTime.Now.Subtract(Bot.Combat.LastAvoidanceMovement).TotalMilliseconds>= Bot.Combat.iSecondsEmergencyMoveFor) { Vector3 reuseV3=Bot.NavigationCache.AttemptToReuseLastLocationFound(); if (reuseV3!=Vector3.Zero) { CurrentTarget=new CacheObject(reuseV3, TargetType.Avoidance, 20000f, "SafeAvoid", 2.5f, -1); return true; } } Vector3 vAnySafePoint; //if (CurrentTarget!=null&&CurrentTarget.targetType.HasValue&&TargetType.ServerObjects.HasFlag(CurrentTarget.targetType.Value)) // LOS=CurrentTarget.Position; //else // LOS=Vector3.Zero; if (Bot.NavigationCache.AttemptFindSafeSpot(out vAnySafePoint, LOS, Bot.Character.ShouldFlee)) { float distance=vAnySafePoint.Distance(Bot.Character.Position); float losdistance=0f; if (LOS!=Vector3.Zero) losdistance=LOS.Distance(Bot.Character.Position); string los=LOS!=Vector3.Zero?("\r\n using LOS location "+LOS.ToString()+" distance "+losdistance.ToString()):" "; Logging.WriteDiagnostic("Avoid Movement found AT {0} with {1} Distance", vAnySafePoint.ToString(), distance); //bFoundSafeSpot = true; //setup avoidance target if (CurrentTarget!=null) Bot.Combat.LastCachedTarget=CurrentTarget.Clone(); CurrentTarget=new CacheObject(vAnySafePoint, TargetType.Avoidance, 20000f, "SafeAvoid", 2.5f, -1); //Estimate time we will be reusing this movement vector3 Bot.Combat.iSecondsEmergencyMoveFor=1+(int)(distance/25f); //Avoidance takes priority over kiting.. Bot.Combat.timeCancelledFleeMove=DateTime.Now; Bot.Combat.iMillisecondsCancelledFleeMoveFor=((Bot.Combat.iSecondsEmergencyMoveFor+1)*1000); return true; } Bot.UpdateAvoidKiteRates(); } #endregion Bot.Combat.bStayPutDuringAvoidance=false; //cluster update Bot.Combat.UpdateTargetClusteringVariables(); //Standard weighting of valid objects -- updates current target. this.WeightEvaluationObjList(); //check Fleeing #region Fleeing if (Bot.SettingsFunky.EnableFleeingBehavior&&Bot.Character.dCurrentHealthPct<=Bot.SettingsFunky.FleeBotMinimumHealthPercent&&Bot.Combat.FleeTriggeringUnits.Count>0 &&(DateTime.Now.Subtract(Bot.Combat.timeCancelledFleeMove).TotalMilliseconds>Bot.Combat.iMillisecondsCancelledFleeMoveFor) &&(!Bot.Combat.bAnyTreasureGoblinsPresent||Bot.SettingsFunky.GoblinPriority<2) &&(Bot.Class.AC!=ActorClass.Wizard||(Bot.Class.AC==ActorClass.Wizard&&(!Bot.Class.HasBuff(SNOPower.Wizard_Archon)||!Bot.SettingsFunky.Class.bKiteOnlyArchon)))) { //Resuse last safespot until timer expires! if (DateTime.Now.Subtract(Bot.Combat.LastFleeAction).TotalSeconds<Bot.Combat.iSecondsFleeMoveFor) { Vector3 reuseV3=Bot.NavigationCache.AttemptToReuseLastLocationFound(); if (reuseV3!=Vector3.Zero) { CurrentTarget=new CacheObject(reuseV3, TargetType.Avoidance, 20000f, "FleeSpot", 2.5f, -1); return true; } } if (CurrentTarget!=null&&CurrentTarget.targetType.HasValue&&TargetType.ServerObjects.HasFlag(CurrentTarget.targetType.Value) &&(Bot.NavigationCache.CurrentGPArea==null||!Bot.NavigationCache.CurrentGPArea.AllGPRectsFailed)) LOS=CurrentTarget.Position; else LOS=Vector3.Zero; Vector3 vAnySafePoint; if (Bot.NavigationCache.AttemptFindSafeSpot(out vAnySafePoint, LOS, true)) { Logging.WriteDiagnostic("Flee Movement found AT {0} with {1} Distance", vAnySafePoint.ToString(), vAnySafePoint.Distance(Bot.Character.Position)); Bot.Combat.IsFleeing=true; if (CurrentTarget!=null) Bot.Character.LastCachedTarget=CurrentTarget; CurrentTarget=new CacheObject(vAnySafePoint, TargetType.Avoidance, 20000f, "FleeSpot", 2.5f, -1); Bot.Combat.iSecondsFleeMoveFor=1+(int)(Vector3.Distance(Bot.Character.Position, vAnySafePoint)/25f); return true; } Bot.UpdateAvoidKiteRates(); } //If we have a cached kite target.. and no current target, lets swap back! if (Bot.Combat.FleeingLastTarget&&CurrentTarget==null &&Bot.Character.LastCachedTarget!=null &&ObjectCache.Objects.ContainsKey(Bot.Character.LastCachedTarget.RAGUID)) { //Swap back to our orginal "kite" target CurrentTarget=ObjectCache.Objects[Bot.Character.LastCachedTarget.RAGUID]; Logging.WriteVerbose("Swapping back to unit {0} after fleeing", CurrentTarget.InternalName); return true; } #endregion // No valid targets but we were told to stay put? if (CurrentTarget==null&&Bot.Combat.bStayPutDuringAvoidance) { if (Bot.Combat.TriggeringAvoidances.Count==0) { CurrentTarget=new CacheObject(Bot.Character.Position, TargetType.Avoidance, 20000, "StayPutPoint", 2.5f, -1); return true; } else Bot.Combat.iMillisecondsCancelledEmergencyMoveFor=0; //reset wait time } //Final Possible Target Check if (CurrentTarget==null) { // See if we should wait for milliseconds for possible loot drops before continuing run if (DateTime.Now.Subtract(Bot.Combat.lastHadUnitInSights).TotalMilliseconds<=Bot.SettingsFunky.AfterCombatDelay&&DateTime.Now.Subtract(Bot.Combat.lastHadEliteUnitInSights).TotalMilliseconds<=10000|| //Cut the delay time in half for non-elite monsters! DateTime.Now.Subtract(Bot.Combat.lastHadUnitInSights).TotalMilliseconds<=Bot.SettingsFunky.AfterCombatDelay) { CurrentTarget=new CacheObject(Bot.Character.Position, TargetType.Avoidance, 20000, "WaitForLootDrops", 2f, -1); return true; } //Herbfunks wait after loot containers are opened. 3s for rare chests, half the settings delay for everything else. if ((DateTime.Now.Subtract(Bot.Combat.lastHadRareChestAsTarget).TotalMilliseconds<=3750)|| (DateTime.Now.Subtract(Bot.Combat.lastHadContainerAsTarget).TotalMilliseconds<=(Bot.SettingsFunky.AfterCombatDelay*1.25))) { CurrentTarget=new CacheObject(Bot.Character.Position, TargetType.Avoidance, 20000, "ContainerLootDropsWait", 2f, -1); return true; } // Finally, a special check for waiting for wrath of the berserker cooldown before engaging Azmodan if (Bot.Class.HotbarPowers.Contains(SNOPower.Barbarian_WrathOfTheBerserker)&&Bot.SettingsFunky.Class.bWaitForWrath&&!Bot.Class.AbilityUseTimer(SNOPower.Barbarian_WrathOfTheBerserker)&& ZetaDia.CurrentWorldId==121214&& (Vector3.Distance(Bot.Character.Position, new Vector3(711.25f, 716.25f, 80.13903f))<=40f||Vector3.Distance(Bot.Character.Position, new Vector3(546.8467f, 551.7733f, 1.576313f))<=40f)) { Logging.Write("[Funky] Waiting for Wrath Of The Berserker cooldown before continuing to Azmodan."); CurrentTarget=new CacheObject(Bot.Character.Position, TargetType.Avoidance, 20000, "GilesWaitForWrath", 0f, -1); InactivityDetector.Reset(); return true; } // And a special check for wizard archon if (Bot.Class.HotbarPowers.Contains(SNOPower.Wizard_Archon)&&!Bot.Class.AbilityUseTimer(SNOPower.Wizard_Archon)&&Bot.SettingsFunky.Class.bWaitForArchon&&ZetaDia.CurrentWorldId==121214&& (Vector3.Distance(Bot.Character.Position, new Vector3(711.25f, 716.25f, 80.13903f))<=40f||Vector3.Distance(Bot.Character.Position, new Vector3(546.8467f, 551.7733f, 1.576313f))<=40f)) { Logging.Write("[Funky] Waiting for Wizard Archon cooldown before continuing to Azmodan."); CurrentTarget=new CacheObject(Bot.Character.Position, TargetType.Avoidance, 20000, "GilesWaitForArchon", 0f, -1); InactivityDetector.Reset(); return true; } // And a very sexy special check for WD BigBadVoodoo if (Bot.Class.HotbarPowers.Contains(SNOPower.Witchdoctor_BigBadVoodoo)&&!PowerManager.CanCast(SNOPower.Witchdoctor_BigBadVoodoo)&&ZetaDia.CurrentWorldId==121214&& (Vector3.Distance(Bot.Character.Position, new Vector3(711.25f, 716.25f, 80.13903f))<=40f||Vector3.Distance(Bot.Character.Position, new Vector3(546.8467f, 551.7733f, 1.576313f))<=40f)) { Logging.Write("[Funky] Waiting for WD BigBadVoodoo cooldown before continuing to Azmodan."); CurrentTarget=new CacheObject(Bot.Character.Position, TargetType.Avoidance, 20000, "GilesWaitForVoodooo", 0f, -1); InactivityDetector.Reset(); return true; } //Check if our current path intersects avoidances. (When not in town, and not currently inside avoidance) if (!Bot.Character.bIsInTown&&(Bot.SettingsFunky.AttemptAvoidanceMovements||Bot.Combat.CriticalAvoidance) &&Navigation.NP.CurrentPath.Count>0 &&Bot.Combat.TriggeringAvoidances.Count==0) { Vector3 curpos=Bot.Character.Position; IndexedList<Vector3> curpath=Navigation.NP.CurrentPath; var CurrentNearbyPath=curpath.Where(v => curpos.Distance(v)<=40f); if (CurrentNearbyPath!=null&&CurrentNearbyPath.Any()) { CurrentNearbyPath.OrderBy(v => curpath.IndexOf(v)); Vector3 lastV3=Vector3.Zero; foreach (var item in CurrentNearbyPath) { if (lastV3==Vector3.Zero) lastV3=item; else if (ObjectCache.Obstacles.TestVectorAgainstAvoidanceZones(item, lastV3)) { CurrentTarget=new CacheObject(Bot.Character.Position, TargetType.Avoidance, 20000, "AvoidanceIntersection", 2.5f, -1); return true; } } } } } else { if (CurrentTarget.targetType.Equals(TargetType.Unit)) { //Update CurrentUnitTarget Variable. if (CurrentUnitTarget==null) CurrentUnitTarget=(CacheUnit)CurrentTarget; //Grouping Movements if (Bot.SettingsFunky.AttemptGroupingMovements &&CurrentUnitTarget.CurrentHealthPct.Value<1d &&DateTime.Compare(DateTime.Now,Bot.NavigationCache.groupingSuspendedDate)>0 &&!CurrentUnitTarget.IsTreasureGoblin||Bot.SettingsFunky.GoblinPriority<2) //only after we engaged the target. { Bot.Combat.UpdateGroupClusteringVariables(); if (Bot.Combat.CurrentGroupClusters.Count>0) { Cluster currentTargetCluster=CurrentUnitTarget.CurrentTargetCluster; if (currentTargetCluster!=null) { int toughUnitCount=currentTargetCluster.ListUnits.Count(unit => unit.UnitMaxHitPointAverageWeight>0&&unit.CurrentHealthPct.Value>0.50d); //Trigger for tough grouping.. if (toughUnitCount>1) { var targetableUnits=Bot.Combat.CurrentGroupClusters[0].ListUnits.Where(unit => unit.ObjectIsValidForTargeting && (unit.UnitMaxHitPointAverageWeight>0||unit.ObjectIsSpecial)); if (targetableUnits.Any()) { if (Bot.SettingsFunky.LogGroupingOutput) Logging.WriteVerbose("Starting Grouping Behavior. Triggered by Tough Group"); //Activate Behavior Bot.NavigationCache.groupRunningBehavior=true; Bot.NavigationCache.groupingOrginUnit=(CacheUnit)ObjectCache.Objects[CurrentTarget.RAGUID]; //Find initial grouping target.. CurrentTarget=targetableUnits.First(); CurrentUnitTarget=(CacheUnit)CurrentTarget; Bot.NavigationCache.groupingCurrentUnit=CurrentUnitTarget; } } } } } } return true; } return false; }
//Constructor public TargetHandler() { CurrentState=RunStatus.Running; CurrentTarget=null; }
public CacheUnit(CacheObject baseobj) : base(baseobj) { }
public CacheInteractable(CacheObject baseobj) : base(baseobj) { }
public CacheItem(CacheObject baseobj) : base(baseobj) { }
internal static void IgnoreThisObject(CacheObject thisobj, bool removal=true, bool blacklistSNOID=true) { Logging.WriteVerbose("[Blacklist] Obj RAGUID {0} SNOID {1} ({2})", thisobj.RAGUID, thisobj.SNOID, thisobj.InternalName); int sno, raguid; sno=thisobj.SNOID; raguid=thisobj.RAGUID; //Add to our blacklist so we don't create it again.. hashRGUIDIgnoreBlacklist.Add(raguid); if (blacklistSNOID) //Blacklist SNO so we don't create it ever again! CacheIDLookup.hashActorSNOIgnoreBlacklist.Add(sno); if (removal) { //Clear SNO cache entries.. cacheSnoCollection.Remove(sno); //Clear previous cache entries.. Objects.Remove(raguid); } }