using System; using System.Collections.Generic; using Cielonos.Core.Interaction; using Cielonos.MainGame.Inventory; using Cielonos.MainGame.Items; using Cielonos.MainGame.UI; using Lean.Pool; using Sirenix.OdinInspector; using SLSUtilities.General; using UnityEngine; namespace Cielonos.MainGame.Interactions { /// /// 机械台(Roguelite 宝箱房)场景交互对象。 /// 生成时根据配置的权重随机决定稀有度,并实例化对应的 table 模型。 /// 玩家交互后呼出 MechanicalTableUIPage,显示该稀有度下的随机装备供选择。 /// 选择后获得装备,标记为 Exhausted(单次使用),不可再次触发。 /// public class MechanicalTable : InteractableObjectBase { private const int OFFER_COUNT = 3; [TitleGroup("稀有度配置")] [Tooltip("每种稀有度对应的 table 模型。生成时,根据稀有度生成对应模型。")] [SerializeField] private Dictionary _tablePrefabs = new Dictionary(); [SerializeField] [Tooltip("当机械台不可用时显示的模型(如已被使用)。")] private GameObject _notAvailableTablePrefab; private GameObject _currentTable; [TitleGroup("运行时状态"), ReadOnly] public ItemRarity rarity; private Dictionary RarityWeights => MainGameManager.Config.mechanicalTableRarityWeights; private List _currentOffers; [ShowInInspector] private bool _isAvailable; private void Start() { if (!_isAvailable) { Setup(new System.Random()); } } protected override void InitializeChoices() { choices.Add(new InteractionChoice("Open Mechanical Table", OpenTable)); } /// /// 由 RunManager 或场景加载逻辑调用,预先配置本机械台的稀有度和物品列表。 /// 使用节点坐标派生的 RNG 确保同 seed 可复现。 /// /// 本节点的随机数生成器。 public void Setup(System.Random rng) { rarity = RollRarity(rng); if (_currentTable != null) Destroy(_currentTable); if (_tablePrefabs.TryGetValue(rarity, out GameObject tablePrefab) && tablePrefab != null) { _currentTable = Instantiate(tablePrefab, transform); } else { Debug.LogWarning($"[MechanicalTable] 稀有度 {rarity} 没有对应的 table 预制体。"); } _currentOffers = RollItems(rng, rarity); _isAvailable = true; } private void OpenTable() { // 如果未通过 Setup() 预配置,自动配置(fallback) if (!_isAvailable && (_currentOffers == null || _currentOffers.Count == 0)) { System.Random fallbackRng = RunManager.Instance?.currentRun?.randomizer?.Next() ?? new System.Random(); Setup(fallbackRng); } if (!_isAvailable) return; if (_currentOffers == null || _currentOffers.Count == 0) { Debug.LogWarning("[MechanicalTable] 候选池为空,没有符合条件的装备。"); return; } var uiPage = PlayerCanvas.MainGamePages.mechanicalTablePage; uiPage.SetOffers(_currentOffers, HandleOfferSelected); uiPage.Open(); } private void HandleOfferSelected(int index) { if (index < 0 || index >= _currentOffers.Count) return; GameObject selectedPrefab = _currentOffers[index]; // 通过 BackpackSubmodule 将物品加入背包 MainGameManager.Player.inventorySc.backpackSm.ObtainItem(selectedPrefab); _isAvailable = false; Destroy(_currentTable); _currentTable = Instantiate(_notAvailableTablePrefab, transform); // 禁用场景中的交互触发器 SetInteractable(false); Debug.Log($"[MechanicalTable] 玩家选择了 '{selectedPrefab.name}'({rarity}),机械台已用完。"); } // ================================================================ // 稀有度逻辑 // ================================================================ /// /// 根据权重表随机选取一个稀有度。 /// private ItemRarity RollRarity(System.Random rng) { float totalWeight = 0f; foreach (var kvp in RarityWeights) { totalWeight += kvp.Value; } if (totalWeight <= 0f) { Debug.LogWarning("[MechanicalTable] 稀有度权重总和为 0,使用默认 Tera。"); return ItemRarity.Tera; } float roll = (float)(rng.NextDouble() * totalWeight); float cumulative = 0f; foreach (var kvp in RarityWeights) { cumulative += kvp.Value; if (roll <= cumulative) { return kvp.Key; } } // 安全回退 return ItemRarity.Tera; } /// /// 从 Resources/Items 中按稀有度筛选并加权随机抽取装备。 /// 机械台只出 Support 和 Passive 类型。 /// private List RollItems(System.Random rng, ItemRarity targetRarity) { ItemFilter filter = ItemFilter.ByRarity(targetRarity); return ItemPoolHelper.Roll(OFFER_COUNT, rng, filter, "SupportEquipment", "PassiveEquipment"); } } }