using System.Collections.Generic; using System.Globalization; using GeometryTD.DataTable; using GeometryTD.Definition; using UnityEngine; namespace GeometryTD.CustomComponent { internal sealed class PhaseLoopRuntime { private readonly List _phases = new(); private DRLevelPhase _currentPhase; private int _currentPhaseIndex = -1; private int _displayPhaseIndex; private int _completedLoopCount; private bool _canEndCombat; private bool _endCombatRequested; private float _currentPhaseElapsed; public DRLevelPhase CurrentPhase => _currentPhase; public int DisplayPhaseIndex => _displayPhaseIndex; public bool CanEndCombat => _canEndCombat; public bool IsEndCombatRequested => _endCombatRequested; public float CurrentPhaseElapsed => _currentPhaseElapsed; public int PhaseCount => _phases.Count; public void Reset() { _phases.Clear(); _currentPhase = null; _currentPhaseIndex = -1; _displayPhaseIndex = 0; _completedLoopCount = 0; _canEndCombat = false; _endCombatRequested = false; _currentPhaseElapsed = 0f; } public void SetPhases(IReadOnlyList phases) { _phases.Clear(); if (phases == null) { return; } for (int i = 0; i < phases.Count; i++) { DRLevelPhase phase = phases[i]; if (phase != null) { _phases.Add(phase); } } } public bool TryRequestEndCombat() { if (!_canEndCombat) { return false; } _endCombatRequested = true; return true; } public void AdvancePhaseElapsed(float elapseSeconds) { _currentPhaseElapsed += elapseSeconds; } public bool ShouldEndCurrentPhase(bool isPhaseSpawnCompleted, int aliveEnemyCount) { if (_currentPhase == null) { return false; } switch (_currentPhase.EndType) { case PhaseEndType.TimeElapsed: return _currentPhaseElapsed >= ResolveTimeElapsedThreshold(_currentPhase); case PhaseEndType.EnemiesCleared: case PhaseEndType.BossDead: return isPhaseSpawnCompleted && aliveEnemyCount <= 0; case PhaseEndType.None: default: if (_currentPhase.DurationSeconds > 0 && _currentPhaseElapsed >= _currentPhase.DurationSeconds) { return true; } return isPhaseSpawnCompleted && aliveEnemyCount <= 0; } } public bool TryEnterNextPhase(out DRLevelPhase nextPhase) { nextPhase = null; if (_phases.Count <= 0) { return false; } _currentPhaseIndex++; if (_currentPhaseIndex >= _phases.Count) { _completedLoopCount++; _canEndCombat = true; if (_endCombatRequested) { _currentPhase = null; return false; } _currentPhaseIndex = 0; } _currentPhase = _phases[_currentPhaseIndex]; _displayPhaseIndex = _completedLoopCount * _phases.Count + _currentPhaseIndex + 1; _currentPhaseElapsed = 0f; nextPhase = _currentPhase; return true; } private static float ResolveTimeElapsedThreshold(DRLevelPhase phase) { if (!string.IsNullOrWhiteSpace(phase.EndParam) && float.TryParse(phase.EndParam, NumberStyles.Float, CultureInfo.InvariantCulture, out float parsed)) { return parsed; } if (phase.DurationSeconds > 0) { return phase.DurationSeconds; } return 0f; } } }