2026-04-24 18:22:21 +08:00

344 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: 白哉
* @Description: 古明地恐惧技能
* @Date: 2026年03月06日
* @Modify: 逻辑-视觉解耦视觉效果改为走PresentationManager队列播放
*/
using System.Collections.Generic;
using Logic.Pool;
using RuntimeData;
using Logic.CrashSight;
using TH1_Anim.Fragments;
using TH1_Core.Managers;
using TH1_Logic.Core;
using TH1_Renderer;
using TH1Renderer;
namespace Logic.Skill
{
public partial class KomeijiFearSkill : SkillBase
{
// 爆炸链锁定:当任意一次爆炸正在进行时,传播的恐惧不会触发二次爆炸
private static bool _isInExplosionChain = false;
public KomeijiFearSkill()
{
IsPermanent = true;
TurnsLimit = 0;
Score = 4;
IsLevelSkill = true;
// 层数无上限但超过2层时会触发爆炸减少2层
_levelLimit = int.MaxValue;
}
public override SkillType GetSkillType()
{
return SkillType.KomeijiFear;
}
public override float GetDefenseMultiplicationParam(MapData mapData, UnitData self, UnitData target = null)
{
return 0.7f;
}
public override void AddLevel(MapData map, UnitData origin, UnitData self, int add)
{
// 先增加层数不调用base.AddLevel避免被_levelLimit限制
_level += add;
// 只有链的发起者才传播恐惧;同一单位多次爆炸也只有第一次传播
bool isChainStarter = !_isInExplosionChain;
if (isChainStarter) _isInExplosionChain = true;
bool canSpread = isChainStarter;
while (_level > 2)
{
Explode(map, self, false, canSpread);
canSpread = false; // 同一单位后续爆炸不再传播
}
if (isChainStarter) _isInExplosionChain = false;
// 通知英雄任务
if (map.GetPlayerDataByUnitId(origin.Id, out var player) && origin.HeroTask(map) != null)
{
origin.HeroTask(map).OnAddSkillLevels(map, GetSkillType(), (uint)add);
}
}
/// <summary>
/// 自身死亡时触发爆炸
/// </summary>
public override void OnAnyUnitDie(MapData map, UnitData self, UnitData dieUnit)
{
// 只有自身死亡时才触发
if (dieUnit == null || self == null || dieUnit.Id != self.Id) return;
// 死亡时触发爆炸
if (_level > 0)
{
bool isChainStarter = !_isInExplosionChain;
if (isChainStarter) _isInExplosionChain = true;
Explode(map, self, true, canSpread: isChainStarter);
if (isChainStarter) _isInExplosionChain = false;
}
}
/// <summary>
/// 爆炸逻辑 - 只处理数据变更视觉效果按scope模式延迟注入攻击Fragment
/// 非scope模式下走原有EnqueueSkillEffect直接入队。
/// </summary>
private void Explode(MapData map, UnitData self, bool isDeathExplode, bool canSpread)
{
var grid = self?.Grid(map);
if (map == null || self == null || grid == null)
{
LogSystem.LogError($"Explode Error self : {self}, grid : {grid}");
return;
}
bool isMainMap = map == Main.MapData;
var scope = isMainMap ? PresentationManager.CurrentScope : null;
// 统一 phase所有爆炸链视觉都排在攻击命中后250
int phase = AnimPhase.AttackImpact + 50;
// 非scope模式下使用旧的 SkillVisualStep 批量入队路径
List<SkillVisualStep> visualSteps = (isMainMap && scope == null) ? new List<SkillVisualStep>() : null;
// 收集需要刷新外观的存活单位
using var pooledUnitsToRefresh = THCollectionPool.GetListHandle<uint>(out var unitsToRefresh);
if (_level >= 2)
{
// ===== 2层及以上爆炸 =====
_level -= 2;
// 先对周围1格范围造成伤害必须在自伤之前否则自伤死亡会清除grid绑定
// 导致后续DamageSettlement因找不到origin的grid而失败
var aroundBuf = RentAroundBuf();
map.GridMap.GetAroundGridData(1, 1, grid, aroundBuf);
foreach (var around in aroundBuf)
{
if (!around.RealUnit(map, out var target)) continue;
if (target.Id != self.Id && !target.GetSkill(SkillType.KomeijiFearImmune, out _))
{
// 在DamageSettlement之前缓存Renderer引用死亡后可能无法获取
var targetRenderer = isMainMap ? target.Renderer(map) : null;
var aroundRenderer = isMainMap ? around.Renderer(map) : null;
Main.UnitLogic.DamageSettlement(map, self, target, 2, DamageType.KillSelf);
if (target.IsAlive())
{
if (canSpread)
{
target.AddOrOverrideSkill(SkillType.KomeijiFear, map, self.Id);
// 播放恐惧VFX
if (scope != null)
{
var rendererForStep = aroundRenderer;
scope.Add(new FragmentStep
{
Phase = phase,
Duration = 0f, // 方案1不阻塞后续phase
Execute = () => rendererForStep?.PlayVFXInSight(new GridVFXParams(GridVFXType.KomeijiFear))
});
}
else
{
aroundRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.KomeijiFear));
}
}
unitsToRefresh.Add(target.Id);
}
else if (isMainMap)
{
// 死亡加入视觉scope走FragmentStep非scope走SkillVisualStep批量
if (scope != null)
{
var gridRendererForStep = aroundRenderer;
var unitRendererForStep = targetRenderer;
var gridDataForStep = around;
scope.Add(new FragmentStep
{
Phase = phase,
Duration = 0f, // 方案1不阻塞后续phase
Execute = () =>
{
gridRendererForStep?.PlayVFXInSight(new GridVFXParams(GridVFXType.Die));
if (unitRendererForStep != null)
{
unitRendererForStep.Die();
if (gridDataForStep != null && MapRenderer.Instance != null && Main.MapData != null)
MapRenderer.Instance.UpdateAroundHighlight(Main.MapData, gridDataForStep);
}
gridRendererForStep?.InstantUpdateGrid();
}
});
}
else
{
visualSteps.Add(new SkillVisualStep
{
GridRenderer = aroundRenderer,
UnitRenderer = targetRenderer,
VFXList = new List<GridVFXParams> { new GridVFXParams(GridVFXType.Die) },
KillUnit = true,
RefreshGrid = true,
GridData = around,
});
}
}
}
}
ReturnAroundBuf();
// 再对自己造成伤害(仅非死亡触发时)
if (!isDeathExplode)
{
var selfRenderer = isMainMap ? self.Renderer(map) : null;
var gridRenderer = isMainMap ? grid.Renderer(map) : null;
Main.UnitLogic.DamageSettlement(map, self, self, 2, DamageType.KillSelf);
if (!self.IsAlive() && isMainMap)
{
if (scope != null)
{
var gridRendererForStep = gridRenderer;
var selfRendererForStep = selfRenderer;
var gridDataForStep = grid;
scope.Add(new FragmentStep
{
Phase = phase,
Duration = 0f, // 方案1不阻塞后续phase
Execute = () =>
{
gridRendererForStep?.PlayVFXInSight(new GridVFXParams(GridVFXType.Die));
if (selfRendererForStep != null)
{
selfRendererForStep.Die();
if (gridDataForStep != null && MapRenderer.Instance != null && Main.MapData != null)
MapRenderer.Instance.UpdateAroundHighlight(Main.MapData, gridDataForStep);
}
gridRendererForStep?.InstantUpdateGrid();
}
});
}
else
{
visualSteps.Add(new SkillVisualStep
{
GridRenderer = gridRenderer,
UnitRenderer = selfRenderer,
VFXList = new List<GridVFXParams> { new GridVFXParams(GridVFXType.Die) },
KillUnit = true,
RefreshGrid = true,
GridData = grid,
});
}
}
}
}
else
{
// ===== 1层爆炸 =====
_level -= 1;
if (canSpread)
{
var aroundBuf = RentAroundBuf();
map.GridMap.GetAroundGridData(1, 1, grid, aroundBuf);
foreach (var around in aroundBuf)
{
if (!around.RealUnit(map, out var target)) continue;
if (target.Id != self.Id && !target.GetSkill(SkillType.KomeijiFearImmune, out _))
{
target.AddOrOverrideSkill(SkillType.KomeijiFear, map, self.Id);
// 播放恐惧VFX
var aroundRenderer = isMainMap ? around.Renderer(map) : null;
if (scope != null)
{
var rendererForStep = aroundRenderer;
scope.Add(new FragmentStep
{
Phase = phase,
Duration = 0f, // 方案1不阻塞后续phase
Execute = () => rendererForStep?.PlayVFXInSight(new GridVFXParams(GridVFXType.KomeijiFear))
});
}
else
{
aroundRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.KomeijiFear));
}
unitsToRefresh.Add(target.Id);
}
}
ReturnAroundBuf();
}
}
// 存活单位的外观刷新
if (isMainMap && unitsToRefresh.Count > 0)
{
if (scope != null)
{
foreach (var unitId in unitsToRefresh)
{
if (MapRenderer.Instance != null &&
MapRenderer.Instance.ROUnitMap.TryGetValue(unitId, out var unitRenderer))
{
var rendererForStep = unitRenderer;
scope.Add(new FragmentStep
{
Phase = phase,
Duration = 0f, // 方案1不阻塞后续phase
Execute = () => rendererForStep.InstantUpdateUnit(false)
});
}
}
}
else
{
var refreshSteps = new List<SkillVisualStep>();
foreach (var unitId in unitsToRefresh)
{
if (MapRenderer.Instance != null &&
MapRenderer.Instance.ROUnitMap.TryGetValue(unitId, out var unitRenderer))
{
refreshSteps.Add(new SkillVisualStep
{
UnitRenderer = unitRenderer,
RefreshUnit = true,
});
}
}
// 存活单位刷新放在第一步(死亡动画之前,这样玩家先看到层数变化,再看到死亡)
visualSteps?.InsertRange(0, refreshSteps);
}
}
// 非scope模式入队播放
if (scope == null && visualSteps != null && visualSteps.Count > 0)
{
PresentationManager.EnqueueSkillEffect(visualSteps);
}
// 如果层数降为0IsFinished会返回true技能自动移除
}
/// <summary>
/// 减少层数
/// </summary>
public override void ReduceLevel(MapData map, UnitData origin, int reduce)
{
_level -= reduce;
if (_level < 0) _level = 0;
}
}
}