465 lines
15 KiB
C#
465 lines
15 KiB
C#
// Filename : NPCShopUIManager.cs
|
|
// Creator : Converted from C++ EC_Shop
|
|
// Date : 2024
|
|
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
using PerfectWorld.Scripts.Shop;
|
|
using BrewMonster;
|
|
using static CSNetwork.Common.ExpTypes;
|
|
using ModelRenderer.Scripts.Common;
|
|
|
|
public class NPCShopUIManager : MonoBehaviour
|
|
{
|
|
[Header("UI Panels")]
|
|
public GameObject npcShopMainPanel;
|
|
public GameObject npcShopDetailPanel;
|
|
|
|
[Header("Tabs")]
|
|
public Transform tabButtonContainer;
|
|
public GameObject tabButtonPrefab;
|
|
public string tabButtonTextComponentName = "Text";
|
|
|
|
[Header("Item Display")]
|
|
public Transform itemContainer;
|
|
public GameObject itemPanelPrefab;
|
|
|
|
[Header("Main Panel Components")]
|
|
public Button closeShopButton;
|
|
|
|
private List<GameObject> currentItemPanels = new List<GameObject>();
|
|
private List<GameObject> currentTabButtons = new List<GameObject>();
|
|
private List<int> tabPageMapping = new List<int>(); // Maps tab index to page index
|
|
private int currentTabIndex = 0;
|
|
private uint currentNPCID = 0;
|
|
private NPC_SELL_SERVICE? cachedSellService = null;
|
|
private NPCShopDetailPanel detailPanelScript;
|
|
|
|
void Start()
|
|
{
|
|
if (closeShopButton != null)
|
|
closeShopButton.onClick.AddListener(CloseShop);
|
|
|
|
// Initialize detail panel reference
|
|
if (npcShopDetailPanel != null)
|
|
{
|
|
detailPanelScript = npcShopDetailPanel.GetComponent<NPCShopDetailPanel>();
|
|
if (detailPanelScript == null)
|
|
detailPanelScript = npcShopDetailPanel.GetComponentInChildren<NPCShopDetailPanel>();
|
|
|
|
// Initially hide the detail panel
|
|
if (npcShopDetailPanel.activeSelf)
|
|
npcShopDetailPanel.SetActive(false);
|
|
}
|
|
}
|
|
|
|
public void OpenNPCShop(uint npcID)
|
|
{
|
|
if (npcShopMainPanel == null)
|
|
{
|
|
Debug.LogError("NPCShopUIManager: npcShopMainPanel is null!");
|
|
return;
|
|
}
|
|
|
|
// Get NPC ID from CECUIManager
|
|
uint actualNPCID = npcID;
|
|
CECUIManager uiManager = CECUIManager.Instance;
|
|
if (uiManager != null)
|
|
{
|
|
int managerNPCID = uiManager.GetCurrentTargetNPCID();
|
|
if (managerNPCID > 0)
|
|
{
|
|
actualNPCID = (uint)managerNPCID;
|
|
}
|
|
}
|
|
|
|
currentNPCID = actualNPCID;
|
|
|
|
// Load sell service data
|
|
if (!LoadSellService(actualNPCID))
|
|
{
|
|
Debug.LogError($"NPCShopUIManager: Failed to load sell service for NPC {actualNPCID}");
|
|
return;
|
|
}
|
|
|
|
// Show panel
|
|
npcShopMainPanel.SetActive(true);
|
|
|
|
// Create tabs
|
|
CreateTabs();
|
|
|
|
// Select first tab
|
|
if (tabPageMapping.Count > 0)
|
|
{
|
|
OnTabSelected(0);
|
|
}
|
|
RefreshShopDisplay();
|
|
}
|
|
|
|
bool LoadSellService(uint npcID)
|
|
{
|
|
try
|
|
{
|
|
var elementDataMan = ElementDataManProvider.GetElementDataMan();
|
|
if (elementDataMan == null)
|
|
return false;
|
|
|
|
// Get NPC_ESSENCE
|
|
DATA_TYPE dataType = DATA_TYPE.DT_INVALID;
|
|
object npcData = elementDataMan.get_data_ptr(npcID, ID_SPACE.ID_SPACE_ESSENCE, ref dataType);
|
|
|
|
if (dataType != DATA_TYPE.DT_NPC_ESSENCE || npcData == null)
|
|
return false;
|
|
|
|
NPC_ESSENCE npcEssence = (NPC_ESSENCE)npcData;
|
|
uint sellServiceID = npcEssence.id_sell_service;
|
|
|
|
if (sellServiceID == 0)
|
|
return false;
|
|
|
|
// Get NPC_SELL_SERVICE
|
|
DATA_TYPE serviceDataType = DATA_TYPE.DT_INVALID;
|
|
object serviceData = elementDataMan.get_data_ptr(sellServiceID, ID_SPACE.ID_SPACE_ESSENCE, ref serviceDataType);
|
|
|
|
if (serviceDataType != DATA_TYPE.DT_NPC_SELL_SERVICE || serviceData == null)
|
|
return false;
|
|
|
|
cachedSellService = (NPC_SELL_SERVICE)serviceData;
|
|
return true;
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Debug.LogError($"NPCShopUIManager: Exception loading sell service: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void CreateTabs()
|
|
{
|
|
ClearTabs();
|
|
|
|
if (currentNPCID == 0 || tabButtonContainer == null || tabButtonPrefab == null)
|
|
return;
|
|
|
|
if (!cachedSellService.HasValue || cachedSellService.Value.pages == null)
|
|
return;
|
|
|
|
var sellService = cachedSellService.Value;
|
|
tabPageMapping.Clear();
|
|
|
|
// Create tabs for each page that has items
|
|
for (int pageIndex = 0; pageIndex < sellService.pages.Length; pageIndex++)
|
|
{
|
|
var page = sellService.pages[pageIndex];
|
|
|
|
// Check if page has any items
|
|
bool hasItems = false;
|
|
if (page.goods != null)
|
|
{
|
|
foreach (var good in page.goods)
|
|
{
|
|
if (good.id != 0)
|
|
{
|
|
hasItems = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasItems)
|
|
continue;
|
|
|
|
tabPageMapping.Add(pageIndex);
|
|
|
|
// Get page title
|
|
string pageTitle = ByteToStringUtils.UshortArrayToUnicodeString(page.page_title);
|
|
if (string.IsNullOrEmpty(pageTitle))
|
|
{
|
|
pageTitle = $"Page {pageIndex + 1}";
|
|
}
|
|
|
|
// Create tab button
|
|
GameObject tabButtonObj = Instantiate(tabButtonPrefab, tabButtonContainer);
|
|
tabButtonObj.name = $"Tab_Page_{pageIndex}";
|
|
tabButtonObj.SetActive(true);
|
|
|
|
// Get button component
|
|
Button tabButton = tabButtonObj.GetComponent<Button>();
|
|
if (tabButton == null)
|
|
tabButton = tabButtonObj.GetComponentInChildren<Button>();
|
|
|
|
// Get text component
|
|
TextMeshProUGUI tabText = tabButtonObj.GetComponent<TextMeshProUGUI>();
|
|
if (tabText == null)
|
|
{
|
|
Transform textTransform = tabButtonObj.transform.Find(tabButtonTextComponentName);
|
|
if (textTransform != null)
|
|
tabText = textTransform.GetComponent<TextMeshProUGUI>();
|
|
else
|
|
tabText = tabButtonObj.GetComponentInChildren<TextMeshProUGUI>();
|
|
}
|
|
|
|
if (tabText != null)
|
|
tabText.text = pageTitle;
|
|
|
|
// Setup click listener
|
|
if (tabButton != null)
|
|
{
|
|
int tabIndex = tabPageMapping.Count - 1; // Current tab index
|
|
tabButton.onClick.AddListener(() => OnTabSelected(tabIndex));
|
|
}
|
|
|
|
currentTabButtons.Add(tabButtonObj);
|
|
}
|
|
}
|
|
|
|
void ClearTabs()
|
|
{
|
|
foreach (GameObject tabButton in currentTabButtons)
|
|
{
|
|
if (tabButton != null)
|
|
Destroy(tabButton);
|
|
}
|
|
currentTabButtons.Clear();
|
|
tabPageMapping.Clear();
|
|
}
|
|
|
|
void OnTabSelected(int tabIndex)
|
|
{
|
|
if (tabIndex == currentTabIndex || tabIndex < 0 || tabIndex >= tabPageMapping.Count)
|
|
return;
|
|
|
|
currentTabIndex = tabIndex;
|
|
RefreshShopDisplay();
|
|
|
|
// Update tab button states
|
|
for (int i = 0; i < currentTabButtons.Count; i++)
|
|
{
|
|
if (currentTabButtons[i] != null)
|
|
{
|
|
Button tabButton = currentTabButtons[i].GetComponent<Button>();
|
|
if (tabButton == null)
|
|
tabButton = currentTabButtons[i].GetComponentInChildren<Button>();
|
|
|
|
if (tabButton != null)
|
|
tabButton.interactable = (i != tabIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RefreshShopDisplay()
|
|
{
|
|
// Clear existing items
|
|
ClearItems();
|
|
|
|
if (itemContainer == null || itemPanelPrefab == null)
|
|
return;
|
|
|
|
if (currentTabIndex < 0 || currentTabIndex >= tabPageMapping.Count)
|
|
return;
|
|
|
|
if (!cachedSellService.HasValue)
|
|
return;
|
|
|
|
int pageIndex = tabPageMapping[currentTabIndex];
|
|
var sellService = cachedSellService.Value;
|
|
|
|
if (pageIndex >= sellService.pages.Length)
|
|
return;
|
|
|
|
var page = sellService.pages[pageIndex];
|
|
|
|
// Create item panels
|
|
if (page.goods != null)
|
|
{
|
|
var elementDataMan = ElementDataManProvider.GetElementDataMan();
|
|
if (elementDataMan == null)
|
|
return;
|
|
|
|
foreach (var good in page.goods)
|
|
{
|
|
if (good.id == 0)
|
|
continue;
|
|
|
|
// Get item essence
|
|
DATA_TYPE itemDataType = DATA_TYPE.DT_INVALID;
|
|
object itemData = elementDataMan.get_data_ptr(good.id, ID_SPACE.ID_SPACE_ESSENCE, ref itemDataType);
|
|
|
|
if (itemData == null)
|
|
continue;
|
|
|
|
// Create GShopItem
|
|
GShopItem shopItem = CreateShopItemFromGood(good, itemData, itemDataType);
|
|
|
|
// Create panel
|
|
CreateItemPanel(shopItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
GShopItem CreateShopItemFromGood(NPC_SELL_SERVICE.SellGood good, object itemData, DATA_TYPE itemDataType)
|
|
{
|
|
GShopItem shopItem = new GShopItem();
|
|
shopItem.id = good.id;
|
|
shopItem.num = 1;
|
|
|
|
// Initialize buy array with at least one option
|
|
shopItem.buy = new GShopBuyOption[4]; // GShopItem supports up to 4 buy options
|
|
|
|
// Get item name and price based on type
|
|
string itemName = "Unknown";
|
|
int shopPrice = 0;
|
|
|
|
switch (itemDataType)
|
|
{
|
|
case DATA_TYPE.DT_WEAPON_ESSENCE:
|
|
var weaponEssence = (WEAPON_ESSENCE)itemData;
|
|
itemName = weaponEssence.Name;
|
|
shopPrice = weaponEssence.shop_price;
|
|
break;
|
|
case DATA_TYPE.DT_ARMOR_ESSENCE:
|
|
var armorEssence = (ARMOR_ESSENCE)itemData;
|
|
itemName = armorEssence.Name;
|
|
shopPrice = armorEssence.shop_price;
|
|
break;
|
|
case DATA_TYPE.DT_MEDICINE_ESSENCE:
|
|
var medicineEssence = (MEDICINE_ESSENCE)itemData;
|
|
itemName = ByteToStringUtils.UshortArrayToUnicodeString(medicineEssence.name);
|
|
shopPrice = medicineEssence.shop_price;
|
|
break;
|
|
case DATA_TYPE.DT_DECORATION_ESSENCE:
|
|
var decorationEssence = (DECORATION_ESSENCE)itemData;
|
|
itemName = ByteToStringUtils.UshortArrayToUnicodeString(decorationEssence.name);
|
|
shopPrice = decorationEssence.shop_price;
|
|
break;
|
|
case DATA_TYPE.DT_STONE_ESSENCE:
|
|
var stoneEssence = (STONE_ESSENCE)itemData;
|
|
itemName = ByteToStringUtils.UshortArrayToUnicodeString(stoneEssence.name);
|
|
shopPrice = stoneEssence.shop_price;
|
|
break;
|
|
case DATA_TYPE.DT_MATERIAL_ESSENCE:
|
|
var materialEssence = (MATERIAL_ESSENCE)itemData;
|
|
itemName = ByteToStringUtils.UshortArrayToUnicodeString(materialEssence.name);
|
|
shopPrice = materialEssence.shop_price;
|
|
break;
|
|
default:
|
|
itemName = $"Item_{good.id}";
|
|
break;
|
|
}
|
|
|
|
shopItem.name = itemName;
|
|
|
|
// Set price from contribution cost or shop price
|
|
if (good.contrib_cost > 0)
|
|
{
|
|
shopItem.buy[0].price = (uint)good.contrib_cost;
|
|
shopItem.buy[0].type = 0; // 0 = permanent
|
|
}
|
|
else if (shopPrice > 0)
|
|
{
|
|
shopItem.buy[0].price = (uint)shopPrice;
|
|
shopItem.buy[0].type = 0; // 0 = permanent
|
|
}
|
|
else
|
|
{
|
|
// Initialize with invalid type if no price
|
|
shopItem.buy[0].type = -1; // -1 = invalid
|
|
shopItem.buy[0].price = 0;
|
|
}
|
|
|
|
return shopItem;
|
|
}
|
|
|
|
void CreateItemPanel(GShopItem item)
|
|
{
|
|
if (itemPanelPrefab == null || itemContainer == null)
|
|
return;
|
|
|
|
GameObject itemPanel = Instantiate(itemPanelPrefab, itemContainer);
|
|
itemPanel.SetActive(true);
|
|
|
|
NPCShopItemPanel itemPanelScript = itemPanel.GetComponent<NPCShopItemPanel>();
|
|
if (itemPanelScript == null)
|
|
itemPanelScript = itemPanel.GetComponentInChildren<NPCShopItemPanel>();
|
|
|
|
if (itemPanelScript != null)
|
|
{
|
|
itemPanelScript.SetupItem(item, this);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError($"[NPCShopUIManager] NPCShopItemPanel component not found on prefab! Prefab name: {itemPanelPrefab.name}");
|
|
}
|
|
|
|
currentItemPanels.Add(itemPanel);
|
|
}
|
|
|
|
void ClearItems()
|
|
{
|
|
foreach (GameObject panel in currentItemPanels)
|
|
{
|
|
if (panel != null)
|
|
Destroy(panel);
|
|
}
|
|
currentItemPanels.Clear();
|
|
}
|
|
|
|
public void ShowItemDetail(GShopItem item)
|
|
{
|
|
if (item.id == 0)
|
|
return;
|
|
|
|
if (npcShopDetailPanel == null)
|
|
{
|
|
Debug.LogWarning("[NPCShopUIManager] npcShopDetailPanel is not assigned!");
|
|
return;
|
|
}
|
|
|
|
// Ensure detail panel script is available
|
|
if (detailPanelScript == null)
|
|
{
|
|
detailPanelScript = npcShopDetailPanel.GetComponent<NPCShopDetailPanel>();
|
|
if (detailPanelScript == null)
|
|
detailPanelScript = npcShopDetailPanel.GetComponentInChildren<NPCShopDetailPanel>();
|
|
}
|
|
|
|
if (detailPanelScript != null)
|
|
{
|
|
npcShopDetailPanel.SetActive(true);
|
|
detailPanelScript.SetupDetailPanel(item, this);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("[NPCShopUIManager] NPCShopDetailPanel component not found on npcShopDetailPanel GameObject!");
|
|
}
|
|
}
|
|
|
|
public void CloseDetailPanel()
|
|
{
|
|
if (npcShopDetailPanel != null)
|
|
npcShopDetailPanel.SetActive(false);
|
|
}
|
|
|
|
public void CloseShop()
|
|
{
|
|
if (npcShopMainPanel != null)
|
|
npcShopMainPanel.SetActive(false);
|
|
|
|
// Close detail panel when closing shop
|
|
CloseDetailPanel();
|
|
|
|
ClearTabs();
|
|
ClearItems();
|
|
cachedSellService = null;
|
|
currentNPCID = 0;
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
ClearTabs();
|
|
ClearItems();
|
|
}
|
|
}
|