Files
Cielonos/Assets/Scripts/MainGame/Rewards/CombatRewardDispatcher.cs
SoulliesOfficial 39b43680a9 爆更
2026-07-18 03:16:20 -04:00

137 lines
5.0 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}
}