예제 #1
0
            ///<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;
            }
예제 #2
0
        //This is the 2nd step in handling.. we recheck target, get a new Ability if needed, and check potion/special movement avoidance here.
        public virtual bool Refresh()
        {
            // Make sure we reset unstucker stuff here
                        Funky.PlayerMover.iTimesReachedStuckPoint=0;
                        Funky.PlayerMover.vSafeMovementLocation=Vector3.Zero;
                        Funky.PlayerMover.timeLastRecordedPosition=DateTime.Now;

                        // Let's calculate whether or not we want a new target list...
                        #region NewtargetChecks
                        // Whether we should refresh the target list or not
                        bool bShouldRefreshDiaObjects=false;

                        if (!Bot.Combat.bWholeNewTarget&&!Bot.Combat.bWaitingForPower&&!Bot.Combat.bWaitingForPotion)
                        {
                             // Update targets at least once every 80 milliseconds
                             if (Bot.Combat.bForceTargetUpdate
                                 ||Bot.Combat.TravellingAvoidance
                                 ||((DateTime.Now.Subtract(Bot.Refresh.lastRefreshedObjects).TotalMilliseconds>=80&&CurrentTarget.targetType.Value!=TargetType.Avoidance)
                                 ||DateTime.Now.Subtract(Bot.Refresh.lastRefreshedObjects).TotalMilliseconds>=1200))
                             {
                                    bShouldRefreshDiaObjects=true;
                             }

                             // If we AREN'T getting new targets - find out if we SHOULD because the current unit has died etc.
                             if (!bShouldRefreshDiaObjects&&CurrentTarget.targetType.Value==TargetType.Unit&&!CurrentTarget.IsStillValid())
                                    bShouldRefreshDiaObjects=true;

                        }

                        // So, after all that, do we actually want a new target list?
                        if (!Bot.Combat.bWholeNewTarget&&!Bot.Combat.bWaitingForPower&&!Bot.Combat.bWaitingForPotion)
                        {
                             // If we *DO* want a new target list, do this...
                             if (bShouldRefreshDiaObjects)
                             {
                                    // Now call the function that refreshes targets
                                  Bot.Refresh.RefreshDiaObjects();

                                    // No target, return success
                                    if (CurrentTarget==null)
                                    {
                                         CurrentState=RunStatus.Success;
                                         return false;
                                    }
                                    else if (Bot.Character.LastCachedTarget!=null&&
                                         Bot.Character.LastCachedTarget.RAGUID!=CurrentTarget.RAGUID&&CurrentTarget.targetType.Value==TargetType.Item)
                                    {
                                         //Reset Item Vars
                                         Bot.Combat.recheckCount=0;
                                         Bot.Combat.reCheckedFinished=false;
                                    }

                                    // Been trying to handle the same target for more than 30 seconds without damaging/reaching it? Blacklist it!
                                    // Note: The time since target picked updates every time the current target loses health, if it's a monster-target
                                    if (CurrentTarget.targetType.Value!=TargetType.Avoidance
                                         &&((CurrentTarget.targetType.Value!=TargetType.Unit&&DateTime.Now.Subtract(Bot.Combat.dateSincePickedTarget).TotalSeconds>12)
                                         ||(CurrentTarget.targetType.Value==TargetType.Unit&&!CurrentTarget.IsBoss&&DateTime.Now.Subtract(Bot.Combat.dateSincePickedTarget).TotalSeconds>40)))
                                    {
                                         // NOTE: This only blacklists if it's remained the PRIMARY TARGET that we are trying to actually directly attack!
                                         // So it won't blacklist a monster "on the edge of the screen" who isn't even being targetted
                                         // Don't blacklist monsters on <= 50% health though, as they can't be in a stuck location... can they!? Maybe give them some extra time!
                                         bool bBlacklistThis=true;
                                         // PREVENT blacklisting a monster on less than 90% health unless we haven't damaged it for more than 2 minutes
                                         if (CurrentTarget.targetType.Value==TargetType.Unit)
                                         {
                                                if (CurrentTarget.IsTreasureGoblin&&Bot.SettingsFunky.GoblinPriority>=3) bBlacklistThis=false;
                                                if (DateTime.Now.Subtract(Bot.Combat.dateSincePickedTarget).TotalSeconds<=120) bBlacklistThis=false;
                                         }

                                         if (bBlacklistThis)
                                         {
                                                if (CurrentTarget.targetType.Value==TargetType.Unit)
                                                {
                                                     //Logging.WriteDiagnostic("[Funky] Blacklisting a monster because of possible stuck issues. Monster="+ObjectData.InternalName+" {"+
                                                     //ObjectData.SNOID.ToString()+"}. Range="+ObjectData.CentreDistance.ToString()+", health %="+ObjectData.CurrentHealthPct.ToString());
                                                }

                                                CurrentTarget.NeedsRemoved=true;
                                                CurrentTarget.BlacklistFlag=BlacklistType.Temporary;
                                         }
                                    }
                                    // Make sure we start trying to move again should we need to!
                                    Bot.Combat.bPickNewAbilities=true;

                                    TargetMovement.NewTargetResetVars();
                             }
                             // Ok we didn't want a new target list, should we at least update the position of the current target, if it's a monster?
                             else if (CurrentTarget.targetType.Value==TargetType.Unit&&CurrentTarget.IsStillValid())
                             {
                                    try
                                    {
                                         CurrentTarget.UpdatePosition();
                                    }
                                    catch
                                    {
                                         // Keep going anyway if we failed to get a new position from DemonBuddy
                                         Logging.WriteDiagnostic("GSDEBUG: Caught position read failure in main target handler loop.");
                                    }
                             }
                        }
                        #endregion

                        // This variable just prevents an instant 2-target update after coming here from the main decorator function above
                        Bot.Combat.bWholeNewTarget=false;

                        //Health Change Timer
                        if (CurrentTarget.targetType.Value==TargetType.Unit)
                        {
                             //Update CurrentUnitTarget Variable.
                             if (CurrentUnitTarget==null) CurrentUnitTarget=(CacheUnit)CurrentTarget;

                             double HealthChangeMS=DateTime.Now.Subtract(Bot.Combat.LastHealthChange).TotalMilliseconds;

                             if (HealthChangeMS>3000&&!CurrentTarget.ObjectIsSpecial||HealthChangeMS>6000)
                             {
                                    Logging.WriteVerbose("Health change has not occured within 3 seconds for unit {0}", CurrentTarget.InternalName);
                                    Bot.Combat.bForceTargetUpdate=true;
                                    CurrentState=RunStatus.Running;
                                    CurrentTarget.BlacklistLoops=10;
                                    return false;
                             }
                        }

                        //We are ready for the specific object type interaction
                        return true;
        }
예제 #3
0
        ///<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;
        }
예제 #4
0
        ///<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
        }