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