geometry-tower-defense-base/src-ref/CustomComponent/CombatNode/CombatScheduler/CombatSchedulerCoordinator.cs

283 lines
9.5 KiB
C#

using System.Collections.Generic;
using GeometryTD.CustomEvent;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using GeometryTD.Procedure;
using GeometryTD.UI;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.CustomComponent
{
internal sealed class CombatSchedulerCoordinator
{
private readonly ICombatSchedulerPort _schedulerPort;
private readonly CombatSchedulerRuntime _runtime;
public ICombatSchedulerPort Port => _schedulerPort;
public CombatSchedulerCoordinator(ICombatSchedulerPort schedulerPort, CombatSchedulerRuntime runtime)
{
_schedulerPort = schedulerPort;
_runtime = runtime;
}
public void ChangeState(CombatStateBase nextState)
{
_schedulerPort.ChangeState(nextState);
}
public int ResolveEnemyHpRateMultiplier(int displayPhaseIndex, int phaseCount)
{
if (displayPhaseIndex <= 0 || phaseCount <= 0)
{
return 1;
}
int completedLoopCount = Mathf.Max(0, (displayPhaseIndex - 1) / phaseCount);
if (completedLoopCount >= 30)
{
return int.MaxValue;
}
return 1 << completedLoopCount;
}
public void ResetRuntime()
{
_runtime.CurrentState = null;
_runtime.PhaseBuffer.Clear();
_runtime.SpawnEntriesByPhaseId.Clear();
_runtime.PhaseLoopRuntime.Reset();
_runtime.LoadSession.Reset();
_runtime.CombatRunResourceStore.Reset();
_runtime.SettlementContext = null;
_runtime.CurrentLevel = null;
_runtime.DidCombatWin = true;
_runtime.IsCompleted = false;
_runtime.NodeEnterFired = false;
_runtime.NodeContext = null;
_runtime.NextDropOrdinal = 0;
_runtime.NextRewardOrdinal = 0;
}
public void CleanupAllCombatEntities()
{
_runtime.LoadSession.Cleanup();
_runtime.EnemyManager.CleanupTrackedEnemies();
}
public void EnsureCombatFinishFormUseCaseBound()
{
_runtime.CombatFinishFormUseCase ??= new CombatFinishFormUseCase(_schedulerPort);
GameEntry.UIRouter.BindUIUseCase(UIFormType.CombatFinishForm, _runtime.CombatFinishFormUseCase);
}
public void EnsureRewardSelectFormUseCaseBound()
{
_runtime.RewardSelectFormUseCase ??= new RewardSelectFormUseCase();
GameEntry.UIRouter.BindUIUseCase(UIFormType.RewardSelectForm, _runtime.RewardSelectFormUseCase);
}
public void OpenCombatFailureDialog(string errorMessage)
{
CloseDialogForm();
GameEntry.UIRouter.OpenUI(UIFormType.DialogForm, new DialogFormRawData
{
Mode = 1,
Title = "Combat Error",
Message = string.IsNullOrWhiteSpace(errorMessage) ? "Combat failed unexpectedly." : errorMessage,
PauseGame = false,
ConfirmText = "Return Menu",
OnClickConfirm = OnCombatFailureDialogConfirmed
});
}
public bool TryBeginNextPhase()
{
if (!_runtime.PhaseLoopRuntime.TryEnterNextPhase(out DRLevelPhase nextPhase))
{
_schedulerPort.ChangeState(new CombatSettlementState(_runtime, this, true));
return false;
}
_runtime.SpawnEntriesByPhaseId.TryGetValue(nextPhase.Id, out IReadOnlyList<DRLevelSpawnEntry> spawnEntries);
_schedulerPort.ChangeState(new CombatRunningPhaseState(_runtime, this, nextPhase, spawnEntries));
return true;
}
public void EnterWaitingForPhaseEnd()
{
_schedulerPort.ChangeState(new CombatWaitingForPhaseEndState(_runtime, this));
}
public void CompleteCurrentPhase()
{
_runtime.EnemyManager.EndPhase();
Log.Info(
"CombatScheduler phase completed. Level={0}, Phase={1}, Elapsed={2:F2}s.",
_runtime.CurrentLevel != null ? _runtime.CurrentLevel.Id : 0,
_runtime.PhaseLoopRuntime.CurrentPhase != null ? _runtime.PhaseLoopRuntime.CurrentPhase.Id : 0,
_runtime.PhaseLoopRuntime.CurrentPhaseElapsed);
TryBeginNextPhase();
}
public bool ShouldEnterSettlementFromActiveState(out bool didCombatWin)
{
if (GetCurrentBaseHp() <= 0)
{
didCombatWin = false;
return true;
}
if (_runtime.PhaseLoopRuntime.IsEndCombatRequested)
{
didCombatWin = true;
return true;
}
didCombatWin = true;
return false;
}
public void OnFullBaseHpRewardSelected(RewardSelectItemRawData selectedReward)
{
if (_runtime.CurrentState is not CombatRewardSelectionState || _runtime.SettlementContext == null)
{
return;
}
_runtime.CombatSettlementService.ApplySelectedReward(_runtime.SettlementContext, selectedReward);
_schedulerPort.ChangeState(new CombatFinishFormState(_runtime, this));
}
public void OnFullBaseHpRewardGiveUp()
{
if (_runtime.CurrentState is not CombatRewardSelectionState || _runtime.SettlementContext == null)
{
return;
}
_schedulerPort.ChangeState(new CombatFinishFormState(_runtime, this));
}
public LevelThemeType ResolveCurrentThemeType()
{
if (_runtime.CurrentLevel != null)
{
return _runtime.CurrentLevel.LevelThemeType;
}
return LevelThemeType.None;
}
public int ApplyBaseDamage(int damage)
{
return _runtime.CombatRunResourceStore.ApplyBaseDamage(damage);
}
public int GetCurrentBaseHp()
{
return Mathf.Max(0, _runtime.CombatRunResourceStore.CurrentBaseHp);
}
public void CloseCombatFinishForm()
{
GameEntry.UIRouter.CloseUI(UIFormType.CombatFinishForm);
}
public void CloseRewardSelectForm()
{
GameEntry.UIRouter.CloseUI(UIFormType.RewardSelectForm);
}
public void CloseDialogForm()
{
GameEntry.UIRouter.CloseUI(UIFormType.DialogForm);
}
public void CompleteNormalCombatAndNotify(bool didCombatWin)
{
CompleteCombat(didCombatWin);
RunNodeExecutionContext nodeContext = _runtime.NodeContext;
GameEntry.Event.Fire(
this,
NodeCompleteEventArgs.Create(
nodeContext?.RunId,
nodeContext?.NodeId ?? 0,
nodeContext?.NodeType ?? RunNodeType.None,
nodeContext?.SequenceIndex ?? -1,
RunNodeCompletionStatus.Completed,
didCombatWin,
nodeContext != null
? nodeContext.CreateCompletionSnapshot(
GameEntry.PlayerInventory != null ? GameEntry.PlayerInventory.GetInventorySnapshot() : null)
: null));
}
public void CompleteFailureCombatAndNotify()
{
CleanupAllCombatEntities();
CloseCombatFinishForm();
CloseRewardSelectForm();
CloseDialogForm();
CompleteCombat(false);
RunNodeExecutionContext nodeContext = _runtime.NodeContext;
GameEntry.Event.Fire(
this,
NodeCompleteEventArgs.Create(
nodeContext?.RunId,
nodeContext?.NodeId ?? 0,
nodeContext?.NodeType ?? RunNodeType.None,
nodeContext?.SequenceIndex ?? -1,
RunNodeCompletionStatus.Exception,
false,
nodeContext != null
? nodeContext.CreateCompletionSnapshot(
GameEntry.PlayerInventory != null ? GameEntry.PlayerInventory.GetInventorySnapshot() : null)
: null));
}
public bool HandleStartFailure(string errorMessage)
{
Log.Warning("{0}", errorMessage);
_runtime.EnemyManager.EndPhase();
CleanupAllCombatEntities();
CloseCombatFinishForm();
CloseRewardSelectForm();
CloseDialogForm();
ResetRuntime();
return false;
}
public void EnterFailureFallback(string errorMessage)
{
if (_runtime.CurrentState is CombatFailedState || _runtime.IsCompleted)
{
return;
}
_schedulerPort.ChangeState(new CombatFailedState(_runtime, this, errorMessage));
}
public void OnCombatFailureDialogConfirmed(object userData)
{
_ = userData;
if (_runtime.CurrentState is not CombatFailedState || _runtime.IsCompleted)
{
return;
}
CompleteFailureCombatAndNotify();
}
private void CompleteCombat(bool succeeded)
{
_runtime.IsCompleted = true;
_runtime.CurrentState = null;
_runtime.CombatRunResourceStore.MarkCombatEnded();
_runtime.CombatEndedCallback?.Invoke(succeeded);
}
}
}