Files
Cielonos/Assets/Scripts/MainGame/Interactions/LogisticsCenter.cs

139 lines
4.8 KiB
C#
Raw Normal View History

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;
2026-07-18 03:16:20 -04:00
using Cielonos.MainGame.Rewards;
2026-05-10 11:47:55 -04:00
using Cielonos.MainGame.UI;
2026-07-18 03:16:20 -04:00
using Sirenix.OdinInspector;
2026-05-10 11:47:55 -04:00
using UnityEngine;
namespace Cielonos.MainGame.Interactions
{
/// <summary>
/// 物流中心(商店)场景交互对象。
/// 玩家靠近按交互键后呼出 LogisticCenterUIPage显示可购买的随机装备。
/// 商店可反复打开(不像机械台单次使用),商品在首次进入时生成,买完即消失。
/// 货币通过消耗背包中的 RareMaterial 消耗品来支付。
/// </summary>
public class LogisticsCenter : InteractableObjectBase
{
2026-07-18 03:16:20 -04:00
[TitleGroup("Reward Profile")]
[SerializeField, Required]
private RewardProfile _profile;
2026-05-10 11:47:55 -04:00
private List<ShopOffer> currentOffers;
private bool isInitialized;
protected override void InitializeChoices()
{
choices.Add(new InteractionChoice("Open Logistic Center", OpenShop));
}
/// <summary>
/// 由 RunManager 或场景加载逻辑调用,预先生成本次商店的商品列表和价格。
/// 若未调用此方法,交互时会自动从 Resources/Items 中生成。
/// </summary>
2026-07-18 03:16:20 -04:00
/// <param name="rng">本局 Run 的随机数生成器。</param>
2026-05-10 11:47:55 -04:00
public void Setup(System.Random rng)
{
currentOffers = RollShopOffers(rng);
isInitialized = true;
}
private void OpenShop()
{
if (!isInitialized)
{
2026-07-18 03:16:20 -04:00
System.Random rng = RunManager.Instance?.currentRun?.randomizer?.Next() ?? new System.Random();
2026-05-10 11:47:55 -04:00
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;
// 将物品加入背包
2026-07-18 03:16:20 -04:00
inventorySc.backpackSm.ObtainItemPrefab(offer.item);
2026-05-10 11:47:55 -04:00
// 从商品列表中移除已购买的商品
currentOffers.RemoveAt(index);
2026-07-18 03:16:20 -04:00
Debug.Log($"[LogisticCenter] 玩家购买了 '{offer.item.name}',花费 {offer.price} RareMaterial剩余 {remaining}。");
2026-05-10 11:47:55 -04:00
}
/// <summary>
2026-07-18 03:16:20 -04:00
/// 从 RewardProfile 生成商店候选并生成包含价格的 ShopOffer。
/// Profile 可明确限制可用主武器,避免废弃武器自动进入商店池。
2026-05-10 11:47:55 -04:00
/// </summary>
2026-07-18 03:16:20 -04:00
private List<ShopOffer> RollShopOffers(System.Random rng)
2026-05-10 11:47:55 -04:00
{
2026-07-18 03:16:20 -04:00
if (_profile == null)
{
Debug.LogError("[LogisticsCenter] RewardProfile is not assigned.");
return new List<ShopOffer>();
}
2026-05-10 11:47:55 -04:00
2026-07-18 03:16:20 -04:00
List<ItemBase> rolledItems = RewardGenerator.GeneratePrefabOffers(_profile, rng,
RewardGenerationContext.FromPlayer().ExcludeOwnedNonConsumables());
2026-05-10 11:47:55 -04:00
List<ShopOffer> offers = new List<ShopOffer>(rolledItems.Count);
2026-07-18 03:16:20 -04:00
foreach (ItemBase item in rolledItems)
2026-05-10 11:47:55 -04:00
{
if (item == null || item.contentData == null) continue;
int price = MainGameManager.Config.RollPrice(item.contentData.itemRarity, rng);
2026-07-18 03:16:20 -04:00
offers.Add(new ShopOffer(item, price));
2026-05-10 11:47:55 -04:00
}
return offers;
}
}
/// <summary>
/// 商店中的单个商品条目:包含物品预制体引用和售价。
/// </summary>
[Serializable]
public class ShopOffer
{
2026-07-18 03:16:20 -04:00
public ItemBase item;
2026-05-10 11:47:55 -04:00
public int price;
2026-07-18 03:16:20 -04:00
public ShopOffer(ItemBase item, int price)
2026-05-10 11:47:55 -04:00
{
2026-07-18 03:16:20 -04:00
this.item = item;
2026-05-10 11:47:55 -04:00
this.price = price;
}
}
}