Files
Continentis/Assets/Scripts/MainGame/Card/CardSubmodules/CardDescriptionInterpreter.cs

249 lines
9.1 KiB
C#
Raw Normal View History

2025-10-03 00:02:43 -04:00
using System;
using System.Collections.Generic;
using System.Globalization;
using DynamicExpresso;
using UnityEngine;
namespace Continentis.MainGame.Card
{
public static partial class CardDescriptionInterpreter
{
public static Interpreter DescriptionInterpreter;
static CardDescriptionInterpreter()
{
DescriptionInterpreter = new Interpreter();
DescriptionInterpreter.SetFunction("GetDynamicValue", new Func<float, float, bool, string>(GetDynamicValue));
DescriptionInterpreter.SetFunction("GetDynamicValue", new Func<float, string>(GetDynamicValue));
DescriptionInterpreter.SetFunction("AttributeCheck", new Func<string, float, float, string>(AttributeCheck));
foreach (KeyValuePair<string,string> keyword in CombatMainManager.Instance.keywordCollection.keywords)
{
DescriptionInterpreter.SetVariable(keyword.Key, keyword.Key);
}
foreach (KeyValuePair<string, InterpretedKeyword> keyword in CombatMainManager.Instance.keywordCollection.interpretedKeywords)
{
DescriptionInterpreter.SetVariable(keyword.Key, keyword.Value.name);
}
}
public static string InterpretDescription(CardLogicBase card)
{
card.contentSubmodule.keywords.Clear();
foreach (KeyValuePair<string, float> attribute in card.attributeSubmodule.attributeGroup.current)
{
DescriptionInterpreter.SetVariable(attribute.Key, attribute.Value);
}
DescriptionInterpreter.SetFunction("RemoveWhenSelecting", new Func<string, string>((toRemove) => RemoveWhenSelecting(card, toRemove)));
string result = ParseKeywords(card.cardData.cardDescription, card.contentSubmodule.keywords);
card.contentSubmodule.cardDescription = result;
Debug.Log($"Interpreted Description: {result}");
return result;
}
}
public partial class CardDescriptionInterpreter
{
public static List<string> GetKeywords(string template)
{
List<string> keywords = new List<string>();
DescriptionInterpreter.UnsetExpression("Keyword");
DescriptionInterpreter.SetFunction("Keyword", new Action<string>((keywordName) =>
{
if (!string.IsNullOrEmpty(keywordName) && !keywords.Contains(keywordName))
{
keywords.Add(keywordName);
}
}));
try
{
//提取所有$Keyword(...)的关键词
//其它的表达式直接跳过
while (template.Contains("$"))
{
int startIndex = template.LastIndexOf('$');
int endIndex = FindMatchingClosingParenthesis(template, startIndex);
if (endIndex == -1)
{
Debug.LogError($"解析错误: 在 '{template}' 中找不到与 '{template.Substring(startIndex)}' 匹配的闭合括号。");
break; // 中断以防止死循环
}
string expressionToEvaluate = template.Substring(startIndex, endIndex - startIndex + 1);
string cleanExpression = expressionToEvaluate.Substring(1);
// 仅处理 Keyword 函数,跳过其他表达式
if (cleanExpression.StartsWith("Keyword"))
{
DescriptionInterpreter.Eval(cleanExpression);
}
// 移除已处理的表达式,继续查找下一个
template = template.Substring(0, startIndex) + template.Substring(endIndex + 1);
}
}
catch (Exception ex)
{
throw new Exception($"解析模板时发生严重错误: {ex.Message}\nStackTrace: {ex.StackTrace}");
}
return keywords;
}
public static string ParseKeywords(string template, List<string> keywords)
{
DescriptionInterpreter.UnsetExpression("Keyword");
DescriptionInterpreter.SetFunction("Keyword", new Func<string, string>((keywordName) =>
{
if (!string.IsNullOrEmpty(keywordName) && !keywords.Contains(keywordName))
{
keywords.Add(keywordName);
}
return Keyword(keywordName);
}));
try
{
while (template.Contains("$"))
{
int startIndex = template.LastIndexOf('$');
int endIndex = FindMatchingClosingParenthesis(template, startIndex);
if (endIndex == -1)
{
Debug.LogError($"解析错误: 在 '{template}' 中找不到与 '{template.Substring(startIndex)}' 匹配的闭合括号。");
return template; // 中断以防止死循环
}
string expressionToEvaluate = template.Substring(startIndex, endIndex - startIndex + 1);
string cleanExpression = expressionToEvaluate.Substring(1);
object result = DescriptionInterpreter.Eval(cleanExpression);
string resultAsLiteral = result.ToString();
template = template.Substring(0, startIndex) + resultAsLiteral + template.Substring(endIndex + 1);
}
}
catch (Exception ex)
{
throw new Exception($"解析模板时发生严重错误: {ex.Message}\nStackTrace: {ex.StackTrace}");
}
return template;
}
private static int FindMatchingClosingParenthesis(string text, int startIndex)
{
int openParenIndex = text.IndexOf('(', startIndex);
if (openParenIndex == -1) return -1;
int parenthesisCounter = 1;
bool isInString = false;
for (int i = openParenIndex + 1; i < text.Length; i++)
{
char c = text[i];
char prevC = i > 0 ? text[i - 1] : '\0';
// 检查是否进入或退出字符串(忽略转义的引号 \"
if (c == '"' && prevC != '\\')
{
isInString = !isInString;
}
// 如果在字符串中,则跳过对括号的计数
if (isInString)
{
continue;
}
if (c == '(')
{
parenthesisCounter++;
}
else if (c == ')')
{
parenthesisCounter--;
}
if (parenthesisCounter == 0)
{
return i;
}
}
return -1; // 没有找到匹配的闭合括号
}
}
public partial class CardDescriptionInterpreter
{
private static string GetDynamicValue(float current, float baseValue, bool normalMode)
{
string color;
if (current > baseValue)
color = normalMode ? "green" : "red";
else if (current < baseValue)
color = normalMode ? "red" : "green";
else
color = "white";
//Debug.Log($"GetDynamicValue: current={current}, baseValue={baseValue}, normalMode={normalMode}, color={color}");
return $"<color={color}>{current}</color>";
}
private static string GetDynamicValue(float current)
{
return current.ToString(CultureInfo.CurrentCulture);
}
private static string Keyword(string keyword)
{
string color = "orange";
return $"<color={color}>{keyword}</color>";
}
private static string RemoveWhenSelecting(CardLogicBase card, string toRemove)
{
return card.handCardView != null && card.handCardView.isSelecting ? "" : toRemove;
}
private static string AttributeCheck(string attributeName, float requirement, float probability)
{
if (probability < 0)
{
return "{" + attributeName + " check: " + requirement + "}";
}
int percent = Mathf.RoundToInt(probability * 100);
string result = percent + "%";
if (percent == 0)
{
result = "<color=red>" + result + "</color>";
}
else if (percent > 0 && percent < 100)
{
result = "<color=yellow>" + result + "</color>";
}
else if (percent == 100)
{
result = "<color=green>" + result + "</color>";
}
return result;
}
}
}