public async Task UpdateCounters() { if (!runningCounterSim) { runningCounterSim = true; DateTime start = DateTime.Now; DateTime timer = new DateTime(start.Ticks); IUserMessage message = await ResponseMessage.SendInfoMessage(Context.Channel, "Starting Pokémon counter recalculations..."); List <Pokemon> allPokemon = Connections.Instance().GetPokemonForSim(); List <string> updates = new List <string>(); int count = 0; foreach (Pokemon pokemon in allPokemon) { CounterCalcResults result = CounterCalculator.RunSim(pokemon, allPokemon); Pokemon currentCounters = new Pokemon { Name = pokemon.Name }; Connections.Instance().GetPokemonCounter(ref currentCounters); if (CheckChange(result.Regular, currentCounters.Counter.Take(currentCounters.Counter.Count / 2).ToList()) || CheckChange(result.Special, currentCounters.Counter.Skip(currentCounters.Counter.Count / 2).ToList())) { Connections.Instance().UpdateCounters(pokemon.Name, result.Regular, result.Special); updates.Add(pokemon.Name); } count++; if ((DateTime.Now - timer).TotalSeconds >= COUNTER_UPDATE_TIMER) { timer = DateTime.Now; await ResponseMessage.ModifyInfoMessage(message, $"Completed {count} / {allPokemon.Count} Pokémon counter recalculations..."); } } double time = Math.Round((DateTime.Now - start).TotalMinutes, 2); bool sendInitMessage = true; string initString = $"Counters successfully updated.\nTime elapsed: {time} Minutes.\n"; count = 0; updates.Add(string.Empty); StringBuilder sb = new StringBuilder(); foreach (string name in updates) { sb.AppendLine(name); count++; if (count % COUNTER_DISPLAY_COUNT == 0 || count == updates.Count) { if (sendInitMessage) { await ResponseMessage.ModifyInfoMessage(message, initString + (updates.Count == 1 ? "No updates were necessary." : $"The following have been updated ({updates.Count - 1}):\n{sb}")); sendInitMessage = false; } else { await ResponseMessage.SendInfoMessage(Context.Channel, sb.ToString()); } sb.Clear(); } } runningCounterSim = false; } else { await ResponseMessage.SendWarningMessage(Context.Channel, "updateCounters", $"Counters are already being recalculated."); } }
/// <summary> /// Runs the counter simulation against a boss using raiders. /// </summary> /// <param name="boss">Boss to fight against.</param> /// <param name="raiders">Raiders used to attack the boss.</param> /// <returns>Counter calculation results.</returns> public static CounterCalcResults RunSim(Pokemon boss, List <Pokemon> raiders) { CounterCalcResults results = new CounterCalcResults(); for (int mode = 0; mode < 2; mode++) { List <Counter> counters = new List <Counter>(); TypeRelation bossTypes = Connections.Instance().GetTypeDefenseRelations(boss.Type); foreach (Pokemon raider in raiders) { if (raider.Released && (mode == REGULAR_COUNTER_INDEX && !raider.Name.Contains("Mega ") || (mode == SPECIAL_COUNTER_INDEX && (raider.Shadow || raider.Name.Contains("Mega ")))) ) { List <Counter> allCounters = new List <Counter>(); TypeRelation raiderTypes = Connections.Instance().GetTypeDefenseRelations(raider.Type); foreach (Move raiderFast in raider.FastMove) { foreach (Move raiderCharge in raider.ChargeMove) { if ((!raiderCharge.Name.Equals(Global.SHADOW_MOVES.ElementAt(Global.PURIFIED_INDEX).Name, StringComparison.OrdinalIgnoreCase) && !raiderCharge.Name.Equals(Global.SHADOW_MOVES.ElementAt(Global.SHADOW_INDEX).Name, StringComparison.OrdinalIgnoreCase)) || (raiderCharge.Name.Equals(Global.SHADOW_MOVES.ElementAt(Global.PURIFIED_INDEX).Name, StringComparison.OrdinalIgnoreCase) && mode == REGULAR_COUNTER_INDEX) || (raiderCharge.Name.Equals(Global.SHADOW_MOVES.ElementAt(Global.SHADOW_INDEX).Name, StringComparison.OrdinalIgnoreCase) && mode == SPECIAL_COUNTER_INDEX)) { SimPokemon raiderSim = new SimPokemon { Number = raider.Number, Name = raider.Name, Fast = raiderFast, Charge = raiderCharge, FastEffect = TypeCalculator.GetMultiplier(bossTypes, raiderFast.Type), ChargeEffect = TypeCalculator.GetMultiplier(bossTypes, raiderCharge.Type), FastStab = raider.Type.Contains(raiderFast.Type) ? STAB_MULTIPLIER : 1.0, ChargeStab = raider.Type.Contains(raiderCharge.Type) ? STAB_MULTIPLIER : 1.0, StadowAtkMul = mode == SPECIAL_COUNTER_INDEX && raider.Shadow ? SHADOW_ATK_MUL : 1.0, StadowDefMul = mode == SPECIAL_COUNTER_INDEX && raider.Shadow ? SHADOW_DEF_MUL : 1.0, AtkStat = (int)((raider.Attack + Global.MAX_IV) * Global.DISCRETE_CPM[Global.MAX_REG_LEVEL - 1]), DefStat = (int)((raider.Defense + Global.MAX_IV) * Global.DISCRETE_CPM[Global.MAX_REG_LEVEL - 1]), StamStat = (int)((raider.Stamina + Global.MAX_IV) * Global.DISCRETE_CPM[Global.MAX_REG_LEVEL - 1]) }; SimPokemon bossSim = new SimPokemon { Number = boss.Number, Name = boss.Name, StadowAtkMul = 1.0, StadowDefMul = 1.0, AtkStat = (int)((boss.Attack + Global.MAX_IV) * Global.DISCRETE_CPM[Global.MAX_REG_LEVEL - 1]), DefStat = (int)((boss.Defense + Global.MAX_IV) * Global.DISCRETE_CPM[Global.MAX_REG_LEVEL - 1]), StamStat = (int)((boss.Stamina + Global.MAX_IV) * Global.DISCRETE_CPM[Global.MAX_REG_LEVEL - 1]) }; double x = 0.0; double y = 0.0; double moveSets = 1; List <Move> bossFastMoves = boss.FastMove.Where(m => !m.IsLegacy).ToList(); List <Move> bossChargeMoves = boss.ChargeMove.Where(m => !m.IsLegacy).ToList(); if (boss.Defense == 0 || bossFastMoves.Count + bossChargeMoves.Count == 0) { if (boss.Defense == 0) { bossSim.DefStat = DEFAULT_DEF; } x = (0.5 * raiderSim.Fast.PvEEnergy) + (0.5 * raiderSim.Charge.PvEEnergy); y = DEFAULT_DPS / (double)raiderSim.DefStat; } else { moveSets = boss.FastMove.Count * boss.ChargeMove.Count; foreach (Move bossFast in bossFastMoves) { bossSim.Fast = bossFast; bossSim.FastEffect = TypeCalculator.GetMultiplier(raiderTypes, bossFast.Type); bossSim.FastStab = boss.Type.Contains(bossFast.Type) ? STAB_MULTIPLIER : 1.0; foreach (Move bossCharge in bossChargeMoves) { if (!bossCharge.Name.Equals(Global.SHADOW_MOVES.ElementAt(Global.PURIFIED_INDEX).Name, StringComparison.OrdinalIgnoreCase) && !bossCharge.Name.Equals(Global.SHADOW_MOVES.ElementAt(Global.SHADOW_INDEX).Name, StringComparison.OrdinalIgnoreCase)) { bossSim.Charge = bossCharge; bossSim.ChargeEffect = TypeCalculator.GetMultiplier(raiderTypes, bossCharge.Type); bossSim.ChargeStab = boss.Type.Contains(bossCharge.Type) ? STAB_MULTIPLIER : 1.0; DPSInput inputs = CalcDPSInput(bossSim, raiderSim); x += inputs.X; y += inputs.Y; } } } } allCounters.Add(CalcDps(bossSim, raiderSim, x / moveSets, y / moveSets)); } } } if (allCounters.Count != 0) { counters.Add(allCounters.OrderByDescending(x => x.Rating).First()); } } } if (mode == REGULAR_COUNTER_INDEX) { results.Regular = counters.OrderByDescending(x => x.Rating).ThenBy(x => x.Name).Take(RESULTS).ToList(); } else { results.Special = counters.OrderByDescending(x => x.Rating).ThenBy(x => x.Name).Take(RESULTS).ToList(); } } return(results); }