Files
Cielonos/Assets/Scripts/MainGame/UI/PlayerUI/MainGamePages/Common/Item/ItemDetailPanel.cs
SoulliesOfficial 9a9e48f8a5
2026-06-27 12:52:03 -04:00

224 lines
7.9 KiB
C#

using System.Collections.Generic;
using Cielonos.MainGame.Inventory;
using Cielonos.MainGame.UI;
using Sirenix.OdinInspector;
using SLSUtilities.General;
using TMPro;
using UniRx;
using UnityEngine;
using UnityEngine.Localization.Settings;
using UnityEngine.Serialization;
using UnityEngine.UI;
namespace SLSUtilities.UI
{
/// <summary>
/// 通用物品详情面板,显示物品图标、名称、类型、描述条目、标签等信息。
/// 可被不同的 UIPage 复用(机械台、商店、背包检视等)。
/// </summary>
public class ItemDetailPanel : UIElementBase
{
[Title("Detail Panel References")]
public TMP_Text selectionHintText;
//public Image itemIcon;
public TMP_Text nameText;
public TMP_Text typeRarityText;
public TMP_Text institutionText;
public RectTransform tagContainer;
public GameObject tagPrefab;
// ─────────────────── 描述条目 ───────────────────
[Title("Description Entries")]
[Tooltip("描述条目的容器,应挂载 VerticalLayoutGroup 以实现垂直排列。")]
public RectTransform descriptionContainer;
[Tooltip("描述条目预制体,需挂载 ItemDescriptionEntry 组件。")]
public GameObject descriptionEntryPrefab;
// ─────────────────── 运行时数据 ───────────────────
private ItemBase currentItem;
private readonly List<ItemDescriptionEntry> activeEntries = new List<ItemDescriptionEntry>();
/// <summary>当前显示的物品。</summary>
public ItemBase CurrentItem => currentItem;
/// <summary>
/// 使用指定物品的数据填充详情面板并显示。
/// </summary>
public void SetItem(ItemBase item)
{
currentItem = item;
if (item == null || item.contentData == null)
{
ClearPanel();
return;
}
ContentData data = item.contentData;
// 图标
/*Sprite icon = data.itemIcon;
if (itemIcon != null)
{
itemIcon.sprite = icon;
itemIcon.enabled = icon != null;
}*/
// 名称(本地化)
nameText.text = data.displayNameKey.Localize("Items");
// 类型
typeRarityText.text = data.itemType.ToString() + " - " + data.itemRarity.ToString();
//机构
institutionText.text = string.Empty;
for (var index = 0; index < data.institutions.Count; index++)
{
var institution = data.institutions[index];
string comma = LocalizationSettings.SelectedLocale.Identifier.Code.StartsWith("zh") ? "、" : ", ";
if(index < data.institutions.Count - 1)
institutionText.text += institution.Localize("Items") + comma;
else
institutionText.text += institution.Localize("Items");
}
// 描述条目
RefreshDescriptions(data);
// 标签
RefreshTags(data);
selectionHintText.gameObject.SetActive(false);
}
/// <summary>清空面板内容并隐藏。</summary>
public void ClearPanel()
{
currentItem = null;
//if (itemIcon != null) itemIcon.enabled = false;
if (nameText != null) nameText.text = string.Empty;
if (typeRarityText != null) typeRarityText.text = string.Empty;
ClearDescriptions();
ClearTags();
selectionHintText.gameObject.SetActive(true);
}
// ================================================================
// 描述条目
// ================================================================
private void RefreshDescriptions(ContentData data)
{
ClearDescriptions();
if (descriptionContainer == null || descriptionEntryPrefab == null) return;
if (data.descriptions == null || data.descriptions.Count == 0) return;
Dictionary<string, string> descriptionArgs = currentItem?.GetDescriptionArgs();
foreach (ItemDescription desc in data.descriptions)
{
ItemDescriptionEntry entry = Instantiate(descriptionEntryPrefab, descriptionContainer).GetComponent<ItemDescriptionEntry>();
entry.SetDescription(desc, descriptionArgs);
activeEntries.Add(entry);
}
LayoutRebuilder.ForceRebuildLayoutImmediate(descriptionContainer);
}
/// <summary>
/// 追加生成“升级预览”描述条目。
/// 用于在基础描述下方用高亮颜色展示某几项属性的升级增益。
/// </summary>
public void AppendUpgradePreview(UpgradeData upgradeData, int currentLevel, int stackAmount = 1)
{
if (descriptionContainer == null || descriptionEntryPrefab == null || upgradeData == null) return;
int targetLevel = currentLevel + stackAmount;
string previewText = $"<color=#55FF55>Lv.{currentLevel} -> Lv.{targetLevel}</color>\n";
bool hasUpgrades = false;
foreach (var upgradeInfo in upgradeData.upgrades)
{
float diff = upgradeInfo.GetDifference(targetLevel, currentLevel);
if (Mathf.Abs(diff) < 1e-5f) continue; // 无实质属性数值变化则跳过
hasUpgrades = true;
string attrName = upgradeInfo.EffectiveKey.Localize("Attributes");
string sign = diff > 0 ? "+" : "";
string valStr;
if (upgradeInfo.EffectiveKey.Contains("Multiplier") || upgradeInfo.EffectiveKey.Contains("Amplifier"))
{
valStr = (diff * 100f).ToString("0.##") + "%";
}
else
{
valStr = diff.ToString("0.##");
}
previewText += $"<color=#55FF55>{attrName}: {sign}{valStr}</color>\n";
}
if (!hasUpgrades) return;
// 去除末尾的多余换行符
previewText = previewText.TrimEnd('\n');
ItemDescriptionEntry entry = Instantiate(descriptionEntryPrefab, descriptionContainer).GetComponent<ItemDescriptionEntry>();
entry.SetRawText(previewText);
activeEntries.Add(entry);
LayoutRebuilder.ForceRebuildLayoutImmediate(descriptionContainer);
}
private void ClearDescriptions()
{
foreach (ItemDescriptionEntry entry in activeEntries)
{
if (entry != null)
{
Destroy(entry.gameObject);
}
}
activeEntries.Clear();
}
// ================================================================
// 标签
// ================================================================
private void RefreshTags(ContentData data)
{
ClearTags();
if (tagContainer == null || tagPrefab == null || data.tags == null) return;
foreach (string tag in data.tags)
{
GameObject tagObj = Instantiate(tagPrefab, tagContainer);
TMP_Text tagText = tagObj.GetComponentInChildren<TMP_Text>();
if (tagText != null)
{
tagText.text = tag;
}
}
}
private void ClearTags()
{
if (tagContainer == null) return;
for (int i = tagContainer.childCount - 1; i >= 0; i--)
{
Destroy(tagContainer.GetChild(i).gameObject);
}
}
}
}