MOD!
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using NaughtyAttributes;
|
||||
using SLSFramework.General;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -10,13 +11,11 @@ namespace Continentis.MainGame
|
||||
/// <summary>
|
||||
/// 基础属性,不会改变,通常情况下不会直接使用
|
||||
/// </summary>
|
||||
[DictionaryDrawerSettings(KeyColumnWidth = 400)]
|
||||
public Dictionary<string, float> original;
|
||||
|
||||
/// <summary>
|
||||
/// 当前属性,会受到buff和其他效果的影响
|
||||
/// </summary>
|
||||
[DictionaryDrawerSettings(KeyColumnWidth = 400)]
|
||||
public Dictionary<string, float> current;
|
||||
|
||||
public AttributeGroup(Dictionary<string, float> original)
|
||||
|
||||
@@ -1,28 +1,45 @@
|
||||
using System.Collections.Generic;
|
||||
using Continentis.MainGame.Card;
|
||||
using Continentis.MainGame.Character;
|
||||
using DamageNumbersPro;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Continentis/MainGame/BasePrefabs", fileName = "MainGameBasePrefabs")]
|
||||
public partial class BasePrefabs : SerializedScriptableObject
|
||||
public enum Rarity
|
||||
{
|
||||
[Title("Character")]
|
||||
None = 0,
|
||||
Common = 10,
|
||||
Uncommon = 20,
|
||||
Rare = 30,
|
||||
Epic = 40,
|
||||
Legendary = 50,
|
||||
Divine = 60
|
||||
}
|
||||
|
||||
[CreateAssetMenu(menuName = "Continentis/MainGame/BasePrefabs", fileName = "MainGameBasePrefabs")]
|
||||
public partial class BasePrefabs : ScriptableObject
|
||||
{
|
||||
[Header("Character")]
|
||||
public GameObject combatCharacterView;
|
||||
|
||||
[Title("Cards")]
|
||||
[Header("Cards")]
|
||||
public GameObject handCardObject;
|
||||
public GameObject intentionCardObject;
|
||||
public GameObject inspectionCardObject;
|
||||
public SerializableDictionary<string, CardViewCollection> cardViewCollections;
|
||||
|
||||
[Title("GeneralUI")]
|
||||
[Header("GeneralUI")]
|
||||
public GameObject informationBox;
|
||||
public SerializableDictionary<Fraction, List<Sprite>> fractionFrames;
|
||||
public SerializableDictionary<Rarity, Color> rarityColors;
|
||||
|
||||
[Title("CombatUI")]
|
||||
[Header("CombatUI")]
|
||||
public GameObject pointerArrow;
|
||||
public GameObject hudContainer;
|
||||
|
||||
[Title("Texts")]
|
||||
[Header("Texts")]
|
||||
public GameObject hurtDamageNumber;
|
||||
public GameObject blockedDamageNumber;
|
||||
public GameObject healNumber;
|
||||
@@ -31,6 +48,31 @@ namespace Continentis.MainGame
|
||||
|
||||
public partial class BasePrefabs
|
||||
{
|
||||
public Color GetRarityColor(Rarity rarity)
|
||||
{
|
||||
if (rarityColors.TryGetValue(rarity, out Color color))
|
||||
{
|
||||
return color;
|
||||
}
|
||||
return Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class BasePrefabs
|
||||
{
|
||||
public DamageNumber GenerateHurtText(int amount, CombatCharacterViewBase characterView)
|
||||
{
|
||||
Vector3 position = characterView.transform.position + Vector3.up * 0.5f;
|
||||
|
||||
if (characterView.numbersPivot != null)
|
||||
{
|
||||
position = characterView.numbersPivot.position;
|
||||
}
|
||||
|
||||
DamageNumber infoText = GenerateHurtText(amount, position);
|
||||
return infoText;
|
||||
}
|
||||
|
||||
public DamageNumber GenerateHurtText(int amount, Vector3 position)
|
||||
{
|
||||
DamageNumber hurtText = GenerateCombatText(hurtDamageNumber, position);
|
||||
@@ -38,6 +80,19 @@ namespace Continentis.MainGame
|
||||
return hurtText;
|
||||
}
|
||||
|
||||
public DamageNumber GenerateBlockedText(int amount, CombatCharacterViewBase characterView)
|
||||
{
|
||||
Vector3 position = characterView.transform.position + Vector3.up * 0.5f;
|
||||
|
||||
if (characterView.numbersPivot != null)
|
||||
{
|
||||
position = characterView.numbersPivot.position;
|
||||
}
|
||||
|
||||
DamageNumber infoText = GenerateBlockedText(amount, position);
|
||||
return infoText;
|
||||
}
|
||||
|
||||
public DamageNumber GenerateBlockedText(int amount, Vector3 position)
|
||||
{
|
||||
DamageNumber blockedText = GenerateCombatText(blockedDamageNumber, position);
|
||||
@@ -45,6 +100,19 @@ namespace Continentis.MainGame
|
||||
return blockedText;
|
||||
}
|
||||
|
||||
public DamageNumber GenerateHealText(int amount, CombatCharacterViewBase characterView)
|
||||
{
|
||||
Vector3 position = characterView.transform.position + Vector3.up * 0.5f;
|
||||
|
||||
if (characterView.numbersPivot != null)
|
||||
{
|
||||
position = characterView.numbersPivot.position;
|
||||
}
|
||||
|
||||
DamageNumber infoText = GenerateHealText(amount, position);
|
||||
return infoText;
|
||||
}
|
||||
|
||||
public DamageNumber GenerateHealText(int amount, Vector3 position)
|
||||
{
|
||||
DamageNumber healText = GenerateCombatText(healNumber, position);
|
||||
@@ -52,6 +120,20 @@ namespace Continentis.MainGame
|
||||
return healText;
|
||||
}
|
||||
|
||||
public DamageNumber GenerateInfoText(string content, CombatCharacterViewBase characterView, Color color = default, float size = 1)
|
||||
{
|
||||
Vector3 position = characterView.transform.position + Vector3.up;
|
||||
|
||||
if (characterView.textsPivot != null)
|
||||
{
|
||||
position = characterView.textsPivot.position;
|
||||
}
|
||||
|
||||
DamageNumber infoText = GenerateCombatText(informationText, position, color, size);
|
||||
infoText.leftText = content;
|
||||
return infoText;
|
||||
}
|
||||
|
||||
public DamageNumber GenerateInfoText(string content, Vector3 position, Color color = default, float size = 1)
|
||||
{
|
||||
DamageNumber infoText = GenerateCombatText(informationText, position, color, size);
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame
|
||||
{
|
||||
public enum BuffDispelLevel
|
||||
{
|
||||
Basic = 0, //弱驱散
|
||||
Strong = 10, //强驱散
|
||||
Immune = 20, //不可驱散(死亡除外)
|
||||
Undispellable = 100 //不可驱散(包括死亡)
|
||||
}
|
||||
|
||||
public enum BuffType
|
||||
{
|
||||
Positive,
|
||||
Negative,
|
||||
Neutral
|
||||
}
|
||||
|
||||
public abstract partial class BuffBase<T>
|
||||
{
|
||||
public string name;
|
||||
public string description;
|
||||
|
||||
public BuffType buffType;
|
||||
public BuffDispelLevel dispelThreshold;
|
||||
|
||||
protected virtual void Initialize(string name, string description, BuffType buffType, BuffDispelLevel dispelThreshold)
|
||||
{
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.buffType = buffType;
|
||||
this.dispelThreshold = dispelThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class BuffBase<T>
|
||||
{
|
||||
protected bool FindExistingBuff<T1, T2>(out T2 existingBuff, List<T1> buffList) where T1 : BuffBase<T> where T2 : BuffBase<T>
|
||||
{
|
||||
existingBuff = null;
|
||||
|
||||
foreach (T1 buff in buffList.Where(buff => buff.GetType() == typeof(T2)))
|
||||
{
|
||||
existingBuff = buff as T2;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract void Apply(T attached);
|
||||
|
||||
public abstract void Remove();
|
||||
|
||||
public abstract void UntriggerRemove();
|
||||
|
||||
public virtual void Dispel(BuffDispelLevel dispelLevel)
|
||||
{
|
||||
if (CanBeDispelled(dispelLevel))
|
||||
{
|
||||
OnBuffDispel();
|
||||
Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class BuffBase<T>
|
||||
{
|
||||
//Buff生命周期函数
|
||||
|
||||
/// <summary>
|
||||
/// Buff被尝试添加到角色时调用。
|
||||
/// </summary>
|
||||
public virtual bool OnBuffApply(out BuffBase<T> existingBuff)
|
||||
{
|
||||
throw new System.NotImplementedException(); //需要在子类中实现
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Buff首次成功添加到角色后调用。在OnBuffApply完成,且返回true之后调用。
|
||||
/// 如果Buff在被添加时,发现已有同类Buff存在,则不会调用此函数。
|
||||
/// </summary>
|
||||
public virtual void OnAfterFirstApply()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Buff被驱散(移除)时调用,在OnBuffRemove之前调用。
|
||||
/// </summary>
|
||||
public virtual void OnBuffDispel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Buff被正常移除时调用。在Buff生命周期结束时调用。
|
||||
/// UntriggerRemove不会调用此函数。但是此函数通常情况下绝不会被调用。
|
||||
/// </summary>
|
||||
public virtual void OnBuffRemove()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public partial class BuffBase<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断该Buff能否被指定驱散等级的驱散效果驱散。
|
||||
/// </summary>
|
||||
protected bool CanBeDispelled(BuffDispelLevel dispelLevel)
|
||||
{
|
||||
return dispelLevel >= dispelThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f2945f2bcd61ff499033e790f23a32b
|
||||
@@ -1,267 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Continentis.MainGame.UI;
|
||||
using SoulliesFramework.General;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Continentis.MainGame
|
||||
{
|
||||
public partial class BuffBase<T>
|
||||
{
|
||||
public abstract class BuffSubmodule : SubmoduleBase<BuffBase<T>>
|
||||
{
|
||||
public BuffBase<T> buff;
|
||||
|
||||
protected BuffSubmodule(BuffBase<T> buff) : base(buff)
|
||||
{
|
||||
this.buff = buff;
|
||||
}
|
||||
}
|
||||
|
||||
public class UISubmodule : BuffSubmodule
|
||||
{
|
||||
public bool hasIcon;
|
||||
public string iconPath;
|
||||
public Sprite icon;
|
||||
public List<Func<string>> setTextFunctions;
|
||||
|
||||
public HUD_CharacterBuffIcon buffIcon;
|
||||
|
||||
public UISubmodule(BuffBase<T> buff, string iconPath = "",
|
||||
params Func<string>[] setTextFunctions) : base(buff)
|
||||
{
|
||||
this.hasIcon = !string.IsNullOrEmpty(iconPath);
|
||||
this.iconPath = iconPath;
|
||||
|
||||
if (hasIcon)
|
||||
{
|
||||
this.icon = AssetLoader.LoadAsset<Sprite>(iconPath);
|
||||
}
|
||||
|
||||
this.setTextFunctions = setTextFunctions.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public class CountSubmodule : BuffSubmodule
|
||||
{
|
||||
public int maximumCount;
|
||||
public int remainingCount;
|
||||
|
||||
public bool isInfinite => maximumCount < 0;
|
||||
public float remainingPercentage => (float)remainingCount / maximumCount;
|
||||
|
||||
/// <summary>
|
||||
/// duration为负数表示无限持续时间。
|
||||
/// </summary>
|
||||
public CountSubmodule(BuffBase<T> buff, int maximumCount) : base(buff)
|
||||
{
|
||||
this.maximumCount = maximumCount;
|
||||
this.remainingCount = maximumCount;
|
||||
}
|
||||
|
||||
public void UpdateModule()
|
||||
{
|
||||
if (isInfinite)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
remainingCount--;
|
||||
|
||||
if (remainingCount <= 0)
|
||||
{
|
||||
buff.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新剩余时间至初始值。
|
||||
/// </summary>
|
||||
public void RefreshDuration()
|
||||
{
|
||||
if (isInfinite)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
remainingCount = maximumCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 覆盖(可选保留更大的duration)并刷新剩余时间。
|
||||
/// </summary>
|
||||
public void RefreshDuration(int overrideDuration, bool keepMaximal = true)
|
||||
{
|
||||
if (isInfinite)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
maximumCount = keepMaximal ? Mathf.Max(maximumCount, overrideDuration) : overrideDuration;
|
||||
remainingCount = maximumCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加持续时间和剩余时间。
|
||||
/// </summary>
|
||||
public void AddDuration(int additionalDuration)
|
||||
{
|
||||
if (isInfinite)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
maximumCount += additionalDuration;
|
||||
remainingCount += additionalDuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅增加剩余时间,不改变总持续时间。
|
||||
/// 如果增加后剩余时间超过总持续时间,则剩余时间等于总持续时间。
|
||||
/// </summary>
|
||||
public void AddTime(int additionalTime)
|
||||
{
|
||||
if (isInfinite)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
remainingCount += additionalTime;
|
||||
remainingCount = Mathf.Min(remainingCount, maximumCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Buff叠加模块,叠加层数统一。
|
||||
/// </summary>
|
||||
public class UnitedStackSubmodule : BuffSubmodule
|
||||
{
|
||||
public bool willRemoveOnZero; //是否在层数为0时移除Buff
|
||||
public int stackAmount; //当前层数
|
||||
public int stackUpperLimit; //层数上限,-1表示无限制
|
||||
|
||||
public UnitedStackSubmodule(BuffBase<T> buff, bool willRemoveOnZero,
|
||||
int stackUpperLimit = -1, int initialStackAmount = 1) : base(buff)
|
||||
{
|
||||
this.willRemoveOnZero = willRemoveOnZero;
|
||||
this.stackAmount = initialStackAmount;
|
||||
this.stackUpperLimit = stackUpperLimit;
|
||||
}
|
||||
|
||||
public void RefreshStackUpperLimit(int upperLimit, bool keepMaximal = true)
|
||||
{
|
||||
stackUpperLimit = keepMaximal ? Mathf.Max(stackUpperLimit, upperLimit) : upperLimit;
|
||||
}
|
||||
|
||||
public void AddStack(int amount)
|
||||
{
|
||||
stackAmount += amount;
|
||||
if (stackUpperLimit > 0)
|
||||
{
|
||||
stackAmount = Mathf.Min(stackAmount, stackUpperLimit);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReduceStack(int amount)
|
||||
{
|
||||
stackAmount -= amount;
|
||||
if (willRemoveOnZero && stackAmount <= 0)
|
||||
{
|
||||
buff.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Buff独立叠加模块,每一层的持续时间和层数可以不同。
|
||||
/// </summary>
|
||||
public class IndependentStackSubmodule : BuffSubmodule
|
||||
{
|
||||
public bool willRemoveOnZero;
|
||||
public List<IndependentStackUnit> independentStacks;
|
||||
public int totalStackAmount;
|
||||
|
||||
public IndependentStackSubmodule(BuffBase<T> buff, bool willRemoveOnZero) : base(buff)
|
||||
{
|
||||
this.willRemoveOnZero = willRemoveOnZero;
|
||||
independentStacks = new List<IndependentStackUnit>();
|
||||
totalStackAmount = 0;
|
||||
}
|
||||
|
||||
public void UpdateModule()
|
||||
{
|
||||
independentStacks.ForEach(x => x.remainingTime--);
|
||||
|
||||
independentStacks.RemoveAll(x => !x.IsInfinite && x.remainingTime <= 0);
|
||||
|
||||
totalStackAmount = independentStacks.Sum(x => x.stackAmount);
|
||||
|
||||
if (willRemoveOnZero && totalStackAmount <= 0)
|
||||
{
|
||||
buff.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
public IndependentStackUnit AddStack(int stackAmount, int duration)
|
||||
{
|
||||
IndependentStackUnit addition = new IndependentStackUnit(stackAmount, duration);
|
||||
independentStacks.Add(addition);
|
||||
independentStacks.Sort();
|
||||
return addition;
|
||||
}
|
||||
|
||||
public void ReduceStack(int stackAmount)
|
||||
{
|
||||
for (int i = 0; i < independentStacks.Count; i++)
|
||||
{
|
||||
if (stackAmount <= independentStacks[i].stackAmount)
|
||||
{
|
||||
independentStacks[i].stackAmount -= stackAmount;
|
||||
if (independentStacks[i].stackAmount <= 0)
|
||||
{
|
||||
independentStacks.RemoveAt(i);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
stackAmount -= independentStacks[i].stackAmount;
|
||||
independentStacks.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
|
||||
totalStackAmount = independentStacks.Sum(x => x.stackAmount);
|
||||
if (willRemoveOnZero && totalStackAmount <= 0)
|
||||
{
|
||||
buff.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
public class IndependentStackUnit : IComparable<IndependentStackUnit>
|
||||
{
|
||||
public int stackAmount;
|
||||
public int duration;
|
||||
public int remainingTime;
|
||||
public Dictionary<string, float> parameters;
|
||||
|
||||
public bool IsInfinite => duration < 0;
|
||||
|
||||
public IndependentStackUnit(int stackAmount, int duration)
|
||||
{
|
||||
this.stackAmount = stackAmount;
|
||||
this.duration = duration;
|
||||
this.remainingTime = duration;
|
||||
this.parameters = new Dictionary<string, float>();
|
||||
}
|
||||
|
||||
public int CompareTo(IndependentStackUnit other)
|
||||
{
|
||||
return remainingTime.CompareTo(other.remainingTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27fbd8e42b698e54281f2ac2c22f4993
|
||||
@@ -1,59 +0,0 @@
|
||||
using SoulliesFramework.General;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
|
||||
namespace Continentis.MainGame
|
||||
{
|
||||
public class EventUnit : IPrioritized
|
||||
{
|
||||
private UnityAction action;
|
||||
public int Priority { get; set; }
|
||||
|
||||
public EventUnit(UnityAction action, int priority = 0)
|
||||
{
|
||||
this.action = action;
|
||||
this.Priority = priority;
|
||||
}
|
||||
|
||||
public void Invoke()
|
||||
{
|
||||
action.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public class EventUnit<T> : IPrioritized
|
||||
{
|
||||
private UnityAction<T> action;
|
||||
public int Priority { get; set; }
|
||||
|
||||
public EventUnit(UnityAction<T> action, int priority = 0)
|
||||
{
|
||||
this.action = action;
|
||||
this.Priority = priority;
|
||||
}
|
||||
|
||||
public void Invoke(T arg)
|
||||
{
|
||||
action.Invoke(arg);
|
||||
}
|
||||
}
|
||||
|
||||
public class EventUnit<T1, T2> : IPrioritized
|
||||
{
|
||||
private UnityAction<T1, T2> action;
|
||||
public int Priority { get; set; }
|
||||
|
||||
public EventUnit(UnityAction<T1, T2> action, int priority = 0)
|
||||
{
|
||||
this.action = action;
|
||||
this.Priority = priority;
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2)
|
||||
{
|
||||
action.Invoke(arg1, arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4a739f10fb7d8d49a75be3de4f95ac8
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f16a5fe2cd8e2741b4791152560326b
|
||||
guid: 5bc79878df4668d44bfbd60ff14a5741
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using DynamicExpresso;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame
|
||||
{
|
||||
public static partial class BuffTextInterpreter
|
||||
{
|
||||
private static readonly Interpreter TextInterpreter;
|
||||
|
||||
static BuffTextInterpreter()
|
||||
{
|
||||
TextInterpreter = new Interpreter();
|
||||
TextInterpreter.SetFunction("Value", new Func<float, string>((cv) => DynamicTextInterpreter.GetValue(cv, false)));
|
||||
TextInterpreter.SetFunction("Value", new Func<float, float, string>((cv, bv) => DynamicTextInterpreter.GetValue(cv, bv, true, false)));
|
||||
TextInterpreter.SetFunction("Value",
|
||||
new Func<float, float, bool, string>((cv, bv, high) => DynamicTextInterpreter.GetValue(cv, bv, high, false)));
|
||||
TextInterpreter.SetFunction("Value",
|
||||
new Func<float, float, bool, bool, string>((cv, bv, high, percent) => DynamicTextInterpreter.GetValue(cv, bv, high, percent)));
|
||||
|
||||
foreach (KeyValuePair<string, InterpretedKeyword> keyword in MainGameManager.Instance.keywordData.interpretedKeywords)
|
||||
{
|
||||
TextInterpreter.SetVariable(keyword.Key, keyword.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public static void InterpretText<T>(BuffBase<T> buff)
|
||||
{
|
||||
TextInterpreter.SetFunction("ParameterInt", new Func<string, string>((paramName) => GetParameterInt(buff, paramName, false)));
|
||||
TextInterpreter.SetFunction("ParameterAbsInt", new Func<string, string>((paramName) => GetParameterInt(buff, paramName, true)));
|
||||
TextInterpreter.SetFunction("ParameterPercent", new Func<string, string>((paramName) => GetParameterPercent(buff, paramName)));
|
||||
TextInterpreter.SetFunction("ParameterFloat", new Func<string, string>((paramName) => GetParameterFloat(buff, paramName)));
|
||||
TextInterpreter.SetFunction("ParameterString", new Func<string, string>((paramName) => GetParameterString(buff, paramName)));
|
||||
string descriptionToParse = buff.contentSubmodule.originalFunctionText;
|
||||
string result = DynamicTextInterpreter.Parse(TextInterpreter, descriptionToParse, new List<string>(), new List<string>());
|
||||
buff.contentSubmodule.interpretedFunctionText = result;
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class BuffTextInterpreter
|
||||
{
|
||||
private static string GetParameterInt<T>(BuffBase<T> buff, string parameterName, bool isAbsolute)
|
||||
{
|
||||
if (buff.contentSubmodule.parameterGetters.TryGetValue(parameterName, out Func<string> getter))
|
||||
{
|
||||
int intValue = Convert.ToInt32(getter());
|
||||
|
||||
if (isAbsolute)
|
||||
{
|
||||
return Math.Abs(intValue).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return intValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogError($"无法找到参数获取器: {parameterName} 在 Buff: {buff.contentSubmodule.displayName}");
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
private static string GetParameterFloat<T>(BuffBase<T> buff, string parameterName)
|
||||
{
|
||||
if (buff.contentSubmodule.parameterGetters.TryGetValue(parameterName, out Func<string> getter))
|
||||
{
|
||||
return Convert.ToSingle(getter()).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
Debug.LogError($"无法找到参数获取器: {parameterName} 在 Buff: {buff.contentSubmodule.displayName}");
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
private static string GetParameterPercent<T>(BuffBase<T> buff, string parameterName)
|
||||
{
|
||||
if (buff.contentSubmodule.parameterGetters.TryGetValue(parameterName, out Func<string> getter))
|
||||
{
|
||||
return Mathf.RoundToInt(Convert.ToSingle(getter()) * 100).ToString() + "%";
|
||||
}
|
||||
|
||||
Debug.LogError($"无法找到参数获取器: {parameterName} 在 Buff: {buff.contentSubmodule.displayName}");
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
private static string GetParameterString<T>(BuffBase<T> buff, string parameterName)
|
||||
{
|
||||
if (buff.contentSubmodule.parameterGetters.TryGetValue(parameterName, out Func<string> getter))
|
||||
{
|
||||
return getter();
|
||||
}
|
||||
|
||||
Debug.LogError($"无法找到参数获取器: {parameterName} 在 Buff: {buff.contentSubmodule.displayName}");
|
||||
return "ERROR";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f764ba86ad36ace4f97961d6765b6710
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Continentis.MainGame.Card;
|
||||
using DynamicExpresso;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame
|
||||
{
|
||||
public static partial class CardTextInterpreter
|
||||
{
|
||||
private static readonly Interpreter TextInterpreter;
|
||||
|
||||
static CardTextInterpreter()
|
||||
{
|
||||
TextInterpreter = new Interpreter();
|
||||
|
||||
TextInterpreter.SetFunction("Value", new Func<float, string>((cv) => DynamicTextInterpreter.GetValue(cv, false)));
|
||||
TextInterpreter.SetFunction("Value", new Func<float, float, string>((cv, bv) => DynamicTextInterpreter.GetValue(cv, bv, true, false)));
|
||||
TextInterpreter.SetFunction("Value", new Func<float, float, bool, string>((cv, bv, high) => DynamicTextInterpreter.GetValue(cv, bv, high, false)));
|
||||
TextInterpreter.SetFunction("Value", new Func<float, float, bool, bool, string>((cv, bv, high, percent) => DynamicTextInterpreter.GetValue(cv, bv, high, percent)));
|
||||
|
||||
foreach (KeyValuePair<string, InterpretedKeyword> keyword in MainGameManager.Instance.keywordData.interpretedKeywords)
|
||||
{
|
||||
TextInterpreter.SetVariable(keyword.Key, keyword.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public static void InterpretText(CardLogicBase card, bool overrideDescription = false)
|
||||
{
|
||||
card.contentSubmodule.keywords.Clear();
|
||||
|
||||
foreach (KeyValuePair<string, float> attribute in card.attributeSubmodule.attributeGroup.current)
|
||||
{
|
||||
TextInterpreter.SetVariable(attribute.Key, attribute.Value);
|
||||
}
|
||||
|
||||
TextInterpreter.SetFunction("RemoveWhenSelecting", new Func<string, string>((toRemove) => RemoveWhenSelecting(card, toRemove)));
|
||||
TextInterpreter.SetFunction("Attribute", new Func<string, string>((name) => GetAttribute(card, name, true, false)));
|
||||
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 descriptionToParse = card.contentSubmodule.originalFunctionText;
|
||||
string result = DynamicTextInterpreter.Parse(TextInterpreter, descriptionToParse, card.contentSubmodule.keywords, card.contentSubmodule.hintKeywords);
|
||||
|
||||
card.contentSubmodule.interpretedFunctionText = result;
|
||||
|
||||
Debug.Log($"Interpreted Description: {result}");
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class CardTextInterpreter
|
||||
{
|
||||
private static string GetAttribute(CardLogicBase card, string attributeName, bool higherIsBetter, bool inPercent)
|
||||
{
|
||||
string displayName = "Display" + attributeName;
|
||||
string baseName = "Base" + attributeName;
|
||||
string baseOffsetName = "Base" + attributeName + "Offset";
|
||||
|
||||
if (!inPercent)
|
||||
{
|
||||
int displayValue = card.GetAttribute(displayName);
|
||||
int baseValue = card.GetAttribute(baseName) + card.GetAttribute(baseOffsetName);
|
||||
return DynamicTextInterpreter.GetValue(displayValue, baseValue, higherIsBetter, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
float rawDisplayValue = card.GetRawAttribute(displayName);
|
||||
float rawBaseValue = card.GetRawAttribute(baseName) + card.GetRawAttribute(baseOffsetName);
|
||||
return DynamicTextInterpreter.GetValue(rawDisplayValue, rawBaseValue, higherIsBetter, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetAttribute(CardLogicBase card, string attributeName, bool inPercent)
|
||||
{
|
||||
string displayName = "Display" + attributeName;
|
||||
int displayValue = card.GetAttribute(displayName);
|
||||
return DynamicTextInterpreter.GetValue(displayValue, inPercent);
|
||||
}
|
||||
|
||||
private static string RemoveWhenSelecting(CardLogicBase card, string toRemove)
|
||||
{
|
||||
return card.handCardView != null && card.handCardView.isSelecting ? "" : toRemove;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef10462731b5127408af93915f8671e9
|
||||
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Continentis.MainGame.Card;
|
||||
using DynamicExpresso;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame
|
||||
{
|
||||
public partial class DynamicTextInterpreter
|
||||
{
|
||||
public static string Parse(Interpreter interpreter, string template, List<string> keywords, List<string> hintKeywords)
|
||||
{
|
||||
interpreter.UnsetFunction("Keyword");
|
||||
interpreter.SetFunction("Keyword", new Func<string, string>(kw => SetKeyword(ref keywords, kw)));
|
||||
interpreter.UnsetFunction("HintKeyword");
|
||||
interpreter.SetFunction("HintKeyword", new Func<string, string>(kw => SetKeyword(ref hintKeywords, kw)));
|
||||
interpreter.UnsetFunction("DescKeyword");
|
||||
interpreter.SetFunction("DescKeyword", new Func<string, string>(DescKeyword));
|
||||
|
||||
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 = interpreter.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;
|
||||
|
||||
//本地函数,用于添加关键词到集合中并返回格式化后的关键词字符串
|
||||
string SetKeyword(ref List<string> collection, string keyword)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(keyword) && !collection.Contains(keyword))
|
||||
{
|
||||
collection.Add(keyword);
|
||||
}
|
||||
|
||||
return Keyword(keyword);
|
||||
}
|
||||
}
|
||||
|
||||
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 DynamicTextInterpreter
|
||||
{
|
||||
public static string GetValue(float currentValue, float baseValue, bool higherIsBetter, bool inPercent)
|
||||
{
|
||||
string color = "white";
|
||||
|
||||
if (currentValue > baseValue)
|
||||
{
|
||||
color = higherIsBetter ? "green" : "red";
|
||||
}
|
||||
else if (currentValue < baseValue)
|
||||
{
|
||||
color = higherIsBetter ? "red" : "green";
|
||||
}
|
||||
|
||||
string valueStr = currentValue.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (inPercent)
|
||||
{
|
||||
valueStr = Mathf.RoundToInt(currentValue * 100) + "%";
|
||||
}
|
||||
|
||||
return $"<color={color}>{valueStr}</color>";
|
||||
}
|
||||
|
||||
public static string GetValue(float currentValue, bool inPercent)
|
||||
{
|
||||
string valueStr = currentValue.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (inPercent)
|
||||
{
|
||||
valueStr = Mathf.RoundToInt(currentValue * 100) + "%";
|
||||
}
|
||||
|
||||
return valueStr;
|
||||
}
|
||||
|
||||
public static string Keyword(string key)
|
||||
{
|
||||
string color = "orange";
|
||||
string result = key;
|
||||
if (MainGameManager.Instance.keywordData.TryGetKeyword(key, out InterpretedKeyword keyword))
|
||||
{
|
||||
result = keyword.name.Localize();
|
||||
}
|
||||
|
||||
return $"<color={color}>{result}</color>";
|
||||
}
|
||||
|
||||
public static string DescKeyword(string key)
|
||||
{
|
||||
string color = "yellow";
|
||||
string result = key;
|
||||
if (MainGameManager.Instance.keywordData.TryGetKeyword(key, out InterpretedKeyword keyword))
|
||||
{
|
||||
result = keyword.name.Localize();
|
||||
}
|
||||
|
||||
return $"<color={color}>{result}</color>";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c47182d113862b84bb5ce50653b608f1
|
||||
73
Assets/Scripts/MainGame/Base/Keywords/KeywordData.cs
Normal file
73
Assets/Scripts/MainGame/Base/Keywords/KeywordData.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NaughtyAttributes;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Continentis/KeywordData", fileName = "KeywordData")]
|
||||
public partial class KeywordData : ScriptableObject
|
||||
{
|
||||
[Tooltip("关键词,在显示上使用InterpretedKeyword的信息")]
|
||||
[KeyWidth(0.2f)]
|
||||
public SerializableDictionary<string, InterpretedKeyword> interpretedKeywords = new SerializableDictionary<string, InterpretedKeyword>();
|
||||
|
||||
/// <summary>
|
||||
/// 尝试获取关键词,基础关键词和解释关键词均可
|
||||
/// </summary>
|
||||
public bool TryGetLocalizedKeyword(string key, out string locName, out string locDesc)
|
||||
{
|
||||
if (TryGetKeyword(key, out InterpretedKeyword keyword))
|
||||
{
|
||||
locName = keyword.name.Localize();
|
||||
locDesc = keyword.description.Localize();
|
||||
return true;
|
||||
}
|
||||
|
||||
locName = keyword.name;
|
||||
locDesc = keyword.description;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试获取关键词,基础关键词和解释关键词均可
|
||||
/// </summary>
|
||||
public bool TryGetKeyword(string key, out InterpretedKeyword keyword)
|
||||
{
|
||||
if (interpretedKeywords.TryGetValue(key, out keyword))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
keyword = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class KeywordData
|
||||
{
|
||||
public string keywordToAdd;
|
||||
|
||||
[Button]
|
||||
private void AddKeywordToCollection()
|
||||
{
|
||||
InterpretedKeyword ik = new InterpretedKeyword("Keyword_" + keywordToAdd, "Keyword_" + keywordToAdd + "_Description");
|
||||
interpretedKeywords.TryAdd(keywordToAdd, ik);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public struct InterpretedKeyword
|
||||
{
|
||||
public string name;
|
||||
public string description;
|
||||
|
||||
public InterpretedKeyword(string name, string description)
|
||||
{
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f37d7342fd3cbf4a9b837fca74655cc
|
||||
15
Assets/Scripts/MainGame/Base/VisualEffectBase.cs
Normal file
15
Assets/Scripts/MainGame/Base/VisualEffectBase.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using SLSFramework.General;
|
||||
using SLSFramework.General.LeanPoolAssistance;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame
|
||||
{
|
||||
public class VisualEffectBase : PooledObject
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
//GetComponentsInChildren<Renderer>().For(rend => rend.sortingOrder = 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/MainGame/Base/VisualEffectBase.cs.meta
Normal file
2
Assets/Scripts/MainGame/Base/VisualEffectBase.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2bff3d4a9372dc6408419c254d757aac
|
||||
Reference in New Issue
Block a user