135 lines
4.1 KiB (Stored with Git LFS)
C#
135 lines
4.1 KiB (Stored with Git LFS)
C#
using System.Collections.Generic;
|
|
using System.Text.RegularExpressions;
|
|
using Superlazy;
|
|
|
|
public class Evaluator
|
|
{
|
|
public static string Evaluate(SLEntity player, string desc)
|
|
{
|
|
if (desc.StartsWith('$') == false) return desc;
|
|
|
|
// 변수 대체: {name} 패턴을 찾아 Global.Get으로 변환
|
|
var replacedDesc = Regex.Replace(desc.Substring(1), @"\{(\w+)\}", match =>
|
|
{
|
|
var varName = match.Groups[1].Value;
|
|
var ret = player["EventValues"].Get(varName); // 그냥 글로벌로 하면 변수 길어질듯해서
|
|
if (ret.IsValue && ret.IsNumeric == false) return $"\"{ret}\"";
|
|
|
|
return ret;
|
|
});
|
|
|
|
return EvaluateExpression(replacedDesc);
|
|
}
|
|
|
|
private static SLEntity EvaluateExpression(string expression)
|
|
{
|
|
var values = new Stack<SLEntity>(); // 값을 저장하는 스택 (숫자 또는 문자열)
|
|
var operators = new Stack<char>(); // 연산자를 저장하는 스택
|
|
|
|
var i = 0;
|
|
while (i < expression.Length)
|
|
{
|
|
if (char.IsDigit(expression[i])) // 숫자 처리
|
|
{
|
|
var number = "";
|
|
while (i < expression.Length && (char.IsDigit(expression[i]) || expression[i] == '.'))
|
|
{
|
|
number += expression[i];
|
|
i++;
|
|
}
|
|
values.Push(float.Parse(number));
|
|
}
|
|
else if (expression[i] == '"') // 문자열 처리
|
|
{
|
|
// 문자열 리터럴 처리 (큰 따옴표로 감싸진 문자열)
|
|
i++;
|
|
var str = "";
|
|
while (i < expression.Length && expression[i] != '"')
|
|
{
|
|
str += expression[i];
|
|
i++;
|
|
}
|
|
i++; // 닫는 따옴표 넘기기
|
|
values.Push(str);
|
|
}
|
|
else if (expression[i] == '(')
|
|
{
|
|
operators.Push('(');
|
|
i++;
|
|
}
|
|
else if (expression[i] == ')')
|
|
{
|
|
while (operators.Peek() != '(')
|
|
{
|
|
values.Push(ApplyOperator(values.Pop(), values.Pop(), operators.Pop()));
|
|
}
|
|
operators.Pop(); // '(' 제거
|
|
i++;
|
|
}
|
|
else if (IsOperator(expression[i]))
|
|
{
|
|
// 연산자 처리
|
|
while (operators.Count > 0 && GetPrecedence(operators.Peek()) >= GetPrecedence(expression[i]))
|
|
{
|
|
values.Push(ApplyOperator(values.Pop(), values.Pop(), operators.Pop()));
|
|
}
|
|
operators.Push(expression[i]);
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
// 공백 등 기타 문자는 그냥 넘김
|
|
i++;
|
|
}
|
|
}
|
|
|
|
while (operators.Count > 0)
|
|
{
|
|
values.Push(ApplyOperator(values.Pop(), values.Pop(), operators.Pop()));
|
|
}
|
|
|
|
return values.Pop();
|
|
}
|
|
|
|
// 연산자 우선순위
|
|
private static int GetPrecedence(char op)
|
|
{
|
|
if (op == '+' || op == '-') return 1;
|
|
if (op == '*' || op == '/') return 2;
|
|
return 0;
|
|
}
|
|
|
|
// 연산자 확인
|
|
private static bool IsOperator(char c)
|
|
{
|
|
return c == '+' || c == '-' || c == '*' || c == '/';
|
|
}
|
|
|
|
// 연산자 적용
|
|
private static SLEntity ApplyOperator(SLEntity right, SLEntity left, char op)
|
|
{
|
|
return op switch
|
|
{
|
|
'+' => left + right,
|
|
'-' => left - right,
|
|
'*' => left * right,
|
|
'/' => left / right,
|
|
_ => SLEntity.Empty,
|
|
};
|
|
}
|
|
|
|
public static void ApplyEvaluate(SLEntity player, SLEntity current)
|
|
{
|
|
foreach (var c in current)
|
|
{
|
|
if (c.IsValue && c.IsNumeric == false)
|
|
{
|
|
current[c.ID] = Evaluate(player, c);
|
|
}
|
|
else if (c.IsValue == false)
|
|
{
|
|
ApplyEvaluate(player, c);
|
|
}
|
|
}
|
|
}
|
|
} |