2025-10-23 00:49:44 -04:00
|
|
|
|
using System;
|
2025-10-03 00:02:43 -04:00
|
|
|
|
using System.Collections.Generic;
|
2025-10-23 00:49:44 -04:00
|
|
|
|
using System.Linq;
|
2025-10-03 00:02:43 -04:00
|
|
|
|
using Continentis.MainGame.Character;
|
2025-10-23 00:49:44 -04:00
|
|
|
|
using Continentis.MainGame.Commands;
|
|
|
|
|
|
using NUnit.Framework;
|
|
|
|
|
|
using SLSFramework.General;
|
2025-10-03 00:02:43 -04:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Continentis.MainGame.Card
|
|
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
#region Fundamental
|
2025-10-03 00:02:43 -04:00
|
|
|
|
public partial class CardLogicBase
|
|
|
|
|
|
{
|
|
|
|
|
|
public bool HasTag(string tag)
|
|
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
return tags.Contains(tag);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public List<string> GetElementTags(List<string> tags = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
tags ??= this.tags;
|
|
|
|
|
|
return tags.Filtered((tag) => MainGameManager.Instance.elementTags.Contains(tag));
|
2025-10-03 00:02:43 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool HasKeyword(string keyword)
|
|
|
|
|
|
{
|
|
|
|
|
|
return contentSubmodule.keywords.Contains(keyword);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-23 00:49:44 -04:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Command
|
|
|
|
|
|
|
|
|
|
|
|
public partial class CardLogicBase
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建一个命令组,组内命令按顺序执行
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="commands">命令模板</param>
|
|
|
|
|
|
protected CommandGroup SingleCommandGroup(params CommandBase[] commands)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SingleCommandGroup(ExecutionMode.Parallel, commands);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建一个命令组,组内命令按指定顺序执行
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="executionMode">执行模式,顺序或并行</param>
|
|
|
|
|
|
/// <param name="commands">命令模板</param>
|
|
|
|
|
|
protected virtual CommandGroup SingleCommandGroup(
|
|
|
|
|
|
ExecutionMode executionMode = ExecutionMode.Parallel, params CommandBase[] commands)
|
|
|
|
|
|
{
|
|
|
|
|
|
CommandGroup singleGroup = new CommandGroup(executionMode);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (CommandBase template in commands)
|
|
|
|
|
|
{
|
|
|
|
|
|
singleGroup.AddCommand(template.Clone());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return singleGroup;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 对目标列表中的每个目标,依次执行一组有参函数命令,每组命令的参数为targetList中的个体,主体Group顺序执行,单体Group并行执行。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="targetList">目标列表</param>
|
|
|
|
|
|
/// <param name="singleCommands">单体命令模板</param>
|
|
|
|
|
|
protected CommandGroup TargetListCommandGroup(List<CharacterBase> targetList,
|
|
|
|
|
|
params CommandBase[] singleCommands)
|
|
|
|
|
|
{
|
|
|
|
|
|
return TargetListCommandGroup(targetList, ExecutionMode.Sequential, ExecutionMode.Parallel, singleCommands);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 对目标列表中的每个目标,依次执行一组有参函数命令,每组命令的参数为targetList中的个体。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="targetList">目标列表</param>
|
|
|
|
|
|
/// <param name="mainExecutionMode">主体Group(各个目标)的执行顺序</param>
|
|
|
|
|
|
/// <param name="singleExecutionMode">单体Group(一个目标中指令)的执行顺序</param>
|
|
|
|
|
|
/// <param name="singleCommands">单体命令模板</param>
|
|
|
|
|
|
protected virtual CommandGroup TargetListCommandGroup(
|
|
|
|
|
|
List<CharacterBase> targetList, ExecutionMode mainExecutionMode = ExecutionMode.Sequential,
|
|
|
|
|
|
ExecutionMode singleExecutionMode = ExecutionMode.Parallel,
|
|
|
|
|
|
params CommandBase[] singleCommands)
|
|
|
|
|
|
{
|
|
|
|
|
|
CommandGroup mainGroup = new CommandGroup(mainExecutionMode);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (CharacterBase target in targetList)
|
|
|
|
|
|
{
|
|
|
|
|
|
CommandGroup singleGroup = new CommandGroup(singleExecutionMode);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (CommandBase template in singleCommands)
|
|
|
|
|
|
{
|
|
|
|
|
|
CommandBase clone = template.Clone();
|
|
|
|
|
|
|
|
|
|
|
|
if (clone is CommandGroup group)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (CommandBase cmd in group.commands)
|
|
|
|
|
|
{
|
|
|
|
|
|
cmd.selfContext.context["Target"] = target;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
clone.selfContext.context["Target"] = target;
|
|
|
|
|
|
singleGroup.AddCommand(clone);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mainGroup.AddCommand(singleGroup);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return mainGroup;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-03 00:02:43 -04:00
|
|
|
|
|
2025-10-23 00:49:44 -04:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Attack
|
2025-10-03 00:02:43 -04:00
|
|
|
|
public partial class CardLogicBase
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取最终伤害
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="target">目标</param>
|
|
|
|
|
|
/// <param name="elementalTags">元素标签,若为null则使用卡牌的元素标签</param>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
public virtual int GetFinalDamage(CharacterBase target, List<string> elementalTags = null)
|
2025-10-03 00:02:43 -04:00
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
return GetFinalDamage(target, elementalTags, out _, out _, out _, out _);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual int GetFinalDamage(CharacterBase target, List<string> elementalTags,
|
|
|
|
|
|
out float baseDamageAfterOffset, out float elementalMultiplier, out float magicMultiplier, out float finalMultiplier)
|
|
|
|
|
|
{
|
|
|
|
|
|
elementalTags ??= GetElementTags();
|
|
|
|
|
|
|
|
|
|
|
|
//----计算基础伤害增量----
|
|
|
|
|
|
int physicsOffset = 0;
|
|
|
|
|
|
if (HasTag("Physics") || HasKeyword("Slash") || HasKeyword("Prick") || HasKeyword("Strike"))
|
2025-10-03 00:02:43 -04:00
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
physicsOffset = user.GetAttribute("PhysicsDamageDealtOffset"); //物理伤害基础增量
|
2025-10-03 00:02:43 -04:00
|
|
|
|
}
|
2025-10-23 00:49:44 -04:00
|
|
|
|
|
|
|
|
|
|
int magicOffset = 0;
|
|
|
|
|
|
if (HasTag("Magic") || HasKeyword("Arcane") || HasKeyword("Sorcery"))
|
|
|
|
|
|
{
|
|
|
|
|
|
magicOffset = user.GetAttribute("MagicDamageDealtOffset"); //魔法伤害基础增量
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----计算伤害因数----
|
2025-10-03 00:02:43 -04:00
|
|
|
|
|
2025-10-23 00:49:44 -04:00
|
|
|
|
//计算元素伤害加成,注意,“物理Physics”也是一种元素,因此下方没有“通用物理伤害加成”的计算
|
|
|
|
|
|
elementalMultiplier = 1;
|
|
|
|
|
|
foreach (string element in elementalTags)
|
|
|
|
|
|
{
|
|
|
|
|
|
elementalMultiplier *= user.GetRawAttribute(element + "DamageDealtMultiplier", 1) *
|
|
|
|
|
|
target.GetRawAttribute(element + "DamageGainMultiplier", 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//计算通用的魔法伤害加成
|
|
|
|
|
|
magicMultiplier = 1;
|
|
|
|
|
|
if (HasTag("Magic") || HasKeyword("Arcane") || HasKeyword("Sorcery"))
|
|
|
|
|
|
{
|
|
|
|
|
|
magicMultiplier = user.GetRawAttribute("MagicDamageDealtMultiplier", 1) *
|
|
|
|
|
|
target.GetRawAttribute("MagicDamageGainMultiplier", 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//计算最终伤害加成
|
|
|
|
|
|
finalMultiplier = user.GetRawAttribute("FinalDamageDealtMultiplier", 1) *
|
|
|
|
|
|
target.GetRawAttribute("FinalDamageGainMultiplier", 1);
|
|
|
|
|
|
|
|
|
|
|
|
//----计算最终伤害----
|
|
|
|
|
|
baseDamageAfterOffset = attributeSubmodule.GetCurrentAttribute("Damage") + physicsOffset + magicOffset;
|
|
|
|
|
|
|
|
|
|
|
|
float finalDamage = baseDamageAfterOffset * elementalMultiplier * magicMultiplier * finalMultiplier;
|
2025-10-03 00:02:43 -04:00
|
|
|
|
|
|
|
|
|
|
return Mathf.RoundToInt(finalDamage);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-23 00:49:44 -04:00
|
|
|
|
#endregion
|
2025-10-03 00:02:43 -04:00
|
|
|
|
|
|
|
|
|
|
#region Attributes
|
|
|
|
|
|
public partial class CardLogicBase
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 设置可变属性值
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="attributeName">属性名,通常为</param>
|
|
|
|
|
|
/// <param name="additive">是否为叠加,true为叠加,false为覆盖,true时,originalValue为外部传入值</param>
|
|
|
|
|
|
/// <param name="originalValue">原始伤害值,仅在additive为true时有效,否则此值被覆盖为BaseAttribute</param>
|
|
|
|
|
|
/// <param name="baseOffset">伤害增量</param>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
public void SetVariableAttribute(string attributeName, int baseOffset, bool additive = false, int originalValue = 0)
|
2025-10-03 00:02:43 -04:00
|
|
|
|
{
|
|
|
|
|
|
string baseName = "Base" + attributeName;
|
|
|
|
|
|
string baseOffsetName = baseName + "Offset";
|
|
|
|
|
|
|
|
|
|
|
|
if (!additive) originalValue = GetAttribute(baseName);
|
|
|
|
|
|
|
|
|
|
|
|
SetAttribute(attributeName, originalValue);
|
|
|
|
|
|
SetAttribute(baseOffsetName, baseOffset);
|
|
|
|
|
|
ModifyAttribute(attributeName, baseOffset);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
/// 检查卡牌是否具有某属性
|
2025-10-03 00:02:43 -04:00
|
|
|
|
/// </summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
public bool HasAttribute(string attributeName)
|
2025-10-03 00:02:43 -04:00
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
return attributeSubmodule.attributeGroup.current.ContainsKey(attributeName);
|
2025-10-03 00:02:43 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
/// 获取卡牌的属性值
|
2025-10-03 00:02:43 -04:00
|
|
|
|
/// </summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
public int GetAttribute(string attributeName, int defaultValue = 0)
|
2025-10-03 00:02:43 -04:00
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
return attributeSubmodule.GetRoundCurrentAttribute(attributeName, defaultValue);
|
2025-10-03 00:02:43 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 00:49:44 -04:00
|
|
|
|
public float GetRawAttribute(string attributeName, float defaultValue = 0)
|
2025-10-03 00:02:43 -04:00
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
return attributeSubmodule.GetCurrentAttribute(attributeName, defaultValue);
|
2025-10-03 00:02:43 -04:00
|
|
|
|
}
|
2025-10-23 00:49:44 -04:00
|
|
|
|
|
2025-10-03 00:02:43 -04:00
|
|
|
|
/// <summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
/// 设置卡牌的属性值
|
2025-10-03 00:02:43 -04:00
|
|
|
|
/// </summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
public void SetAttribute(string attributeName, int value)
|
2025-10-03 00:02:43 -04:00
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
attributeSubmodule.attributeGroup.current[attributeName] = value;
|
2025-10-03 00:02:43 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
/// 设置卡牌的属性值
|
2025-10-03 00:02:43 -04:00
|
|
|
|
/// </summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
public void SetAttribute(string attributeName, float value)
|
2025-10-03 00:02:43 -04:00
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
attributeSubmodule.attributeGroup.current[attributeName] = value;
|
2025-10-03 00:02:43 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
/// 修改卡牌的属性值
|
2025-10-03 00:02:43 -04:00
|
|
|
|
/// </summary>
|
2025-10-23 00:49:44 -04:00
|
|
|
|
public void ModifyAttribute(string attributeName, int delta)
|
2025-10-03 00:02:43 -04:00
|
|
|
|
{
|
2025-10-23 00:49:44 -04:00
|
|
|
|
attributeSubmodule.attributeGroup.current[attributeName] += delta;
|
2025-10-03 00:02:43 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-23 00:49:44 -04:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region CombatResoures
|
|
|
|
|
|
public partial class CardLogicBase
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
2025-10-03 00:02:43 -04:00
|
|
|
|
}
|