diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatLoadSession.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatLoadSession.cs index cdf2579..f0c1155 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatLoadSession.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatLoadSession.cs @@ -45,7 +45,7 @@ namespace GeometryTD.CustomComponent _currentMap = null; } - public bool StartLoading(DRLevel level, MapData mapData, out string errorMessage) + public bool StartLoading(DRLevel level, MapData mapData, CombatScheduler scheduler, out string errorMessage) { errorMessage = null; if (_entity == null) @@ -59,7 +59,7 @@ namespace GeometryTD.CustomComponent return false; } - if (!TryOpenCombatInfoForm(out errorMessage)) + if (!TryOpenCombatInfoForm(scheduler, out errorMessage)) { return false; } @@ -249,7 +249,7 @@ namespace GeometryTD.CustomComponent return true; } - private bool TryOpenCombatInfoForm(out string errorMessage) + private bool TryOpenCombatInfoForm(CombatScheduler scheduler, out string errorMessage) { errorMessage = null; if (_combatInfoFormUseCase == null) @@ -258,6 +258,10 @@ namespace GeometryTD.CustomComponent GameEntry.UIRouter.BindUIUseCase(UIFormType.CombatInfoForm, _combatInfoFormUseCase); } + _combatInfoFormUseCase.Configure( + () => BuildCombatInfoFormRawData(scheduler), + () => scheduler != null && scheduler.CanEndCombat && scheduler.TryEndCombatByPlayer()); + int? serialId = GameEntry.UIRouter.OpenUI(UIFormType.CombatInfoForm); if (!serialId.HasValue) { @@ -270,6 +274,28 @@ namespace GeometryTD.CustomComponent return true; } + private static CombatInfoFormRawData BuildCombatInfoFormRawData(CombatScheduler scheduler) + { + if (scheduler == null) + { + return null; + } + + DRLevel level = scheduler.CurrentLevel; + LevelThemeType themeType = level != null ? level.LevelThemeType : LevelThemeType.None; + int levelId = level != null ? level.Id : 0; + int baseHpMax = level != null ? Mathf.Max(0, level.BaseHp) : 0; + return CombatInfoFormUseCase.BuildRawData( + themeType, + levelId, + scheduler.DisplayPhaseIndex, + scheduler.PhaseCount, + scheduler.CurrentCoin, + scheduler.CurrentBaseHp, + baseHpMax, + scheduler.CanEndCombat); + } + private void CloseCombatInfoForm() { GameEntry.UIRouter.CloseUI(UIFormType.CombatInfoForm); diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatStates/CombatLoadingState.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatStates/CombatLoadingState.cs index 4567c92..33050ae 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatStates/CombatLoadingState.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatStates/CombatLoadingState.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using GeometryTD.Definition; using GeometryTD.Entity.EntityData; +using GeometryTD.UI; using UnityEngine; namespace GeometryTD.CustomComponent @@ -22,7 +23,7 @@ namespace GeometryTD.CustomComponent } MapData mapData = BuildMapData(); - if (!Scheduler._loadSession.StartLoading(Scheduler._currentLevel, mapData, out string errorMessage)) + if (!Scheduler._loadSession.StartLoading(Scheduler._currentLevel, mapData, Scheduler, out string errorMessage)) { Scheduler.EnterFailureFallback($"Combat loading failed. {errorMessage}"); } @@ -60,6 +61,12 @@ namespace GeometryTD.CustomComponent position: Vector3.zero, initialCoin: Scheduler._combatInRunResourceManager.CurrentCoin, buildTowerStatsSnapshot: buildTowerStatsSnapshot, + inventorySnapshot: GameEntry.PlayerInventory != null + ? GameEntry.PlayerInventory.GetInventorySnapshot() + : null, + participantTowerSnapshot: GameEntry.PlayerInventory != null + ? GameEntry.PlayerInventory.GetParticipantTowerSnapshot() + : null, tryConsumeCoin: Scheduler.TryConsumeCoin, addCoin: Scheduler.AddCoin); } diff --git a/Assets/GameMain/Scripts/Entity/EntityData/MapData.cs b/Assets/GameMain/Scripts/Entity/EntityData/MapData.cs index 977c164..730f5c3 100644 --- a/Assets/GameMain/Scripts/Entity/EntityData/MapData.cs +++ b/Assets/GameMain/Scripts/Entity/EntityData/MapData.cs @@ -12,6 +12,8 @@ namespace GeometryTD.Entity.EntityData [SerializeField] private int _levelId = 0; [SerializeField] private int _initialCoin = 0; [SerializeField] private TowerStatsData[] _buildTowerStatsSnapshot = Array.Empty(); + [SerializeField] private BackpackInventoryData _inventorySnapshot; + [SerializeField] private TowerItemData[] _participantTowerSnapshot = Array.Empty(); [NonSerialized] private Func _tryConsumeCoin; [NonSerialized] private Action _addCoin; @@ -33,6 +35,8 @@ namespace GeometryTD.Entity.EntityData Vector3 position, int initialCoin, IReadOnlyList buildTowerStatsSnapshot, + BackpackInventoryData inventorySnapshot, + IReadOnlyList participantTowerSnapshot, Func tryConsumeCoin, Action addCoin) : base(entityId, typeId) { @@ -40,6 +44,10 @@ namespace GeometryTD.Entity.EntityData Position = position; _initialCoin = Mathf.Max(0, initialCoin); SetBuildTowerStatsSnapshot(buildTowerStatsSnapshot); + _inventorySnapshot = inventorySnapshot != null + ? InventoryCloneUtility.CloneInventory(inventorySnapshot) + : null; + SetParticipantTowerSnapshot(participantTowerSnapshot); _tryConsumeCoin = tryConsumeCoin; _addCoin = addCoin; } @@ -57,6 +65,10 @@ namespace GeometryTD.Entity.EntityData } public int CurrentBuildTowerCount => _buildTowerStatsSnapshot != null ? _buildTowerStatsSnapshot.Length : 0; + public BackpackInventoryData InventorySnapshot => _inventorySnapshot != null + ? InventoryCloneUtility.CloneInventory(_inventorySnapshot) + : null; + public IReadOnlyList ParticipantTowerSnapshot => _participantTowerSnapshot; public void BindCombatCallbacks(Func tryConsumeCoin, Action addCoin) { @@ -128,8 +140,25 @@ namespace GeometryTD.Entity.EntityData position, _initialCoin, _buildTowerStatsSnapshot, + _inventorySnapshot, + _participantTowerSnapshot, _tryConsumeCoin, _addCoin); } + + public void SetParticipantTowerSnapshot(IReadOnlyList participantTowerSnapshot) + { + if (participantTowerSnapshot == null || participantTowerSnapshot.Count <= 0) + { + _participantTowerSnapshot = Array.Empty(); + return; + } + + _participantTowerSnapshot = new TowerItemData[participantTowerSnapshot.Count]; + for (int i = 0; i < participantTowerSnapshot.Count; i++) + { + _participantTowerSnapshot[i] = InventoryCloneUtility.CloneTower(participantTowerSnapshot[i]); + } + } } } diff --git a/Assets/GameMain/Scripts/Entity/EntityLogic/MapEntity.cs b/Assets/GameMain/Scripts/Entity/EntityLogic/MapEntity.cs index 3c96445..43fa1b1 100644 --- a/Assets/GameMain/Scripts/Entity/EntityLogic/MapEntity.cs +++ b/Assets/GameMain/Scripts/Entity/EntityLogic/MapEntity.cs @@ -243,12 +243,6 @@ namespace GeometryTD.Entity private void ConfigureCombatSelectUseCase() { _combatSelectFormUseCase.SetCoinProvider(GetCurrentCoin); - BackpackInventoryData inventorySnapshot = GameEntry.PlayerInventory != null - ? GameEntry.PlayerInventory.GetInventorySnapshot() - : null; - IReadOnlyList participantTowers = GameEntry.PlayerInventory != null - ? GameEntry.PlayerInventory.GetParticipantTowerSnapshot() - : null; _combatSelectUseCaseConfigurator?.Configure( _combatSelectFormUseCase, GetCurrentCoin, @@ -259,8 +253,8 @@ namespace GeometryTD.Entity _destroyGain, _buildTowerCosts, GetCurrentBuildTowerCount(), - inventorySnapshot, - participantTowers); + _mapData != null ? _mapData.InventorySnapshot : null, + _mapData != null ? _mapData.ParticipantTowerSnapshot : null); } private void HandleCombatSelectInput() diff --git a/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatFinishFormUseCase.cs b/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatFinishFormUseCase.cs index 7eee4d7..55eb122 100644 --- a/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatFinishFormUseCase.cs +++ b/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatFinishFormUseCase.cs @@ -45,12 +45,8 @@ namespace GeometryTD.UI { if (!_isSummaryPrepared) { - _defeatedEnemyCount = GameEntry.CombatNode != null - ? Mathf.Max(0, GameEntry.CombatNode.LastDefeatedEnemyCount) - : 0; - _gainedGold = GameEntry.CombatNode != null - ? Mathf.Max(0, GameEntry.CombatNode.LastGainedGold) - : 0; + _defeatedEnemyCount = 0; + _gainedGold = 0; _rewardInventory = null; } diff --git a/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatInfoFormUseCase.cs b/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatInfoFormUseCase.cs index 3fdb665..161f0d9 100644 --- a/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatInfoFormUseCase.cs +++ b/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatInfoFormUseCase.cs @@ -1,9 +1,14 @@ +using System; using GeometryTD.Definition; +using UnityEngine; namespace GeometryTD.UI { public class CombatInfoFormUseCase : IUIUseCase { + private Func _modelProvider; + private Func _tryEndCombat; + public CombatInfoFormRawData CreateInitialModel() { return BuildModel(); @@ -14,43 +19,49 @@ namespace GeometryTD.UI return BuildModel(); } + public void Configure(Func modelProvider, Func tryEndCombat) + { + _modelProvider = modelProvider; + _tryEndCombat = tryEndCombat; + } + public bool TryEndCombat() { - if (GameEntry.CombatNode == null || !GameEntry.CombatNode.CanEndCombat) + if (_tryEndCombat == null) { return false; } - return GameEntry.CombatNode.TryEndCombatByPlayer(); + return _tryEndCombat.Invoke(); } - private static CombatInfoFormRawData BuildModel() + private CombatInfoFormRawData BuildModel() { - if (GameEntry.CombatNode == null) - { - return null; - } - - var level = GameEntry.CombatNode.CurrentLevel; - LevelThemeType themeType = level != null ? level.LevelThemeType : GameEntry.CombatNode.CurrentThemeType; - int levelId = level != null ? level.Id : 0; - int baseHpMax = level != null ? level.BaseHp : 0; - int enemyHpRateMultiplier = ResolveEnemyHpRateMultiplier( - GameEntry.CombatNode.CurrentPhaseIndex, - GameEntry.CombatNode.CurrentLevelPhaseCount); + return _modelProvider != null ? _modelProvider.Invoke() : null; + } + public static CombatInfoFormRawData BuildRawData( + LevelThemeType themeType, + int levelId, + int currentPhaseIndex, + int totalPhaseCount, + int coin, + int baseHp, + int baseHpMax, + bool canEnd) + { return new CombatInfoFormRawData { LevelThemeType = themeType, LevelId = levelId, - CurrentPhaseIndex = GameEntry.CombatNode.CurrentPhaseIndex, - TotalPhaseCount = GameEntry.CombatNode.CurrentLevelPhaseCount, - Coin = GameEntry.CombatNode.CurrentCoin, - BaseHp = GameEntry.CombatNode.CurrentBaseHp, - BaseHpMax = baseHpMax, - EnemyHpRateMultiplier = enemyHpRateMultiplier, + CurrentPhaseIndex = Mathf.Max(0, currentPhaseIndex), + TotalPhaseCount = Mathf.Max(0, totalPhaseCount), + Coin = Mathf.Max(0, coin), + BaseHp = Mathf.Max(0, baseHp), + BaseHpMax = Mathf.Max(0, baseHpMax), + EnemyHpRateMultiplier = ResolveEnemyHpRateMultiplier(currentPhaseIndex, totalPhaseCount), CanPause = true, - CanEnd = GameEntry.CombatNode.CanEndCombat + CanEnd = canEnd }; } @@ -61,7 +72,7 @@ namespace GeometryTD.UI return 1; } - int completedLoopCount = UnityEngine.Mathf.Max(0, (currentPhaseIndex - 1) / totalPhaseCount); + int completedLoopCount = Mathf.Max(0, (currentPhaseIndex - 1) / totalPhaseCount); if (completedLoopCount >= 30) { return int.MaxValue; diff --git a/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatSelectFormUseCase.cs b/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatSelectFormUseCase.cs index 7351736..26e8c20 100644 --- a/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatSelectFormUseCase.cs +++ b/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatSelectFormUseCase.cs @@ -269,12 +269,7 @@ namespace GeometryTD.UI private static int DefaultCoinProvider() { - if (GameEntry.CombatNode == null) - { - return 0; - } - - return Mathf.Max(0, GameEntry.CombatNode.CurrentCoin); + return 0; } private static bool CanExecute(Option option, int currentCoin)