From 703fd6f5404b39e01098ee20102527f2d7d3b310 Mon Sep 17 00:00:00 2001 From: basil Date: Sat, 7 Mar 2026 20:09:50 +0800 Subject: [PATCH] Refine combat settlement exit flow --- .../CombatScheduler/CombatSchedulerFlowCoordinator.cs | 7 ++----- .../CombatNode/CombatScheduler/CombatSettlementContext.cs | 1 - .../CombatScheduler/CombatSettlementFlowService.cs | 5 +---- .../CombatScheduler/CombatStates/CombatFinishFormState.cs | 1 - .../CombatStates/CombatRunningPhaseState.cs | 4 ++-- .../CombatScheduler/CombatStates/CombatSettlementState.cs | 4 ---- .../CombatStates/CombatWaitingForPhaseEndState.cs | 4 ++-- .../CombatStates/CombatWaitingForReturnState.cs | 7 +++++++ docs/CodeX-TODO.md | 2 ++ 9 files changed, 16 insertions(+), 19 deletions(-) diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSchedulerFlowCoordinator.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSchedulerFlowCoordinator.cs index debc069..3219ea8 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSchedulerFlowCoordinator.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSchedulerFlowCoordinator.cs @@ -92,7 +92,7 @@ namespace GeometryTD.CustomComponent { if (!_context.PhaseLoopRuntime.TryEnterNextPhase(out DRLevelPhase nextPhase)) { - _schedulerHost.ChangeState(new CombatSettlementState(_context, this, "Combat ended after loop completion.", true)); + _schedulerHost.ChangeState(new CombatSettlementState(_context, this, true)); return false; } @@ -118,23 +118,20 @@ namespace GeometryTD.CustomComponent TryBeginNextPhase(); } - public bool ShouldEnterSettlementFromActiveState(out string reason, out bool isVictory) + public bool ShouldEnterSettlementFromActiveState(out bool isVictory) { if (GetCurrentBaseHp() <= 0) { - reason = "Combat ended because base HP reached zero."; isVictory = false; return true; } if (_context.PhaseLoopRuntime.IsEndCombatRequested) { - reason = "Combat ended by player."; isVictory = true; return true; } - reason = null; isVictory = true; return false; } diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementContext.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementContext.cs index 277eabf..aa61c92 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementContext.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementContext.cs @@ -25,7 +25,6 @@ namespace GeometryTD.CustomComponent public int DefeatedEnemyCount; public int GainedGold; public BackpackInventoryData RewardInventory; - public string Reason; public CombatSettlementPenaltyResult Penalty { get; } = new(); } diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementFlowService.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementFlowService.cs index 11326eb..1bb72bc 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementFlowService.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementFlowService.cs @@ -18,7 +18,6 @@ namespace GeometryTD.CustomComponent private const float LowBaseHpTowerEndurancePenalty = 10f; public CombatSettlementContext BuildSettlementContext( - string reason, bool isVictory, DRLevel currentLevel, int defeatedEnemyCount, @@ -49,7 +48,6 @@ namespace GeometryTD.CustomComponent settlementContext.Result.RewardInventory = resourceManager != null ? resourceManager.GetRewardInventorySnapshot() : new BackpackInventoryData(); - settlementContext.Result.Reason = reason; settlementContext.Result.Penalty.ShouldApplyLowBaseHpPenalty = appliedLowBaseHpPenalty; settlementContext.Result.Penalty.LowBaseHpEndurancePenaltyValue = appliedLowBaseHpPenalty ? LowBaseHpTowerEndurancePenalty : 0f; @@ -60,9 +58,8 @@ namespace GeometryTD.CustomComponent settlementContext.Summary.RewardInventory = settlementContext.Result.RewardInventory; Log.Info( - "Combat settlement resolved. Level={0}, Reason={1}, BaseHp={2}/{3}, LevelReward={4}, BonusRate={5:P0}, BonusGold={6}, FullHpRewardSelect={7}, LowHpPenalty={8}.", + "Combat settlement resolved. Level={0}, BaseHp={1}/{2}, LevelReward={3}, BonusRate={4:P0}, BonusGold={5}, FullHpRewardSelect={6}, LowHpPenalty={7}.", currentLevel != null ? currentLevel.Id : 0, - reason, currentBaseHp, maxBaseHp, levelRewardGold, diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatFinishFormState.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatFinishFormState.cs index 293af57..0d8a49f 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatFinishFormState.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatFinishFormState.cs @@ -15,7 +15,6 @@ namespace GeometryTD.CustomComponent return; } - Context.SettlementFlowService.CommitSettlementInventory(Context.SettlementContext); Flow.EnsureCombatFinishFormUseCaseBound(); Context.SettlementFlowService.OpenCombatFinishForm( Context.SettlementContext, diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatRunningPhaseState.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatRunningPhaseState.cs index af6daf4..cf29545 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatRunningPhaseState.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatRunningPhaseState.cs @@ -60,9 +60,9 @@ namespace GeometryTD.CustomComponent Context.PhaseLoopRuntime.AdvancePhaseElapsed(elapseSeconds); Context.EnemyManager.OnUpdate(elapseSeconds, realElapseSeconds); - if (Flow.ShouldEnterSettlementFromActiveState(out string reason, out bool isVictory)) + if (Flow.ShouldEnterSettlementFromActiveState(out bool isVictory)) { - Flow.ChangeState(new CombatSettlementState(Context, Flow, reason, isVictory)); + Flow.ChangeState(new CombatSettlementState(Context, Flow, isVictory)); return; } diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatSettlementState.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatSettlementState.cs index 1ada035..f3f92b4 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatSettlementState.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatSettlementState.cs @@ -2,16 +2,13 @@ namespace GeometryTD.CustomComponent { internal sealed class CombatSettlementState : CombatStateBase { - private readonly string _reason; private readonly bool _isVictory; public CombatSettlementState( CombatSchedulerRuntimeContext context, CombatSchedulerFlowCoordinator flow, - string reason, bool isVictory) : base(context, flow) { - _reason = reason; _isVictory = isVictory; } @@ -21,7 +18,6 @@ namespace GeometryTD.CustomComponent Context.EnemyManager.CleanupTrackedEnemies(); Context.IsFinishAsVictory = _isVictory; Context.SettlementContext = Context.SettlementFlowService.BuildSettlementContext( - _reason, _isVictory, Context.CurrentLevel, Context.EnemyManager.DefeatedEnemyCount, diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatWaitingForPhaseEndState.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatWaitingForPhaseEndState.cs index 27a52aa..a04d3d8 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatWaitingForPhaseEndState.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatWaitingForPhaseEndState.cs @@ -22,9 +22,9 @@ namespace GeometryTD.CustomComponent Context.PhaseLoopRuntime.AdvancePhaseElapsed(elapseSeconds); - if (Flow.ShouldEnterSettlementFromActiveState(out string reason, out bool isVictory)) + if (Flow.ShouldEnterSettlementFromActiveState(out bool isVictory)) { - Flow.ChangeState(new CombatSettlementState(Context, Flow, reason, isVictory)); + Flow.ChangeState(new CombatSettlementState(Context, Flow, isVictory)); return; } diff --git a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatWaitingForReturnState.cs b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatWaitingForReturnState.cs index 0bbad42..ffa7790 100644 --- a/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatWaitingForReturnState.cs +++ b/Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/CombatWaitingForReturnState.cs @@ -24,6 +24,13 @@ namespace GeometryTD.CustomComponent return; } + if (Context.SettlementContext == null) + { + Flow.EnterFailureFallback("Combat return failed. Settlement context is missing."); + return; + } + + Context.SettlementFlowService.CommitSettlementInventory(Context.SettlementContext); Context.LoadSession.Cleanup(); Flow.CloseCombatFinishForm(); Flow.CloseRewardSelectForm(); diff --git a/docs/CodeX-TODO.md b/docs/CodeX-TODO.md index 659caef..d234959 100644 --- a/docs/CodeX-TODO.md +++ b/docs/CodeX-TODO.md @@ -174,6 +174,7 @@ - 奖励选择相关流程标记 - 低血惩罚相关事实 - 低血惩罚已改为“先记录事实,提交阶段再统一落库”,不再在结算构造期直接写库存 +- 结算背包合并当前发生在 `WaitingForReturn` 的真正退出点,而不是 `FinishForm` - `CombatFinishForm` 当前只消费它真正展示需要的摘要,不再把额外结算事实继续灌进 UI Context 关键文件: @@ -247,6 +248,7 @@ - 流程控制字段现在集中在 `Flow` - 结算事实与惩罚事实现在集中在 `Result` - `CombatFinishFormUseCase` 当前只消费 `Summary` +- 已去掉单独的结束原因字段,结束链不再依赖 `CombatEndReason` 风格数据 - 奖励选择与延迟提交惩罚已同步切到分层后的上下文访问路径 关键文件: