209 lines
7.0 KiB
C#
209 lines
7.0 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using Cielonos.MainGame.Characters;
|
||
using SLSUtilities.General;
|
||
using SLSUtilities.FunctionalAnimation;
|
||
using UnityEngine;
|
||
|
||
namespace Cielonos.MainGame
|
||
{
|
||
public static class Attack
|
||
{
|
||
public enum Type
|
||
{
|
||
Energy = 1,
|
||
Kinetics = 2,
|
||
Explosion = 3,
|
||
Magic = 4,
|
||
Pure = 5,
|
||
Blank = 6, // 代表不具有特定攻击类型的伤害,例如持续伤害、反伤等
|
||
}
|
||
|
||
public static string AttackTypeToString(this Type type)
|
||
{
|
||
return type switch
|
||
{
|
||
Type.Energy => "Energy",
|
||
Type.Kinetics => "Kinetics",
|
||
Type.Explosion => "Explosion",
|
||
Type.Magic => "Magic",
|
||
Type.Pure => "Pure",
|
||
Type.Blank => "Blank",
|
||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||
};
|
||
}
|
||
|
||
public class Value : ICloneable<Value>
|
||
{
|
||
public bool isCritical;
|
||
public float damage;
|
||
public Type type;
|
||
public Breakthrough.Type breakthroughType;
|
||
public DisruptionType disruptionType;
|
||
public List<string> tags;
|
||
|
||
public float damageMultiplier = 1f;
|
||
public float additionalFlatDamage = 0f;
|
||
|
||
public Value(bool isCritical, float damage, Type type,
|
||
DisruptionType disruptionType = DisruptionType.None, Breakthrough.Type breakthroughType = Breakthrough.Type.None,
|
||
List<string> tags = null)
|
||
{
|
||
this.isCritical = isCritical;
|
||
this.damage = damage;
|
||
this.type = type;
|
||
this.disruptionType = disruptionType;
|
||
this.breakthroughType = breakthroughType;
|
||
this.tags = tags != null ? new List<string>(tags) : new List<string>();
|
||
}
|
||
|
||
public Value Clone()
|
||
{
|
||
Value cloned = new Value(isCritical, damage, type, disruptionType, breakthroughType, tags);
|
||
cloned.damageMultiplier = this.damageMultiplier;
|
||
cloned.additionalFlatDamage = this.additionalFlatDamage;
|
||
return cloned;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 攻击上下文:在伤害结算前传递,允许订阅者修改攻击参数和前置决策标记。
|
||
/// <para> 用于 onStartAttack / onBeforeGetAttacked 阶段。 </para>
|
||
/// </summary>
|
||
public class Context
|
||
{
|
||
public CharacterBase attacker;
|
||
public CharacterBase target;
|
||
public Vector3 hitPosition;
|
||
public string spamGroupID;
|
||
|
||
/// <summary>
|
||
/// 可修改的攻击值,订阅者可在结算前调整 damageMultiplier、additionalFlatDamage 等。
|
||
/// </summary>
|
||
public Value value;
|
||
|
||
/// <summary>
|
||
/// 前置否决标记:设为 true 则跳过伤害结算,攻击完全无效化。
|
||
/// </summary>
|
||
public bool isImmune;
|
||
|
||
/// <summary>
|
||
/// 前置否决标记:设为 true 则强制中断攻击流程。
|
||
/// </summary>
|
||
public bool isForcedInterrupt;
|
||
|
||
public Context(CharacterBase attacker, CharacterBase target,
|
||
string spamGroupMainPart, Vector3 hitPosition = default)
|
||
{
|
||
this.attacker = attacker;
|
||
this.target = target;
|
||
StringBuilder fullIDBuilder = new StringBuilder();
|
||
fullIDBuilder.Append(attacker is null ? "Null" : attacker.GetInstanceID().ToString());
|
||
fullIDBuilder.Append("_");
|
||
fullIDBuilder.Append(spamGroupMainPart);
|
||
fullIDBuilder.Append("_");
|
||
fullIDBuilder.Append(target is null ? "Null" : target.GetInstanceID().ToString());
|
||
this.spamGroupID = fullIDBuilder.ToString();
|
||
this.hitPosition = hitPosition;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 攻击结果:伤害结算完成后的数据载体,包含结算结果和对原始上下文的引用。
|
||
/// <para> 用于 onFinishAttack / onAfterGetAttacked 阶段。 </para>
|
||
/// </summary>
|
||
public class Result
|
||
{
|
||
/// <summary>
|
||
/// 引用原始攻击上下文,包含攻击参数和前置决策。
|
||
/// </summary>
|
||
public Context context;
|
||
|
||
public bool isBlocked;
|
||
public bool isDodged;
|
||
public bool isReflected;
|
||
public bool isMissed;
|
||
public bool isEvaded;
|
||
public bool causedDeath;
|
||
|
||
public float shieldBlockedDamage;
|
||
public float finalDamage;
|
||
|
||
// 便捷访问属性,代理到 Context
|
||
public CharacterBase attacker => context.attacker;
|
||
public CharacterBase target => context.target;
|
||
public Vector3 hitPosition => context.hitPosition;
|
||
public string spamGroupID => context.spamGroupID;
|
||
|
||
public Value value
|
||
{
|
||
get => context.value;
|
||
set => context.value = value;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从已有上下文构建结果。用于标准攻击流程:Context 阶段完成后包装为 Result。
|
||
/// </summary>
|
||
public Result(Context context)
|
||
{
|
||
this.context = context;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 直接从参数构建结果,用于Buff直接附伤等流程。会自动构建 Context 并关联 Value。
|
||
/// </summary>
|
||
public Result(Context context, Value value)
|
||
{
|
||
this.context = context;
|
||
this.value = value;
|
||
}
|
||
}
|
||
}
|
||
|
||
public static class Breakthrough
|
||
{
|
||
public enum Type
|
||
{
|
||
None = 0,
|
||
Weak = 10,
|
||
Medium = 20,
|
||
Heavy = 30,
|
||
Disruption = 40,
|
||
Forced = 50,
|
||
Unstoppable = 100 // 不可用于攻击,只能用于防御状态,表示无法被打断
|
||
}
|
||
|
||
public static readonly List<Type> Types = new List<Type>()
|
||
{
|
||
Type.None,
|
||
Type.Weak,
|
||
Type.Medium,
|
||
Type.Heavy,
|
||
Type.Disruption,
|
||
Type.Forced,
|
||
Type.Unstoppable
|
||
};
|
||
|
||
public static List<Type> GetLowerTypes(Type type)
|
||
{
|
||
return Types.Where(t => t < type).ToList();
|
||
}
|
||
|
||
public static List<Type> GetEqualOrLowerTypes(Type type)
|
||
{
|
||
return Types.Where(t => t <= type).ToList();
|
||
}
|
||
|
||
public static List<Type> GetHigherTypes(Type type)
|
||
{
|
||
return Types.Where(t => t > type).ToList();
|
||
}
|
||
|
||
public static List<Type> GetEqualOrHigherTypes(Type type)
|
||
{
|
||
return Types.Where(t => t >= type).ToList();
|
||
}
|
||
}
|
||
} |