Files
Cielonos/Assets/Scripts/MainGame/GameRun/RunManager/RunManager_CombatSubmodule.cs

106 lines
4.5 KiB
C#
Raw Permalink Normal View History

2026-07-18 03:16:20 -04:00
using System.Collections.Generic;
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.Rewards;
using UnityEngine;
namespace Cielonos.MainGame
{
public partial class RunManager
{
/// <summary>
/// CombatRoom 到 Run 流程的桥接层。
/// CombatRoomSubmodule 只负责报告“战斗清空”,这里负责判断当前节点是否合法、生成 CombatRewardSession 并推动节点完成。
/// </summary>
public class RunCombatSubmodule : SubmoduleBase<RunManager>
{
public RunCombatSubmodule(RunManager owner) : base(owner)
{
}
public void SubscribeRoomEvents()
{
// RunManager 是战斗结果进入 Run 流程的唯一入口,避免 UI/奖励系统重复解释 CombatRoom 事件。
CombatManager.CombatRoomSm.OnRoomCleared += OnRoomCleared;
CombatManager.CombatRoomSm.OnEnemyDefeated += OnEnemyDefeated;
}
public void UnsubscribeRoomEvents()
{
if (CombatManager.Instance == null || CombatManager.CombatRoomSm == null)
{
return;
}
CombatManager.CombatRoomSm.OnRoomCleared -= OnRoomCleared;
CombatManager.CombatRoomSm.OnEnemyDefeated -= OnEnemyDefeated;
}
private void OnEnemyDefeated(CharacterBase enemy)
{
owner.progressSm.RecordEnemyDefeated(enemy);
EnemyDefeatRewardDispatcher.Dispatch(enemy, owner.currentRun?.randomizer?.Channel("EnemyDrop"));
}
private void OnRoomCleared()
{
if (owner.currentRun == null) return;
if (!owner.currentRun.mapData.nodes.TryGetValue(owner.currentRun.currentPosition, out RunMapNode node))
{
return;
}
if (!RunNodeTypeUtility.IsCombatNode(node.nodeType))
{
// 起点或非战斗节点不应该因为空房间触发 Run 完成逻辑。
Debug.LogWarning($"[RunManager] Ignored OnRoomCleared because current node is not a Combat node: {node.nodeType}.");
return;
}
owner.RaiseCombatRoomCleared(node);
if (owner.currentRun.currentPosition == owner.currentRun.mapData.bossPosition)
{
Debug.Log("[RunManager] Boss 房间已清空,等待玩家交互并离开。");
owner.phaseSm.TransitionToPhase(RunPhase.MapSelection);
return;
}
CombatRewardContext rewardContext = new CombatRewardContext(
owner.currentRun,
node,
owner.currentRun.currentPosition,
owner.currentRun.randomizer?.Next() ?? new System.Random());
// 奖励结算分三步:建立 session、解析配置、让装备/被动修正奖励列表。
owner.combatRewardSm.BeginCombatRewardSession(rewardContext);
List<CombatRewardInstruction> rewards =
CombatRewardResolver.Resolve(MainGameManager.Config?.combatRewardProfile, rewardContext);
owner.combatRewardSm.ApplyCombatRewardModifiers(rewardContext, rewards);
bool hasInteractableReward = RunCombatRewardSubmodule.HasInteractableCombatReward(rewards);
if (hasInteractableReward)
{
owner.phaseSm.TransitionToPhase(RunPhase.MapSelection);
}
bool hasPendingReward = rewards.Count > 0 && CombatRewardDispatcher.Dispatch(rewardContext, rewards);
owner.combatRewardSm.NotifyCombatRewardDispatched(rewardContext);
if (hasPendingReward)
{
Debug.Log($"[RunManager] Combat 房间已清空,生成 {owner.combatRewardSm.PendingCount} 个待领取奖励。");
return;
}
if (hasInteractableReward)
{
Debug.LogWarning("[RunManager] Combat 奖励规则包含交互奖励,但没有成功生成任何待领取奖励。");
}
Debug.Log("[RunManager] 收到 OnRoomCleared完成当前 Combat 节点。");
owner.combatRewardSm.CompleteCombatRewardSessionIfEmpty();
}
}
}
}