207 lines
7.4 KiB
C#
207 lines
7.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Logic;
|
|
using RuntimeData;
|
|
using TH1_Anim.Fragments;
|
|
using TH1_Logic.Core;
|
|
using TH1_Renderer;
|
|
using TH1Renderer;
|
|
|
|
namespace Logic.Action
|
|
{
|
|
public class ActionVisualEventCollector : IDisposable
|
|
{
|
|
private readonly List<FragmentStep> _steps = new List<FragmentStep>();
|
|
private readonly Dictionary<uint, uint> _deathReplacementUnitIds = new Dictionary<uint, uint>();
|
|
private readonly MapData _mapData;
|
|
private readonly uint _mainTargetUnitId;
|
|
private readonly ActionVisualEventCollector _previous;
|
|
private uint _settlingVisualTargetId;
|
|
private bool _flushed;
|
|
|
|
public static ActionVisualEventCollector Current { get; private set; }
|
|
public bool MainTargetKilledBeforeAttack { get; private set; }
|
|
public int MainTargetPreAttackDamage { get; private set; }
|
|
|
|
private ActionVisualEventCollector(MapData mapData, uint originUnitId, uint mainTargetUnitId)
|
|
{
|
|
_mapData = mapData;
|
|
_mainTargetUnitId = mainTargetUnitId;
|
|
_previous = Current;
|
|
Current = this;
|
|
}
|
|
|
|
public static ActionVisualEventCollector Begin(MapData mapData, uint originUnitId, uint mainTargetUnitId)
|
|
{
|
|
if (mapData != Main.MapData) return null;
|
|
return new ActionVisualEventCollector(mapData, originUnitId, mainTargetUnitId);
|
|
}
|
|
|
|
public bool TryRegisterDeathReplacement(uint targetUnitId, uint replacementUnitId)
|
|
{
|
|
if (targetUnitId == 0 || replacementUnitId == 0) return false;
|
|
if (_settlingVisualTargetId != targetUnitId) return false;
|
|
_deathReplacementUnitIds[targetUnitId] = replacementUnitId;
|
|
return true;
|
|
}
|
|
|
|
public SettlementInfo SettleDamageWithVisual(
|
|
UnitData origin,
|
|
UnitData target,
|
|
int damage,
|
|
DamageType damageType,
|
|
int phase,
|
|
float delay = 0f,
|
|
bool markMainTargetPreAttackKill = false,
|
|
bool includeDamageVfx = true,
|
|
bool showoff = false)
|
|
{
|
|
if (_mapData == null || origin == null || target == null)
|
|
return Main.UnitLogic.DamageSettlement(_mapData, origin, target, damage, damageType);
|
|
|
|
var targetGrid = target.Grid(_mapData);
|
|
var targetCity = target.City(_mapData);
|
|
var targetRenderer = target.Renderer(_mapData);
|
|
var canBeKilled = target.CanBeKilled(_mapData);
|
|
var targetId = target.Id;
|
|
|
|
SettlementInfo settlement;
|
|
var previousSettlingTargetId = _settlingVisualTargetId;
|
|
_settlingVisualTargetId = targetId;
|
|
try
|
|
{
|
|
settlement = Main.UnitLogic.DamageSettlement(_mapData, origin, target, damage, damageType);
|
|
}
|
|
finally
|
|
{
|
|
_settlingVisualTargetId = previousSettlingTargetId;
|
|
}
|
|
if (settlement == null) return null;
|
|
|
|
bool killed = settlement.IsKill || !target.IsAlive();
|
|
if (markMainTargetPreAttackKill && killed && targetId == _mainTargetUnitId)
|
|
{
|
|
MainTargetKilledBeforeAttack = true;
|
|
MainTargetPreAttackDamage += damage;
|
|
}
|
|
|
|
if (targetGrid != null)
|
|
{
|
|
AddDamageStep(
|
|
targetGrid,
|
|
targetCity,
|
|
targetRenderer,
|
|
targetId,
|
|
damage,
|
|
killed,
|
|
canBeKilled,
|
|
phase,
|
|
delay,
|
|
includeDamageVfx,
|
|
showoff);
|
|
}
|
|
|
|
return settlement;
|
|
}
|
|
|
|
private void AddDamageStep(
|
|
GridData targetGrid,
|
|
CityData targetCity,
|
|
UnitRenderer targetRenderer,
|
|
uint targetId,
|
|
int damage,
|
|
bool killed,
|
|
bool canBeKilled,
|
|
int phase,
|
|
float delay,
|
|
bool includeDamageVfx,
|
|
bool showoff)
|
|
{
|
|
_steps.Add(new FragmentStep
|
|
{
|
|
Phase = phase,
|
|
Duration = 0f,
|
|
Execute = () =>
|
|
{
|
|
void RunVisual()
|
|
{
|
|
if (targetGrid == null) return;
|
|
var gridRenderer = targetGrid.Renderer(_mapData);
|
|
bool inMainSight = targetGrid.InMainSight();
|
|
if (inMainSight)
|
|
{
|
|
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Hurt));
|
|
if (includeDamageVfx)
|
|
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Damage, damage));
|
|
}
|
|
|
|
if (killed)
|
|
{
|
|
if (inMainSight)
|
|
{
|
|
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
|
|
if (canBeKilled)
|
|
gridRenderer?.PlayVFXInSight(new GridVFXParams(GridVFXType.Die));
|
|
}
|
|
targetRenderer?.Die();
|
|
ShowDeathReplacement(targetId);
|
|
targetCity?.SetCityRenderer(_mapData);
|
|
MapRenderer.Instance?.UpdateAroundHighlight(_mapData, targetGrid);
|
|
}
|
|
else
|
|
{
|
|
targetRenderer?.InstantUpdateUnit(showoff);
|
|
}
|
|
|
|
gridRenderer?.InstantUpdateGrid();
|
|
}
|
|
|
|
if (delay > 0f && Timer.Instance != null)
|
|
Timer.Instance.TimerRegister(this, RunVisual, delay, "ActionVisualEventCollector Damage Visual");
|
|
else
|
|
RunVisual();
|
|
}
|
|
});
|
|
}
|
|
|
|
private void ShowDeathReplacement(uint targetId)
|
|
{
|
|
if (!_deathReplacementUnitIds.Remove(targetId, out var replacementUnitId)) return;
|
|
if (_mapData?.UnitMap == null ||
|
|
!_mapData.UnitMap.GetUnitDataByUnitId(replacementUnitId, out var replacementUnit) ||
|
|
replacementUnit == null)
|
|
return;
|
|
|
|
var replacementRenderer = replacementUnit.Renderer(_mapData);
|
|
if (replacementRenderer == null)
|
|
{
|
|
MapRenderer.Instance?.RenderUpdateUnitMap();
|
|
replacementRenderer = replacementUnit.Renderer(_mapData);
|
|
}
|
|
|
|
replacementRenderer?.InstantUpdateUnit(true);
|
|
}
|
|
|
|
public void FlushTo(FragmentBase fragment)
|
|
{
|
|
if (fragment == null) return;
|
|
foreach (var step in _steps)
|
|
fragment.InjectStep(step);
|
|
_flushed = true;
|
|
_steps.Clear();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (!_flushed)
|
|
{
|
|
foreach (var targetId in new List<uint>(_deathReplacementUnitIds.Keys))
|
|
ShowDeathReplacement(targetId);
|
|
_deathReplacementUnitIds.Clear();
|
|
}
|
|
_steps.Clear();
|
|
Current = _previous;
|
|
}
|
|
}
|
|
}
|