/// <summary> /// Computes the average uptime of specific effects being active/inactive. /// </summary> /// <param name="triggerInterval">Average time interval between triggers in seconds for each effect.</param> /// <param name="triggerChance">Chance that trigger of correct type is produced for each effect.</param> /// <param name="active">Determines if specific effects are being active/inactive for the uptime calculation.</param> /// <param name="offset">Initial cooldown for each effect.</param> /// <param name="attackSpeed">Average unhasted attack speed, used in PPM calculations.</param> /// <param name="fightDuration">Duration of fight in seconds.</param> /// <param name="scale">Chance that the effect will give the desired proc.</param> /// <param name="effects">The effects for which the combined uptime is to be computed.</param> /// <param name="value">The value of special effects when procced, used to compute the value in returned WeightedStat.</param> public static WeightedStat[] GetAverageCombinedUptimeCombinationsMultiplicative(SpecialEffect[] effects, float[] triggerInterval, float[] triggerChance, float[] offset, float[] scale, float attackSpeed, float fightDuration, float[] value) { // CombinedAverageUptime = integrate_0..fightDuration prod_i Uptime[i](t) dt // initialize data, translate into interval time Parameters p = new Parameters(effects, triggerInterval, triggerChance, offset, attackSpeed, scale, value, fightDuration); // integrate using adaptive Simspon's method // if there's only one nonstationary use noncombination solution for efficiency if (p.N > 1) { AdaptiveSimpsonsMethodCombinations(p, fightDuration, 0.001f, maxRecursionDepth); } else if (p.N == 1) { p.partialIntegral[0, 1] = fightDuration * p.k[0] * p.effects[0].GetAverageUptime(triggerInterval[p.I], triggerChance[p.I], attackSpeed, fightDuration); p.partialIntegral[0, 0] = fightDuration - p.partialIntegral[0, 1]; } WeightedStat[] result = new WeightedStat[1 << effects.Length]; int mask = p.NC - 1; for (int i = 0; i < (1 << effects.Length); i++) { if (p.N > 0) { result[i].Chance = p.partialIntegral[0, i & mask] / fightDuration; } else { result[i].Chance = 1.0f; } for (int j = 0; j < effects.Length; j++) { if ((i & (1 << j)) != 0) { result[i].Value = (1 + result[i].Value) * (1 + p.v[j]) - 1; if (j >= p.N) { result[i].Chance *= p.uptime[j]; } } else { if (j >= p.N) { result[i].Chance *= (1.0f - p.uptime[j]); } } } } return(result); }
/// <summary> /// Computes the average uptime of specific effects being active/inactive. /// </summary> /// <param name="triggerInterval">Average time interval between triggers in seconds for each effect.</param> /// <param name="triggerChance">Chance that trigger of correct type is produced for each effect.</param> /// <param name="active">Determines if specific effects are being active/inactive for the uptime calculation.</param> /// <param name="offset">Initial cooldown for each effect.</param> /// <param name="attackSpeed">Average unhasted attack speed, used in PPM calculations.</param> /// <param name="fightDuration">Duration of fight in seconds.</param> /// <param name="scale">Chance that the effect will give the desired proc.</param> /// <param name="effects">The effects for which the combined uptime is to be computed.</param> /// <param name="value">The value of special effects when procced, used to compute the value in returned WeightedStat.</param> public static WeightedStat[] GetAverageCombinedUptimeCombinationsMultiplicative(SpecialEffect[] effects, float[] triggerInterval, float[] triggerChance, float[] offset, float[] scale, float attackSpeed, float fightDuration, float[] value) { // CombinedAverageUptime = integrate_0..fightDuration prod_i Uptime[i](t) dt // initialize data, translate into interval time Parameters p = new Parameters(effects, triggerInterval, triggerChance, offset, attackSpeed, scale, value, fightDuration); // integrate using adaptive Simspon's method // if there's only one nonstationary use noncombination solution for efficiency if (p.N > 1) { AdaptiveSimpsonsMethodCombinations(p, fightDuration, 0.001f, maxRecursionDepth); } else if (p.N == 1) { p.partialIntegral[0, 1] = fightDuration * p.k[0] * p.effects[0].GetAverageUptime(triggerInterval[p.I], triggerChance[p.I], attackSpeed, fightDuration); p.partialIntegral[0, 0] = fightDuration - p.partialIntegral[0, 1]; } WeightedStat[] result = new WeightedStat[1 << effects.Length]; int mask = p.NC - 1; for (int i = 0; i < (1 << effects.Length); i++) { if (p.N > 0) { result[i].Chance = p.partialIntegral[0, i & mask] / fightDuration; } else { result[i].Chance = 1.0f; } for (int j = 0; j < effects.Length; j++) { if ((i & (1 << j)) != 0) { result[i].Value = (1 + result[i].Value) * (1 + p.v[j]) - 1; if (j >= p.N) { result[i].Chance *= p.uptime[j]; } } else { if (j >= p.N) { result[i].Chance *= (1.0f - p.uptime[j]); } } } } return result; }