137 lines
5.0 KiB
C#
137 lines
5.0 KiB
C#
using System.Collections.Generic;
|
||
using Cielonos.MainGame.Interactions;
|
||
using Cielonos.MainGame.Inventory.Collections;
|
||
using Cielonos.MainGame.Map;
|
||
using Cielonos.MainGame.UI;
|
||
using UnityEngine;
|
||
|
||
namespace Cielonos.MainGame.Rewards
|
||
{
|
||
/// <summary>
|
||
/// 将 CombatRewardInstruction 转换为实际奖励效果。
|
||
/// Dispatcher 只负责“发放/生成”,奖励会话的生命周期仍由 RunManager.RunCombatRewardSubmodule 管理。
|
||
/// </summary>
|
||
public static class CombatRewardDispatcher
|
||
{
|
||
private const string CombatRewardSpawnGroup = "CombatReward";
|
||
|
||
public static bool Dispatch(CombatRewardContext context, IReadOnlyList<CombatRewardInstruction> rewards)
|
||
{
|
||
bool hasPendingInteractable = false;
|
||
if (rewards == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
foreach (CombatRewardInstruction reward in rewards)
|
||
{
|
||
if (reward == null || reward.count <= 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
switch (reward.type)
|
||
{
|
||
case CombatRewardInstructionType.RareMaterial:
|
||
// 即时奖励:直接进入背包,不会阻塞玩家选择下一个节点。
|
||
GrantRareMaterial(reward, context.rng);
|
||
break;
|
||
case CombatRewardInstructionType.SupplyPack:
|
||
case CombatRewardInstructionType.MechanicalTable:
|
||
// 交互奖励:生成实体并登记 pending,玩家领取前不能离开当前节点。
|
||
hasPendingInteractable |= SpawnInteractableReward(reward, context.rng);
|
||
break;
|
||
}
|
||
}
|
||
|
||
return hasPendingInteractable;
|
||
}
|
||
|
||
private static void GrantRareMaterial(CombatRewardInstruction reward, System.Random rng)
|
||
{
|
||
int totalAmount = 0;
|
||
for (int i = 0; i < reward.count; i++)
|
||
{
|
||
totalAmount += reward.RollRareMaterial(rng);
|
||
}
|
||
|
||
if (totalAmount <= 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
MainGameManager.Player.inventorySc.backpackSm.ObtainItem<RareMaterial>(totalAmount);
|
||
PlayerCanvas.NotificationUIArea?.PushRareMaterial(totalAmount, "战斗奖励");
|
||
}
|
||
|
||
private static bool SpawnInteractableReward(CombatRewardInstruction reward, System.Random rng)
|
||
{
|
||
int spawnCount = Mathf.Max(1, reward.count);
|
||
bool spawnedAny = false;
|
||
|
||
for (int i = 0; i < spawnCount; i++)
|
||
{
|
||
if (!TryCreateInteractableReward(reward, rng))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
spawnedAny = true;
|
||
}
|
||
|
||
return spawnedAny;
|
||
}
|
||
|
||
private static bool TryCreateInteractableReward(CombatRewardInstruction reward, System.Random rng)
|
||
{
|
||
string prefabId = reward.ResolveInteractablePrefabId();
|
||
GameObject instance = null;
|
||
CombatRewardSession session = RunManager.Instance?.GetActiveCombatRewardSession();
|
||
int spawnIndex = session?.NextSpawnIndex() ?? 0;
|
||
CombatRewardSpawnRequest spawnRequest = new(
|
||
CombatRewardSpawnGroup,
|
||
spawnIndex,
|
||
1.35f,
|
||
session?.OccupiedSpawnPositions);
|
||
|
||
if (ZoneManager.Instance != null)
|
||
{
|
||
ZoneManager.Instance.TrySpawnInteractable(prefabId, spawnRequest, out instance);
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning("[CombatRewardDispatcher] ZoneManager.Instance 为空,无法生成 Combat 奖励。");
|
||
}
|
||
|
||
if (instance == null)
|
||
{
|
||
Debug.LogWarning($"[CombatRewardDispatcher] 无法在 '{CombatRewardSpawnGroup}' 生成交互奖励 '{prefabId}'。");
|
||
return false;
|
||
}
|
||
|
||
ICombatRewardInteractable rewardInteractable = null;
|
||
foreach (MonoBehaviour component in instance.GetComponents<MonoBehaviour>())
|
||
{
|
||
if (component is ICombatRewardInteractable candidate)
|
||
{
|
||
rewardInteractable = candidate;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (rewardInteractable == null)
|
||
{
|
||
Debug.LogWarning($"[CombatRewardDispatcher] '{prefabId}' 没有实现 ICombatRewardInteractable。");
|
||
Object.Destroy(instance);
|
||
return false;
|
||
}
|
||
|
||
rewardInteractable.SetupCombatReward(reward, rng);
|
||
// 只有成功生成并完成 Setup 的交互奖励才登记 pending,避免阻塞 Run 流程。
|
||
RunManager.Instance?.RegisterPendingCombatReward(instance.transform.position);
|
||
Debug.Log($"[CombatRewardDispatcher] 已在 '{CombatRewardSpawnGroup}' 生成 Combat 奖励 '{prefabId}'。");
|
||
return true;
|
||
}
|
||
}
|
||
}
|