344 lines
15 KiB
C#
344 lines
15 KiB
C#
/*
|
||
* @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);
|
||
}
|
||
|
||
// 如果层数降为0,IsFinished会返回true,技能自动移除
|
||
}
|
||
|
||
/// <summary>
|
||
/// 减少层数
|
||
/// </summary>
|
||
public override void ReduceLevel(MapData map, UnitData origin, int reduce)
|
||
{
|
||
_level -= reduce;
|
||
if (_level < 0) _level = 0;
|
||
}
|
||
}
|
||
}
|