public void CopyFrom(MissionReward other) { this.Category = other.Category; this.Name = other.Name; this.Id = other.Id; this.RequiredPlayerLevel = other.RequiredPlayerLevel; this.RequiredSuccessChance = other.RequiredSuccessChance; this._ItemInfo = other._ItemInfo; this._CurrencyInfo = other._CurrencyInfo; }
/// <summary> /// Return true if the specified mission has x or less than x count of ItemId as a reward. /// </summary> /// <param name="itemId"></param> /// <param name="x"></param> /// <returns></returns> private static bool IsNumberRewardInferiorOrEqualTo(MissionReward reward, int x) { return reward.Quantity <= x; }
/// <summary> /// Return array of items to respect the following rule: if the specified mission has x or less than x count /// of itemId as a reward, return everything. /// </summary> /// <param name="itemId"></param> /// <returns></returns> private static IEnumerable<object> GetNumberRewardInferiorOrEqualTo(MissionReward reward) { var retval = new List<object>(); retval.Add(reward.Quantity); return retval; }
/// <summary> /// Return array of items to respect the following rule: if the specified character have x or less than x count /// of itemId carried, return everything. /// </summary> /// <param name="itemId"></param> /// <returns></returns> private static IEnumerable<object> GetNumberPlayerHasInferiorOrEqualTo(MissionReward reward) { var numCarried = Enumerable.Empty<object>(); if (reward.IsItemReward) { numCarried = HbApi.GetItemCarried((uint)reward.Id); } else if (reward.IsCurrencyReward) { var currency = WoWCurrency.GetCurrencyById((uint)reward.Id); numCarried = new List<WoWCurrency>(); ((List<WoWCurrency>)numCarried).Add(currency); } else if (reward.IsGold) { var gold = (int)StyxWoW.Me.Gold; numCarried = new List<object>(); ((List<object>)numCarried).Add((object)gold); } return numCarried; }
//***************************** //***************************** //***************************** /// <summary> /// Return true if the specified mission has reward more than x count of ItemId. /// </summary> /// <param name="itemId"></param> /// <param name="x"></param> /// <returns></returns> private static bool IsNumberRewardSuperiorTo(MissionReward reward, int x) { return reward.Quantity > x; }
/// <summary> /// Return true if the specified character have x or less than x count of ItemId carried. /// </summary> /// <param name="itemId"></param> /// <param name="x"></param> /// <returns></returns> private static bool IsNumberPlayerHasInferiorOrEqualTo(MissionReward reward, int x) { uint numCarried = 0; if (reward.IsItemReward) { numCarried = (uint)HbApi.GetNumberItemCarried((uint)reward.Id); } else if (reward.IsCurrencyReward) { numCarried = reward._CurrencyInfo.Amount; } else if (reward.IsGold) { numCarried = (uint)StyxWoW.Me.Gold; } return numCarried != 0 && numCarried <= x; }
// A rule must have a method returning a bool and a method returning the list of items /// <summary> /// Return true if the specified character has more than x count of ItemId carried. /// </summary> /// <param name="itemId"></param> /// <param name="x"></param> /// <returns></returns> private static bool IsNumberPlayerHasSuperiorTo(MissionReward reward, int x) { uint numCarried = 0; if (reward.IsItemReward) { numCarried = (uint)HbApi.GetNumberItemCarried((uint)reward.Id); } else if (reward.IsCurrencyReward) { numCarried = reward._CurrencyInfo.Amount; } else if (reward.IsGold) { numCarried = (uint)StyxWoW.Me.Gold; } //else if (reward.IsFollowerXP) //{ // numCarried = x; //} return numCarried > x; }
/// <summary> /// Returns items to send or null if none. /// </summary> /// <param name="itemId"></param> /// <returns></returns> public async Task<IEnumerable<object>> GetItemsOrNull(MissionReward reward) { switch (_condition) { case Conditions.NumberPlayerHasSuperiorTo: return GetNumberPlayerHasSuperiorTo(reward); case Conditions.NumberPlayerHasSuperiorOrEqualTo: return GetNumberPlayerHasSuperiorOrEqualTo(reward); case Conditions.NumberPlayerHasInferiorTo: return GetNumberPlayerHasInferiorTo(reward); case Conditions.NumberPlayerHasInferiorOrEqualTo: return GetNumberPlayerHasInferiorOrEqualTo(reward); case Conditions.NumberRewardSuperiorTo: return (IEnumerable<object>)GetNumberRewardSuperiorTo(reward); case Conditions.NumberRewardSuperiorOrEqualTo: return GetNumberRewardSuperiorOrEqualTo(reward); case Conditions.NumberRewardInferiorTo: return GetNumberRewardInferiorTo(reward); case Conditions.NumberRewardInferiorOrEqualTo: return GetNumberRewardInferiorOrEqualTo(reward); //case Conditions.NumberInBagsSuperiorTo: // return GetNumberInBagsSuperiorTo(itemId); //case Conditions.NumberInBagsSuperiorOrEqualTo: // return GetNumberInBagsSuperiorOrEqualTo(itemId); //case Conditions.KeepNumberInBags: // return await GetNumberKeepNumberInBags(itemId, _checkValue); case Conditions.None: return null; default: GarrisonButler.Diagnostic("GetItemsOrNull: This mission rule has not been implemented! Id: " + reward.Id + " Name: " + reward.Name); break; } return null; }
/// <summary> /// Returns value of the condition /// </summary> /// <param name="itemId"></param> /// <returns></returns> public bool GetCondition(MissionReward reward) { switch (_condition) { case Conditions.NumberPlayerHasSuperiorTo: return IsNumberPlayerHasSuperiorTo(reward, _checkValue); case Conditions.NumberPlayerHasSuperiorOrEqualTo: return IsNumberPlayerHasSuperiorOrEqualTo(reward, _checkValue); case Conditions.NumberPlayerHasInferiorTo: return IsNumberPlayerHasInferiorTo(reward, _checkValue); case Conditions.NumberPlayerHasInferiorOrEqualTo: return IsNumberPlayerHasInferiorOrEqualTo(reward, _checkValue); case Conditions.NumberRewardSuperiorTo: return IsNumberRewardSuperiorTo(reward, _checkValue); case Conditions.NumberRewardSuperiorOrEqualTo: return IsNumberRewardSuperiorOrEqualTo(reward, _checkValue); case Conditions.NumberRewardInferiorTo: return IsNumberRewardInferiorTo(reward, _checkValue); case Conditions.NumberRewardInferiorOrEqualTo: return IsNumberRewardInferiorOrEqualTo(reward, _checkValue); case Conditions.None: return true; default: GarrisonButler.Diagnostic("GetCondition: This mission rule has not been implemented! Id: {0} Name: {1}", reward.Id, reward.Name); break; } return true; }
// Returns list mission/followers combos with combosTried, acceptedCombos, totalSuccessChance public static Tuple<List<Tuple<Mission, Follower[]>>, long, int, double> DoMissionCalc( List<Follower> followersToConsider, List<Mission> missionsThatMeetRequirement, MissionReward reward, List<Follower> followers) { long combosTried = 0; var acceptedCombos = 0; double totalSuccessChance = 0; var toStart = new List<Tuple<Mission, Follower[]>>(); var followersToRemoveIfFailure = new List<Follower>(); var excludedFollowers = new List<Follower>(); foreach (var mission in missionsThatMeetRequirement) { GarrisonButler.Diagnostic("************* BEGIN Mission=" + mission.Name + "**************"); if (followersToConsider.Count < mission.NumFollowers) { var shouldBreak = true; // Attempt to "fill up" slots if they didn't enable AllowFollowerXPMissionsToFillAllSlotsWithEpicMaxLevelFollowers if (!GaBSettings.Get().AllowFollowerXPMissionsToFillAllSlotsWithEpicMaxLevelFollowers && reward.Category == MissionReward.MissionRewardCategory.FollowerExperience) { followersToRemoveIfFailure = FillFollowersWithEpicLevel100(followersToConsider, followers, mission); if (followersToRemoveIfFailure.Count > 0) { shouldBreak = false; } // Followers were excluded (followers.Count > followersToConsider.Count) // but still a follower remaining in the queue that needs experience (followersToConsider.Count > 0) //if (followersToConsider.Count > 0 // && followers.Count > followersToConsider.Count) //{ // var reducedFollowerSet = followers.Except(followersToConsider).ToList(); // if (!reducedFollowerSet.Any()) // continue; // // Get only the followers that were excluded // //var reducedFollowerSet = // // followers // // .SkipWhile((f, i) => f.FollowerId == followersToConsider[i].FollowerId) // // .ToList(); // // Adding some followers back in would allow us to complete the mission // if ((followersToConsider.Count + reducedFollowerSet.Count) >= mission.NumFollowers) // { // var amount = mission.NumFollowers - followersToConsider.Count; // followersToRemoveIfFailure = reducedFollowerSet.Take(amount).ToList(); // if (followersToRemoveIfFailure.Count > 0) // { // GarrisonButler.Diagnostic("Using epic level 100 followers to help fill up mission slots:"); // followersToRemoveIfFailure.ForEach(f => GarrisonButler.Diagnostic(" -> " + f.Name)); // followersToConsider.AddRange(followersToRemoveIfFailure); // shouldBreak = false; // } // } //} } if (shouldBreak) { GarrisonButler.Diagnostic( "Breaking mission loop due to followersToConsider < mission.NumFollowers"); continue; } } // Abort if we don't have enough Garrison Resources var gr = WoWCurrency.GetCurrencyById(824).Amount; var mingr = GaBSettings.Get().MinimumGarrisonResourcesToStartMissions; if (gr < mingr) { GarrisonButler.Diagnostic( "[Missions] Breaking MissionCalc due to Minimum Required Garrison Resources. Have {0} and need {1}.", gr, mingr); } if (mission.Cost > gr) { GarrisonButler.Diagnostic( "[Missions] Breaking MissionCalc due to insufficient Garrison Resources to start mission ({0}) {1}. Have {2} and need {3}.", mission.MissionId, mission.Name, gr, mission.Cost); break; } // Garrison Resources if (mission.Rewards.Any(r => r.IsGarrisonResources)) { if (GaBSettings.Get().PreferFollowersWithScavengerForGarrisonResourcesReward) { GarrisonButler.Diagnostic( "[Missions] Mission reward is GARRISON RESOURCES and user settings indicate to prefer followers with Scavenger trait. {0} followers have Scavenger", followersToConsider.Count(f => f.HasScavenger)); followersToConsider = followersToConsider.OrderByDescending(f => f.HasScavenger).ToList(); } } // NOT Garrison Resources & user wants to disallow followers with Scavenger on these missions else if (GaBSettings.Get().DisallowScavengerOnNonGarrisonResourcesMissions) { GarrisonButler.Diagnostic( "[Missions] Mission reward is ***NOT*** GARRISON RESOURCES and user settings indicate to NOT allow followers with Scavenger. {0} followers have Scavenger", followersToConsider.Count(f => f.HasScavenger)); excludedFollowers = followersToConsider.Where(f => f.HasScavenger).ToList(); followersToConsider.RemoveAll(f => excludedFollowers.Any(e => e.FollowerId == f.FollowerId)); } // Gold if (mission.Rewards.Any(r => r.IsGold)) { if (GaBSettings.Get().PreferFollowersWithTreasureHunterForGoldReward) { GarrisonButler.Diagnostic( "[Missions] Mission reward is GOLD and user settings indicate to prefer followers with Treasure Hunter trait. {0} followers have Treasure Hunter", followersToConsider.Count(f => f.HasTreasureHunter)); followersToConsider = followersToConsider.OrderByDescending(f => f.HasTreasureHunter).ToList(); } } // NOTGold & user wants to disallow followers with Treasure Hunter on these missions else if (GaBSettings.Get().DisallowTreasureHunterOnNonGoldMissions) { GarrisonButler.Diagnostic( "[Missions] Mission reward is ***NOT*** GOLD and user settings indicate to NOT allow followers with Treasure Hunter. {0} followers have Treasure Hunter", followersToConsider.Count(f => f.HasTreasureHunter)); excludedFollowers = followersToConsider.Where(f => f.HasTreasureHunter).ToList(); followersToConsider.RemoveAll(f => excludedFollowers.Any(e => e.FollowerId == f.FollowerId)); } DateTime startedAt = DateTime.Now; Combinations<Follower> followerCombinations = new Combinations<Follower>(followersToConsider, mission.NumFollowers); MissionCalc.mission = mission; var bestCombo = Enumerable.Empty<Follower>(); var bestSuccess = 0.0d; List<Tuple<IList<Follower>, double>> successChances = new List<Tuple<IList<Follower>, double>>(); foreach (var combo in followerCombinations) { var allMaxLevelEpic = combo.All(c => c.IsMaxLevelEpic); var isFollowerExperienceCategory = reward.Category == MissionReward.MissionRewardCategory.FollowerExperience; if (!GaBSettings.Get().AllowFollowerXPMissionsToFillAllSlotsWithEpicMaxLevelFollowers && isFollowerExperienceCategory && allMaxLevelEpic) { // Don't fill all slots with epic max level followers continue; } // Restrict combinations based on user settings // Only for FollowerExperience if (GaBSettings.Get().UseEpicMaxLevelFollowersToBoostLowerFollowers && reward.Category == MissionReward.MissionRewardCategory.FollowerExperience) { // Skip any combinations where # of epic followers is greater than allowed var maxEpicFollowers = GaBSettings.Get().MaxNumberOfEpicMaxLevelFollowersToUseWhenBoosting; maxEpicFollowers = maxEpicFollowers < 0 ? 0 : maxEpicFollowers; if (combo.Count(c => c.IsMaxLevelEpic) > maxEpicFollowers) continue; } MissionCalc.followers = combo.ToList(); var result = MissionCalc.CalculateSuccessChance(); successChances.Add(new Tuple<IList<Follower>, double>(combo, result.Item1)); } if (successChances != null && successChances.Count > 0) { GarrisonButler.Diagnostic("Total combinations tried = " + followerCombinations.Count); GarrisonButler.DiagnosticLogTimeTaken("Trying all " + followerCombinations.Count + " combinations", startedAt); var first = successChances.OrderByDescending(sc => sc.Item2).FirstOrDefault(); if (first != null) { bestCombo = first.Item1; bestSuccess = first.Item2; var sucChanceToCompareAgainst = reward.IndividualSuccessChanceEnabled ? reward.RequiredSuccessChance : GaBSettings.Get().DefaultMissionSuccessChance; if (Convert.ToInt32(bestSuccess) < sucChanceToCompareAgainst) { GarrisonButler.Diagnostic( "Best combo doesn't meet minimum success chance requirements! Need {0}% and only have {1}%", sucChanceToCompareAgainst, Convert.ToInt32(bestSuccess)); bestCombo.ForEach(c => GarrisonButler.Diagnostic(" -> Follower: " + c.Name)); RemoveAddedMaxLevelFollowers(followersToConsider, followersToRemoveIfFailure); AddExcludedFollowers(followersToConsider, excludedFollowers); GarrisonButler.Diagnostic("************* END Mission=" + mission.Name + "**************"); continue; } } else { GarrisonButler.Diagnostic( "Error retrieving success chance for best combo: bestCombo.Count={0}, successChances.Count={1}", bestCombo.GetEmptyIfNull().Count(), successChances.GetEmptyIfNull().Count()); RemoveAddedMaxLevelFollowers(followersToConsider, followersToRemoveIfFailure); AddExcludedFollowers(followersToConsider, excludedFollowers); GarrisonButler.Diagnostic("************* END Mission=" + mission.Name + "**************"); continue; } combosTried += (int) followerCombinations.Count; if (bestCombo.IsNullOrEmpty()) { GarrisonButler.Diagnostic("[Missions] No best combo found for mission {0}", mission.Name); RemoveAddedMaxLevelFollowers(followersToConsider, followersToRemoveIfFailure); AddExcludedFollowers(followersToConsider, excludedFollowers); GarrisonButler.Diagnostic("************* END Mission=" + mission.Name + "**************"); continue; } acceptedCombos++; GarrisonButler.Diagnostic("[Missions] Best Combination with success=" + bestSuccess + "% for Mission=" + mission.Name + " is "); bestCombo.ForEach(c => GarrisonButler.Diagnostic(" -> Follower: " + c.Name)); //successChances.ForEach(c => //{ // totalSuccessChance += c.Item2; //}); totalSuccessChance += bestSuccess; toStart.Add(new Tuple<Mission, Follower[]>(mission, bestCombo.ToArray())); GarrisonButler.Diagnostic("[Missions] Followers before removal: " + followersToConsider.Count); bestCombo.ForEach(c => { followersToConsider.RemoveAll(f => f.FollowerId == c.FollowerId); followers.RemoveAll(f => f.FollowerId == c.FollowerId); }); GarrisonButler.Diagnostic("Followers after removal: " + followersToConsider.Count); AddExcludedFollowers(followersToConsider, excludedFollowers); } // if (bestCombo != null) GarrisonButler.Diagnostic("************* END Mission=" + mission.Name + "**************"); } // if (successChances != null && successChances.Any()) return new Tuple<List<Tuple<Mission, Follower[]>>, long, int, double>(toStart, combosTried, acceptedCombos, totalSuccessChance); }