This commit is contained in:
SoulliesOfficial
2026-04-01 12:23:27 -04:00
parent aff7ac0e03
commit c3b1561375
933 changed files with 114333 additions and 119360 deletions

View File

@@ -33,9 +33,12 @@ namespace Continentis.MainGame
TextInterpreter.SetFunction("Attribute", new Func<string, bool, string>((name, high) => GetAttribute(card, name, high, false)));
TextInterpreter.SetFunction("Attribute", new Func<string, bool, bool, string>((name, high, percent) => GetAttribute(card, name, high, percent)));
string result = DynamicTextInterpreter.Parse(TextInterpreter, textToInterpret);
// 第一阶段:根据卡牌上下文(持有者、目标等)裁剪条件标签块
string resolved = CardTextTagResolver.Resolve(card, textToInterpret);
// 第二阶段Dynamic Expresso 求值 $Attribute / $Keyword 等表达式
string result = DynamicTextInterpreter.Parse(TextInterpreter, resolved);
Debug.Log($"Interpreted Text: {result}");
return result;
}

View File

@@ -0,0 +1,144 @@
using System;
using System.Text.RegularExpressions;
using Continentis.MainGame.Card;
using Continentis.MainGame.Character;
using UnityEngine;
namespace Continentis.MainGame
{
/// <summary>
/// 卡牌文本条件标签解析器。
/// 在 Dynamic Expresso 求值之前,根据卡牌的上下文(持有者、目标等)裁剪条件标签块。
///
/// 支持的标签:
/// [Showcase]...[/Showcase] 仅在展示界面(无持有者)显示
/// [Owner: PlayerHero]...[/Owner] 持有者为 PlayerHero 时显示
/// [Owner: CombatNPC]...[/Owner] 持有者为 CombatNPC 时显示
/// [Target: PlayerHero]...[/Target] 目标为 PlayerHero 时显示
/// [Target: CombatNPC]...[/Target] 目标为 CombatNPC 时显示
///
/// 解析规则:
/// - 文本无任何标签 → 原样返回
/// - 无持有者(展示界面) → 仅显示 [Showcase],剥离 [Owner] / [Target]
/// - 有持有者,无目标 → 按持有者类型反推默认目标PlayerHero → CombatNPC, 反之亦然)
/// - 有持有者,有目标 → 按实际目标类型匹配 [Target]
/// </summary>
public static class CardTextTagResolver
{
/// <summary>
/// 匹配条件标签块。支持两种格式:
/// 带参数:[Category: Value]content[/Category]
/// 无参数:[Showcase]content[/Showcase]
/// </summary>
private static readonly Regex TagPattern = new Regex(
@"\[(?<category>Showcase|Owner|Target)(?:\s*:\s*(?<value>\w+))?\](?<content>.*?)\[/\k<category>\]",
RegexOptions.Singleline | RegexOptions.IgnoreCase);
/// <summary>
/// 解析文本中的条件标签块,根据卡牌上下文保留或移除。
/// 如果文本中没有任何标签,原样返回。
/// </summary>
public static string Resolve(CardInstance card, string text)
{
if (string.IsNullOrEmpty(text)) return text;
if (!TagPattern.IsMatch(text)) return text;
CharacterBase owner = card.owner as CharacterBase;
CharacterBase target = card.currentTextTarget;
bool isShowcase = (owner == null);
return TagPattern.Replace(text, match =>
{
string category = match.Groups["category"].Value;
string value = match.Groups["value"].Success ? match.Groups["value"].Value : null;
string content = match.Groups["content"].Value;
switch (category.ToLower())
{
case "showcase":
return ResolveShowcase(isShowcase, content);
case "owner":
return ResolveOwner(owner, value, content);
case "target":
return ResolveTarget(owner, target, value, content);
default:
Debug.LogWarning($"[CardTextTagResolver] Unknown tag category: '{category}'.");
return string.Empty;
}
});
}
/// <summary>
/// [Showcase] 标签:仅在展示界面(无持有者)显示。
/// </summary>
private static string ResolveShowcase(bool isShowcase, string content)
{
return isShowcase ? content : string.Empty;
}
/// <summary>
/// [Owner: X] 标签:根据持有者类型匹配。展示界面下不显示。
/// </summary>
private static string ResolveOwner(CharacterBase owner, string value, string content)
{
if (owner == null) return string.Empty;
return MatchesCharacterType(owner, value) ? content : string.Empty;
}
/// <summary>
/// [Target: X] 标签:根据目标类型匹配。
/// - 展示界面:不显示
/// - 有明确目标:按实际目标匹配
/// - 无明确目标按持有者反推默认目标PlayerHero → CombatNPC反之亦然
/// </summary>
private static string ResolveTarget(CharacterBase owner, CharacterBase target, string value, string content)
{
if (owner == null) return string.Empty;
// 有明确目标时,按实际类型匹配
if (target != null)
{
return MatchesCharacterType(target, value) ? content : string.Empty;
}
// 无明确目标时,按持有者类型反推默认目标
if (owner is PlayerHero)
{
return string.Equals(value, "CombatNPC", StringComparison.OrdinalIgnoreCase) ? content : string.Empty;
}
if (owner is CombatNPC)
{
return string.Equals(value, "PlayerHero", StringComparison.OrdinalIgnoreCase) ? content : string.Empty;
}
Debug.LogWarning($"[CardTextTagResolver] Cannot infer default target for owner type '{owner.GetType().Name}'.");
return content; // 未知持有者类型,保留内容作为兜底
}
/// <summary>
/// 检查角色是否匹配指定的类型名。
/// </summary>
private static bool MatchesCharacterType(CharacterBase character, string typeName)
{
if (string.IsNullOrEmpty(typeName))
{
Debug.LogWarning("[CardTextTagResolver] Tag value is empty for Owner/Target tag.");
return false;
}
return typeName.ToLower() switch
{
"playerhero" => character is PlayerHero,
"combatnpc" => character is CombatNPC,
_ => LogUnknownType(typeName)
};
}
private static bool LogUnknownType(string typeName)
{
Debug.LogWarning($"[CardTextTagResolver] Unknown character type: '{typeName}'.");
return false;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ec0a58018fe36a1469ea1ee568a662e0