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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|