卡牌更新
This commit is contained in:
@@ -15,11 +15,7 @@ namespace Continentis.MainGame.Base
|
||||
public partial class EditorBaseCollection : BaseCollection<EditorBaseCollection>
|
||||
{
|
||||
[Title("角色")]
|
||||
[Tooltip("核心属性\nKey 为词条 ID(如 Strength),Value 为词条中文描述(如 力量)")]
|
||||
[SerializedDictionarySettings("Key", "Description")]
|
||||
public SerializedDictionary<string, string> characterCoreAttributes = new SerializedDictionary<string, string>();
|
||||
|
||||
[Tooltip("通用与状态属性\nKey 为词条 ID(如 Health),Value 为词条中文描述(如 角色生命值)")]
|
||||
[Tooltip("角色属性\nKey 为词条 ID(如 Health),Value 为词条中文描述(如 角色生命值)")]
|
||||
[SerializedDictionarySettings("Key", "Description")]
|
||||
public SerializedDictionary<string, string> characterGeneralAttributes = new SerializedDictionary<string, string>();
|
||||
|
||||
@@ -81,15 +77,6 @@ namespace Continentis.MainGame.Base
|
||||
|
||||
foreach (var coll in GetAllCollections())
|
||||
{
|
||||
if (coll.characterCoreAttributes != null)
|
||||
{
|
||||
allItems.AddRange(coll.characterCoreAttributes.Select(kvp => new ValueDropdownItem<string>
|
||||
{
|
||||
Text = $"{kvp.Key} ({kvp.Value})",
|
||||
Value = kvp.Key
|
||||
}));
|
||||
}
|
||||
|
||||
if (coll.characterGeneralAttributes != null)
|
||||
{
|
||||
allItems.AddRange(coll.characterGeneralAttributes.Select(kvp => new ValueDropdownItem<string>
|
||||
@@ -176,24 +163,8 @@ namespace Continentis.MainGame.Base
|
||||
sb.AppendLine($" public static class {className}");
|
||||
sb.AppendLine(" {");
|
||||
|
||||
// 生成核心属性
|
||||
sb.AppendLine(" // ── 核心属性 (Core) ──────────────────────────────────");
|
||||
if (characterCoreAttributes != null)
|
||||
{
|
||||
foreach (var kvp in characterCoreAttributes)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(kvp.Key)) continue;
|
||||
if (!string.IsNullOrWhiteSpace(kvp.Value))
|
||||
{
|
||||
sb.AppendLine($" /// <summary> {kvp.Value} </summary>");
|
||||
}
|
||||
sb.AppendLine($" public const string {kvp.Key} = \"{kvp.Key}\";");
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
// 生成通用属性
|
||||
sb.AppendLine(" // ── 通用属性 (General) ───────────────────────────────");
|
||||
// 生成属性
|
||||
sb.AppendLine(" // ── 属性 (General) ───────────────────────────────");
|
||||
if (characterGeneralAttributes != null)
|
||||
{
|
||||
foreach (var kvp in characterGeneralAttributes)
|
||||
|
||||
@@ -12,77 +12,4 @@ namespace Continentis.MainGame
|
||||
public class GameAttributeCollectionAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏通用属性名称常量。
|
||||
/// 请始终使用此类中的常量而非裸字符串访问属性,以避免 typo 错误。
|
||||
/// </summary>
|
||||
[GameAttributeCollection]
|
||||
public static class GameAttributes
|
||||
{
|
||||
// ── 生命值 ──────────────────────────────────
|
||||
public const string Health = "Health";
|
||||
public const string MaximumHealth = "MaximumHealth";
|
||||
|
||||
// ── 资源 ────────────────────────────────────
|
||||
public const string Stamina = "Stamina";
|
||||
public const string MaximumStamina = "MaximumStamina";
|
||||
public const string StaminaRecoverPerAction = "StaminaRecoverPerAction";
|
||||
public const string Mana = "Mana";
|
||||
public const string MaximumMana = "MaximumMana";
|
||||
public const string ManaRecoverPerAction = "ManaRecoverPerAction";
|
||||
|
||||
// ── 防御 ────────────────────────────────────
|
||||
public const string Block = "Block";
|
||||
public const string TemporaryHealth = "TemporaryHealth";
|
||||
public const string Dodge = "Dodge";
|
||||
|
||||
public const string BlockGainOffset = "BlockGainOffset";
|
||||
public const string BlockGainMultiplier = "BlockGainMultiplier";
|
||||
public const string DodgeGainOffset = "DodgeGainOffset";
|
||||
public const string DodgeGainMultiplier = "DodgeGainMultiplier";
|
||||
public const string TemporaryHealthGainOffset = "TemporaryHealthGainOffset";
|
||||
public const string TemporaryHealthGainMultiplier = "TemporaryHealthGainMultiplier";
|
||||
|
||||
public const string KeepBlockOnActionStart = "KeepBlockOnActionStart";
|
||||
public const string KeepDodgeOnActionStart = "KeepDodgeOnActionStart";
|
||||
|
||||
// ── 速度与行动 ──────────────────────────────
|
||||
public const string Speed = "Speed";
|
||||
public const string DrawCardAmountPerAction = "DrawCardAmountPerAction";
|
||||
public const string DeckCapacity = "DeckCapacity";
|
||||
|
||||
// ── 伤害调整(通用)──────────────────────────
|
||||
public const string PhysicsDamageDealtOffset = "PhysicsDamageDealtOffset";
|
||||
public const string MagicDamageDealtOffset = "MagicDamageDealtOffset";
|
||||
public const string FinalDamageDealtMultiplier = "FinalDamageDealtMultiplier";
|
||||
public const string FinalDamageGainMultiplier = "FinalDamageGainMultiplier";
|
||||
public const string MagicDamageDealtMultiplier = "MagicDamageDealtMultiplier";
|
||||
public const string MagicDamageGainMultiplier = "MagicDamageGainMultiplier";
|
||||
|
||||
// ── 核心属性(角色创建时)──────────────────────
|
||||
public const string Strength = "Strength";
|
||||
public const string Agility = "Agility";
|
||||
public const string Intelligence = "Intelligence";
|
||||
public const string Physique = "Physique";
|
||||
public const string Perception = "Perception";
|
||||
public const string Charisma = "Charisma";
|
||||
public const string Level = "Level";
|
||||
|
||||
// ── 感知与闪避检测 ──────────────────────────
|
||||
public const string Awareness = "Awareness";
|
||||
public const string DodgeCheckStartDamageMultiplier = "DodgeCheckStartDamageMultiplier";
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 提供给 Odin Inspector [ValueDropdown] 使用的方法。
|
||||
/// 从所有 Mod 的 EditorBaseCollection 资产中聚合角色属性(Core + General),
|
||||
/// 覆盖旧的反射扫描方式,天然支持多 Mod 叠加,无需关心程序集加载顺序。
|
||||
/// </summary>
|
||||
public static IEnumerable<Sirenix.OdinInspector.ValueDropdownItem<string>> GetAllAvailableAttributes()
|
||||
{
|
||||
return Continentis.MainGame.Base.EditorBaseCollection.GetCharacterAttributesDropdown(null);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +54,9 @@ namespace Continentis.MainGame
|
||||
{
|
||||
private static string GetAttribute(CardInstance card, string attributeName, bool higherIsBetter, bool inPercent)
|
||||
{
|
||||
string displayName = "Display" + attributeName;
|
||||
string baseName = "Base" + attributeName;
|
||||
string baseOffsetName = "Base" + attributeName + "Offset";
|
||||
string displayName = "Display_" + attributeName;
|
||||
string baseName = "Base_" + attributeName;
|
||||
string baseOffsetName = "Base_" + attributeName + "_Offset";
|
||||
|
||||
if (!inPercent)
|
||||
{
|
||||
@@ -74,7 +74,7 @@ namespace Continentis.MainGame
|
||||
|
||||
private static string GetAttribute(CardInstance card, string attributeName, bool inPercent)
|
||||
{
|
||||
string displayName = "Display" + attributeName;
|
||||
string displayName = "Display_" + attributeName;
|
||||
int displayValue = card.GetAttribute(displayName);
|
||||
return DynamicTextInterpreter.GetValue(displayValue, inPercent);
|
||||
}
|
||||
|
||||
@@ -61,8 +61,8 @@ namespace Continentis.MainGame.Card
|
||||
public void SetVariableAttribute(string attributeName, int baseOffset, bool additive = false,
|
||||
int originalValue = 0)
|
||||
{
|
||||
var baseName = "Base" + attributeName;
|
||||
var baseOffsetName = baseName + "Offset";
|
||||
var baseName = "Base_" + attributeName;
|
||||
var baseOffsetName = "Base_" + attributeName + "_Offset";
|
||||
|
||||
if (!additive) originalValue = GetAttribute(baseName);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
/// 基于 EditorBaseCollection 自动生成的卡牌属性常量字典。
|
||||
/// 包含所有配置的 Key,以防止手写出现 Typo。
|
||||
/// </summary>
|
||||
[GameAttributeCollection]
|
||||
public static class CardAttributes
|
||||
{
|
||||
/// <summary> 体力值消耗 </summary>
|
||||
|
||||
@@ -17,16 +17,19 @@
|
||||
|
||||
/// <summary> 可选目标为全体角色 </summary>
|
||||
public const string TargetAll = "TargetAll";
|
||||
|
||||
/// <summary> 多目标选择时允许复选 </summary>
|
||||
public const string AllowDuplicateTargets = "AllowDuplicateTargets";
|
||||
|
||||
/// <summary> 物理 </summary>
|
||||
public const string Physics = "Physics";
|
||||
/// <summary> 多目标选择时允许复选 </summary>
|
||||
public const string AllowDuplicateTargets = "AllowDuplicateTargets";
|
||||
|
||||
/// <summary> 随机目标 </summary>
|
||||
public const string RandomTarget = "RandomTarget";
|
||||
|
||||
/// <summary> 魔法 </summary>
|
||||
public const string Magic = "Magic";
|
||||
|
||||
/// <summary> 物理 </summary>
|
||||
public const string Physics = "Physics";
|
||||
|
||||
/// <summary> 风 </summary>
|
||||
public const string Wind = "Wind";
|
||||
|
||||
@@ -48,29 +51,11 @@
|
||||
/// <summary> 暗 </summary>
|
||||
public const string Darkness = "Darkness";
|
||||
|
||||
/// <summary> 打击(力量) </summary>
|
||||
public const string Strike = "Strike";
|
||||
/// <summary> 毒 </summary>
|
||||
public const string Poison = "Poison";
|
||||
|
||||
/// <summary> 突刺(敏捷) </summary>
|
||||
public const string Prick = "Prick";
|
||||
|
||||
/// <summary> 斩击(力量&敏捷) </summary>
|
||||
public const string Slash = "Slash";
|
||||
|
||||
/// <summary> 奥术(智力) </summary>
|
||||
public const string Arcane = "Arcane";
|
||||
|
||||
/// <summary> 邪术(魅力) </summary>
|
||||
public const string Sorcery = "Sorcery";
|
||||
|
||||
/// <summary> 迅捷(敏捷) </summary>
|
||||
public const string Swiftness = "Swiftness";
|
||||
|
||||
/// <summary> 坚韧(体质) </summary>
|
||||
public const string Fortitude = "Fortitude";
|
||||
|
||||
/// <summary> 预判(感知) </summary>
|
||||
public const string Prediction = "Prediction";
|
||||
/// <summary> 灵能 </summary>
|
||||
public const string Psionics = "Psionics";
|
||||
|
||||
/// <summary> 消耗(打出后移至消耗堆) </summary>
|
||||
public const string Exhaust = "Exhaust";
|
||||
@@ -101,5 +86,17 @@
|
||||
|
||||
/// <summary> 先决(在手牌中时,必须先打出此牌) </summary>
|
||||
public const string Prerequisite = "Prerequisite";
|
||||
|
||||
/// <summary> 弱驱散 </summary>
|
||||
public const string BasicDispel = "BasicDispel";
|
||||
|
||||
/// <summary> 强驱散 </summary>
|
||||
public const string StrongDispel = "StrongDispel";
|
||||
|
||||
/// <summary> 穿透(无视格挡) </summary>
|
||||
public const string Penetration = "Penetration";
|
||||
|
||||
/// <summary> 必中(无视闪避) </summary>
|
||||
public const string GuaranteedHit = "GuaranteedHit";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,16 +30,16 @@ namespace Continentis.MainGame.Card
|
||||
|
||||
foreach (KeyValuePair<string, float> attribute in cardData.variableAttributes)
|
||||
{
|
||||
string baseName = "Base" + attribute.Key;
|
||||
string baseName = "Base_" + attribute.Key;
|
||||
originalAttributes.Add(baseName, attribute.Value);
|
||||
|
||||
string mainName = attribute.Key;
|
||||
endowingAttributes.Add(mainName, baseName);
|
||||
|
||||
string baseOffset = "Base" + attribute.Key + "Offset";
|
||||
string baseOffset = "Base_" + attribute.Key + "_Offset";
|
||||
endowingAttributes.Add(baseOffset, "0");
|
||||
|
||||
string displayName = "Display" + attribute.Key;
|
||||
string displayName = "Display_" + attribute.Key;
|
||||
endowingAttributes.Add(displayName, baseName);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Continentis.MainGame.Card
|
||||
float final_pAccumulation = cha_pAccumulation + card_pAccumulation;
|
||||
float final_pMultiplication = cha_pMultiplication * card_pMultiplication;
|
||||
attributeGroup.ModifyAttribute(attributeName, final_numeric, final_pAccumulation, final_pMultiplication);
|
||||
string displayAttributeName = "Display" + attributeName;
|
||||
string displayAttributeName = "Display_" + attributeName;
|
||||
if(attributeGroup.current.ContainsKey(displayAttributeName))
|
||||
{
|
||||
attributeGroup.SetAttribute(displayAttributeName, attributeGroup.current[attributeName]);
|
||||
@@ -87,7 +87,7 @@ namespace Continentis.MainGame.Card
|
||||
{
|
||||
owner.combatBuffSubmodule.GetAttributeChange(attributeName, out float numeric, out float pAccumulation, out float pMultiplication);
|
||||
attributeGroup.ModifyAttribute(attributeName, numeric, pAccumulation, pMultiplication);
|
||||
string displayAttributeName = "Display" + attributeName;
|
||||
string displayAttributeName = "Display_" + attributeName;
|
||||
if(attributeGroup.current.ContainsKey(displayAttributeName))
|
||||
{
|
||||
attributeGroup.SetAttribute(displayAttributeName, attributeGroup.current[attributeName]);
|
||||
|
||||
@@ -107,9 +107,9 @@ namespace Continentis.MainGame.Card
|
||||
|
||||
int targetCount = card.attributeSubmodule.targetCount;
|
||||
|
||||
if (targetCount > 1)
|
||||
if (targetCount > 1 && !card.HasKeyword(CardKeywords.RandomTarget))
|
||||
{
|
||||
// 多目标模式:先执行通用的可打出校验
|
||||
// 多目标手动选择模式:先执行通用的可打出校验
|
||||
if (!CheckCanStartPlay())
|
||||
{
|
||||
ResetSelectionState();
|
||||
@@ -255,7 +255,8 @@ namespace Continentis.MainGame.Card
|
||||
CombatUIManager.Instance.arrowsPage.otherPointerArrows.ForEach(arrow => { arrow.gameObject.SetActive(false); });
|
||||
}
|
||||
}
|
||||
else if (card.attributeSubmodule.targetCount == 0)
|
||||
else if (card.attributeSubmodule.targetCount == 0
|
||||
|| card.HasKeyword(CardKeywords.RandomTarget))
|
||||
{
|
||||
Vector3 cardPosition = SpaceConverter.ScreenPointToUIPoint(arrowCanvasRect, eventData.position, uiCamera);
|
||||
cardTransform.position = cardPosition;
|
||||
@@ -289,7 +290,7 @@ namespace Continentis.MainGame.Card
|
||||
|
||||
if (!CheckCanStartPlay()) return;
|
||||
|
||||
if (!card.HasKeyword("TargetSelf"))
|
||||
if (!card.HasKeyword("TargetSelf") && !card.HasKeyword(CardKeywords.RandomTarget))
|
||||
{
|
||||
if (!validTargets.Contains(hoveringCharacter))
|
||||
{
|
||||
@@ -320,6 +321,10 @@ namespace Continentis.MainGame.Card
|
||||
{
|
||||
targetList.AddRange(validTargets);
|
||||
}
|
||||
else if (card.HasKeyword(CardKeywords.RandomTarget))
|
||||
{
|
||||
targetList.AddRange(card.SetRandomTargets(validTargets));
|
||||
}
|
||||
else if (card.HasKeyword("TargetSelf") && card.attributeSubmodule.targetCount == 0)
|
||||
{
|
||||
targetList.Add(card.user);
|
||||
|
||||
@@ -205,6 +205,54 @@ namespace Continentis.MainGame.Card
|
||||
}
|
||||
|
||||
|
||||
[BoxGroup("Fundamental")]
|
||||
[PropertyOrder(6)]
|
||||
[Button("📄 打开逻辑脚本", ButtonSizes.Medium)]
|
||||
[GUIColor(1f, 0.92f, 0.6f)]
|
||||
[ShowIf("@!string.IsNullOrEmpty(className)")]
|
||||
private void OpenCardLogicScript()
|
||||
{
|
||||
if (string.IsNullOrEmpty(className))
|
||||
{
|
||||
Debug.LogWarning("[CardData] 尚未选择逻辑类,无法打开对应脚本。");
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据 modName / categoryName / className 拼接可能的文件路径
|
||||
// 路径格式: Assets/Mods/{modName}/Cards/Scripts/{categoryName}/{className}.cs
|
||||
// | Assets/Mods/{modName}/Cards/Scripts/{className}.cs (无分类时)
|
||||
var candidatePaths = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(categoryName))
|
||||
candidatePaths.Add($"Assets/Mods/{modName}/Cards/Scripts/{categoryName}/{className}.cs");
|
||||
|
||||
candidatePaths.Add($"Assets/Mods/{modName}/Cards/Scripts/{className}.cs");
|
||||
|
||||
// 在全项目中也搜一遍(应对目录结构不规范的情况)
|
||||
string[] guids = AssetDatabase.FindAssets($"{className} t:MonoScript");
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string p = AssetDatabase.GUIDToAssetPath(guid);
|
||||
if (Path.GetFileNameWithoutExtension(p) == className)
|
||||
candidatePaths.Add(p);
|
||||
}
|
||||
|
||||
foreach (string path in candidatePaths)
|
||||
{
|
||||
var script = AssetDatabase.LoadAssetAtPath<UnityEditor.MonoScript>(path);
|
||||
if (script != null)
|
||||
{
|
||||
AssetDatabase.OpenAsset(script);
|
||||
EditorGUIUtility.PingObject(script);
|
||||
Debug.Log($"[CardData] 已打开逻辑脚本:{path}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogError($"[CardData] 未找到逻辑类 '{className}' 对应的脚本文件。\n" +
|
||||
$"已搜索路径:\n{string.Join("\n", candidatePaths)}");
|
||||
}
|
||||
|
||||
[BoxGroup("Display")]
|
||||
[PropertyOrder(11)]
|
||||
[Button("✨ 预览卡牌效果", ButtonSizes.Medium)]
|
||||
|
||||
@@ -9,12 +9,12 @@ namespace Continentis.MainGame.Card
|
||||
{
|
||||
protected override void TargetingEffect(CharacterBase target)
|
||||
{
|
||||
card.SetAttribute("DisplayDamage", mainLogic.GetTargetedFinalDamage(target));
|
||||
card.SetAttribute("Display_Damage", mainLogic.GetTargetedFinalDamage(target));
|
||||
}
|
||||
|
||||
protected override void UntargetingEffect()
|
||||
{
|
||||
card.SetAttribute("DisplayDamage", mainLogic.GetNoTargetFinalDamage());
|
||||
card.SetAttribute("Display_Damage", mainLogic.GetNoTargetFinalDamage());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -38,48 +38,20 @@ namespace Continentis.MainGame.Card
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 斩击伤害计算,伤害=基础伤害+(力量加成+敏捷加成)/2
|
||||
/// 物理伤害计算,伤害=基础伤害+物理伤害加成
|
||||
/// </summary>
|
||||
public void SetDamage_Slash(string damageAttributeName = "Damage", bool additive = false, int originalDamage = 0)
|
||||
public void SetDamage_Physics(string damageAttributeName = "Damage", bool additive = false, int originalDamage = 0)
|
||||
{
|
||||
float rawDamageOffsetFromStrength = user.GetRawAttribute("OffsetFromStrength");
|
||||
float rawDamageOffsetFromAgility = user.GetRawAttribute("OffsetFromAgility");
|
||||
SetDamage(Mathf.RoundToInt((rawDamageOffsetFromStrength + rawDamageOffsetFromAgility) / 2f), damageAttributeName, additive, originalDamage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打击伤害计算,伤害=基础伤害+力量加成
|
||||
/// </summary>
|
||||
public void SetDamage_Strike(string damageAttributeName = "Damage", bool additive = false, int originalDamage = 0)
|
||||
{
|
||||
int damageOffset = user.GetAttribute("OffsetFromStrength");
|
||||
SetDamage(damageOffset, damageAttributeName, additive, originalDamage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 突刺伤害计算,伤害=基础伤害+敏捷加成
|
||||
/// </summary>
|
||||
public void SetDamage_Prick(string damageAttributeName = "Damage", bool additive = false, int originalDamage = 0)
|
||||
{
|
||||
int damageOffset = user.GetAttribute("OffsetFromAgility");
|
||||
int damageOffset = user.GetAttribute("PhysicsDamageDealtOffset");
|
||||
SetDamage(damageOffset, damageAttributeName, additive, originalDamage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 奥术伤害计算,伤害=基础伤害+智力加成
|
||||
/// 魔法伤害计算,伤害=基础伤害+魔法伤害加成
|
||||
/// </summary>
|
||||
public void SetDamage_Arcane(string damageAttributeName = "Damage", bool additive = false, int originalDamage = 0)
|
||||
public void SetDamage_Magic(string damageAttributeName = "Damage", bool additive = false, int originalDamage = 0)
|
||||
{
|
||||
int damageOffset = user.GetAttribute("OffsetFromIntelligence");
|
||||
SetDamage(damageOffset, damageAttributeName, additive, originalDamage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 契术伤害计算,伤害=基础伤害+魅力加成
|
||||
/// </summary>
|
||||
public void SetDamage_Sorcery(string damageAttributeName = "Damage", bool additive = false, int originalDamage = 0)
|
||||
{
|
||||
int damageOffset = user.GetAttribute("OffsetFromCharisma");
|
||||
int damageOffset = user.GetAttribute("MagicDamageDealtOffset");
|
||||
SetDamage(damageOffset, damageAttributeName, additive, originalDamage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ namespace Continentis.MainGame.Card
|
||||
{
|
||||
if (card.HasAttribute("Block"))
|
||||
{
|
||||
card.SetAttribute("DisplayBlock", card.GetAttribute("Block"));
|
||||
card.SetAttribute("Display_Block", card.GetAttribute("Block"));
|
||||
}
|
||||
else if(card.HasAttribute("Dodge"))
|
||||
{
|
||||
card.SetAttribute("DisplayDodge", card.GetAttribute("Dodge"));
|
||||
card.SetAttribute("Display_Dodge", card.GetAttribute("Dodge"));
|
||||
}
|
||||
else if(card.HasAttribute("TemporaryHealth"))
|
||||
{
|
||||
card.SetAttribute("DisplayTemporaryHealth", card.GetAttribute("TemporaryHealth"));
|
||||
card.SetAttribute("Display_TemporaryHealth", card.GetAttribute("TemporaryHealth"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,79 +26,34 @@ namespace Continentis.MainGame.Card
|
||||
{
|
||||
if (card.HasAttribute("Block"))
|
||||
{
|
||||
card.SetAttribute("DisplayBlock", card.GetAttribute("Block"));
|
||||
card.SetAttribute("Display_Block", card.GetAttribute("Block"));
|
||||
}
|
||||
else if(card.HasAttribute("Dodge"))
|
||||
{
|
||||
card.SetAttribute("DisplayDodge", card.GetAttribute("Dodge"));
|
||||
card.SetAttribute("Display_Dodge", card.GetAttribute("Dodge"));
|
||||
}
|
||||
else if(card.HasAttribute("TemporaryHealth"))
|
||||
{
|
||||
card.SetAttribute("DisplayTemporaryHealth", card.GetAttribute("TemporaryHealth"));
|
||||
card.SetAttribute("Display_TemporaryHealth", card.GetAttribute("TemporaryHealth"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置格挡值,默认由体质加成
|
||||
/// 设置格挡值,加成来自 BlockGainOffset
|
||||
/// </summary>
|
||||
public void SetBlock_Fortitude(bool additive = false, int originalBlock = 0)
|
||||
public void SetBlock(bool additive = false, int originalBlock = 0)
|
||||
{
|
||||
int blockOffsetFromPhysique = user.GetAttribute("OffsetFromPhysique");
|
||||
card.SetVariableAttribute("Block", blockOffsetFromPhysique, additive, originalBlock);
|
||||
int blockOffset = user.GetAttribute("BlockGainOffset");
|
||||
card.SetVariableAttribute("Block", blockOffset, additive, originalBlock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置格挡值,由智力加成
|
||||
/// 设置闪避值,加成来自 DodgeGainOffset
|
||||
/// </summary>
|
||||
public void SetBlock_Arcane(bool additive = false, int originalBlock = 0)
|
||||
public void SetDodge(bool additive = false, int originalDodge = 0)
|
||||
{
|
||||
int blockOffsetFromIntelligence = user.GetAttribute("OffsetFromIntelligence");
|
||||
card.SetVariableAttribute("Block", blockOffsetFromIntelligence, additive, originalBlock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置格挡值,由魅力加成
|
||||
/// </summary>
|
||||
public void SetBlock_Sorcery(bool additive = false, int originalBlock = 0)
|
||||
{
|
||||
int blockOffsetFromCharisma = user.GetAttribute("OffsetFromCharisma");
|
||||
card.SetVariableAttribute("Block", blockOffsetFromCharisma, additive, originalBlock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置闪避值,由敏捷加成
|
||||
/// </summary>
|
||||
public void SetDodge_Swiftness(bool additive = false, int originalDodge = 0)
|
||||
{
|
||||
int dodgeOffsetFromAgility = user.GetAttribute("OffsetFromAgility");
|
||||
card.SetVariableAttribute("Dodge", dodgeOffsetFromAgility, additive, originalDodge);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置闪避值,由智力加成
|
||||
/// </summary>
|
||||
public void SetDodge_Arcane(bool additive = false, int originalDodge = 0)
|
||||
{
|
||||
int dodgeOffsetFromIntelligence = user.GetAttribute("OffsetFromIntelligence");
|
||||
card.SetVariableAttribute("Dodge", dodgeOffsetFromIntelligence, additive, originalDodge);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置闪避值,由魅力加成
|
||||
/// </summary>
|
||||
public void SetDodge_Sorcery(bool additive = false, int originalDodge = 0)
|
||||
{
|
||||
int dodgeOffsetFromCharisma = user.GetAttribute("OffsetFromCharisma");
|
||||
card.SetVariableAttribute("Dodge", dodgeOffsetFromCharisma, additive, originalDodge);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置闪避值,由感知加成
|
||||
/// </summary>
|
||||
public void SetDodge_Prediction(bool additive = false, int originalDodge = 0)
|
||||
{
|
||||
int dodgeOffsetFromPrediction = user.GetAttribute("OffsetFromPerception");
|
||||
card.SetVariableAttribute("Dodge", dodgeOffsetFromPrediction, additive, originalDodge);
|
||||
int dodgeOffset = user.GetAttribute("DodgeGainOffset");
|
||||
card.SetVariableAttribute("Dodge", dodgeOffset, additive, originalDodge);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,12 +7,12 @@ namespace Continentis.MainGame.Card
|
||||
{
|
||||
protected override void TargetingEffect(CharacterBase target)
|
||||
{
|
||||
card.SetAttribute("DisplayLifeStealPercent", GetLifeStealPercent());
|
||||
card.SetAttribute("Display_LifeStealPercent", GetLifeStealPercent());
|
||||
}
|
||||
|
||||
protected override void UntargetingEffect()
|
||||
{
|
||||
card.SetAttribute("DisplayLifeStealPercent", card.GetRawAttribute("LifeStealPercent"));
|
||||
card.SetAttribute("Display_LifeStealPercent", card.GetRawAttribute("LifeStealPercent"));
|
||||
}
|
||||
|
||||
public float GetLifeStealPercent()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Continentis.MainGame.Commands;
|
||||
@@ -10,6 +11,7 @@ namespace Continentis.MainGame.Card
|
||||
public class CardLogicComponent_SelectCustomCards : CardLogicComponentBase
|
||||
{
|
||||
public List<CardInstance> selectedCards;
|
||||
public Action<CardInstance> selectEffect;
|
||||
|
||||
/// <summary>
|
||||
/// 添加选择手牌的指令
|
||||
@@ -24,24 +26,16 @@ namespace Continentis.MainGame.Card
|
||||
selectedCards = new List<CardInstance>();
|
||||
CustomCardSelectionInterface customCardSelector = CombatUIManager.Instance.combatMainPage.customCardSelector;
|
||||
|
||||
commandGroup.AddCommand(new Cmd_Function(() =>
|
||||
commandGroup.AddCommand(Cmd.Do(() =>
|
||||
{
|
||||
customCardSelector.Setup(title, mainLogic.card, cardsToSelect, maxSelection, forceMax);
|
||||
}));
|
||||
commandGroup.AddCommand(new Cmd_WaitForUI(customCardSelector));
|
||||
commandGroup.AddCommand(new Cmd_Function(() =>
|
||||
commandGroup.AddCommand(Cmd.Do(() =>
|
||||
{
|
||||
selectedCards = customCardSelector.selectedCards.ToList();
|
||||
selectedCards.ForEach(SelectEffect);
|
||||
selectedCards.ForEach(selectEffect);
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卡牌被选择后的效果
|
||||
/// </summary>
|
||||
public void SelectEffect(CardInstance card)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace Continentis.MainGame.Card
|
||||
selectedCards = new List<CardInstance>();
|
||||
HandCardSelectionInterface handCardSelector = CombatUIManager.Instance.combatMainPage.handCardSelector;
|
||||
|
||||
commandGroup.AddCommand(new Cmd_Function(() =>
|
||||
commandGroup.AddCommand(Cmd.Do(() =>
|
||||
{
|
||||
handCardSelector.Setup(title, mainLogic.card, maxSelection, selectCondition, forceMax);
|
||||
if (!includeTeam)
|
||||
@@ -51,7 +51,7 @@ namespace Continentis.MainGame.Card
|
||||
}
|
||||
}));
|
||||
commandGroup.AddCommand(new Cmd_WaitForUI(handCardSelector));
|
||||
commandGroup.AddCommand(new Cmd_Function(() =>
|
||||
commandGroup.AddCommand(Cmd.Do(() =>
|
||||
{
|
||||
selectedCards = handCardSelector.selectedCards.ToList();
|
||||
selectedCards.ForEach(selectEffect);
|
||||
|
||||
@@ -44,41 +44,31 @@ namespace Continentis.MainGame.Character
|
||||
public partial class CharacterBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取角色的属性值,自动判断属性组(Core/General)
|
||||
/// 获取角色的属性值
|
||||
/// </summary>
|
||||
public int GetAttribute(string attributeName, int defaultValue = 0)
|
||||
{
|
||||
if (attributeSubmodule.coreAttributeGroup.current.ContainsKey(attributeName))
|
||||
{
|
||||
return attributeSubmodule.GetCurrentCoreAttribute(attributeName);
|
||||
}
|
||||
|
||||
if (attributeSubmodule.generalAttributeGroup.current.ContainsKey(attributeName))
|
||||
{
|
||||
return attributeSubmodule.GetGeneralAttribute(attributeName);
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Attribute {attributeName} not found in any attribute group.");
|
||||
Debug.LogWarning($"Attribute {attributeName} not found in attribute group.");
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取角色的原始属性值,自动判断属性组(Core/General)
|
||||
/// 获取角色的原始属性值
|
||||
/// 如果属性名包含“Multiplier”,默认值改为1
|
||||
/// </summary>
|
||||
public float GetRawAttribute(string attributeName, float defaultValue = 0)
|
||||
{
|
||||
if (attributeSubmodule.coreAttributeGroup.current.TryGetValue(attributeName, out float rawAttribute))
|
||||
{
|
||||
return rawAttribute;
|
||||
}
|
||||
|
||||
if (attributeSubmodule.generalAttributeGroup.current.TryGetValue(attributeName, out float attribute))
|
||||
{
|
||||
return attribute;
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Attribute {attributeName} not found in any attribute group.");
|
||||
Debug.LogWarning($"Attribute {attributeName} not found in attribute group.");
|
||||
|
||||
if(attributeName.Contains("Multiplier"))
|
||||
{
|
||||
@@ -89,47 +79,55 @@ namespace Continentis.MainGame.Character
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置角色的属性值,自动判断属性组(Core/General)
|
||||
/// 设置角色的属性值
|
||||
/// </summary>
|
||||
/// <param name="attributeName"></param>
|
||||
/// <param name="value"></param>
|
||||
public void SetAttribute(string attributeName, int value)
|
||||
{
|
||||
if (attributeSubmodule.coreAttributeGroup.current.ContainsKey(attributeName))
|
||||
{
|
||||
attributeSubmodule.coreAttributeGroup.current[attributeName] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (attributeSubmodule.generalAttributeGroup.current.ContainsKey(attributeName))
|
||||
{
|
||||
attributeSubmodule.generalAttributeGroup.current[attributeName] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Attribute {attributeName} not found in any attribute group.");
|
||||
Debug.LogWarning($"Attribute {attributeName} not found in attribute group.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改角色的属性值,自动判断属性组(Core/General)
|
||||
/// 修改角色的属性值
|
||||
/// </summary>
|
||||
/// <param name="attributeName"></param>
|
||||
/// <param name="delta"></param>
|
||||
public void ModifyAttribute(string attributeName, int delta)
|
||||
{
|
||||
if (attributeSubmodule.coreAttributeGroup.current.ContainsKey(attributeName))
|
||||
{
|
||||
attributeSubmodule.coreAttributeGroup.current[attributeName] += delta;
|
||||
return;
|
||||
}
|
||||
|
||||
if (attributeSubmodule.generalAttributeGroup.current.ContainsKey(attributeName))
|
||||
{
|
||||
attributeSubmodule.generalAttributeGroup.current[attributeName] += delta;
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Attribute {attributeName} not found in any attribute group.");
|
||||
Debug.LogWarning($"Attribute {attributeName} not found in attribute group.");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 修改角色的属性值并进行范围限制
|
||||
/// </summary>
|
||||
/// <returns>实际的添加或减少的数值(可能因为范围限制而小于 delta)</returns>
|
||||
public int ModifyAndClampAttribute(string attributeName, int delta, int min = 0, int max = int.MaxValue)
|
||||
{
|
||||
int currentAttribute = GetAttribute(attributeName);
|
||||
int actualModifiedValue = delta;
|
||||
if (delta < 0)
|
||||
{
|
||||
actualModifiedValue = Mathf.Min(-delta, currentAttribute - min);
|
||||
}
|
||||
else if (delta > 0)
|
||||
{
|
||||
actualModifiedValue = Mathf.Min(delta, max - currentAttribute);
|
||||
}
|
||||
|
||||
ModifyAttribute(attributeName, delta);
|
||||
ClampAttribute(attributeName, min, max);
|
||||
|
||||
return actualModifiedValue;
|
||||
}
|
||||
|
||||
public void ClampAttribute(string attributeName, int min, int max)
|
||||
|
||||
@@ -17,36 +17,6 @@ namespace Continentis.MainGame.Character
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Buff的角色核心属性调整模块
|
||||
/// </summary>
|
||||
public class CoreAttributeSubmodule : CharacterBuffSubmodule
|
||||
{
|
||||
public Dictionary<string, float> numericChange;
|
||||
public Dictionary<string, float> percentageChangeOfAccumulation;
|
||||
public Dictionary<string, float> percentageChangeOfMultiplication;
|
||||
|
||||
public CoreAttributeSubmodule(CharacterBuffBase buff) : base(buff)
|
||||
{
|
||||
this.numericChange = new Dictionary<string, float>();
|
||||
this.percentageChangeOfAccumulation = new Dictionary<string, float>();
|
||||
this.percentageChangeOfMultiplication = new Dictionary<string, float>();
|
||||
}
|
||||
|
||||
public List<string> RefreshAllModifiedAttributes()
|
||||
{
|
||||
List<string> modifiedAttributes = new List<string>();
|
||||
modifiedAttributes.AddRange(numericChange.Select(kvp => kvp.Key));
|
||||
modifiedAttributes.AddRange(percentageChangeOfAccumulation.Select(kvp => kvp.Key));
|
||||
modifiedAttributes.AddRange(percentageChangeOfMultiplication.Select(kvp => kvp.Key));
|
||||
|
||||
modifiedAttributes.ForEach(attr => character.attributeSubmodule.RefreshCoreAttribute(attr));
|
||||
character.attributeSubmodule.RefreshAllGeneralAttributes(); //刷新核心属性后,需要刷新通用属性
|
||||
|
||||
return modifiedAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Buff的角色通常属性调整模块
|
||||
/// </summary>
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace Continentis.MainGame.Character
|
||||
|
||||
public UnitedStackSubmodule unitedStackSubmodule;
|
||||
public IndependentStackSubmodule independentStackSubmodule;
|
||||
public CoreAttributeSubmodule coreAttributeSubmodule;
|
||||
public GeneralAttributeSubmodule generalAttributeSubmodule;
|
||||
public StatusSubmodule statusSubmodule;
|
||||
}
|
||||
@@ -187,14 +186,7 @@ namespace Continentis.MainGame.Character
|
||||
{
|
||||
private void RefreshAttributes()
|
||||
{
|
||||
if (coreAttributeSubmodule != null)
|
||||
{
|
||||
coreAttributeSubmodule.RefreshAllModifiedAttributes();
|
||||
}
|
||||
else
|
||||
{
|
||||
generalAttributeSubmodule?.RefreshAllModifiedAttributes();
|
||||
}
|
||||
generalAttributeSubmodule?.RefreshAllModifiedAttributes();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,29 +7,10 @@
|
||||
[GameAttributeCollection]
|
||||
public static class CharacterAttributes
|
||||
{
|
||||
// ── 核心属性 (Core) ──────────────────────────────────
|
||||
// ── 属性 (General) ───────────────────────────────
|
||||
/// <summary> 等级 </summary>
|
||||
public const string Level = "Level";
|
||||
|
||||
/// <summary> 力量 </summary>
|
||||
public const string Strength = "Strength";
|
||||
|
||||
/// <summary> 敏捷 </summary>
|
||||
public const string Agility = "Agility";
|
||||
|
||||
/// <summary> 智力 </summary>
|
||||
public const string Intelligence = "Intelligence";
|
||||
|
||||
/// <summary> 体质 </summary>
|
||||
public const string Physique = "Physique";
|
||||
|
||||
/// <summary> 感知 </summary>
|
||||
public const string Perception = "Perception";
|
||||
|
||||
/// <summary> 魅力 </summary>
|
||||
public const string Charisma = "Charisma";
|
||||
|
||||
// ── 通用属性 (General) ───────────────────────────────
|
||||
/// <summary> 生命值 </summary>
|
||||
public const string Health = "Health";
|
||||
|
||||
@@ -72,8 +53,8 @@
|
||||
/// <summary> 闪避 </summary>
|
||||
public const string Dodge = "Dodge";
|
||||
|
||||
/// <summary> 护盾 </summary>
|
||||
public const string Shield = "Shield";
|
||||
/// <summary> 临时生命 </summary>
|
||||
public const string TemporaryHealth = "TemporaryHealth";
|
||||
|
||||
/// <summary> 回合开始时保留格挡 </summary>
|
||||
public const string KeepBlockOnActionStart = "KeepBlockOnActionStart";
|
||||
@@ -87,9 +68,6 @@
|
||||
/// <summary> 获得闪避偏移量 </summary>
|
||||
public const string DodgeGainOffset = "DodgeGainOffset";
|
||||
|
||||
/// <summary> 获得护盾偏移量 </summary>
|
||||
public const string ShieldGainOffset = "ShieldGainOffset";
|
||||
|
||||
/// <summary> 闪避攻击前,闪避值乘以此值 </summary>
|
||||
public const string DodgeCheckStartDamageMultiplier = "DodgeCheckStartDamageMultiplier";
|
||||
|
||||
|
||||
@@ -16,12 +16,7 @@ namespace Continentis.MainGame.Character
|
||||
[TitleGroup("属性模板")]
|
||||
|
||||
[DictionaryDrawerSettings(KeyLabel = "属性名", ValueLabel = "属性值")]
|
||||
[LabelText("核心属性 (Core)")]
|
||||
[Tooltip("对应 CharacterData.coreAttributes")]
|
||||
public SerializableDictionary<string, float> coreAttributes;
|
||||
|
||||
[DictionaryDrawerSettings(KeyLabel = "属性名", ValueLabel = "属性值")]
|
||||
[LabelText("通常属性 (General)")]
|
||||
[LabelText("属性 (General)")]
|
||||
[Tooltip("对应 CharacterData.generalAttributes")]
|
||||
public SerializableDictionary<string, float> generalAttributes;
|
||||
|
||||
|
||||
@@ -72,11 +72,7 @@ namespace Continentis.MainGame.Character
|
||||
// ── Attributes ────────────────────────────────────────────────────────
|
||||
|
||||
[TabGroup("Data", "属性"), PropertyOrder(20)]
|
||||
[Tooltip("角色的核心属性:支持智能下拉菜单")]
|
||||
public SerializedDictionary<string, float, CharacterAttributePair> coreAttributes = new SerializedDictionary<string, float, CharacterAttributePair>();
|
||||
|
||||
[TabGroup("Data", "属性"), PropertyOrder(21)]
|
||||
[Tooltip("角色的通常属性:支持智能下拉菜单")]
|
||||
[Tooltip("角色的属性:支持智能下拉菜单")]
|
||||
public SerializedDictionary<string, float, CharacterAttributePair> generalAttributes = new SerializedDictionary<string, float, CharacterAttributePair>();
|
||||
|
||||
[TabGroup("Data", "属性"), PropertyOrder(22)]
|
||||
|
||||
@@ -40,13 +40,13 @@ namespace Continentis.MainGame.Character
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消耗体力
|
||||
/// 修改体力
|
||||
/// </summary>
|
||||
public void ModifyStamina(int staminaValue)
|
||||
public void ModifyStamina(int staminaValue, bool clampMax = false)
|
||||
{
|
||||
ModifyAttribute("Stamina", staminaValue);
|
||||
ClampAttribute("Stamina", 0, GetAttribute("MaximumStamina"));
|
||||
|
||||
ClampAttribute("Stamina", 0, clampMax ? GetAttribute("MaximumStamina") : int.MaxValue);
|
||||
|
||||
if (this is PlayerHero)
|
||||
{
|
||||
CombatUIManager.Instance.combatMainPage.combatResourcesDisplayer.UpdateIcons();
|
||||
@@ -64,11 +64,11 @@ namespace Continentis.MainGame.Character
|
||||
/// <summary>
|
||||
/// 消耗魔法
|
||||
/// </summary>
|
||||
public void ModifyMana(int manaValue)
|
||||
public void ModifyMana(int manaValue, bool clampMax = false)
|
||||
{
|
||||
ModifyAttribute("Mana", manaValue);
|
||||
ClampAttribute("Mana", 0, GetAttribute("MaximumMana"));
|
||||
|
||||
ClampAttribute("Mana", 0, clampMax ? GetAttribute("MaximumMana") : int.MaxValue);
|
||||
|
||||
if (this is PlayerHero)
|
||||
{
|
||||
CombatUIManager.Instance.combatMainPage.combatResourcesDisplayer.UpdateIcons();
|
||||
@@ -387,9 +387,9 @@ namespace Continentis.MainGame.Character
|
||||
/// <summary>
|
||||
/// 添加临时生命(不会自动清空)
|
||||
/// </summary>
|
||||
public void AddShield(int shield, CharacterBase target = null)
|
||||
public void AddTemporaryHealth(int tempHealth, CharacterBase target = null)
|
||||
{
|
||||
int baseShieldAfterOffset = shield + GetAttribute("TemporaryHealthGainOffset");
|
||||
int baseShieldAfterOffset = tempHealth + GetAttribute("TemporaryHealthGainOffset");
|
||||
int finalShield = Mathf.RoundToInt(baseShieldAfterOffset * GetRawAttribute("TemporaryHealthGainMultiplier", 1));
|
||||
|
||||
target ??= this;
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Continentis.MainGame.Rules;
|
||||
using SLSFramework.General;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame.Character
|
||||
{
|
||||
public partial class AttributeSubmodule : SubmoduleBase<CharacterBase>
|
||||
{
|
||||
public AttributeGroup coreAttributeGroup;
|
||||
public AttributeGroup generalAttributeGroup;
|
||||
|
||||
public AttributeSubmodule(CharacterBase character) : base(character)
|
||||
@@ -19,10 +16,7 @@ namespace Continentis.MainGame.Character
|
||||
|
||||
private void Initialize(CharacterData characterData)
|
||||
{
|
||||
coreAttributeGroup = new AttributeGroup(characterData.coreAttributes.ToDictionary());
|
||||
generalAttributeGroup = new AttributeGroup(characterData.generalAttributes.ToDictionary());
|
||||
|
||||
RulesManager.Instance.attributeRulesMerger.convertCoreIntoGeneral(coreAttributeGroup.current, generalAttributeGroup.original);
|
||||
generalAttributeGroup.ApplyAllAttributes();
|
||||
generalAttributeGroup.SetUpEndowments(characterData.runtimeGeneralAttributes.ToDictionary());
|
||||
}
|
||||
@@ -30,16 +24,6 @@ namespace Continentis.MainGame.Character
|
||||
|
||||
public partial class AttributeSubmodule
|
||||
{
|
||||
public float GetRawCurrentCoreAttribute(string attributeName, float defaultValue = 0)
|
||||
{
|
||||
return coreAttributeGroup.current.GetValueOrDefault(attributeName, defaultValue);
|
||||
}
|
||||
|
||||
public int GetCurrentCoreAttribute(string attributeName, int defaultValue = 0)
|
||||
{
|
||||
return coreAttributeGroup.current.GetRoundValue(attributeName, defaultValue);
|
||||
}
|
||||
|
||||
public float GetRawGeneralAttribute(string attributeName, float defaultValue = 0)
|
||||
{
|
||||
return generalAttributeGroup.current.GetValueOrDefault(attributeName, defaultValue);
|
||||
@@ -51,80 +35,6 @@ namespace Continentis.MainGame.Character
|
||||
}
|
||||
}
|
||||
|
||||
public partial class AttributeSubmodule
|
||||
{
|
||||
/// <summary>
|
||||
/// 得出对某个核心属性的检定成功概率
|
||||
/// 计算方式为:达到需求值为100%,每低于1点属性值,成功率降低20%。
|
||||
/// </summary>
|
||||
/// <param name="coreAttributeName">属性名</param>
|
||||
/// <param name="requirement">需求值</param>
|
||||
/// <param name="higherPass">设true为高于需求值算作通过(probability),如果为false,则最终概率为(1-probability)</param>
|
||||
/// <param name="additionalAmount">额外加成</param>
|
||||
/// <returns>最终概率</returns>
|
||||
public float Probability(string coreAttributeName, int requirement, bool higherPass = true, int additionalAmount = 0)
|
||||
{
|
||||
return Probability(GetCurrentCoreAttribute(coreAttributeName), requirement, higherPass, additionalAmount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对某个核心属性进行检定
|
||||
/// </summary>
|
||||
/// <param name="coreAttributeName">属性名</param>
|
||||
/// <param name="requirement">需求值</param>
|
||||
/// <param name="higherPass">设true为高于需求值算作通过(probability),如果为false,则最终概率为(1-probability)</param>
|
||||
/// <param name="additionalAmount">额外加成</param>
|
||||
/// <returns>本次检定是否通过</returns>
|
||||
public bool Check(string coreAttributeName, int requirement, bool higherPass = true, int additionalAmount = 0)
|
||||
{
|
||||
return Check(GetCurrentCoreAttribute(coreAttributeName), requirement, higherPass, additionalAmount);
|
||||
}
|
||||
|
||||
private float Calculate(int value, int requirement)
|
||||
{
|
||||
int difference = value - requirement;
|
||||
return Mathf.Clamp01(1 + difference * 0.2f);
|
||||
}
|
||||
|
||||
private float Probability(int attributeValue, int requirement, bool higherPass = true, int additionalAmount = 0)
|
||||
{
|
||||
float probability = Calculate(attributeValue + additionalAmount, requirement);
|
||||
return higherPass ? probability : 1 - probability;
|
||||
}
|
||||
|
||||
private bool Check(int attributeValue, int requirement, bool higherPass = true, int additionalAmount = 0)
|
||||
{
|
||||
float baseProbability = Probability(attributeValue, requirement, higherPass, additionalAmount);
|
||||
return baseProbability >= Random.Range(0f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class AttributeSubmodule
|
||||
{
|
||||
public void RefreshCoreAttribute(string attributeName)
|
||||
{
|
||||
coreAttributeGroup.ResetAttribute(attributeName);
|
||||
|
||||
owner.equipmentSubmodule.GetCoreAttributeChange(attributeName, out float e_numeric, out float e_pAccumulation, out float e_pMultiplication);
|
||||
owner.combatBuffSubmodule.GetCoreAttributeChange(attributeName, out float cb_numeric, out float cb_pAccumulation, out float cb_pMultiplication);
|
||||
|
||||
float numeric = e_numeric + cb_numeric;
|
||||
float pAccumulation = e_pAccumulation + cb_pAccumulation;
|
||||
float pMultiplication = e_pMultiplication * cb_pMultiplication;
|
||||
coreAttributeGroup.ModifyAttribute(attributeName, numeric, pAccumulation, pMultiplication);
|
||||
|
||||
RulesManager.Instance.attributeRulesMerger.convertCoreIntoGeneral(coreAttributeGroup.current, generalAttributeGroup.original);
|
||||
}
|
||||
|
||||
public void RefreshAllCoreAttributes()
|
||||
{
|
||||
foreach (string attributeName in coreAttributeGroup.current.Keys)
|
||||
{
|
||||
RefreshCoreAttribute(attributeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class AttributeSubmodule
|
||||
{
|
||||
public void RefreshGeneralAttribute(string attributeName)
|
||||
@@ -138,8 +48,6 @@ namespace Continentis.MainGame.Character
|
||||
float pAccumulation = e_pAccumulation + cb_pAccumulation;
|
||||
float pMultiplication = e_pMultiplication * cb_pMultiplication;
|
||||
generalAttributeGroup.ModifyAttribute(attributeName, numeric, pAccumulation, pMultiplication);
|
||||
|
||||
//Debug.Log($"Refreshed general attribute: {attributeName}, new value: {generalAttributeGroup.current[attributeName]}");
|
||||
}
|
||||
|
||||
public void RefreshAllGeneralAttributes()
|
||||
@@ -149,15 +57,5 @@ namespace Continentis.MainGame.Character
|
||||
RefreshGeneralAttribute(attributeName);
|
||||
}
|
||||
}
|
||||
|
||||
private void ModifyGeneralAttributeFromEquipments(string attributeName)
|
||||
{
|
||||
/*EntityEquipmentModule equipmentModule = entity.equipmentModule;
|
||||
equipmentModule.GetAttributeChange(attributeName, out int numericChange,
|
||||
out float percentageChangeOfAccumulation, out float percentChangeOfMultiplication);
|
||||
currentCombatAttributes[attributeName] += numericChange;
|
||||
currentCombatAttributes[attributeName] = (int)((1 + percentageChangeOfAccumulation) * currentCombatAttributes[attributeName]);
|
||||
currentCombatAttributes[attributeName] = (int)(percentChangeOfMultiplication * currentCombatAttributes[attributeName]);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,25 +106,6 @@ namespace Continentis.MainGame.Character
|
||||
|
||||
public partial class CombatBuffSubmodule
|
||||
{
|
||||
public void GetCoreAttributeChange(string attributeName, out float numericChange,
|
||||
out float percentageChangeOfAccumulation, out float percentChangeOfMultiplication)
|
||||
{
|
||||
numericChange = buffList.Where(buff => buff.coreAttributeSubmodule != null)
|
||||
.SelectMany(buff => buff.coreAttributeSubmodule.numericChange)
|
||||
.Where(change => change.Key == attributeName)
|
||||
.Sum(change => change.Value);
|
||||
|
||||
percentageChangeOfAccumulation = buffList.Where(buff => buff.coreAttributeSubmodule != null)
|
||||
.SelectMany(buff => buff.coreAttributeSubmodule.percentageChangeOfAccumulation)
|
||||
.Where(change => change.Key == attributeName)
|
||||
.Sum(change => change.Value);
|
||||
|
||||
percentChangeOfMultiplication = buffList.Where(buff => buff.coreAttributeSubmodule != null)
|
||||
.SelectMany(buff => buff.coreAttributeSubmodule.percentageChangeOfMultiplication)
|
||||
.Where(change => change.Key == attributeName)
|
||||
.Aggregate<KeyValuePair<string, float>, float>(1, (current, change) => current * change.Value);
|
||||
}
|
||||
|
||||
public void GetGeneralAttributeChange(string attributeName, out float numericChange,
|
||||
out float percentageChangeOfAccumulation, out float percentChangeOfMultiplication)
|
||||
{
|
||||
|
||||
@@ -17,25 +17,6 @@ namespace Continentis.MainGame.Character
|
||||
|
||||
public partial class EquipmentSubmodule
|
||||
{
|
||||
public void GetCoreAttributeChange(string attributeName, out float numericChanges,
|
||||
out float percentageChangesOfAccumulation, out float percentChangesOfMultiplication)
|
||||
{
|
||||
numericChanges = currentEquipments
|
||||
.SelectMany(eq => eq.coreAttributeSubmodule.numericChange)
|
||||
.Where(change => change.Key == attributeName)
|
||||
.Sum(change => change.Value);
|
||||
|
||||
percentageChangesOfAccumulation = currentEquipments
|
||||
.SelectMany(eq => eq.coreAttributeSubmodule.percentageChangeOfAccumulation)
|
||||
.Where(change => change.Key == attributeName)
|
||||
.Sum(change => change.Value);
|
||||
|
||||
percentChangesOfMultiplication = currentEquipments
|
||||
.SelectMany(ew => ew.coreAttributeSubmodule.percentageChangeOfMultiplication)
|
||||
.Where(change => change.Key == attributeName)
|
||||
.Aggregate<KeyValuePair<string, float>, float>(1, (current, change) => current * change.Value);
|
||||
}
|
||||
|
||||
public void GetGeneralAttributeChange(string attributeName, out float numericChanges,
|
||||
out float percentageChangesOfAccumulation, out float percentChangesOfMultiplication)
|
||||
{
|
||||
|
||||
@@ -164,11 +164,9 @@ namespace Continentis.MainGame.Character
|
||||
[GUIColor(0.7f, 1f, 0.7f)]
|
||||
public void PasteDefaultAttributes()
|
||||
{
|
||||
if (coreAttributes == null) coreAttributes = new SLSUtilities.General.SerializedDictionary<string, float, CharacterAttributePair>();
|
||||
if (generalAttributes == null) generalAttributes = new SLSUtilities.General.SerializedDictionary<string, float, CharacterAttributePair>();
|
||||
if (runtimeGeneralAttributes == null) runtimeGeneralAttributes = new SLSUtilities.General.SerializedDictionary<string, string>();
|
||||
|
||||
coreAttributes.Clear();
|
||||
generalAttributes.Clear();
|
||||
runtimeGeneralAttributes.Clear();
|
||||
|
||||
@@ -181,18 +179,6 @@ namespace Continentis.MainGame.Character
|
||||
|
||||
foreach (var coll in collections)
|
||||
{
|
||||
if (coll.characterCoreAttributes != null)
|
||||
{
|
||||
foreach (var kvp in coll.characterCoreAttributes)
|
||||
{
|
||||
if (!coreAttributes.ContainsKey(kvp.Key))
|
||||
{
|
||||
float defaultVal = kvp.Key.Contains("Multiplier") ? 1f : 0f;
|
||||
coreAttributes.Add(kvp.Key, defaultVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (coll.characterGeneralAttributes != null)
|
||||
{
|
||||
foreach (var kvp in coll.characterGeneralAttributes)
|
||||
@@ -220,7 +206,7 @@ namespace Continentis.MainGame.Character
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(this);
|
||||
Debug.Log($"[CharacterData] '{this.name}' 提取完毕。从 {collections.Count} 个主库中提取了 {coreAttributes.Count} 个核心属性,{generalAttributes.Count} 个通用属性以及 {runtimeGeneralAttributes.Count} 个运行时约束!");
|
||||
Debug.Log($"[CharacterData] '{this.name}' 提取完毕。从 {collections.Count} 个主库中提取了 {generalAttributes.Count} 个属性以及 {runtimeGeneralAttributes.Count} 个运行时约束!");
|
||||
}
|
||||
|
||||
// ── 内部共享辅助方法 ─────────────────────────────────────────────────
|
||||
|
||||
@@ -15,8 +15,7 @@ namespace Continentis.MainGame.Equipment
|
||||
[Header("Base Info")] public Guid equipmentID;
|
||||
public List<string> tags;
|
||||
|
||||
[Header("Submodules")] public AttributeSubmodule coreAttributeSubmodule { get; private set; }
|
||||
public AttributeSubmodule generalAttributeSubmodule { get; private set; }
|
||||
[Header("Submodules")] public AttributeSubmodule generalAttributeSubmodule { get; private set; }
|
||||
public EventSubmodule eventSubmodule { get; private set; }
|
||||
public ContentSubmodule contentSubmodule { get; private set; }
|
||||
|
||||
@@ -24,8 +23,6 @@ namespace Continentis.MainGame.Equipment
|
||||
{
|
||||
this.equipmentID = Guid.NewGuid();
|
||||
this.tags = new List<string>(equipmentData.tags);
|
||||
this.coreAttributeSubmodule = new AttributeSubmodule(this, equipmentData.coreNumericChange,
|
||||
equipmentData.corePercentageChangeOfAccumulation, equipmentData.corePercentageChangeOfMultiplication);
|
||||
this.generalAttributeSubmodule = new AttributeSubmodule(this, equipmentData.generalNumericChange,
|
||||
equipmentData.generalPercentageChangeOfAccumulation,
|
||||
equipmentData.generalPercentageChangeOfMultiplication);
|
||||
@@ -38,26 +35,12 @@ namespace Continentis.MainGame.Equipment
|
||||
if (character != null)
|
||||
{
|
||||
this.character = character;
|
||||
this.character.equipmentSubmodule.currentEquipments.Add(this); //TODO: 后续换成装备函数
|
||||
this.character.equipmentSubmodule.currentEquipments.Add(this);
|
||||
|
||||
List<string> coreNames = coreAttributeSubmodule.GetModifiedAttributeNames();
|
||||
|
||||
if (coreNames.Count > 0)
|
||||
generalAttributeSubmodule.GetModifiedAttributeNames().ForEach(attributeName =>
|
||||
{
|
||||
coreAttributeSubmodule.GetModifiedAttributeNames().ForEach(attributeName =>
|
||||
{
|
||||
this.character.attributeSubmodule.RefreshCoreAttribute(attributeName);
|
||||
});
|
||||
|
||||
this.character.attributeSubmodule.RefreshAllGeneralAttributes();
|
||||
}
|
||||
else
|
||||
{
|
||||
generalAttributeSubmodule.GetModifiedAttributeNames().ForEach(attributeName =>
|
||||
{
|
||||
this.character.attributeSubmodule.RefreshGeneralAttribute(attributeName);
|
||||
});
|
||||
}
|
||||
this.character.attributeSubmodule.RefreshGeneralAttribute(attributeName);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,41 +64,21 @@ namespace Continentis.MainGame.Equipment
|
||||
[LabelText("装备描述 Key")]
|
||||
public string equipmentDescription;
|
||||
|
||||
// ── 核心属性变化 ──────────────────────────────────────────────────────
|
||||
// ── 属性变化 ──────────────────────────────────────────────────────
|
||||
|
||||
[TabGroup("Data", "核心属性"), PropertyOrder(20)]
|
||||
[DictionaryDrawerSettings(KeyLabel = "属性名", ValueLabel = "数值变化")]
|
||||
[Tooltip("对角色 CoreAttributes 施加固定数值加成")]
|
||||
[LabelText("数值变化 (Numeric)")]
|
||||
public SerializableDictionary<string, float> coreNumericChange = new SerializableDictionary<string, float>();
|
||||
|
||||
[TabGroup("Data", "核心属性"), PropertyOrder(21)]
|
||||
[DictionaryDrawerSettings(KeyLabel = "属性名", ValueLabel = "百分比(累加)")]
|
||||
[Tooltip("对角色 CoreAttributes 施加百分比累加加成(如 +10% 填写 0.1)")]
|
||||
[LabelText("百分比变化—累加 (Accum%)")]
|
||||
public SerializableDictionary<string, float> corePercentageChangeOfAccumulation = new SerializableDictionary<string, float>();
|
||||
|
||||
[TabGroup("Data", "核心属性"), PropertyOrder(22)]
|
||||
[DictionaryDrawerSettings(KeyLabel = "属性名", ValueLabel = "百分比(乘法)")]
|
||||
[Tooltip("对角色 CoreAttributes 施加百分比乘法加成")]
|
||||
[LabelText("百分比变化—乘法 (Multi%)")]
|
||||
public SerializableDictionary<string, float> corePercentageChangeOfMultiplication = new SerializableDictionary<string, float>();
|
||||
|
||||
// ── 通用属性变化 ──────────────────────────────────────────────────────
|
||||
|
||||
[TabGroup("Data", "通用属性"), PropertyOrder(30)]
|
||||
[TabGroup("Data", "属性"), PropertyOrder(20)]
|
||||
[DictionaryDrawerSettings(KeyLabel = "属性名", ValueLabel = "数值变化")]
|
||||
[Tooltip("对角色 GeneralAttributes 施加固定数值加成")]
|
||||
[LabelText("数值变化 (Numeric)")]
|
||||
public SerializableDictionary<string, float> generalNumericChange = new SerializableDictionary<string, float>();
|
||||
|
||||
[TabGroup("Data", "通用属性"), PropertyOrder(31)]
|
||||
[TabGroup("Data", "属性"), PropertyOrder(21)]
|
||||
[DictionaryDrawerSettings(KeyLabel = "属性名", ValueLabel = "百分比(累加)")]
|
||||
[Tooltip("对角色 GeneralAttributes 施加百分比累加加成(如 +10% 填写 0.1)")]
|
||||
[LabelText("百分比变化—累加 (Accum%)")]
|
||||
public SerializableDictionary<string, float> generalPercentageChangeOfAccumulation = new SerializableDictionary<string, float>();
|
||||
|
||||
[TabGroup("Data", "通用属性"), PropertyOrder(32)]
|
||||
[TabGroup("Data", "属性"), PropertyOrder(22)]
|
||||
[DictionaryDrawerSettings(KeyLabel = "属性名", ValueLabel = "百分比(乘法)")]
|
||||
[Tooltip("对角色 GeneralAttributes 施加百分比乘法加成")]
|
||||
[LabelText("百分比变化—乘法 (Multi%)")]
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Continentis.MainGame
|
||||
continue;
|
||||
}
|
||||
|
||||
int maxHP = Mathf.RoundToInt(data.coreAttributes.TryGetValue("MaximumHealth", out float hp) ? hp : 0f);
|
||||
int maxHP = Mathf.RoundToInt(data.generalAttributes.TryGetValue("MaximumHealth", out float hp) ? hp : 0f);
|
||||
HeroSave hero = new HeroSave(heroID, maxHP, maxHP);
|
||||
|
||||
foreach (string cardID in data.initialDeckRef)
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame.Rules
|
||||
{
|
||||
public class AttributeRulesCollectionBase : RulesCollectionBase
|
||||
{
|
||||
public virtual void ApplyRules_ConvertCoreIntoGeneral(Dictionary<string, float> core, Dictionary<string, float> general)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Continentis.MainGame.Rules
|
||||
{
|
||||
public class AttributeRulesMerger
|
||||
{
|
||||
public List<AttributeRulesCollectionBase> rulesCollections;
|
||||
|
||||
public UnityAction<Dictionary<string, float>, Dictionary<string, float>> convertCoreIntoGeneral;
|
||||
|
||||
public AttributeRulesMerger()
|
||||
{
|
||||
rulesCollections = new List<AttributeRulesCollectionBase>();
|
||||
convertCoreIntoGeneral = (coreAttributes, generalAttributes) => { };
|
||||
}
|
||||
|
||||
public void ApplyRules()
|
||||
{
|
||||
rulesCollections.Sort();
|
||||
|
||||
foreach (var rules in rulesCollections)
|
||||
{
|
||||
convertCoreIntoGeneral += rules.ApplyRules_ConvertCoreIntoGeneral;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using Continentis.MainGame;
|
||||
using Continentis.MainGame.Card;
|
||||
using I2.Loc;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -20,6 +22,18 @@ namespace SLSFramework.General
|
||||
return original;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 本地化字符串,并使用卡牌上下文解析 $Attribute / $Keyword 等文本内函数
|
||||
/// </summary>
|
||||
/// <param name="original">本地化 Key</param>
|
||||
/// <param name="card">提供属性上下文的卡牌实例</param>
|
||||
/// <returns>翻译并解析后的最终文本</returns>
|
||||
public static string Localize(this string original, CardInstance card)
|
||||
{
|
||||
string translated = original.Localize();
|
||||
return CardTextInterpreter.InterpretText(card, translated);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 本地化字符串,使用指定的根GameObject进行i2Loc参数替换
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user