using System;
using System.Collections.Generic;
using Cielonos.Core.Interaction;
using Cielonos.MainGame.Inventory;
using Cielonos.MainGame.Inventory.Collections;
using Cielonos.MainGame.UI;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Cielonos.MainGame.Interactions
{
public enum RewardTier
{
Minor,
Major
}
///
/// 奖励台(奖励战斗后出现)。
/// 生成时隐藏,当 CombatRoomSm 通知清空时出现。
/// 交互后打开奖励选择面板,在 3 个候选奖励中选择 1 个。
///
public class RewardTable : InteractableObjectBase
{
private const int OFFER_COUNT = 3;
[TitleGroup("RewardTier & Prefabs")]
[SerializeField]
[Tooltip("不同稀有度对应的 table 模型。")]
private Dictionary _tablePrefabs = new Dictionary();
[SerializeField]
[Tooltip("被使用后或不可用时显示的模型。")]
private GameObject _notAvailableTablePrefab;
private GameObject _currentTable;
[TitleGroup("Reward Config")]
public RewardTier tier;
[TitleGroup("Runtime State"), ReadOnly]
private List _selectedTypes = new List();
[TitleGroup("Runtime State"), ReadOnly]
private List _currentOffers = new List();
[ShowInInspector, ReadOnly]
private bool _isAvailable;
private void Start()
{
// 初始状态:隐藏模型
if (_currentTable != null)
{
_currentTable.SetActive(false);
}
// 监听战斗房间清空事件以显示模型
CombatManager.CombatRoomSm.OnRoomCleared += OnRoomCleared;
// 如果房间已提前清空(例如非战斗阶段),直接显示模型
if (RunManager.Instance != null && RunManager.Instance.currentPhase == RunPhase.MapSelection)
{
OnRoomCleared();
}
}
private void OnDestroy()
{
CombatManager.CombatRoomSm.OnRoomCleared -= OnRoomCleared;
// 清理内存中未被选中的剩余候选物品
ClearCurrentOffers();
}
private void OnRoomCleared()
{
// 激活并显示台子模型
Setup();
if (_currentTable != null)
{
_currentTable.SetActive(true);
}
Debug.Log($"[RewardTable] 战斗房间已清空,奖励台模型已激活 ({tier})。");
}
protected override void InitializeChoices()
{
choices.Add(new InteractionChoice("查看", OpenTable));
}
private void Setup()
{
if (_currentTable != null) Destroy(_currentTable);
if (_tablePrefabs.TryGetValue(tier, out GameObject tablePrefab) && tablePrefab != null)
{
_currentTable = Instantiate(tablePrefab, transform);
}
DetermineRewardTypes();
_isAvailable = true;
}
private void DetermineRewardTypes()
{
_selectedTypes.Clear();
// 根据游戏运行种子初始化随机数生成器
System.Random rng = RunManager.Instance?.currentRun?.randomizer?.Next() ?? new System.Random();
// 检查玩家背包中当前是否有任何可升级的装备
var backpack = MainGameManager.Player.inventorySc.backpackSm;
bool hasUpgradeable = backpack.mainWeapons.Exists(i => i.IsUpgradable) ||
backpack.supportEquipments.Exists(i => i.IsUpgradable) ||
backpack.passiveEquipments.Exists(i => i.IsUpgradable);
// 可用的奖励类型池
// 0: 增加最大生命值, 1: 增加最大能量值, 2: 升级装备值, 3: 稀有材料
List pool = new List { 0, 1, 3 };
if (hasUpgradeable)
{
pool.Add(2);
}
// 恰好挑选 3 个不重复的奖励选项
while (_selectedTypes.Count < OFFER_COUNT && pool.Count > 0)
{
int index = rng.Next(pool.Count);
_selectedTypes.Add(pool[index]);
pool.RemoveAt(index);
}
}
private void OpenTable()
{
if (!_isAvailable)
{
Debug.Log("[RewardTable] 奖励台已被使用。");
return;
}
// 若尚未生成候选奖励,则进行生成
if (_currentOffers.Count == 0)
{
GenerateOffers();
}
if (_currentOffers == null || _currentOffers.Count == 0)
{
Debug.LogWarning("[RewardTable] 生成候选奖励失败。");
return;
}
// 打开奖励选择 UI 页面
var uiPage = PlayerCanvas.MainGamePages.rewardChoicePage;
if (uiPage != null)
{
uiPage.SetOffers(_currentOffers, HandleRewardSelected);
uiPage.Open();
}
else
{
Debug.LogError("[RewardTable] PlayerCanvas.MainGamePages.rewardChoicePage 未注册!");
}
}
private void GenerateOffers()
{
ClearCurrentOffers();
// 仅在首次打开奖励台的瞬间,动态拉取玩家背包中当前拥有的所有可升级装备
var backpack = MainGameManager.Player.inventorySc.backpackSm;
List upgradeableItems = new List();
foreach (var item in backpack.mainWeapons)
{
if (item.IsUpgradable) upgradeableItems.Add(item);
}
foreach (var item in backpack.supportEquipments)
{
if (item.IsUpgradable) upgradeableItems.Add(item);
}
foreach (var item in backpack.passiveEquipments)
{
if (item.IsUpgradable) upgradeableItems.Add(item);
}
// 根据之前随机选定的类型,实例化奖励选项的实例物体
foreach (int typeIndex in _selectedTypes)
{
ItemBase itemInstance = null;
if (typeIndex == 0) // 增加最大生命值
{
itemInstance = CreateItemInstance("PermanentCoating");
if (itemInstance is PermanentCoating coating)
{
coating.stackAmount = (tier == RewardTier.Major) ? 2 : 1;
}
}
else if (typeIndex == 1) // 增加最大能量值
{
itemInstance = CreateItemInstance("EnergyReservoir");
if (itemInstance is EnergyReservoir reservoir)
{
reservoir.stackAmount = (tier == RewardTier.Major) ? 2 : 1;
}
}
else if (typeIndex == 2) // 装备升级组件
{
itemInstance = CreateItemInstance("PrefabricatedComponent");
if (itemInstance is PrefabricatedComponent prefabricatedComponent)
{
// 预制组件的数量(升级的次数)也与奖励档次挂钩:普通奖为 1 次,Major 奖为 2 次
prefabricatedComponent.stackAmount = (tier == RewardTier.Major) ? 2 : 1;
if (upgradeableItems.Count > 0)
{
// 此处使用 Unity 的 Random 随机抽取目标装备,避免在 UI 交互时推进游戏主运行种子的状态
int randIdx = UnityEngine.Random.Range(0, upgradeableItems.Count);
prefabricatedComponent.targetEquipment = upgradeableItems[randIdx];
}
}
}
else if (typeIndex == 3) // 稀有材料
{
itemInstance = CreateItemInstance("RareMaterial");
if (itemInstance is RareMaterial rareMaterial)
{
// 此处同样使用 Unity 的 Random,避免推进主运行种子,并根据奖励档次生成对应区间的数量
int amount = (tier == RewardTier.Major) ? UnityEngine.Random.Range(120, 181) : UnityEngine.Random.Range(40, 61);
rareMaterial.stackAmount = amount;
}
}
if (itemInstance != null)
{
_currentOffers.Add(itemInstance);
}
}
}
private ItemBase CreateItemInstance(string prefabName) where T : ItemBase
{
string resourcePath = $"Items/Consumable/{prefabName}";
GameObject prefab = Resources.Load(resourcePath);
if (prefab == null)
{
Debug.LogError($"[RewardTable] Failed to load prefab from Resources/{resourcePath}");
return null;
}
GameObject inst = Instantiate(prefab, transform);
inst.name = prefabName;
T component = inst.GetComponent();
if (component == null)
{
Debug.LogError($"[RewardTable] Prefab {prefabName} is missing script {typeof(T).Name}");
Destroy(inst);
return null;
}
return component;
}
private void HandleRewardSelected(int index)
{
if (index < 0 || index >= _currentOffers.Count) return;
ItemBase selectedItem = _currentOffers[index];
var backpack = MainGameManager.Player.inventorySc.backpackSm;
// 判断该物品是否为可堆叠的消耗品
ConsumableBase selectedConsumable = selectedItem as ConsumableBase;
bool wasStackedIntoExisting = false;
if (selectedConsumable != null)
{
// 如果背包中已经存在该消耗品,那么在获取时它会合并堆叠,
// 此时当前的实例将不需要以单独元素形式加入背包列表。
ConsumableBase existingItem = backpack.consumables.Find(c => c.GetType() == selectedConsumable.GetType());
if (existingItem != null)
{
wasStackedIntoExisting = true;
}
}
// 将选中的物品加入到玩家背包
backpack.ObtainItem(selectedItem);
// 处理临时生成的物品实例的生命周期清理(如果它没有在自身的 OnObtained 逻辑中自毁)
if (selectedItem != null)
{
if (wasStackedIntoExisting && selectedConsumable != null)
{
// 如果已堆叠合并,销毁临时游戏物体
Destroy(selectedConsumable.gameObject);
}
else if (selectedConsumable != null && backpack.consumables.Contains(selectedConsumable))
{
// 如果是作为新的一项添加到背包,将其移动到背包容器节点下并归零坐标
selectedConsumable.transform.SetParent(MainGameManager.Player.inventorySc.consumableContainer);
selectedConsumable.transform.localPosition = Vector3.zero;
}
}
// 销毁其余未被选中的候选物品实例
for (int i = 0; i < _currentOffers.Count; i++)
{
if (i != index && _currentOffers[i] != null)
{
Destroy(_currentOffers[i].gameObject);
}
}
_currentOffers.Clear();
// 将奖励台标记为已使用,并替换模型为不可用模型
_isAvailable = false;
if (_currentTable != null) Destroy(_currentTable);
if (_notAvailableTablePrefab != null)
{
_currentTable = Instantiate(_notAvailableTablePrefab, transform);
}
SetExhausted();
Debug.Log($"[RewardTable] 已选择索引为 {index} 的奖励,奖励台交互关闭并进入耗尽状态。");
}
private void ClearCurrentOffers()
{
foreach (var item in _currentOffers)
{
if (item != null)
{
Destroy(item.gameObject);
}
}
_currentOffers.Clear();
}
}
}