// ********************************************************************************************** // ***** Pickup Validation - Determines what should or should not be picked up ***** // ********************************************************************************************** internal static bool GilesPickupItemValidation(CacheItem item) { // Calculate giles item types and base types etc. GilesItemType thisGilesItemType=DetermineItemType(item.InternalName, item.BalanceData.thisItemType, item.BalanceData.thisFollowerType); GilesBaseItemType thisGilesBaseType=DetermineBaseType(thisGilesItemType); // If it's legendary, we always want it *IF* it's level is right if (item.Itemquality>=ItemQuality.Legendary) { if (Bot.SettingsFunky.MinimumLegendaryItemLevel>0&&(item.BalanceData.iThisItemLevel>=Bot.SettingsFunky.MinimumLegendaryItemLevel||Bot.SettingsFunky.MinimumLegendaryItemLevel==1)) return true; return false; } // Error logging for DemonBuddy item mis-reading ItemType gilesDBItemType=GilesToDBItemType(thisGilesItemType); if (gilesDBItemType!=item.BalanceData.thisItemType) { Log("GSError: Item type mis-match detected: Item Internal="+item.InternalName+". DemonBuddy ItemType thinks item type is="+item.BalanceData.thisItemBaseType.ToString()+". Giles thinks item type is="+ gilesDBItemType.ToString()+". [pickup]", true); } switch (thisGilesBaseType) { case GilesBaseItemType.WeaponTwoHand: case GilesBaseItemType.WeaponOneHand: case GilesBaseItemType.WeaponRange: // Not enough DPS, so analyse for possibility to blacklist if (item.Itemquality<ItemQuality.Magic1) { // White item, blacklist return false; } if (item.Itemquality>=ItemQuality.Magic1&&item.Itemquality<ItemQuality.Rare4) { if (Bot.SettingsFunky.MinimumWeaponItemLevel[0]==0||(Bot.SettingsFunky.MinimumWeaponItemLevel[0]!=0&&item.BalanceData.iThisItemLevel<Bot.SettingsFunky.MinimumWeaponItemLevel[0])) { // Between magic and rare, and either we want no blues, or this level is higher than the blue level we want return false; } } else { if (Bot.SettingsFunky.MinimumWeaponItemLevel[1]==0||(Bot.SettingsFunky.MinimumWeaponItemLevel[1]!=0&&item.BalanceData.iThisItemLevel<Bot.SettingsFunky.MinimumWeaponItemLevel[1])) { // Between magic and rare, and either we want no blues, or this level is higher than the blue level we want return false; } } break; case GilesBaseItemType.Armor: case GilesBaseItemType.Offhand: if (item.Itemquality<ItemQuality.Magic1) { // White item, blacklist return false; } if (item.Itemquality>=ItemQuality.Magic1&&item.Itemquality<ItemQuality.Rare4) { if (Bot.SettingsFunky.MinimumArmorItemLevel[0]==0||(Bot.SettingsFunky.MinimumArmorItemLevel[0]!=0&&item.BalanceData.iThisItemLevel<Bot.SettingsFunky.MinimumArmorItemLevel[0])) { // Between magic and rare, and either we want no blues, or this level is higher than the blue level we want return false; } } else { if (Bot.SettingsFunky.MinimumArmorItemLevel[1]==0||(Bot.SettingsFunky.MinimumArmorItemLevel[1]!=0&&item.BalanceData.iThisItemLevel<Bot.SettingsFunky.MinimumArmorItemLevel[1])) { // Between magic and rare, and either we want no blues, or this level is higher than the blue level we want return false; } } break; case GilesBaseItemType.Jewelry: if (item.Itemquality<ItemQuality.Magic1) { // White item, blacklist return false; } if (item.Itemquality>=ItemQuality.Magic1&&item.Itemquality<ItemQuality.Rare4) { if (Bot.SettingsFunky.MinimumJeweleryItemLevel[0]==0||(Bot.SettingsFunky.MinimumJeweleryItemLevel[0]!=0&&item.BalanceData.iThisItemLevel<Bot.SettingsFunky.MinimumJeweleryItemLevel[0])) { // Between magic and rare, and either we want no blues, or this level is higher than the blue level we want return false; } } else { if (Bot.SettingsFunky.MinimumJeweleryItemLevel[1]==0||(Bot.SettingsFunky.MinimumJeweleryItemLevel[1]!=0&&item.BalanceData.iThisItemLevel<Bot.SettingsFunky.MinimumJeweleryItemLevel[1])) { // Between magic and rare, and either we want no blues, or this level is higher than the blue level we want return false; } } break; case GilesBaseItemType.FollowerItem: if (item.BalanceData.iThisItemLevel<60||!Bot.SettingsFunky.PickupFollowerItems||item.Itemquality<ItemQuality.Rare4) { if (!_hashsetItemFollowersIgnored.Contains(item.DynamicID.Value)) { _hashsetItemFollowersIgnored.Add(item.DynamicID.Value); iTotalFollowerItemsIgnored++; } return false; } break; case GilesBaseItemType.Gem: if (item.BalanceData.iThisItemLevel<Bot.SettingsFunky.MinimumGemItemLevel||(thisGilesItemType==GilesItemType.Ruby&&!Bot.SettingsFunky.PickupGems[0])||(thisGilesItemType==GilesItemType.Emerald&&!Bot.SettingsFunky.PickupGems[1])|| (thisGilesItemType==GilesItemType.Amethyst&&!Bot.SettingsFunky.PickupGems[2])||(thisGilesItemType==GilesItemType.Topaz&&!Bot.SettingsFunky.PickupGems[3])) { return false; } break; case GilesBaseItemType.Misc: // Note; Infernal keys are misc, so should be picked up here - we aren't filtering them out, so should default to true at the end of this function if (thisGilesItemType==GilesItemType.CraftingMaterial) { if (item.BalanceData.iThisItemLevel==63&&Bot.SettingsFunky.PickupDemonicEssence) return true; return item.BalanceData.iThisItemLevel<Bot.SettingsFunky.MiscItemLevel; } if (thisGilesItemType==GilesItemType.CraftTome&&(item.BalanceData.iThisItemLevel<Bot.SettingsFunky.MiscItemLevel||!Bot.SettingsFunky.PickupCraftTomes)) { return false; } if (thisGilesItemType==GilesItemType.CraftingPlan) { if (!Bot.SettingsFunky.PickupCraftPlans) return false; int gamebalanceID=item.BalanceID.Value; if (CacheIDLookup.HashPlansPropertiesSix.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupBlacksmithPlanSix) return false; if (CacheIDLookup.HashPlansPropertiesFive.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupBlacksmithPlanFive) return false; if (CacheIDLookup.HashPlansPropertiesFour.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupBlacksmithPlanFour) return false; if (CacheIDLookup.HashPlansArchonSpaulders.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupBlacksmithPlanArchonSpaulders) return false; if (CacheIDLookup.HashPlansArchonGauntlets.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupBlacksmithPlanArchonGauntlets) return false; if (CacheIDLookup.HashPlansRazorspikes.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupBlacksmithPlanRazorspikes) return false; if (CacheIDLookup.HashDesignAmulet.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupJewelerDesignAmulet) return false; if (CacheIDLookup.HashDesignFlawlessStarGem.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupJewelerDesignFlawlessStar) return false; if (CacheIDLookup.HashDesignMarquiseGem.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupJewelerDesignMarquise) return false; if (CacheIDLookup.HashDesignPerfectStarGem.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupJewelerDesignPerfectStar) return false; if (CacheIDLookup.HashDesignRadiantStarGem.Contains(gamebalanceID)&&!Bot.SettingsFunky.PickupJewelerDesignRadiantStar) return false; } if (thisGilesItemType==GilesItemType.InfernalKey) { if (!Bot.SettingsFunky.PickupInfernalKeys) return false; } // Potion filtering if (thisGilesItemType==GilesItemType.HealthPotion) { if (Bot.SettingsFunky.MaximumHealthPotions<=0) return false; var Potions = Bot.Character.BackPack.ReturnCurrentPotions(); if (Potions==null||!Potions.Any()||Bot.Character.BackPack.BestPotionToUse==null) return true; else if (Bot.Character.BackPack.BestPotionToUse!=null&&item.BalanceData.iThisItemLevel<Bot.Character.BackPack.BestPotionToUse.Level) return false; else if (Potions.Sum(potions => potions.ItemStackQuantity)>=Bot.SettingsFunky.MaximumHealthPotions) return false; } break; case GilesBaseItemType.HealthGlobe: return false; case GilesBaseItemType.Unknown: return false; default: return false; } // Switch giles base item type // Didn't cancel it, so default to true! return true; }
/// <summary> /// /// </summary> /// <param name="name"></param> /// <param name="level"></param> /// <param name="itemQuality"></param> /// <param name="itemBaseType"></param> /// <param name="itemType"></param> /// <param name="isOneHand"></param> /// <param name="isTwoHand"></param> /// <param name="gameBalanceId"></param> private void fillPickupDic(CacheItem item) { object result; itemDic=new Dictionary<string, object>(); // add log unique key itemDic.Add("[KEY]", item.DynamicID.ToString()); // - BASETYPE ---------------------------------------------------------// itemDic.Add("[BASETYPE]", item.BalanceData.thisItemBaseType.ToString()); // - TYPE -------------------------------------------------------------// /// TODO remove this check if it isnt necessary anymore if (item.BalanceData.thisItemType==ItemType.Unknown&&(item.InternalName.Contains("Plan")||item.InternalName.Contains("Design"))) { Logging.Write("There are still buggy itemType infos for craftingPlan around {0} has itemType = {1}", item.InternalName, item.BalanceData.thisItemType); result=ItemType.CraftingPlan.ToString(); } else result=item.BalanceData.thisItemType.ToString(); itemDic.Add("[TYPE]", result); // - QUALITY -------------------------------------------------------// itemDic.Add("[QUALITY]", Regex.Replace(item.Itemquality.ToString(), @"[\d-]", string.Empty)); itemDic.Add("[D3QUALITY]", item.Itemquality.ToString()); // - ROLL ----------------------------------------------------------// float roll; if (float.TryParse(Regex.Replace(item.Itemquality.ToString(), @"[^\d]", string.Empty), out roll)) itemDic.Add("[ROLL]", roll); else itemDic.Add("[ROLL]", 0); // - NAME -------------------------------------------------------------// itemDic.Add("[NAME]", item.InternalName.ToString().Replace(" ", "")); // - LEVEL ------------------------------------------------------------// itemDic.Add("[LEVEL]", (float)item.BalanceData.iThisItemLevel); itemDic.Add("[ONEHAND]", item.BalanceData.bThisOneHand); itemDic.Add("[TWOHAND]", item.BalanceData.bThisTwoHand); itemDic.Add("[UNIDENT]", (bool)true); itemDic.Add("[INTNAME]", item.InternalName); itemDic.Add("[ITEMID]", item.BalanceID.ToString()); }
///<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> /// /// </summary> /// <param name="item"></param> /// <returns></returns> internal InterpreterAction checkPickUpItem(CacheItem item, ItemEvaluationType evaluationType) { fillPickupDic(item); return checkItem(evaluationType); }