Files
Cielonos/Assets/Scripts/MainGame/Interactions/MechanicalTable.cs
SoulliesOfficial 649b7a5ddc 更新
2026-05-23 08:27:50 -04:00

168 lines
5.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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");
}
}
}