//
// 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];
}
}