/// <summary>To be used only after spell casting stats are set</summary> private void PopulateTriggers( Dictionary <int, float> periods, Dictionary <int, float> chances) { float totalCasts = 0f; float totalTicks = 0f; float corruptionTicks = 0f; SimulatedStat castsPerCrittable = new SimulatedStat(); foreach (Spell spell in CastSpells.Values) { if (spell.BaseDamage == 0 && spell.BaseTickDamage == 0) { continue; } float numCasts = spell.GetNumCasts(); float numTicks = HitChance * numCasts * spell.NumTicks; totalCasts += numCasts; totalTicks += numTicks; float numCrittables = 0f; if (spell.BaseDamage > 0) { numCrittables += HitChance * numCasts; } if (spell.BaseTickDamage > 0 && spell.CanTickCrit) { numCrittables += numTicks; } castsPerCrittable.AddSample( numCrittables == 0 ? 0f : numCasts / numCrittables, numCasts); if (spell is Corruption) { corruptionTicks += numTicks; } } PopulateTriggers( periods, chances, Options.Duration / totalCasts, totalTicks / Options.Duration, corruptionTicks == 0 ? -1 : Options.Duration / corruptionTicks, castsPerCrittable.GetValue()); }
public void RecordSimulatedStat(string statName, float value, float weight) { if (!SimulatedStats.ContainsKey(statName)) { SimulatedStats[statName] = new SimulatedStat(); } SimulatedStats[statName].AddSample(value, weight); }
public float GetAvgTickBonus() { if (AvgBonus > 0) { return AvgBonus; } // Consider the window from cast time until the next (actual, not // planned) cast time. This can be broken into three cases, when // it hits, when it misses & the previous cast hit, and when it // misses & the previous cast missed. Calculate the average uprate // in each case, then combine them with a weighted average to get // the overall uprate. float uprate; float tolerance = 12f - RecastPeriod; SimulatedStat delayStats = SimulatedStats["delay"]; SimulatedStat hitUprate = new SimulatedStat(); SimulatedStat missFollowingHitUprate = new SimulatedStat(); for (int i = delayStats.Values.Count; --i >= 0; ) { float collisionDelay = delayStats.Values[i]; float probability = delayStats.Weights[i]; // CASE 1: this cast hits. // uprate = duration / window // duration = 12 // window = RecastPeriod + collisionDelay uprate = Math.Min(1f, 12f / (RecastPeriod + collisionDelay)); hitUprate.AddSample(uprate, probability); // CASE 2: this cast misses, previous cast hit. // uprate = leftoverUptime / window // leftoverUptime = tolerance - collisionDelay // window = Cooldown + collisionDelay uprate = Math.Max(tolerance - collisionDelay, 0) / (Cooldown + delayStats.GetValue()); missFollowingHitUprate.AddSample(uprate, probability); // CASE 3: this cast misses, previous cast missed. // This case will always yeild zero uptime/uprate. } // average them all together for the overall uprate float hitChance = Mommy.HitChance; float missChance = 1 - hitChance; uprate = Utilities.GetWeightedSum(hitUprate.GetValue(), hitChance, missFollowingHitUprate.GetValue(), missChance * hitChance, 0f, missChance * missChance); AvgBonus = (Mommy.Talents.GlyphOfHaunt ? .23f : .2f) * uprate; return AvgBonus; }
/// <summary> /// To be used only after spell casting stats are set /// </summary> private void PopulateTriggers(Dictionary<int, float> periods, Dictionary<int, float> chances) { float totalCasts = 0f; float totalTicks = 0f; float corruptionTicks = 0f; SimulatedStat castsPerCrittable = new SimulatedStat(); foreach (Spell spell in CastSpells.Values) { if (spell.BaseDamage == 0 && spell.BaseTickDamage == 0) { continue; } float numCasts = spell.GetNumCasts(); float numTicks = HitChance * numCasts * spell.NumTicks; totalCasts += numCasts; totalTicks += numTicks; float numCrittables = 0f; if (spell.BaseDamage > 0) { numCrittables += HitChance * numCasts; } if (spell.BaseTickDamage > 0 && spell.CanTickCrit) { numCrittables += numTicks; } castsPerCrittable.AddSample(numCrittables == 0 ? 0f : numCasts / numCrittables, numCasts); if (spell is Corruption) { corruptionTicks += numTicks; } } PopulateTriggers( periods, chances, BossOpts.BerserkTimer / totalCasts, totalTicks / BossOpts.BerserkTimer, corruptionTicks == 0 ? -1 : BossOpts.BerserkTimer / corruptionTicks, castsPerCrittable.GetValue()); }