// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.OpenMU.GameLogic; using System.Collections.Concurrent; using org.mariuszgromada.math.mxparser; /// /// Extension methods regarding master skills. /// public static class MasterSkillExtensions { private static readonly ConcurrentDictionary ValueResultCache = new(); /// /// Calculates the effective value of the specified skill, depending on its formula and level. /// /// The skill entry of the master skill. /// The value of the specified skill, depending on its formula and level. public static float CalculateValue(this SkillEntry skillEntry) => skillEntry.Skill?.MasterDefinition?.CalculateValue(skillEntry.Level) ?? 0; /// /// Calculates the display value of the specified skill, depending on its formula and level. /// /// The skill entry of the master skill. /// The value of the specified skill, depending on its formula and level. public static float CalculateDisplayValue(this SkillEntry skillEntry) => skillEntry.Skill?.MasterDefinition?.CalculateDisplayValue(skillEntry.Level) ?? 0; /// /// Calculates the next display value of the specified skill, depending on its formula and level. /// /// The skill entry of the master skill. /// The value of the specified skill, depending on its formula and level. public static float CalculateNextDisplayValue(this SkillEntry skillEntry) { var level = Math.Min(skillEntry.Level + 1, skillEntry.Skill?.MasterDefinition?.MaximumLevel ?? 0); return skillEntry.Skill?.MasterDefinition.CalculateDisplayValue(level) ?? 0; } /// /// Gets the base of a . /// /// The . /// The base . public static Skill GetBaseSkill(this SkillEntry skillEntry) { return skillEntry.Skill!.GetBaseSkill(); } /// /// Gets the base of a . /// /// The . /// The base . public static Skill GetBaseSkill(this Skill skill) { while (skill.MasterDefinition?.ReplacedSkill is { } replacedSkill) { skill = replacedSkill; } return skill; } /// /// Gets the base s of a . /// /// The . /// If set to true, only master skills are returned. /// The base . public static IEnumerable GetBaseSkills(this Skill skill, bool onlyMasterSkills = false) { while (skill.MasterDefinition?.ReplacedSkill is { } replacedSkill) { if (onlyMasterSkills && replacedSkill.MasterDefinition is null) { yield break; } else { skill = replacedSkill; yield return skill; } } } private static float CalculateValue(this MasterSkillDefinition? skillDefinition, int level) => skillDefinition?.ValueFormula.GetValue(level, skillDefinition.MaximumLevel) ?? 0; private static float CalculateDisplayValue(this MasterSkillDefinition? skillDefinition, int level) => skillDefinition?.DisplayValueFormula.GetValue(level, skillDefinition.MaximumLevel) ?? 0; private static float GetValue(this string formula, int level, int maximumLevel) { if (level <= 0 || level > maximumLevel) { return 0f; } if (!ValueResultCache.TryGetValue(formula, out var results)) { results = new float[maximumLevel]; var argument = new Argument("level", 0); var expression = new Expression(formula); expression.addArguments(argument); for (int i = 0; i < maximumLevel; i++) { argument.setArgumentValue(i + 1); results[i] = (float)expression.calculate(); } ValueResultCache.TryAdd(formula, results); } return results[level - 1]; } }