106 lines
4.5 KiB
C#
106 lines
4.5 KiB
C#
|
|
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();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|