private double[] simpleSimulation(Stats[] partyStats, int frontRowSeparator) { var partyHpLoss = new double[partyStats.Length]; double monsterHp = monster.HP; while(partyHpLoss.Any(x => x < 1) && monsterHp > 0) { frontRowSeparator = partyHpLoss.Take(frontRowSeparator).Any(x => x < 1) ? frontRowSeparator : partyStats.Length; int frontRowCount = partyHpLoss.Take(frontRowSeparator).Count(x => x < 1); for(int i = 0; i < partyStats.Length; i++) { if (partyHpLoss[i] >= 1) continue; double critRate = 1 - Math.Pow(1 - partyStats[i].CriticalRate, 1); monsterHp -= partyStats[i].Damage * (1 + critRate) * partyStats[i].Accuracy / 2; if (i < frontRowSeparator) partyHpLoss[i] += ( monster.Attack / (1 + partyStats[i].Defense) + monster.MagicAttack / (1 + partyStats[i].MagicDefense) ) / (2 * frontRowCount * partyStats[i].Hp); if (partyHpLoss[i] > 1) partyHpLoss[i] = 1; } } var totalHp = new double[partyStats.Length + 1]; Array.Copy(partyHpLoss, totalHp, partyStats.Length); totalHp[partyStats.Length] = (monsterHp < 0) ? 0 : (monsterHp / monster.HP); return totalHp; }
public Stats(Stats original) { this.OriginalItem = original.OriginalItem; this.Damage = original.Damage; this.Accuracy = original.Accuracy; this.CriticalRate = original.CriticalRate; this.Defense = original.Defense; this.MagicDefense = original.MagicDefense; this.Hp = original.Hp; }
protected ASimulator(Monster monster, int heroLevel, int itemLevel) { this.HeroLevel = heroLevel; this.monster = monster; foreach (var hero in Library.Heroes) { var relevantItems = ItemFilter.RelevantFor(hero, itemLevel, monster, StatsFilter.All); var items = new Stats[(int)ItemSlot.N][]; for (int i = 0; i < relevantItems.Count; i++) { items[i] = relevantItems[(ItemSlot)i]; maxItemChoices = Math.Max(maxItemChoices, items[i].Length); } AllItems.Add(hero, items); } }
public override double[] Run(IList<HeroBuild> builds, int frontCount) { var partyStats = new Stats[builds.Count]; var partyHpLoss = new double[builds.Count]; var totalHpLoss = new double[builds.Count]; for(int i = 0; i < builds.Count; i++) partyStats[i] = this.HeroStats(builds[i]); if (exhaustive) takeTurn( totalHpLoss, partyStats, partyHpLoss, monster.HP, frontCount, frontCount, 0, 1 ); else totalHpLoss = simpleSimulation(partyStats, frontCount); return totalHpLoss; }
protected Stats HeroStats(HeroBuild build) { var hero = Library.Heroes[build.HeroType]; double potionStrength = Math.Max(10, HeroLevel) / 10.0; var heroStats = new Stats(hero, HeroLevel, monster); heroStats += enhancmentBonus(build.EnhancmentTypes[0]) * potionStrength * build.EnhancmentCounts[0]; heroStats += enhancmentBonus(build.EnhancmentTypes[1]) * potionStrength * build.EnhancmentCounts[1]; for(int i = 0; i < build.Items.Length; i++) if (AllItems[hero][i] != null) heroStats += AllItems[hero][i][build.Items[i]]; heroStats.Accuracy = Math.Min(1, heroStats.Accuracy + 0.8 / (1 + 2 * monster.Evasion / 100.0)); heroStats.CriticalRate = Math.Min(heroStats.CriticalRate, 1); return heroStats; }
public bool isSuperiorTo(Stats other, StatsFilter statsMask) { return (this.Damage >= other.Damage || !statsMask.HasFlag(StatsFilter.Damage)) && (this.Accuracy >= other.Accuracy || !statsMask.HasFlag(StatsFilter.Accuracy)) && (this.CriticalRate >= other.CriticalRate || !statsMask.HasFlag(StatsFilter.CriticalRate)) && (this.Defense >= other.Defense || !statsMask.HasFlag(StatsFilter.Defense)) && (this.MagicDefense >= other.MagicDefense || !statsMask.HasFlag(StatsFilter.MagicDefense)) && (this.Hp >= other.Hp || !statsMask.HasFlag(StatsFilter.Hp)); }
private void takeTurn(double[] totalHpLoss, Stats[] partyStats, double[] partyHpLoss, double monsterHp, int frontRowSeparator, int frontRowCount, int currentHero, double stateChance) { if (partyHpLoss.All(x => x >= 1)) { addHpLoss(totalHpLoss, partyHpLoss, stateChance); return; } while(currentHero < partyStats.Length && partyHpLoss[currentHero] >= 1) currentHero++; if (currentHero >= partyStats.Length) { frontRowSeparator = partyHpLoss.Take(frontRowSeparator).Any(x => x < 1) ? frontRowSeparator : partyStats.Length; frontRowCount = partyHpLoss.Take(frontRowSeparator).Count(x => x < 1); currentHero = 0; } while(partyHpLoss[currentHero] >= 1) currentHero++; if (partyStats[currentHero].Accuracy < 1) { takeTurn(totalHpLoss, partyStats, monsterTurn(partyStats, partyHpLoss, frontRowCount, currentHero), monsterHp, frontRowSeparator, frontRowCount, currentHero + 1, stateChance * (1 - partyStats[currentHero].Accuracy)); } stateChance *= partyStats[currentHero].Accuracy; if (partyStats[currentHero].CriticalRate > 0) { if (monsterHp > partyStats[currentHero].Damage * 2) takeTurn(totalHpLoss, partyStats, monsterTurn(partyStats, partyHpLoss, frontRowCount, currentHero), monsterHp - partyStats[currentHero].Damage * 2, frontRowSeparator, frontRowCount, currentHero + 1, stateChance * partyStats[currentHero].CriticalRate); else addHpLoss(totalHpLoss, partyHpLoss, stateChance * partyStats[currentHero].CriticalRate); } if (partyStats[currentHero].CriticalRate < 1) { if (monsterHp > partyStats[currentHero].Damage) takeTurn(totalHpLoss, partyStats, monsterTurn(partyStats, partyHpLoss, frontRowCount, currentHero), monsterHp - partyStats[currentHero].Damage, frontRowSeparator, frontRowCount, currentHero + 1, stateChance * (1 - partyStats[currentHero].CriticalRate)); else addHpLoss(totalHpLoss, partyHpLoss, stateChance * (1 - partyStats[currentHero].CriticalRate)); } }