public static double GetStatValue(this StatsGroup self, Stat stat) { StatsGroup higher = self.Copy(); higher[stat] += 1; return(Formulas.CalculateDamageFromGCD(higher) - Formulas.CalculateDamageFromGCD(self)); }
public double GetDamageOfGCDAttack(StatsGroup stats) { bool isCrit; bool isDirectHit; return(GetDamageOfGCDAttack(stats, out isCrit, out isDirectHit)); }
private static void RunGraph() { foreach (var statNum in Enum.GetValues(typeof(Stat))) { var stat = (Stat)statNum; Console.WriteLine($"{(int)(stat + 1)} - {stat.ToString()}"); } int choice = int.Parse(Console.ReadKey(true).KeyChar.ToString()) - 1; FileInfo outFile = new FileInfo("out.csv"); using (Stream outStream = outFile.OpenWrite()) { StreamWriter writer = new StreamWriter(outStream); double baseResult = 0; for (int stat = StatsGroup.Baseline[(Stat)choice]; stat < 5000; stat += 10) { StatsGroup stats = CurrentStats.Copy(); stats[(Stat)choice] = stat; double result = RunSimulation(stats, CurrentRotation.Value); if (baseResult == 0) { baseResult = result; } Console.WriteLine($"{stat}\t{result / baseResult}"); writer.WriteLine($"{stat}\t{result / baseResult}"); } writer.Flush(); } }
public double GetDamageOfGCDAttack(StatsGroup stats, out bool isCrit, out bool isDirectHit) { double critRate = RatingConversions.GetCritChance(stats.CritRating); double critMult = RatingConversions.GetCritDamageMultiplier(stats.CritRating); double directHitRate = RatingConversions.GetDirectHitChance(stats.DirectHitRating); double determinationFactor = RatingConversions.GetDeterminationFactor(stats.Determination); double tenacityFactor = RatingConversions.GetTenacityFactor(stats.Tenacity); isCrit = (rng.NextDouble() < critRate); isDirectHit = (rng.NextDouble() < directHitRate); double damage = 1; if (isCrit) { damage *= critMult; } if (isDirectHit) { damage *= RatingConversions.GetDirectHitDamageFactor(stats.DirectHitRating); } damage *= determinationFactor; damage *= tenacityFactor; TotalCrits += isCrit ? 1 : 0; TotalDirectHits += isDirectHit ? 1 : 0; TotalAttacks++; return(damage); }
public double GetDamageOfDoTTick(StatsGroup stats) { double critRate = RatingConversions.GetCritChance(stats.CritRating); double critMult = RatingConversions.GetCritDamageMultiplier(stats.CritRating); double directHitRate = RatingConversions.GetDirectHitChance(stats.DirectHitRating); double directHitMult = RatingConversions.GetDirectHitDamageFactor(stats.DirectHitRating); double determinationFactor = RatingConversions.GetDeterminationFactor(stats.Determination); double tenacityFactor = RatingConversions.GetTenacityFactor(stats.Tenacity); double speedFactor = RatingConversions.GetSpeedDoTContribution(stats.SpeedRating); bool isCrit = (rng.NextDouble() < critRate); bool isDirectHit = (rng.NextDouble() < directHitRate); double damage = 1; if (isCrit) { damage *= critMult; } if (isDirectHit) { damage *= directHitMult; } damage *= determinationFactor; damage *= tenacityFactor; damage *= speedFactor; return(damage); }
public static double GetContribution(this StatsGroup self, Stat stat) { StatsGroup lower = self.Copy(); lower[stat] = StatsGroup.Baseline[stat]; return(Formulas.CalculateDamageFromGCD(self) - Formulas.CalculateDamageFromGCD(lower)); }
public double GetDamageOfDoT(StatsGroup stats, int ticks) { double totalDamage = 0; for (int i = 0; i < ticks; ++i) { totalDamage += GetDamageOfDoTTick(stats); } return(totalDamage / ticks); }
public static double CalculateDamageFromAbility(StatsGroup stats) { double critRate = RatingConversions.GetCritChance(stats.CritRating); double critMult = RatingConversions.GetCritDamageMultiplier(stats.CritRating); double directHitRate = RatingConversions.GetDirectHitChance(stats.DirectHitRating); double determinationFactor = RatingConversions.GetDeterminationFactor(stats.Determination); double tenacityFactor = RatingConversions.GetTenacityFactor(stats.Tenacity); return(CalculateDamageFromGCD(critRate, critMult, 1.0, directHitRate, determinationFactor, tenacityFactor)); }
public static StatsGroup operator -(StatsGroup lhs, StatsGroup rhs) { StatsGroup ret = new StatsGroup(); ret.CritRating = lhs.CritRating - rhs.CritRating; ret.SpeedRating = lhs.SpeedRating - rhs.SpeedRating; ret.Determination = lhs.Determination - rhs.Determination; ret.Tenacity = lhs.Tenacity - rhs.Tenacity; ret.DirectHitRating = lhs.DirectHitRating - rhs.DirectHitRating; return(ret); }
public double GetDamageOfGCDAttack(StatsGroup stats) { double critRate = RatingConversions.GetCritChance(stats.CritRating); double critMult = RatingConversions.GetCritDamageMultiplier(stats.CritRating); double directHitRate = RatingConversions.GetDirectHitChance(stats.DirectHitRating); double determinationFactor = RatingConversions.GetDeterminationFactor(stats.Determination); double tenacityFactor = RatingConversions.GetTenacityFactor(stats.Tenacity); double critFactor = (1 - critRate) + (critRate * critMult); double directHitFactor = (1 - directHitRate) + (directHitRate * 1.25); return(critFactor * directHitFactor * determinationFactor * tenacityFactor); }
static void SelectStats() { OpenFileDialog openFile = new OpenFileDialog(); openFile.Filter = "Character stat files (*.char)|*.char|All files (*.*)|*.*"; openFile.ShowDialog(); string file = openFile.FileName; try { CurrentStats = StatsGroup.Load(new FileInfo(file)); } catch (Exception e) { Console.WriteLine(e.ToString()); } }
public static double MonteCarlo(AttackPattern toSimulate, StatsGroup stats, double duration, int count) { double total = 0; double[] results = new double[count]; Parallel.For(0, count, i => { SimpleSimulator sim = new SimpleSimulator(); results[i] = sim.Simulate(toSimulate, stats, duration); }); for (int i = 0; i < count; ++i) { //results[i] = Simulate(toSimulate, stats, duration); total += results[i]; } return(total / count); }
private static void ModifyStats() { var stats = (CurrentStats ?? StatsGroup.Baseline).Copy(); foreach (var statNum in Enum.GetValues(typeof(Stat))) { var stat = (Stat)statNum; Console.Write($"{stat.ToString()} = {stats[stat]}+"); try { int amount = int.Parse(Console.ReadLine()); stats[stat] += amount; } catch { } } CurrentStats = stats; }
public static StatsGroup Load(FileInfo fromFile) { using (var stream = fromFile.OpenRead()) { var reader = new StreamReader(stream); var ret = new StatsGroup(); while (stream.CanRead) { string line = reader.ReadLine(); if (line == null) { break; } string[] toks = line.Split(new char[] { ' ', '=' }, StringSplitOptions.RemoveEmptyEntries); if (toks.Length >= 2) { Stat stat = (Stat)Enum.Parse(typeof(Stat), toks[0]); ret[stat] = int.Parse(toks[1]); } } return(ret); } }
static void MainMenu() { bool terminate = false; while (!terminate) { char selected; Console.Clear(); Console.WriteLine($"Stats Loaded: {CurrentStats != null}"); Console.WriteLine($"Rotation Selected: {CurrentRotation.Key}"); Console.WriteLine($"Rulesset Selected: {CurrentSimulationRules.GetType().Name}"); Console.WriteLine("Choose an Action"); Console.WriteLine("1 - Load Stats"); Console.WriteLine("2 - Select Rotation"); Console.WriteLine("3 - Change Rules"); Console.WriteLine("4 - Enter Stats Manually"); if (CurrentStats != null && CurrentRotation.Value != null) { Console.WriteLine("G - Go!"); } Console.WriteLine("Q - Quit"); selected = Console.ReadKey(true).KeyChar; switch (selected) { case '1': SelectStats(); break; case '2': SelectRotation(); break; case '3': SelectRules(); break; case '4': ModifyStats(); break; case '0': CurrentStats = StatsGroup.Baseline; break; case 'G': case 'g': RunBasicSimulation(); break; case 'R': case 'r': RunAllRotations(); break; case 'S': case 's': RunStatSimulation(); break; case 'V': case 'v': RunGraph(); break; case 'P': case 'p': SaveStats(); break; case 'I': case 'i': PrintInfo(); break; case 'Q': case 'q': terminate = true; break; default: selected = '\0'; break; } } }
private static void EnterStats() { CurrentStats = StatsGroup.Baseline; ModifyStats(); }
public SimulatedAttackPattern(AttackPattern toSimulate, StatsGroup stats, SimpleSimulator sim) { this.ToSimulate = toSimulate; this.Stats = stats; this.Sim = sim; }
public double Simulate(AttackPattern toSimulate, StatsGroup stats, double duration) { SimulatedAttackPattern simulated = new SimulatedAttackPattern(toSimulate, stats, this); return(simulated.SimulateTotalPotencyOver(duration)); }
static void RunStatSimulation() { bool done = false; while (!done) { try { Console.WriteLine("Simulating stat variance"); Console.Write("Potential Loss: "); int potentialLoss = int.Parse(Console.ReadLine()); Console.Write("Potential Gain: "); int potentialGain = int.Parse(Console.ReadLine()); Dictionary <string, StatsGroup> possibleStats = new Dictionary <string, StatsGroup>(); if (potentialLoss > 0 && potentialGain > 0) { foreach (var lostStat in StatsGroup.GetEachDPSStat()) { foreach (var gainedStat in StatsGroup.GetEachDPSStat()) { if (lostStat == gainedStat) { continue; } string name = $"{lostStat}->{gainedStat}"; StatsGroup newStats = CurrentStats.Copy(); newStats[lostStat] -= potentialLoss; newStats[gainedStat] += potentialGain; possibleStats[name] = newStats; } } } else if (potentialLoss > 0) { foreach (var lostStatNum in Enum.GetValues(typeof(Stat))) { Stat lostStat = (Stat)lostStatNum; string name = $"-{potentialLoss} {lostStat}"; StatsGroup newStats = CurrentStats.Copy(); newStats[lostStat] -= potentialLoss; possibleStats[name] = newStats; } } else if (potentialGain > 0) { foreach (var gainedStatNum in Enum.GetValues(typeof(Stat))) { Stat gainedStat = (Stat)gainedStatNum; string name = $"+{potentialGain} {gainedStat}"; StatsGroup newStats = CurrentStats.Copy(); newStats[gainedStat] += potentialGain; possibleStats[name] = newStats; } } done = true; double baseline = RunSimulation(CurrentStats, CurrentRotation.Value, true); Console.WriteLine($"Baseline is {baseline}"); foreach (var stats in possibleStats) { double result = RunSimulation(stats.Value, CurrentRotation.Value); double delta = result - baseline; double percentage = delta / baseline * 100; string sign = result > baseline ? "+" : ""; Console.WriteLine($"{stats.Key}: {sign}{percentage:0.00}% ({sign}{delta:#.0})"); } Console.WriteLine(); Console.ReadKey(true); } catch { } } }
static double RunSimulation(StatsGroup stats, RotationFactory rotation, bool enableLogging = false) { double totalPotency = 0; if (CurrentSimulationRules is DeterministicSimulator) { Battle battle = new Battle(new DeterministicSimulator(), sampleDuration); if (enableLogging) { battle.Logger += Console.WriteLine; } WarriorOfLight hero = rotation(battle, stats); battle.Simulate(hero); totalPotency = battle.TotalPotency; if (enableLogging) { Console.WriteLine(); Console.WriteLine("Breakdown by Ability"); foreach (var breakdown in battle.PotencyBySource) { double percent = breakdown.Value / battle.TotalPotency * 100; Console.WriteLine($" {breakdown.Key}: {breakdown.Value:#.0} ({percent:0.00}%)"); } } } else if (CurrentSimulationRules is RandomSimulator) { double[] potencies = new double[monteCarloCount]; Stopwatch timer = new Stopwatch(); timer.Start(); int count = 0; Battle firstBattle = new Battle(new RandomSimulator(), sampleDuration); { WarriorOfLight hero = rotation(firstBattle, stats); firstBattle.Simulate(hero); potencies[0] = firstBattle.TotalPotency; } Parallel.For(1, monteCarloCount, (i) => { if (timer.Elapsed > monteCarloDuration) { return; } Battle battle = new Battle(new RandomSimulator(), sampleDuration); WarriorOfLight hero = rotation(battle, stats); battle.Simulate(hero); potencies[i] = battle.TotalPotency; }); timer.Stop(); double minPotency = double.MaxValue, maxPotency = double.MinValue; for (int i = 0; i < monteCarloCount; ++i) { totalPotency += potencies[i]; if (potencies[i] != 0) { minPotency = Math.Min(minPotency, potencies[i]); maxPotency = Math.Max(maxPotency, potencies[i]); count++; } } totalPotency /= count; if (enableLogging) { foreach (var breakdown in firstBattle.PotencyBySource) { double percent = breakdown.Value / firstBattle.TotalPotency * 100; Console.WriteLine($" {breakdown.Key}: {breakdown.Value:#.0} ({percent:0.00}%)"); } Console.WriteLine(); Console.WriteLine($"Over {count} trials, PPS ranged from {minPotency / sampleDuration:#.0} to {maxPotency / sampleDuration:#.0}"); } } return(totalPotency); }