using SepCore.Definition; using UnityEngine; namespace SepCore.Battle { /// /// 伤害结算管线(纯 C# 静态计算器)。 /// 实现武器类型加成、百分比放大、闪避判定、暴击判定、双曲护甲折减、保底伤害与生命偷取判定。 /// public static class DamagePipeline { public const float ArmorDivisor = 15f; // Brotato 双曲护甲基数 public const float DefaultCritMultiplier = 1.5f; public const float DefaultBaseCrit = 0.05f; /// /// 计算最终伤害结果。 /// public static DamageResult Calculate(in DamageContext context) { // 1. 闪避判定 (Defender Dodge) float dodgeChance = context.DefenderPipeline != null ? context.DefenderPipeline.GetValue(StatType.Dodge) : context.FallbackDefenderDodge; float maxDodge = 0.8f; if (GameEntry.Luban != null && GameEntry.Luban.IsReady) { maxDodge = GameEntry.Luban.Global.MaxDodgeRate / 1000f; } dodgeChance = Mathf.Clamp(dodgeChance, 0f, maxDodge); if (dodgeChance > 0f && Random.value < dodgeChance) { return new DamageResult { Damage = 0, IsDodge = true, IsCrit = false, IsLifeSteal = false, LifeStealAmount = 0 }; } // 2. 武器类型伤害加成 (Melee / Ranged / Elemental) float rawDamage = context.BaseDamage; if (context.AttackerPipeline != null && context.DamageScalingStat != StatType.None) { float scalingBonus = context.AttackerPipeline.GetValue(context.DamageScalingStat); float ratio = context.ScalingRatio > 0f ? context.ScalingRatio : 1f; rawDamage += scalingBonus * ratio; } rawDamage = Mathf.Max(rawDamage, 1f); // 3. 全局百分比增伤放大 (DamagePercent) float damagePercent = context.AttackerPipeline != null ? context.AttackerPipeline.GetValue(StatType.DamagePercent) : 0f; float amplifiedDamage = rawDamage * (1f + damagePercent); amplifiedDamage = Mathf.Max(amplifiedDamage, 1f); // 4. 暴击判定 (CritChance & CritMultiplier) float attackerCrit = context.AttackerPipeline != null ? context.AttackerPipeline.GetValue(StatType.CritChance) : 0f; float baseCrit = context.BaseCritChance; if (baseCrit <= 0f && GameEntry.Luban != null && GameEntry.Luban.IsReady) { baseCrit = GameEntry.Luban.Global.WeaponBaseCrit; } float totalCritChance = Mathf.Clamp(baseCrit + attackerCrit, 0f, 0.9f); bool isCrit = totalCritChance > 0f && Random.value < totalCritChance; float critMultiplier = context.CritMultiplier; if (critMultiplier <= 0f) { critMultiplier = GameEntry.Luban != null && GameEntry.Luban.IsReady ? GameEntry.Luban.Global.CritMultiplier : DefaultCritMultiplier; } float damageAfterCrit = isCrit ? (amplifiedDamage * critMultiplier) : amplifiedDamage; // 5. Brotato 标准双曲护甲折减 (Armor Mitigation) float armor = context.DefenderPipeline != null ? context.DefenderPipeline.GetValue(StatType.Armor) : context.FallbackDefenderArmor; float mitigation; if (armor >= 0f) { mitigation = 1f / (1f + armor / ArmorDivisor); } else { // 负护甲易伤放大: 2 - 1/(1 - armor/15) mitigation = 2f - (1f / (1f - armor / ArmorDivisor)); } float finalDamageFloat = damageAfterCrit * mitigation; int minDamage = 1; if (GameEntry.Luban != null && GameEntry.Luban.IsReady) { minDamage = GameEntry.Luban.Global.MinDamage; } int finalDamage = Mathf.Max(Mathf.CeilToInt(finalDamageFloat), minDamage); // 6. 生命偷取判定 (LifeSteal) bool isLifeSteal = false; int lifeStealAmount = 0; if (finalDamage > 0 && context.AttackerPipeline != null) { float lifeStealRate = context.AttackerPipeline.GetValue(StatType.LifeSteal); if (lifeStealRate > 0f && Random.value < lifeStealRate) { isLifeSteal = true; lifeStealAmount = 1; } } return new DamageResult { Damage = finalDamage, IsDodge = false, IsCrit = isCrit, IsLifeSteal = isLifeSteal, LifeStealAmount = lifeStealAmount }; } } }