168 lines
5.9 KiB
C#
168 lines
5.9 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// 机械台(Roguelite 宝箱房)场景交互对象。
|
||
/// 生成时根据配置的权重随机决定稀有度,并实例化对应的 table 模型。
|
||
/// 玩家交互后呼出 MechanicalTableUIPage,显示该稀有度下的随机装备供选择。
|
||
/// 选择后获得装备,标记为 Exhausted(单次使用),不可再次触发。
|
||
/// </summary>
|
||
public class MechanicalTable : InteractableObjectBase
|
||
{
|
||
private const int OFFER_COUNT = 3;
|
||
|
||
[TitleGroup("稀有度配置")]
|
||
[Tooltip("每种稀有度对应的 table 模型。生成时,根据稀有度生成对应模型。")]
|
||
[SerializeField]
|
||
private Dictionary<ItemRarity, GameObject> _tablePrefabs = new Dictionary<ItemRarity, GameObject>();
|
||
[SerializeField]
|
||
[Tooltip("当机械台不可用时显示的模型(如已被使用)。")]
|
||
private GameObject _notAvailableTablePrefab;
|
||
private GameObject _currentTable;
|
||
|
||
[TitleGroup("运行时状态"), ReadOnly]
|
||
public ItemRarity rarity;
|
||
private Dictionary<ItemRarity, float> RarityWeights => MainGameManager.Config.mechanicalTableRarityWeights;
|
||
private List<GameObject> _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));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 由 RunManager 或场景加载逻辑调用,预先配置本机械台的稀有度和物品列表。
|
||
/// 使用节点坐标派生的 RNG 确保同 seed 可复现。
|
||
/// </summary>
|
||
/// <param name="rng">本节点的随机数生成器。</param>
|
||
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}),机械台已用完。");
|
||
}
|
||
|
||
// ================================================================
|
||
// 稀有度逻辑
|
||
// ================================================================
|
||
|
||
/// <summary>
|
||
/// 根据权重表随机选取一个稀有度。
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从 Resources/Items 中按稀有度筛选并加权随机抽取装备。
|
||
/// 机械台只出 Support 和 Passive 类型。
|
||
/// </summary>
|
||
private List<GameObject> RollItems(System.Random rng, ItemRarity targetRarity)
|
||
{
|
||
ItemFilter filter = ItemFilter.ByRarity(targetRarity);
|
||
|
||
return ItemPoolHelper.Roll(OFFER_COUNT, rng, filter, "SupportEquipment", "PassiveEquipment");
|
||
}
|
||
}
|
||
}
|