internal static void SimulateMission(Mission mission) { GarrisonBase.Log("Simulating Mission {0}", mission.Name); RefreshFollowers(); var firstFollowers = Followers.Values.Where(follower => (follower.Status == GarrisonFollowerStatus.Idle || follower.Status == GarrisonFollowerStatus.InParty) && follower.Level >= mission.Level && follower.ItemLevel >= mission.ItemLevel).ToList(); var firstFollowerIds = firstFollowers.Select(f => f.ID).ToList(); var idleFollowers = Followers.Values.Where(follower => !firstFollowerIds.Contains(follower.ID) && (follower.Status == GarrisonFollowerStatus.Idle || follower.Status == GarrisonFollowerStatus.InParty)).OrderByDescending(f => f.ItemLevel).ThenByDescending(f => f.Level).ToList(); int followerCount = idleFollowers.Count; int missionSlots = mission.Followers; MissionSimulatorOptions options = new MissionSimulatorOptions(true, false, false, false, true, true, false, false, false); //mission.RewardTypes.HasFlag(RewardTypes.XP), var results = new List <MissionSimulatorResults>(); foreach (var follower in firstFollowers) { //int followerIndex1 = idleFollowers.IndexOf(follower); //if (followerIndex1 > followerCount - missionSlots) // break; GarrisonFollower follower1 = follower._refFollower; GarrisonFollower follower2, follower3; if (missionSlots > 1) { for (int i = 0; i < (missionSlots > 2?followerCount - 1:followerCount); i++) { follower2 = idleFollowers[i]._refFollower; if (missionSlots > 2) { for (int j = i + 1; j < followerCount; j++) { follower3 = idleFollowers[j]._refFollower; results.Add(SimulatorResults(mission, new[] { follower1, follower2, follower3 }, null)); //break; } } else { results.Add(SimulatorResults(mission, new[] { follower1, follower2 }, null)); } //break; } } else { results.Add(SimulatorResults(mission, new[] { follower1 }, null)); } //break; } //foreach (var result in results) //{ // string followernames = result.Followers.Aggregate(string.Empty, (current, f) => current + f.Name + "\t"); // GarrisonBase.Log("Result: Success {0}%, Followers {1}", result.SuccessChance, followernames); //} }
private static MissionSimulatorResults SimulatorResults(Mission mission, GarrisonFollower[] followers, MissionSimulatorOptions options) { var _options = options ?? SuccessOnlyOptions; var result = GarrisonMissionSimulator.Simulate(mission.refGarrisonMission, followers, _options); string followernames = result.Followers.Aggregate(String.Empty, (current, f) => current + f.Name + "\t"); GarrisonBase.Log("Result: Success {0}%, Followers {1}", result.SuccessChance, followernames); return(result); }
public static Tuple<double, double> CalculateSuccessChance() { var successChance = 0.0d; var chanceOver = 0.0d; var returnValue = new Tuple<double, double>(-1.0, 0); if(enableDebugPrint) GarrisonButler.Diagnostic("----- Start CalculateSuccessChance -----"); if (DefaultSuccessChanceIs100Percent) { GarrisonButler.Diagnostic("Returning 100% success chance due to DefaultSuccessChanceIs100Percent being true."); return new Tuple<double, double>(100.0d, 0.0d); } // Probably because this mission has a base success chance of 100% and wowhead has no data on it if (!valid) { try { GarrisonButler.Diagnostic("Mission not valid, manually determine success chance"); var hbMission = GarrisonInfo.Missions.FirstOrDefault( m => m.Id == mission.MissionId.ToInt32()); if (hbMission == null) { GarrisonButler.Diagnostic("[Missions] hbMission object is null!"); return returnValue; } var hbFollowers = GarrisonInfo.Followers.Where(f => followers.Any(fl => fl.FollowerId.ToInt32() == f.GarrFollowerId)); if (!hbFollowers.Any()) { GarrisonButler.Diagnostic("[Missions] hbFollowers returned NONE!"); return returnValue; } MissionSimulatorOptions options = new MissionSimulatorOptions( true, // computeSuccessChance false, // clampSuccessTo100 true, // computerModifiedDuration true, // computeXpBonusModifier true, // computerMaterialBonusModifier true, // computerBuffsAndEnvironmentCounter true, // computeRewards true, // computeModifiedRewards true // computeGoldBonusModifier ); var result = GarrisonMissionSimulator.Simulate(hbMission, hbFollowers, options); GarrisonButler.Diagnostic("[Missions] MissonSimulatorResults: \nGold Bonus Mod: {0}\nMaterial Bonus Mod: {1}\nSuccess Chance: {2}", result.GoldBonusModifier, result.MaterialBonusModifier, result.SuccessChance); returnValue = new Tuple<double, double>((double)result.SuccessChance, 0.0d); //var followersToAssign = followers.Take(mission.NumFollowers); //if (!followersToAssign.Any()) // return returnValue; //followersToAssign.ForEach(f => API.FollowersLua.AddFollowerToMission(mission.MissionId.ToInt32(), f.UniqueId.ToInt32())); //var missionInfo = API.MissionLua.GetPartyMissionInfo(mission); //returnValue = new Tuple<double, double>(missionInfo.SuccessChance.ToFloat(), 0.0d); //followersToAssign.ForEach(f => API.FollowersLua.RemoveFollowerFromMission(mission.MissionId.ToInt32(), f.UniqueId.ToInt32())); //InterfaceLua.ClickCloseMission(); } catch (Exception e) { GarrisonButler.Diagnostic("ERROR in !valid workaround during CalculateSuccessChance - " + e.GetType() + " - " + e.StackTrace); } return returnValue; } var mentorinfo = GetMentorInfo(); foreach (var currentFollower in followerInfo) { if (mentorinfo.Item1 > currentFollower.level) { if (enableDebugPrint) GarrisonButler.Diagnostic("Mentored follower {0} from level {1} to level {2}", currentFollower.follower, currentFollower.level, mentorinfo.Item1); currentFollower.level = mentorinfo.Item1; } if (mentorinfo.Item2 > currentFollower.avgilvl) { if (enableDebugPrint) GarrisonButler.Diagnostic("Mentored follower {0} from item level {1} to item level {2}", currentFollower.follower, currentFollower.avgilvl, mentorinfo.Item2); currentFollower.avgilvl = mentorinfo.Item2; } currentFollower.bias = GetFollowerBias(currentFollower.level, currentFollower.avgilvl); if (enableDebugPrint) GarrisonButler.Diagnostic("Follower {0} bias: {1:0.00}", currentFollower.follower, currentFollower.bias); } var D = mission.NumFollowers*100; var B = D; if (mechanicInfo.Count > 0) { foreach (Hashtable currentMechanic in mechanicInfo) { //Integers = setkey, id, amount, type, category //Strings = name, description, icon var category = currentMechanic["category"]; if (category == null) continue; var categoryInt = category.ToString().ToInt32(); if (categoryInt != 2) { D = B; } else { var amount = currentMechanic["amount"]; if (amount == null) continue; var amountInt = amount.ToString().ToInt32(); D = B + amountInt; B += amountInt; } } } if (D <= 0) { return new Tuple<double, double>(100, 0); } double coeff = 100.0d/(double)D; if (enableDebugPrint) GarrisonButler.Diagnostic("coeff: {0}", coeff); for (int followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) { var currentFollower = followerInfo[followerIndex]; var calcChance = CalcChance(100, 150, currentFollower.bias); var z = calcChance * coeff; successChance += z; if (enableDebugPrint) GarrisonButler.Diagnostic("Added {0} to success due to follower {1} bias - CalcChance returned {2}", z, currentFollower.follower, calcChance); } var mechanicIndex = 0; registeredThreatCounters = new bool[100, 100, 100]; var typeAmountHashtable = new Hashtable(); if (mechanicInfo.Count > 0) { do { Hashtable currentMechanic = (Hashtable)mechanicInfo[mechanicIndex]; // Category 2 = Abilities if (!currentMechanic.ContainsKey("category") || currentMechanic["category"].ToString().ToInt32() == 2) { var amt = currentMechanic["amount"].ToString().ToInt32(); //Hashtable currentIndex = o.ContainsKey(currentMechanic["type"]) ? (Hashtable)o[currentMechanic["type"]] : o.Add(currentMechanic["type"].ToString(), ); if (typeAmountHashtable.ContainsKey(currentMechanic["type"])) { Hashtable currentIndex = (Hashtable)typeAmountHashtable[currentMechanic["type"]]; currentIndex["amount1"] = currentIndex["amount1"].ToString().ToInt32() + amt; currentIndex["amount2"] = currentIndex["amount2"].ToString().ToInt32() + amt; } else { Hashtable currentIndex = new Hashtable(); currentIndex.Add("amount1", amt); currentIndex.Add("amount2", amt); currentIndex.Add("id", currentMechanic["id"].ToString().ToInt32()); typeAmountHashtable.Add(currentMechanic["type"], currentIndex); } //var mechanicAmount = currentMechanic["amount"].ToString().ToInt32(); //if (mission.NumFollowers > 0) //{ // for (int followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) // { // var currentFollower = followerInfo[followerIndex]; // for (int abilityIndex = 0; // abilityIndex < currentFollower.abilities.Count; // abilityIndex++) // { // var currentAbility = (Hashtable)g_garrison_abilities[currentFollower.abilities[abilityIndex].ToString()]; // var currentAbilityType = (ArrayList)currentAbility["type"]; // var numTypes = currentAbilityType.Count; // for (var typeIndex = 0; typeIndex < numTypes; typeIndex++) // { // var counters = (ArrayList) currentAbility["counters"]; // var amount1 = (ArrayList) currentAbility["amount1"]; // var amount2 = (ArrayList) currentAbility["amount2"]; // var amount3 = (ArrayList) currentAbility["amount3"]; // var currentMechanicType = currentMechanic["type"]; // var currentMechanicTypeInt = currentMechanicType.ToString().ToInt32(); // var counterInt = counters[typeIndex].ToString().ToInt32(); // var amount1Int = amount1[typeIndex].ToString().ToInt32(); // var amount2Int = amount2[typeIndex].ToString().ToInt32(); // var amount3Int = amount3[typeIndex].ToString().ToInt32(); // if ((currentMechanicTypeInt == counterInt) // && ((amount1Int & 1) != 1) // && (mechanicAmount > 0) // && !ThreatCounterIsAlreadyRegistered(followerIndex, abilityIndex, typeIndex)) // { // var q = CalcChance(amount2Int, amount3Int, currentFollower.bias); // var a = currentMechanic["amount"].ToString().ToInt32(); // if (q <= a) // a = Convert.ToInt32(q); // RegisterThreatCounter(followerIndex, abilityIndex, typeIndex); // // Reduce mechanic amount by amount countered // mechanicAmount -= a; // } // } // } // } //} // if (mission.NumFollowers > 0) //if (mechanicAmount < 0) // mechanicAmount = 0; //// Calculate success based on how much of the mechanic was countered //var f = ((double)(currentMechanic["amount"].ToString().ToInt32() - mechanicAmount))*coeff; //successChance += f; //if (enableDebugPrint) GarrisonButler.Diagnostic("Added {0} to success due to followers countering boss mechanics {1}.", f, currentMechanic["id"]); } mechanicIndex++; } while (mechanicIndex < mechanicInfo.Count); } //if (mechanicInfo.Count > 0) //for(var currentTypeAmountIndex = 0; currentTypeAmountIndex < typeAmountHashtable.Count; currentTypeAmountIndex++) foreach (DictionaryEntry currentTypeAmountDictionaryEntry in typeAmountHashtable) { Hashtable currentTypeAmount = (Hashtable)currentTypeAmountDictionaryEntry.Value; // currentTypeAmount produces Hashtable with the following structure: // amount1: <int> // amount2: <int> // type: <int> var currentTypeAmount_Amount2 = currentTypeAmount["amount2"].ToString().ToInt32(); if (mission.NumFollowers > 0) { for (var followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) { var currentFollower = followerInfo[followerIndex]; for (int abilityIndex = 0; abilityIndex < currentFollower.abilities.Count; abilityIndex++) { var currentAbility = (Hashtable)g_garrison_abilities[currentFollower.abilities[abilityIndex].ToString()]; var type = (ArrayList)currentAbility["type"]; var numTypes = type.Count; for (var typeIndex = 0; typeIndex < numTypes; typeIndex++) { var counters = (ArrayList)currentAbility["counters"]; var amount1 = (ArrayList)currentAbility["amount1"]; var amount2 = (ArrayList)currentAbility["amount2"]; var amount3 = (ArrayList)currentAbility["amount3"]; if (typeIndex >= counters.Count || typeIndex >= amount1.Count || typeIndex >= amount2.Count || typeIndex >= amount3.Count) continue; var typeInt = type[typeIndex].ToString().ToInt32(); var counterInt = counters[typeIndex].ToString().ToInt32(); var amount1Int = amount1[typeIndex].ToString().ToInt32(); var amount2Int = amount2[typeIndex].ToString().ToInt32(); var amount3Int = amount3[typeIndex].ToString().ToInt32(); if (currentTypeAmountDictionaryEntry.Key.ToString().ToInt32() == counterInt && ((amount1Int & 1) != 1) && currentTypeAmount_Amount2 > 0) { var q = CalcChance(amount2Int, amount3Int, currentFollower.bias); var s = currentTypeAmount_Amount2 - q; if (s < 0) s = 0; currentTypeAmount_Amount2 = Convert.ToInt32(s); //if (enableDebugPrint) GarrisonButler.Diagnostic("Added {0} to success due to follower {1} enemy race ability {2}", q, currentFollower.follower, currentMechanic["id"]); } } } } // for (var followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) } // if (mission.NumFollowers > 0) var v28 = (currentTypeAmount["amount1"].ToString().ToInt32() - currentTypeAmount_Amount2)*coeff; successChance += v28; if (enableDebugPrint) GarrisonButler.Diagnostic("Added {0} to success due to followers countering boss mechanic type {1}.", v28, currentTypeAmount["id"]); } for (mechanicIndex = 0; mechanicIndex < mechanicInfo.Count; mechanicIndex++) { Hashtable currentMechanic = (Hashtable)mechanicInfo[mechanicIndex]; // Category 1 = Races if (currentMechanic["category"].ToString().ToInt32() == 1) { if (mission.NumFollowers > 0) { for (var followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) { var currentFollower = followerInfo[followerIndex]; for (int abilityIndex = 0; abilityIndex < currentFollower.abilities.Count; abilityIndex++) { var currentAbility = (Hashtable) g_garrison_abilities[currentFollower.abilities[abilityIndex].ToString()]; var type = (ArrayList) currentAbility["type"]; var numTypes = type.Count; for (var typeIndex = 0; typeIndex < numTypes; typeIndex++) { var counters = (ArrayList) currentAbility["counters"]; var amount1 = (ArrayList) currentAbility["amount1"]; var amount2 = (ArrayList) currentAbility["amount2"]; var amount3 = (ArrayList) currentAbility["amount3"]; if (typeIndex >= counters.Count || typeIndex >= amount1.Count || typeIndex >= amount2.Count || typeIndex >= amount3.Count) continue; var typeInt = type[typeIndex].ToString().ToInt32(); var counterInt = counters[typeIndex].ToString().ToInt32(); var amount1Int = amount1[typeIndex].ToString().ToInt32(); var amount2Int = amount2[typeIndex].ToString().ToInt32(); var amount3Int = amount3[typeIndex].ToString().ToInt32(); if (currentMechanic["type"].ToString().ToInt32() == counterInt) { var q = CalcChance(amount2Int, amount3Int, currentFollower.bias); q *= coeff; successChance += q; if (enableDebugPrint) GarrisonButler.Diagnostic("Added {0} to success due to follower {1} enemy race ability {2}", q, currentFollower.follower, currentMechanic["id"]); } } } } // for (var followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) } // if (mission.NumFollowers > 0) } // if ((double) currentMechanic["category"] == 1.0d) } // for (mechanicIndex = 0; mechanicIndex < mechanicInfo.Count; mechanicIndex++) if (mission.NumFollowers > 0) { for (var followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) { var currentFollower = followerInfo[followerIndex]; for (int abilityIndex = 0; abilityIndex < currentFollower.abilities.Count; abilityIndex++) { var currentAbility = (Hashtable)g_garrison_abilities[currentFollower.abilities[abilityIndex].ToString()]; var type = (ArrayList)currentAbility["type"]; var numTypes = type.Count; for (var typeIndex = 0; typeIndex < numTypes; typeIndex++) { var counters = (ArrayList)currentAbility["counters"]; var amount1 = (ArrayList)currentAbility["amount1"]; var amount2 = (ArrayList)currentAbility["amount2"]; var amount3 = (ArrayList)currentAbility["amount3"]; if (typeIndex >= counters.Count || typeIndex >= amount1.Count || typeIndex >= amount2.Count || typeIndex >= amount3.Count) continue; var typeInt = type[typeIndex].ToString().ToInt32(); var counterInt = counters[typeIndex].ToString().ToInt32(); var amount1Int = amount1[typeIndex].ToString().ToInt32(); var amount2Int = amount2[typeIndex].ToString().ToInt32(); var amount3Int = amount3[typeIndex].ToString().ToInt32(); if (wowheadMissionObject["mechanictype"].ToString().ToInt32() == counterInt) { var q = CalcChance(amount2Int, amount3Int, currentFollower.bias); q *= coeff; successChance += q; if (enableDebugPrint) GarrisonButler.Diagnostic("Added {0} to success due to follower {1} environment ability {2}", q, currentFollower.follower, currentAbility["id"]); } } } } // for (var followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) } // if (mission.NumFollowers > 0) var y = GetMissionTimes(); if (mission.NumFollowers > 0) { for (var followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) { var currentFollower = followerInfo[followerIndex]; for (int abilityIndex = 0; abilityIndex < currentFollower.abilities.Count; abilityIndex++) { var currentAbility = (Hashtable)g_garrison_abilities[currentFollower.abilities[abilityIndex].ToString()]; var type = (ArrayList)currentAbility["type"]; var numTypes = type.Count; for (var typeIndex = 0; typeIndex < numTypes; typeIndex++) { var u = false; var counters = (ArrayList)currentAbility["counters"]; var amount1 = (ArrayList)currentAbility["amount1"]; var amount2 = (ArrayList)currentAbility["amount2"]; var amount3 = (ArrayList)currentAbility["amount3"]; var race = (ArrayList) currentAbility["race"]; var hours = (ArrayList) currentAbility["hours"]; if (typeIndex >= counters.Count || typeIndex >= amount1.Count || typeIndex >= amount2.Count || typeIndex >= amount3.Count || typeIndex >= race.Count || typeIndex >= hours.Count) continue; var typeInt = type[typeIndex].ToString().ToInt32(); var counterInt = counters[typeIndex].ToString().ToInt32(); var amount1Int = amount1[typeIndex].ToString().ToInt32(); var amount2Int = amount2[typeIndex].ToString().ToInt32(); var amount3Int = amount3[typeIndex].ToString().ToInt32(); var raceInt = race[typeIndex].ToString().ToInt32(); var hoursInt = hours[typeIndex].ToString().ToInt32(); switch (typeInt) { // Lone Wolf - Increases success chance when on a mission alone case 1: if (followerInfo.Count == 1) u = true; break; // Combat Experience - Grants a bonus to mission success chance case 2: u = true; break; // Race - Gnome-Lover / Humanist / Dwarvenborn / etc... // Increases success chance when on a mission with a <race> case 5: if (CheckEffectRace(raceInt, followerIndex)) u = true; break; // High Stamina - Increases success chance on missions with duration longer than 7 hours case 6: if (y.Item1 > 3600*hoursInt) u = true; break; // Burst of Power - Increases success chance on missions with duration shorter than 7 hours case 7: if (y.Item1 < 3600*hoursInt) u = true; break; // Doesn't appear to matter anymore?? travel time?? case 9: if (y.Item2 > 3600*hoursInt) u = true; break; // doesn't appear to matter anymore?? travel time?? case 10: if (y.Item2 < 3600*hoursInt) u = true; break; default: break; } if (u) { var q = CalcChance(amount2Int, amount3Int, currentFollower.bias); q *= coeff; successChance += q; if (enableDebugPrint) GarrisonButler.Diagnostic("Added {0} to success due to follower {1} trait {2}.", q, currentFollower.follower, typeInt); } } } } // for (var followerIndex = 0; followerIndex < followerInfo.Count; followerIndex++) } // if (mission.NumFollowers > 0) if (enableDebugPrint) GarrisonButler.Diagnostic("Total before adding base chance: {0}", successChance); var t = true; var k = 100; var h = 0d; var p = (((100 - wowheadMissionObject["basebonuschance"].ToString().ToFloat()) * successChance) * 0.01d) + wowheadMissionObject["basebonuschance"].ToString().ToFloat(); if (enableDebugPrint) GarrisonButler.Diagnostic("Total after base chance: {0}", p); h = p; var g = h; if (t && k <= p) { h = k; } if (t && g > 100) if (enableDebugPrint) GarrisonButler.Diagnostic("Total success chance: {0}, ({1} before clamping)", h, g); else if (enableDebugPrint) GarrisonButler.Diagnostic("Total success chance: {0}", h); if (enableDebugPrint) GarrisonButler.Diagnostic("----- End CalculateSuccessChance -----"); returnValue = new Tuple<double, double>(Math.Floor(h), g - h); //how do I find encounter data? return returnValue; }