2026-05-10 11:47:55 -04:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using Cielonos.Core.Interaction;
|
|
|
|
|
|
using Cielonos.MainGame.Characters;
|
2026-05-23 08:27:50 -04:00
|
|
|
|
using Cielonos.MainGame.Inventory;
|
|
|
|
|
|
using Cielonos.MainGame.Inventory.Collections;
|
2026-05-10 11:47:55 -04:00
|
|
|
|
using Cielonos.MainGame.Items;
|
|
|
|
|
|
using Cielonos.MainGame.UI;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Cielonos.MainGame.Interactions
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 物流中心(商店)场景交互对象。
|
|
|
|
|
|
/// 玩家靠近按交互键后呼出 LogisticCenterUIPage,显示可购买的随机装备。
|
|
|
|
|
|
/// 商店可反复打开(不像机械台单次使用),商品在首次进入时生成,买完即消失。
|
|
|
|
|
|
/// 货币通过消耗背包中的 RareMaterial 消耗品来支付。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class LogisticsCenter : InteractableObjectBase
|
|
|
|
|
|
{
|
|
|
|
|
|
private const int OFFER_COUNT = 5;
|
|
|
|
|
|
|
|
|
|
|
|
private List<ShopOffer> currentOffers;
|
|
|
|
|
|
private bool isInitialized;
|
|
|
|
|
|
|
|
|
|
|
|
protected override void InitializeChoices()
|
|
|
|
|
|
{
|
|
|
|
|
|
choices.Add(new InteractionChoice("Open Logistic Center", OpenShop));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 由 RunManager 或场景加载逻辑调用,预先生成本次商店的商品列表和价格。
|
|
|
|
|
|
/// 若未调用此方法,交互时会自动从 Resources/Items 中生成。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="rng">本局 Run 的随机数生成器。</param
|
|
|
|
|
|
public void Setup(System.Random rng)
|
|
|
|
|
|
{
|
|
|
|
|
|
currentOffers = RollShopOffers(rng);
|
|
|
|
|
|
isInitialized = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OpenShop()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!isInitialized)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Random rng = RunManager.Instance?.currentRun?.randomizer?.Next()
|
|
|
|
|
|
?? new System.Random();
|
|
|
|
|
|
currentOffers = RollShopOffers(rng);
|
|
|
|
|
|
isInitialized = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (currentOffers == null || currentOffers.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("[LogisticCenter] 候选池为空,没有可售卖的装备。");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var uiPage = PlayerCanvas.MainGamePages.logisticsCenterPage;
|
|
|
|
|
|
uiPage.SetOffers(currentOffers, HandlePurchase);
|
|
|
|
|
|
uiPage.Open();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void HandlePurchase(int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (index < 0 || index >= currentOffers.Count) return;
|
|
|
|
|
|
|
|
|
|
|
|
ShopOffer offer = currentOffers[index];
|
|
|
|
|
|
|
|
|
|
|
|
// 获取玩家背包中的 RareMaterial
|
|
|
|
|
|
PlayerInventorySubcontroller inventorySc = MainGameManager.Player.inventorySc;
|
|
|
|
|
|
RareMaterial rareMaterial = MainGameManager.Player.inventorySc.GetRareMaterial();
|
|
|
|
|
|
|
|
|
|
|
|
if (rareMaterial == null || rareMaterial.stackAmount < offer.price)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("[LogisticCenter] RareMaterial 不足,无法购买。");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 扣除 RareMaterial
|
|
|
|
|
|
rareMaterial.Use(offer.price);
|
|
|
|
|
|
int remaining = rareMaterial != null ? rareMaterial.stackAmount : 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 将物品加入背包
|
|
|
|
|
|
inventorySc.backpackSm.ObtainItem(offer.prefab);
|
|
|
|
|
|
|
|
|
|
|
|
// 从商品列表中移除已购买的商品
|
|
|
|
|
|
currentOffers.RemoveAt(index);
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Log($"[LogisticCenter] 玩家购买了 '{offer.prefab.name}',花费 {offer.price} RareMaterial,剩余 {remaining}。");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 从 Resources/Items 中筛选可售卖的装备并生成 ShopOffer(含随机价格)。
|
|
|
|
|
|
/// 商店出售所有类型装备(MainWeapon、Support、Passive),但排除 None 稀有度。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private static List<ShopOffer> RollShopOffers(System.Random rng)
|
|
|
|
|
|
{
|
|
|
|
|
|
ItemFilter filter = ItemFilter.ByRarity(ItemRarity.None).Not();
|
|
|
|
|
|
|
|
|
|
|
|
List<GameObject> rolledItems = ItemPoolHelper.Roll(
|
|
|
|
|
|
OFFER_COUNT, rng, filter,
|
|
|
|
|
|
"MainWeapon", "SupportEquipment", "PassiveEquipment"
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
List<ShopOffer> offers = new List<ShopOffer>(rolledItems.Count);
|
|
|
|
|
|
foreach (GameObject prefab in rolledItems)
|
|
|
|
|
|
{
|
|
|
|
|
|
ItemBase item = prefab.GetComponent<ItemBase>();
|
|
|
|
|
|
if (item == null || item.contentData == null) continue;
|
|
|
|
|
|
|
|
|
|
|
|
int price = MainGameManager.Config.RollPrice(item.contentData.itemRarity, rng);
|
|
|
|
|
|
offers.Add(new ShopOffer(prefab, price));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return offers;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 商店中的单个商品条目:包含物品预制体引用和售价。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
|
public class ShopOffer
|
|
|
|
|
|
{
|
|
|
|
|
|
public GameObject prefab;
|
|
|
|
|
|
public int price;
|
|
|
|
|
|
|
|
|
|
|
|
public ShopOffer(GameObject prefab, int price)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.prefab = prefab;
|
|
|
|
|
|
this.price = price;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|