diff --git a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset
index 74e9014887..3abddba683 100644
--- a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset
+++ b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset
@@ -63,3 +63,7 @@ MonoBehaviour:
prefab: {fileID: 6225996695219405878, guid: 2ed5e05eaa1d87341bf25c3cf111cc01, type: 3}
- id: Win_Settings
prefab: {fileID: 5193882765232824931, guid: 12e3fbc87fab9044abb62aba808775c8, type: 3}
+ - id: EC_StorageUI
+ prefab: {fileID: 3837460183159982207, guid: 0986049a141406946b0ed97344b84f78, type: 3}
+ - id: DlgQuantity
+ prefab: {fileID: 8147986291757959694, guid: 11d09ee52b0c5f24fb3ef21e177ebe2d, type: 3}
diff --git a/Assets/PerfectWorld/Scripts/Common/DialogScriptTableObject.cs b/Assets/PerfectWorld/Scripts/Common/DialogScriptTableObject.cs
index a44265bc23..63c5b91ceb 100644
--- a/Assets/PerfectWorld/Scripts/Common/DialogScriptTableObject.cs
+++ b/Assets/PerfectWorld/Scripts/Common/DialogScriptTableObject.cs
@@ -12,7 +12,10 @@ namespace BrewMonster.UI
public GameObject GetPrefabDialog(string id)
{
- return lstPrefabDialog.Find(x => x.id.Equals(id)).prefab;
+ if (string.IsNullOrEmpty(id) || lstPrefabDialog == null)
+ return null;
+ var entry = lstPrefabDialog.Find(x => !string.IsNullOrEmpty(x.id) && x.id.Equals(id));
+ return entry.prefab;
}
}
diff --git a/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs b/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs
index 9064fcc8d0..a4bd58d806 100644
--- a/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs
+++ b/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs
@@ -1,95 +1,100 @@
-namespace BrewMonster.Scripts
-{
- public class InventoryConst
- {
- // Index of item in equipment inventory
- public const int EQUIPIVTR_WEAPON = 0;
- public const int EQUIPIVTR_HEAD = 1;
- public const int EQUIPIVTR_NECK = 2;
- public const int EQUIPIVTR_SHOULDER = 3;
- public const int EQUIPIVTR_BODY = 4;
- public const int EQUIPIVTR_WAIST = 5;
- public const int EQUIPIVTR_LEG = 6;
- public const int EQUIPIVTR_FOOT = 7;
- public const int EQUIPIVTR_WRIST = 8;
- public const int EQUIPIVTR_FINGER1 = 9;
- public const int EQUIPIVTR_FINGER2 = 10;
- public const int EQUIPIVTR_PROJECTILE = 11;
- public const int EQUIPIVTR_FLYSWORD = 12;
- public const int EQUIPIVTR_FASHION_BODY = 13;
- public const int EQUIPIVTR_FASHION_LEG = 14;
- public const int EQUIPIVTR_FASHION_FOOT = 15;
- public const int EQUIPIVTR_FASHION_WRIST = 16;
- public const int EQUIPIVTR_RUNE = 17;
- public const int EQUIPIVTR_BIBLE = 18;
- public const int EQUIPIVTR_SPEAKER = 19;
- public const int EQUIPIVTR_AUTOHP = 20;
- public const int EQUIPIVTR_AUTOMP = 21;
- public const int EQUIPIVTR_POCKET = 22;
- public const int EQUIPIVTR_GOBLIN = 23;
- public const int EQUIPIVTR_CERTIFICATE = 24;
- public const int EQUIPIVTR_FASHION_HEAD = 25;
- public const int EQUIPIVTR_FORCE_TOKEN = 26;
- public const int EQUIPIVTR_DYNSKILLEQUIP1 = 27;
- public const int EQUIPIVTR_DYNSKILLEQUIP2 = 28;
- public const int EQUIPIVTR_FASHION_WEAPON = 29;
- public const int SIZE_EQUIPIVTR = 30;
- public const int EQUIPIVTR_UNUSED1 = 30;
- public const int EQUIPIVTR_UNUSED2 = 31;
- public const int EQUIPIVTR_GENERALCARD1 = 32;
- public const int EQUIPIVTR_GENERALCARD2 = 33;
- public const int EQUIPIVTR_GENERALCARD3 = 34;
- public const int EQUIPIVTR_GENERALCARD4 = 35;
- public const int EQUIPIVTR_GENERALCARD5 = 36;
- public const int EQUIPIVTR_GENERALCARD6 = 37;
- public const int SIZE_ALL_EQUIPIVTR = 38;
- public const int SIZE_GENERALCARD_EQUIPIVTR = 6; // SIZE_ALL_EQUIPIVTR - EQUIPIVTR_GENERALCARD1
-
- // Inventory size constants
- public const int IVTRSIZE_EQUIPPACK = 32; // Equipment (SIZE_ALL_EQUIPIVTR)
- public const int IVTRSIZE_TASKPACK = 32; // Task pack
- public const int IVTRSIZE_DEALPACK = 24; // Deal pack
- public const int IVTRSIZE_NPCPACK = 32; // NPC pack
- public const int IVTRSIZE_TRASHBOX = 16; // Trash box
- public const int IVTRSIZE_BUYPACK = 12; // Buy pack
- public const int IVTRSIZE_SELLPACK = 12; // Sell pack
- public const int IVTRSIZE_BOOTHSPACK = 12; // Default booth pack for selling
- public const int IVTRSIZE_BOOTHBPACK = 12; // Default booth pack for buying
- public const int IVTRSIZE_BOOTHSPACK_MAX = 20; // Max booth pack for selling (player may use certificate...)
- public const int IVTRSIZE_BOOTHBPACK_MAX = 20; // Max booth pack for buying
-
- public const int IVTRSIZE_CLIENTCARDPACK = 32; // Client pack for general card collection
-
- // Main bag UI (C++ DlgInventory.h: CECDLGSHOP_PACKMAX / PACKLINEMAX)
- public const int IVTRSIZE_PACK_UI_PAGE = 32;
- public const int IVTRSIZE_PACK_UI_LINE = 8;
- /// Upper bound for client pack slots (server ivtr_size is byte).
- public const int IVTRSIZE_PACK_MAX = 255;
-
- public const int NUM_NPCIVTR = 8; // NPC inventory number
-
- // Inventory package types (match legacy C++ IVTRTYPE_*)
- public const byte IVTRTYPE_PACK = 0;
- public const byte IVTRTYPE_EQUIPPACK = 1;
- public const byte IVTRTYPE_TASKPACK = 2;
- }
- public enum Shortcut
- {
- NUM_HOSTSCSETS1 = 5, // expanded from 3 to 5 (2009.05.27)
- NUM_HOSTSCSETS2 = 3,
- SIZE_HOSTSCSET1 = 9, // expanded from 6 to 9 (2009.05.27)
- SIZE_HOSTSCSET2 = 8,
-
- SIZE_FASHIONSCSET = 240,
- };
- // Pet food type
- enum PetFoodType
- {
- PET_FOOD_GRASS = 0,
- PET_FOOD_MEAT,
- PET_FOOD_VEGETABLE,
- PET_FOOD_FRUIT,
- PET_FOOD_WATER,
- MAX_PET_FOOD,
- };
+namespace BrewMonster.Scripts
+{
+ public class InventoryConst
+ {
+ // Index of item in equipment inventory
+ public const int EQUIPIVTR_WEAPON = 0;
+ public const int EQUIPIVTR_HEAD = 1;
+ public const int EQUIPIVTR_NECK = 2;
+ public const int EQUIPIVTR_SHOULDER = 3;
+ public const int EQUIPIVTR_BODY = 4;
+ public const int EQUIPIVTR_WAIST = 5;
+ public const int EQUIPIVTR_LEG = 6;
+ public const int EQUIPIVTR_FOOT = 7;
+ public const int EQUIPIVTR_WRIST = 8;
+ public const int EQUIPIVTR_FINGER1 = 9;
+ public const int EQUIPIVTR_FINGER2 = 10;
+ public const int EQUIPIVTR_PROJECTILE = 11;
+ public const int EQUIPIVTR_FLYSWORD = 12;
+ public const int EQUIPIVTR_FASHION_BODY = 13;
+ public const int EQUIPIVTR_FASHION_LEG = 14;
+ public const int EQUIPIVTR_FASHION_FOOT = 15;
+ public const int EQUIPIVTR_FASHION_WRIST = 16;
+ public const int EQUIPIVTR_RUNE = 17;
+ public const int EQUIPIVTR_BIBLE = 18;
+ public const int EQUIPIVTR_SPEAKER = 19;
+ public const int EQUIPIVTR_AUTOHP = 20;
+ public const int EQUIPIVTR_AUTOMP = 21;
+ public const int EQUIPIVTR_POCKET = 22;
+ public const int EQUIPIVTR_GOBLIN = 23;
+ public const int EQUIPIVTR_CERTIFICATE = 24;
+ public const int EQUIPIVTR_FASHION_HEAD = 25;
+ public const int EQUIPIVTR_FORCE_TOKEN = 26;
+ public const int EQUIPIVTR_DYNSKILLEQUIP1 = 27;
+ public const int EQUIPIVTR_DYNSKILLEQUIP2 = 28;
+ public const int EQUIPIVTR_FASHION_WEAPON = 29;
+ public const int SIZE_EQUIPIVTR = 30;
+ public const int EQUIPIVTR_UNUSED1 = 30;
+ public const int EQUIPIVTR_UNUSED2 = 31;
+ public const int EQUIPIVTR_GENERALCARD1 = 32;
+ public const int EQUIPIVTR_GENERALCARD2 = 33;
+ public const int EQUIPIVTR_GENERALCARD3 = 34;
+ public const int EQUIPIVTR_GENERALCARD4 = 35;
+ public const int EQUIPIVTR_GENERALCARD5 = 36;
+ public const int EQUIPIVTR_GENERALCARD6 = 37;
+ public const int SIZE_ALL_EQUIPIVTR = 38;
+ public const int SIZE_GENERALCARD_EQUIPIVTR = 6; // SIZE_ALL_EQUIPIVTR - EQUIPIVTR_GENERALCARD1
+
+ // Inventory size constants
+ public const int IVTRSIZE_EQUIPPACK = 32; // Equipment (SIZE_ALL_EQUIPIVTR)
+ public const int IVTRSIZE_TASKPACK = 32; // Task pack
+ public const int IVTRSIZE_DEALPACK = 24; // Deal pack
+ public const int IVTRSIZE_NPCPACK = 32; // NPC pack
+ public const int IVTRSIZE_TRASHBOX = 16; // Trash box
+ public const int IVTRSIZE_BUYPACK = 12; // Buy pack
+ public const int IVTRSIZE_SELLPACK = 12; // Sell pack
+ public const int IVTRSIZE_BOOTHSPACK = 12; // Default booth pack for selling
+ public const int IVTRSIZE_BOOTHBPACK = 12; // Default booth pack for buying
+ public const int IVTRSIZE_BOOTHSPACK_MAX = 20; // Max booth pack for selling (player may use certificate...)
+ public const int IVTRSIZE_BOOTHBPACK_MAX = 20; // Max booth pack for buying
+
+ public const int IVTRSIZE_CLIENTCARDPACK = 32; // Client pack for general card collection
+
+ // Main bag UI (C++ DlgInventory.h: CECDLGSHOP_PACKMAX / PACKLINEMAX)
+ public const int IVTRSIZE_PACK_UI_PAGE = 32;
+ public const int IVTRSIZE_PACK_UI_LINE = 8;
+ /// Upper bound for client pack slots (server ivtr_size is byte).
+ public const int IVTRSIZE_PACK_MAX = 255;
+
+ public const int NUM_NPCIVTR = 8; // NPC inventory number
+
+ // Inventory package types (match legacy C++ IVTRTYPE_*)
+ public const byte IVTRTYPE_PACK = 0;
+ public const byte IVTRTYPE_EQUIPPACK = 1;
+ public const byte IVTRTYPE_TASKPACK = 2;
+ public const byte IVTRTYPE_TRASHBOX = 3;
+ public const byte IVTRTYPE_TRASHBOX2 = 4;
+ public const byte IVTRTYPE_TRASHBOX3 = 5;
+ public const byte IVTRTYPE_ACCOUNT_BOX = 6;
+ public const byte IVTRTYPE_GENERALCARD_BOX = 7;
+ }
+ public enum Shortcut
+ {
+ NUM_HOSTSCSETS1 = 5, // expanded from 3 to 5 (2009.05.27)
+ NUM_HOSTSCSETS2 = 3,
+ SIZE_HOSTSCSET1 = 9, // expanded from 6 to 9 (2009.05.27)
+ SIZE_HOSTSCSET2 = 8,
+
+ SIZE_FASHIONSCSET = 240,
+ };
+ // Pet food type
+ enum PetFoodType
+ {
+ PET_FOOD_GRASS = 0,
+ PET_FOOD_MEAT,
+ PET_FOOD_VEGETABLE,
+ PET_FOOD_FRUIT,
+ PET_FOOD_WATER,
+ MAX_PET_FOOD,
+ };
}
\ No newline at end of file
diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs
index e374f7d57e..a014dc3809 100644
--- a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs
+++ b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs
@@ -43,6 +43,8 @@ namespace BrewMonster.Scripts.Managers
[SerializeField] private EC_UIUtility.TextOutlet descriptionText;
[SerializeField] private Button equipButton;
[SerializeField] private Button dropButton;
+ [Tooltip("Optional. When warehouse is open: Bỏ vào / Lấy ra. If unset, equipButton is reused.")]
+ [SerializeField] private Button storageTransferButton;
[Header("Stack Split UI (assign in Inspector)")]
[SerializeField] private GameObject splitPanelRoot;
@@ -113,15 +115,19 @@ namespace BrewMonster.Scripts.Managers
}
// Current selected item for equip/unequip operations
- private byte currentSelectedPackage;
- private int currentSelectedSlot;
+ internal byte currentSelectedPackage;
+ internal int currentSelectedSlot;
private EC_IvtrItem currentSelectedItem;
private EC_IvtrItem currentSelectedEquipment;
+ private Transform _detailPanelOriginalParent;
+ private int _detailPanelOriginalSiblingIndex = -1;
+
private const byte PKG_INVENTORY = InventoryConst.IVTRTYPE_PACK;
private const byte PKG_EQUIPMENT = InventoryConst.IVTRTYPE_EQUIPPACK;
private const byte PKG_TASK = InventoryConst.IVTRTYPE_TASKPACK;
private const byte PKG_FASHION = 3; // Trash / fashion box slot in legacy client (GetInventory may not resolve; see host)
+ private const byte PKG_TRASHBOX = InventoryConst.IVTRTYPE_TRASHBOX;
public enum InventoryBagTab
{
@@ -132,6 +138,26 @@ namespace BrewMonster.Scripts.Managers
private InventoryBagTab _bagTab = InventoryBagTab.Item;
private bool _inventorySlotTemplateResolved;
+ public override void Show(bool value)
+ {
+ if (!value && GetHostPlayer() != null && GetHostPlayer().IsUsingTrashBox())
+ {
+ CECHostPlayer.PopupStorageDialog(true);
+ return;
+ }
+ base.Show(value);
+ }
+
+ public override void CloseDialogue()
+ {
+ if (GetHostPlayer() != null && GetHostPlayer().IsUsingTrashBox())
+ {
+ CECHostPlayer.PopupStorageDialog(true);
+ return;
+ }
+ base.CloseDialogue();
+ }
+
private void Awake()
{
model = new InventoryModel();
@@ -646,31 +672,42 @@ namespace BrewMonster.Scripts.Managers
}
}
- private void OnInventoryButtonClicked(byte package, int slot)
+ /// Show item detail for pack or warehouse slot (click only opens detail).
+ public void ShowItemDetailForPackage(byte package, int slot)
{
- UnityGameSession.RequestCheckSecurityPassWd("");
- var data = model.GetInventoryData(package);
- if (data != null && data.TryGetValue(slot, out var itemData))
+ EC_IvtrItem itemData = null;
+ if (package == PKG_TRASHBOX)
{
- // Store current selection for equip/unequip operations
- currentSelectedPackage = package;
- currentSelectedSlot = slot;
- currentSelectedItem = itemData;
-
- // Create equipment object if this is equipment
- currentSelectedEquipment = CreateEquipmentFromItemData(itemData);
-
- // Position detail panel near the clicked item button
-
- FillDetailPanel(package, itemData);
- PositionDetailPanelNearButton(package, slot);
+ var host = CECGameRun.Instance?.GetHostPlayer();
+ itemData = host?.GetTrashBox()?.GetItem(slot, false);
}
else
{
- ShowDetailPanel(false);
+ var data = model.GetInventoryData(package);
+ data?.TryGetValue(slot, out itemData);
+ }
+
+ if (itemData != null)
+ {
+ currentSelectedPackage = package;
+ currentSelectedSlot = slot;
+ currentSelectedItem = itemData;
+ currentSelectedEquipment = CreateEquipmentFromItemData(itemData);
+ FillDetailPanel(package, itemData);
+ PositionDetailPanelNearButton(package, slot);
+ EC_UIUtility.BringPanelToFront(detailPanelRoot.gameObject);
+ }
+ else
+ {
+ DismissItemDetail();
}
}
+ public void DismissItemDetail() => ShowDetailPanel(false);
+
+ private void OnInventoryButtonClicked(byte package, int slot) =>
+ ShowItemDetailForPackage(package, slot);
+
///
/// Create EC_IvtrEquip object from InventoryItemData
///
@@ -1465,14 +1502,50 @@ namespace BrewMonster.Scripts.Managers
private void ShowDetailPanel(bool show)
{
- EC_UIUtility.ShowPanel(detailPanelRoot.gameObject, show);
- if (!show)
+ if (detailPanelRoot == null)
+ return;
+
+ if (show)
{
+ AttachDetailPanelToDialogCanvas();
+ EC_UIUtility.ShowPanel(detailPanelRoot.gameObject, true);
+ EC_UIUtility.BringPanelToFront(detailPanelRoot.gameObject);
+ }
+ else
+ {
+ EC_UIUtility.ShowPanel(detailPanelRoot.gameObject, false);
+ RestoreDetailPanelParent();
RefreshSplitControlsVisibility(0, null);
RefreshCombineControlsVisibility(0, null);
}
}
+ void AttachDetailPanelToDialogCanvas()
+ {
+ var panelTransform = detailPanelRoot.transform;
+ var canvasRoot = CECUIManager.Instance?.DialogCanvasTransform;
+ if (canvasRoot == null || panelTransform.parent == canvasRoot)
+ return;
+
+ _detailPanelOriginalParent = panelTransform.parent;
+ _detailPanelOriginalSiblingIndex = panelTransform.GetSiblingIndex();
+ panelTransform.SetParent(canvasRoot, true);
+ }
+
+ void RestoreDetailPanelParent()
+ {
+ if (_detailPanelOriginalParent == null)
+ return;
+
+ var panelTransform = detailPanelRoot.transform;
+ panelTransform.SetParent(_detailPanelOriginalParent, true);
+ if (_detailPanelOriginalSiblingIndex >= 0)
+ panelTransform.SetSiblingIndex(_detailPanelOriginalSiblingIndex);
+
+ _detailPanelOriginalParent = null;
+ _detailPanelOriginalSiblingIndex = -1;
+ }
+
///
/// Split affordance only for main bag stacks (same as ).
/// If splitCloseButton is parented under splitPanelRoot, its visibility follows the modal (not this rule).
@@ -1531,6 +1604,9 @@ namespace BrewMonster.Scripts.Managers
private Button GetButtonForSlot(byte package, int slot)
{
+ if (package == PKG_TRASHBOX)
+ return EC_StorageUI.GetSlotButtonStatic(slot);
+
List