using BrewMonster.Managers; using BrewMonster.Network; using BrewMonster.Scripts; using BrewMonster.Scripts.Managers; using BrewMonster.Scripts.Skills; using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.S2CCommand; using System; using BrewMonster.UI; using BrewMonster.Scripts.Managers; using UnityEngine; using static BrewMonster.Scripts.CECHPWork; using static BrewMonster.Scripts.EC_Inventory; namespace BrewMonster { public partial class CECHostPlayer { public void OnMsgHstIvtrInfo(ECMSG Msg) { var data = Msg.dwParam1 as byte[]; int cmd = Convert.ToInt32(Msg.dwParam2); int hostId = Convert.ToInt32(Msg.dwParam3); switch (cmd) { case CommandID.OWN_IVTR_DATA: { LogInventoryPacket("OWN_IVTR_DATA", data, hostId); // C++: pPack->ResetItems(*pCmd) where cmd_own_ivtr_info.content is a compact stream: // for each slot [0..ivtr_size): tid (int); if tid>=0 then expire_date (int) and amount (int). if (data != null && data.Length >= 6) { byte byPackage = data[0]; byte ivtrSize = data[1]; uint contentLength = BitConverter.ToUInt32(data, 2); int index = 6; int remaining = data.Length - index; int contentBytes = remaining; if (contentLength < (uint)remaining) contentBytes = (int)contentLength; var inv = GetInventory(byPackage); if (inv != null) { inv.Resize(ivtrSize); inv.RemoveAllItems(); int end = index + Math.Max(0, contentBytes); for (int slot = 0; slot < ivtrSize; slot++) { if (index + 4 > end) break; int tid = BitConverter.ToInt32(data, index); index += 4; if (tid < 0) { inv.SetItem(slot, null); continue; } if (index + 8 > end) break; int expireDate = BitConverter.ToInt32(data, index); index += 4; int amount = BitConverter.ToInt32(data, index); index += 4; if (amount > 0) { var item = EC_IvtrItem.CreateItem(tid, expireDate, amount); if (item != null) { item.Package = byPackage; item.Slot = slot; item.SetCount(amount); inv.SetItem(slot, item); } } else { inv.SetItem(slot, null); } } } if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK) { UpdateEquipSkins(); } else if (byPackage == InventoryConst.IVTRTYPE_TRASHBOX && m_bUsingTrashBox) { PopupStorageDialog(); } var ui = GameObject.FindFirstObjectByType(); ui?.RefreshAll(); if (byPackage == InventoryConst.IVTRTYPE_TRASHBOX) EC_StorageUI.RefreshAllStatic(); } break; } case CommandID.OWN_IVTR_DETAIL_DATA: { // EC_Inventory.LogInventoryPacket("OWN_IVTR_DETAIL_DATA", data, hostId); // Parse and store if (data != null && data.Length >= 6) { byte byPackage = data[0]; byte ivtrSize = data[1]; if (EC_IvtrItemUtils.Instance.TryParseInventoryDetail(data, out var pkg, out var size, out var items)) { var inv = GetInventory(pkg); if (inv != null) { inv.Resize(size); inv.RemoveAllItems(); if (items != null) { foreach (var it in items) { if (it != null && it.Slot >= 0 && it.Slot < size) { if (it.Content != null && it.Content.Length > 0) it.SetItemInfo(it.Content, it.Content.Length); inv.SetItem(it.Slot, it); } } } } } // check if we got the item from the Equipment Pack. If so, we have to load the equipment items if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK) { UpdateEquipSkins(); } else if (byPackage == InventoryConst.IVTRTYPE_TRASHBOX && m_bUsingTrashBox) { PopupStorageDialog(); } var uiDetail = GameObject.FindFirstObjectByType(); uiDetail?.RefreshAll(); if (byPackage == InventoryConst.IVTRTYPE_TRASHBOX) EC_StorageUI.RefreshAllStatic(); } break; } case CommandID.CHANGE_IVTR_SIZE: { // C++ EC_HostMsg.cpp: m_pPack->Resize + FIXMSG_NEW_INVENTORY_SIZE if (data != null && data.Length >= 4) { int newSize = BitConverter.ToInt32(data, 0); if (m_pPack != null) m_pPack.Resize(newSize); EC_Game.GetGameRun()?.AddFixedMessage((int)FixedMsg.FIXMSG_NEW_INVENTORY_SIZE, newSize); var ui = GameObject.FindFirstObjectByType(); ui?.RefreshAll(); } break; } case CommandID.GET_OWN_MONEY: { //if (data != null) //{ // try // { // var money = GPDataTypeHelper.FromBytes(data); // SetMoneyAmount(money.amount); // var ui = GameObject.FindFirstObjectByType(); // if (ui == null) // { // var all = Resources.FindObjectsOfTypeAll(); // if (all != null) // { // for (int i = 0; i < all.Length; i++) // { // var candidate = all[i]; // if (candidate != null && candidate.gameObject.scene.IsValid()) // { // ui = candidate; // break; // } // } // } // } // if (ui != null) // { // ui.UpdateMoney(money.amount, money.max_amount); // } // else // { // BrewMonster.Scripts.Managers.EC_InventoryUI.CacheMoney(money.amount, money.max_amount); // } // } // catch (Exception ex) // { // Debug.LogWarning($"[Inventory] Failed to parse GET_OWN_MONEY: {ex.Message}"); // } //} if (data != null) { try { var money = GPDataTypeHelper.FromBytes(data); SetMoneyAmount(money.amount); m_iMaxMoney = (int)money.max_amount; EC_InventoryUI ui = GameObject.FindFirstObjectByType(); if (ui != null && ui.gameObject.activeInHierarchy) { ui.UpdateMoney(money.amount, money.max_amount); } else { EC_InventoryUI.CacheMoney(money.amount, money.max_amount); } } catch (Exception ex) { Debug.LogWarning($"[Inventory] Failed to parse GET_OWN_MONEY: {ex.Message}"); } } break; } case CommandID.PLAYER_CASH: { if (data != null) { try { var cash = GPDataTypeHelper.FromBytes(data); var ui = GameObject.FindFirstObjectByType(); if (ui == null) { var all = Resources.FindObjectsOfTypeAll(); if (all != null) { for (int i = 0; i < all.Length; i++) { var candidate = all[i]; if (candidate != null && candidate.gameObject.scene.IsValid()) { ui = candidate; break; } } } } } catch (Exception ex) { Debug.LogWarning($"[Inventory] Failed to parse PLAYER_CASH: {ex.Message}"); } } break; } } } public void OnMsgHstOwnItemInfo(ECMSG Msg) { int cmd = Convert.ToInt32(Msg.dwParam2); switch (cmd) { case CommandID.OWN_ITEM_INFO: { // if (Application.isEditor || Debug.isDebugBuild) // Debug.Log($"[INVNET] HST_OWNITEMINFO cmd=OWN_ITEM_INFO bytes={(Msg.dwParam1 as byte[])?.Length ?? 0}"); // Match C++ cmd_own_item_info layout and behavior: update an existing item in place. // If the slot is missing (can happen if client missed OWN_IVTR_DATA), create it to match server state. var data = Msg.dwParam1 as byte[]; if (data == null || data.Length < 22) return; byte byPackage = data[0]; byte bySlot = data[1]; int type = BitConverter.ToInt32(data, 2); int expire_date = BitConverter.ToInt32(data, 6); int state = BitConverter.ToInt32(data, 10); uint count = BitConverter.ToUInt32(data, 14); ushort content_length = BitConverter.ToUInt16(data, 20); byte[] content = null; if (content_length > 0 && 22 + content_length <= data.Length) { content = new byte[content_length]; Buffer.BlockCopy(data, 22, content, 0, content_length); } EC_Inventory pInventory = GetInventory(byPackage); if (pInventory == null) return; if (bySlot >= pInventory.GetSize()) pInventory.Resize(bySlot + 1); var pItem = pInventory.GetItem(bySlot, false); if (pItem == null) { pItem = EC_IvtrItem.CreateItem(type, expire_date, (int)count); if (pItem == null) return; pItem.Package = byPackage; pItem.Slot = bySlot; pInventory.SetItem(bySlot, pItem); } pItem.SetExpireDate(expire_date); pItem.SetProcType(state); pItem.SetAmount((int)count); if (content != null && content.Length > 0) pItem.SetItemInfo(content, content.Length); else pItem.SetItemInfo(null, 0); // #if UNITY_EDITOR // Debug.Log($"[Inventory] OWN_ITEM_INFO pkg={byPackage} slot={bySlot} tid={type} count={count} contentLen={content_length}"); // #endif if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK) { UpdateEquipSkins(); } else if (byPackage == InventoryConst.IVTRTYPE_PACK) { if (pItem != null && pItem.IsEquipment()) { // TODO } } var ui = GameObject.FindFirstObjectByType(); if (ui != null) { ui.RefreshAll(); //Debug.Log($"[OWN_ITEM_INFO] Refreshed inventory UI after updating item at package={byPackage}, slot={bySlot}"); } break; } case CommandID.EMPTY_ITEM_SLOT: { var data = Msg.dwParam1 as byte[]; cmd_empty_item_slot pCmd = GPDataTypeHelper.FromBytes(data); EC_Inventory pInventory = GetPack(pCmd.byPackage); if (pInventory == null) return; EC_IvtrItem pItem = pInventory.GetItem(pCmd.bySlot); if (pItem != null) { //UpdateRemovedItemSC(pItem->GetTemplateID(), pCmd->byPackage, pCmd->bySlot); } pInventory.SetItem(pCmd.bySlot, null); var ui = GameObject.FindFirstObjectByType(); if (ui != null) { ui.RefreshAll(); } break; } } } public void OnMsgHstItemOperation(ECMSG Msg) { var data = Msg.dwParam1 as byte[]; int cmd = Convert.ToInt32(Msg.dwParam2); switch (cmd) { case CommandID.EXG_IVTR_ITEM: { // S2C::cmd_exg_ivtr_item { byte index1; byte index2; } if (data == null || data.Length < 2) { Debug.LogWarning("[Inventory] EXG_IVTR_ITEM: Invalid data length"); break; } byte index1 = data[0]; byte index2 = data[1]; if (m_pPack != null) { m_pPack.ExchangeItem(index1, index2); var pItem1 = m_pPack.GetItem(index1, false); if (pItem1 != null) { pItem1.Package = InventoryConst.IVTRTYPE_PACK; pItem1.Slot = index1; } var pItem2 = m_pPack.GetItem(index2, false); if (pItem2 != null) { pItem2.Package = InventoryConst.IVTRTYPE_PACK; pItem2.Slot = index2; } } var ui = GameObject.FindFirstObjectByType(); ui?.RefreshAll(); break; } case CommandID.MOVE_IVTR_ITEM: { // S2C::cmd_move_ivtr_item { byte src; byte dest; uint count; } if (data == null || data.Length < 6) { Debug.LogWarning("[Inventory] MOVE_IVTR_ITEM: Invalid data length"); break; } byte src = data[0]; byte dest = data[1]; uint count = BitConverter.ToUInt32(data, 2); if (m_pPack != null) { // Client-side mirror of server operation. // When dest is empty and count < stack, this becomes "separate/split stack". m_pPack.MoveItem(src, dest, (int)count); var pItemSrc = m_pPack.GetItem(src, false); if (pItemSrc != null) { pItemSrc.Package = InventoryConst.IVTRTYPE_PACK; pItemSrc.Slot = src; } var pItemDest = m_pPack.GetItem(dest, false); if (pItemDest != null) { pItemDest.Package = InventoryConst.IVTRTYPE_PACK; pItemDest.Slot = dest; } } var ui = GameObject.FindFirstObjectByType(); ui?.RefreshAll(); break; } case CommandID.PLAYER_DROP_ITEM: { // Parse the drop item data from the server response if (data != null && data.Length >= 6) { byte byPackage = data[0]; byte bySlot = data[1]; int count = BitConverter.ToInt32(data, 2); int tid = BitConverter.ToInt32(data, 6); byte reason = data[10]; Debug.Log( $"[Inventory] PLAYER_DROP_ITEM: package={byPackage}, slot={bySlot}, count={count}, tid={tid}, reason={reason}"); // Update the inventory by removing the item var inv = GetInventory(byPackage); bool success = inv != null && inv.RemoveItem(bySlot, count); if (success) { Debug.Log( $"[Inventory] Successfully removed {count} items from package {byPackage}, slot {bySlot}"); // Trigger UI refresh if an EC_InventoryUI is present in scene var ui = GameObject.FindFirstObjectByType(); if (ui != null) { ui.RefreshAll(); } } else { Debug.LogWarning( $"[Inventory] Failed to remove items from package {byPackage}, slot {bySlot}"); } } else { Debug.LogWarning("[Inventory] PLAYER_DROP_ITEM: Invalid data length"); } break; } case CommandID.EQUIP_ITEM: { byte index_inv = data[0]; byte index_equip = data[1]; // Update client-side data: move item between PACK_INVENTORY and PACK_EQUIPMENT var packInv = GetInventory(InventoryConst.IVTRTYPE_PACK); var equipInv = GetInventory(InventoryConst.IVTRTYPE_EQUIPPACK); var invItem = packInv?.GetItem(index_inv, true); var equipItem = equipInv?.GetItem(index_equip, true); UpdateEquipSkins(); if (invItem != null) { invItem.Package = InventoryConst.IVTRTYPE_EQUIPPACK; invItem.Slot = index_equip; equipInv?.SetItem(index_equip, invItem); } if (equipItem != null) { equipItem.Package = InventoryConst.IVTRTYPE_PACK; equipItem.Slot = index_inv; packInv?.SetItem(index_inv, equipItem); } // Trigger UI refresh if an EC_InventoryUI is present in scene var ui = GameObject.FindFirstObjectByType(); if (ui != null) { ui.RefreshAll(); ui.RefreshCharacterModelPreview(); } UpdateEquipSkins(); break; } } } /// /// Message MSG_HST_PICKUPITEM handler. Matches C++ flow: switch only fills idItem/iExpireDate/iAmount/iCmdLastSlot/iCmdSlotAmount/iPack/iMsg; /// then single common path: MergeItem (or PutItemInSlot to match server slot), GetItemInfo request for equipment, notifications, RefreshAll. /// public void OnMsgHstPickupItem(in ECMSG Msg) { var data = Msg.dwParam1 as byte[]; int cmd = Convert.ToInt32(Msg.dwParam2); if (data == null) return; if (Application.isEditor || Debug.isDebugBuild) Debug.Log($"[INVNET] HST_PICKUPITEM cmd={cmd} bytes={data.Length}"); bool bDoOther = false; int idItem = 0, iExpireDate = 0, iAmount = 0, iCmdLastSlot = 0, iCmdSlotAmount = 0, iPack = 0, iMsg = -1; switch (cmd) { case CommandID.PICKUP_ITEM: { var pCmdPickup = GPDataTypeHelper.FromBytes(data); idItem = pCmdPickup.tid; iExpireDate = pCmdPickup.expire_date; iAmount = (int)pCmdPickup.iAmount; iCmdLastSlot = pCmdPickup.bySlot; iCmdSlotAmount = (int)pCmdPickup.iSlotAmount; iPack = pCmdPickup.byPackage; iMsg = (int)FixedMsg.FIXMSG_PICKUPITEM; break; } case CommandID.HOST_OBTAIN_ITEM: { var pCmdObtain = GPDataTypeHelper.FromBytes(data); idItem = pCmdObtain.type; iExpireDate = pCmdObtain.expire_date; iAmount = (int)pCmdObtain.amount; iCmdLastSlot = pCmdObtain.index; iCmdSlotAmount = (int)pCmdObtain.slot_amount; iPack = pCmdObtain.where; iMsg = (int)FixedMsg.FIXMSG_GAINITEM; break; } case CommandID.PRODUCE_ONCE: { var pCmdProduce = GPDataTypeHelper.FromBytes(data); idItem = pCmdProduce.type; iExpireDate = 0; iAmount = (int)pCmdProduce.amount; iCmdLastSlot = pCmdProduce.index; iCmdSlotAmount = (int)pCmdProduce.slot_amount; iPack = pCmdProduce.where; iMsg = (int)FixedMsg.FIXMSG_PRODUCEITEM; var dlgProduce = UnityEngine.Object.FindFirstObjectByType(); dlgProduce?.OnProduceOnce(pCmdProduce); break; } case CommandID.TASK_DELIVER_ITEM: { var pCmdTask = GPDataTypeHelper.FromBytes(data); idItem = pCmdTask.type; iExpireDate = pCmdTask.expire_date; iAmount = (int)pCmdTask.amount; iCmdLastSlot = pCmdTask.index; iCmdSlotAmount = (int)pCmdTask.slot_amount; iPack = pCmdTask.where; iMsg = (int)FixedMsg.FIXMSG_GAINITEM; bDoOther = true; break; } default: return; } #if UNITY_EDITOR Debug.Log($"[Inventory] PICKUP_FLOW cmd={cmd} pack={iPack} slot={iCmdLastSlot} tid={idItem} amt={iAmount} slotAmt={iCmdSlotAmount}"); #endif EC_Inventory pInventory = GetPack(iPack); if (pInventory == null) return; if (iCmdLastSlot >= pInventory.GetSize()) pInventory.Resize(iCmdLastSlot + 1); bool placed = pInventory.PutItemInSlot(iCmdLastSlot, idItem, iExpireDate, iAmount, out int iLastSlot, out int iSlotNum); if (!placed) { placed = pInventory.MergeItem(idItem, iExpireDate, iAmount, out iLastSlot, out iSlotNum); if (!placed || iLastSlot != iCmdLastSlot || iSlotNum != iCmdSlotAmount) { #if UNITY_EDITOR Debug.LogWarning($"[Inventory] PICKUP_FLOW desync: placed={placed} lastSlot={iLastSlot} slotNum={iSlotNum} expectedSlot={iCmdLastSlot} expectedSlotAmt={iCmdSlotAmount}"); #endif return; } } if (cmd == CommandID.HOST_OBTAIN_ITEM && iPack == Inventory_type.IVTRTYPE_PACK) { // C++: CECShoppingManager::Instance().OnObtainItem(iPack, idItem, iAmount); } EC_IvtrItem pItem = pInventory.GetItem(iCmdLastSlot, false); if (pItem != null) { pItem.Package = (byte)iPack; pItem.Slot = iCmdLastSlot; int cid = pItem.GetClassID(); if (pItem.IsEquipment() || cid == (int)EC_IvtrItem.InventoryClassId.ICID_TASKNMMATTER || cid == (int)EC_IvtrItem.InventoryClassId.ICID_TASKDICE || cid == (int)EC_IvtrItem.InventoryClassId.ICID_TASKITEM || cid == (int)EC_IvtrItem.InventoryClassId.ICID_GOBLIN_EXPPILL || cid == (int)EC_IvtrItem.InventoryClassId.ICID_WEDDINGBOOKCARD || cid == (int)EC_IvtrItem.InventoryClassId.ICID_WEDDINGINVITECARD || cid == (int)EC_IvtrItem.InventoryClassId.ICID_SKILLTOME || cid == (int)EC_IvtrItem.InventoryClassId.ICID_GOBLIN || cid == (int)EC_IvtrItem.InventoryClassId.ICID_PETEGG) { UnityGameSession.c2s_CmdGetItemInfo((byte)iPack, (byte)iCmdLastSlot); } if (iMsg >= 0) { CECGameRun pGameRun = EC_Game.GetGameRun(); pGameRun?.AddFixedMessage(iMsg, iAmount, pItem.GetName()); } } if (bDoOther) { // C++: m_pTaskInterface->DoAutoTeamForTask(idItem); } if (cmd == CommandID.PICKUP_ITEM) { var pickupScript = UnityEngine.Object.FindFirstObjectByType(); pickupScript?.OnPickupSuccess(idItem); } var ui = GameObject.FindFirstObjectByType(); ui?.RefreshAll(); UpdateEquipSkins(); } /// /// Buy from NPC/booth: S2C PURCHASE_ITEM (cmd_purchase_item). /// Port of CECHostPlayer::OnMsgHstPurchaseItems (EC_HostMsg.cpp): prefer MergeItem like the C++ client. /// If merge lands on a different slot than inv_index (common when stacking into an earlier pile), we still accept /// the merged slot—the strict C++ iLastSlot == inv_index check would skip updates and break buy/stack UI here. /// Fallback: PutItemInSlot(inv_index) then MergeItem when merge alone fails. /// public void OnMsgHstPurchaseItems(ECMSG Msg) { var data = Msg.dwParam1 as byte[]; if (data == null || data.Length < 11) return; var header = GPDataTypeHelper.FromBytes(data); int index = 11; const int itemSize = 15; // item_id(4) + expire_date(4) + count(4) + inv_index(2) + booth_slot(1) EC_Inventory pPack = GetPack(Inventory_type.IVTRTYPE_PACK); if (pPack == null) return; var slotsNeedingDetail = new System.Collections.Generic.List(); bool purchaseSlotMismatch = false; for (int i = 0; i < header.item_count && index + itemSize <= data.Length; i++) { int item_id = BitConverter.ToInt32(data, index); index += 4; int expire_date = BitConverter.ToInt32(data, index); index += 4; int count = (int)BitConverter.ToUInt32(data, index); index += 4; ushort inv_index = BitConverter.ToUInt16(data, index); index += 2; byte booth_slot = data[index]; index += 1; if (inv_index >= pPack.GetSize()) pPack.Resize(inv_index + 1); int iLastSlot = 0; int iSlotNum = 0; bool placed = pPack.MergeItem(item_id, expire_date, count, out iLastSlot, out iSlotNum); if (!placed) placed = pPack.PutItemInSlot(inv_index, item_id, expire_date, count, out iLastSlot, out iSlotNum); if (!placed) placed = pPack.MergeItem(item_id, expire_date, count, out iLastSlot, out iSlotNum); if (!placed) { #if UNITY_EDITOR UnityEngine.Debug.LogWarning( $"[OnMsgHstPurchaseItems] Could not place purchase tid={item_id} count={count} inv_index={inv_index}"); #endif continue; } if (iLastSlot != inv_index) purchaseSlotMismatch = true; #if UNITY_EDITOR if (iLastSlot != inv_index) { UnityEngine.Debug.Log( $"[OnMsgHstPurchaseItems] Using merge slot {iLastSlot} (packet inv_index={inv_index}) tid={item_id}"); } #endif var pItem = pPack.GetItem(iLastSlot, false); if (pItem != null) { pItem.Package = (byte)Inventory_type.IVTRTYPE_PACK; pItem.Slot = iLastSlot; // Keep stack size in sync with MergeItem/PutItemInSlot totals (authoritative for this slot). if (iSlotNum > 0) pItem.SetCount(iSlotNum); if (pItem.IsEquipment()) slotsNeedingDetail.Add((byte)iLastSlot); } if (header.flag != 0 && GetBoothState() == 2) { var boothBPack = GetBoothBuyPack(); if (boothBPack != null) { // C++: CDlgInfo FIXMSG_BOOTHBUY — no matching in-game UI hook here; update booth pack only. boothBPack.RemoveItemByFlag(booth_slot, count); } } } AddMoneyAmount(-(int)header.cost); foreach (byte slot in slotsNeedingDetail) UnityGameSession.c2s_CmdGetItemInfo((byte)Inventory_type.IVTRTYPE_PACK, slot); { var ui = GameObject.FindFirstObjectByType(); ui?.RefreshAll(); if (purchaseSlotMismatch) { UnityGameSession.RequestInventoryAsync(0, () => { var ui2 = GameObject.FindFirstObjectByType(); ui2?.RefreshAll(); }); } } UpdateEquipSkins(); } /// /// Sell to NPC: server sends ITEM_TO_MONEY. This removes sold items from pack and adds gained money. /// Payload layout differs across server builds, so we parse defensively. /// // NOTE: Kept as a helper implementation; the message dispatcher calls OnMsgHstItemToMoney in CECHostPlayer.cs. private void OnMsgHstItemToMoney_Inventory(ECMSG Msg) { var data = Msg.dwParam1 as byte[]; if (data == null || data.Length < 4) return; // Two observed/expected formats: // A) [u32 itemCount] + itemCount * npc_sell_item(16 bytes) // B) [u32 moneyGain] [u32 itemCount] + itemCount * npc_sell_item(16 bytes) uint a = BitConverter.ToUInt32(data, 0); int offset = 0; uint moneyGain = 0; uint itemCount = 0; const int itemSize = 16; // npc_sell_item: tid(4) index(4) count(4) price(4) bool formatA = (data.Length - 4) >= 0 && ((data.Length - 4) % itemSize == 0) && (a == (uint)((data.Length - 4) / itemSize)); if (formatA) { itemCount = a; offset = 4; } else if (data.Length >= 8) { uint b = BitConverter.ToUInt32(data, 4); bool formatB = (data.Length - 8) >= 0 && ((data.Length - 8) % itemSize == 0) && (b == (uint)((data.Length - 8) / itemSize)); if (formatB) { moneyGain = a; itemCount = b; offset = 8; } } if (itemCount == 0 || offset == 0) { // Fallback: if we cannot parse, request a full refresh so UI doesn't get stuck. UnityGameSession.RequestInventoryAsync(0, () => { var ui = UnityEngine.Object.FindFirstObjectByType(); ui?.RefreshAll(); }); return; } long computedGain = moneyGain; var pPack = GetPack(Inventory_type.IVTRTYPE_PACK); if (pPack == null) return; for (int i = 0; i < itemCount; i++) { int baseIndex = offset + i * itemSize; if (baseIndex + itemSize > data.Length) break; int tid = BitConverter.ToInt32(data, baseIndex); uint invIndex = BitConverter.ToUInt32(data, baseIndex + 4); uint count = BitConverter.ToUInt32(data, baseIndex + 8); int price = BitConverter.ToInt32(data, baseIndex + 12); if (invIndex >= (uint)pPack.GetSize()) continue; if (count > 0) pPack.RemoveItem((int)invIndex, (int)count); // If server didn't include total moneyGain, sum per-item prices. if (moneyGain == 0 && price > 0) computedGain += price; // Optional: request item info if something remains in slot but template changed. var remain = pPack.GetItem((int)invIndex, false); if (remain != null && remain.m_tid != tid) UnityGameSession.c2s_CmdGetItemInfo((byte)Inventory_type.IVTRTYPE_PACK, (byte)invIndex); } if (computedGain > 0) AddMoneyAmount((int)Mathf.Min(int.MaxValue, computedGain)); var invUi = UnityEngine.Object.FindFirstObjectByType(); invUi?.RefreshAll(); UpdateEquipSkins(); } private void OnMsgHstUseItem(ECMSG Msg) { cmd_host_use_item pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); EC_Inventory pPack = GetPack(pCmd.byPackage); if (pPack == null) { return; } EC_IvtrItem pItem = pPack.GetItem(pCmd.bySlot, false); if (pItem == null || pItem.GetTemplateID() != pCmd.item_id) { return; } pItem.Use(); if (pCmd.use_count > 0) { bool removed = pPack.RemoveItem(pCmd.bySlot, pCmd.use_count); if (removed) { if (pPack.GetItem(pCmd.bySlot, false) == null) { //Debug.Log($"[OnMsgHstUseItem] Item {pCmd.item_id} removed from slot {pCmd.bySlot}"); } } else { //Debug.LogError($"[OnMsgHstUseItem] Failed to remove item {pCmd.item_id} from slot {pCmd.bySlot}"); } var ui = GameObject.FindFirstObjectByType(); if (ui != null) { ui.RefreshAll(); ui.UpdateCooldownOverlays(); } else { //Debug.LogError("[OnMsgHstUseItem] EC_InventoryUI not found, UI may not update"); } } if (m_pWorkMan != null) { CECHPWork pWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_USEITEM); if (pWork is CECHPWorkUse useWork) { if (useWork.GetItem() == pCmd.item_id) { m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_USEITEM); } } } } public void OnMsgHstProduceItem(in ECMSG Msg) { var data = Msg.dwParam1 as byte[]; int cmd = Convert.ToInt32(Msg.dwParam2); // Get DlgProduce to notify var dlgProduce = GameObject.FindFirstObjectByType(); if (dlgProduce == null) { Debug.LogWarning("[OnMsgHstProduceItem] DlgProduce not found"); return; } switch (cmd) { case CommandID.PRODUCE_START: { cmd_produce_start pCmd = GPDataTypeHelper.FromBytes(data); Debug.Log($"[PRODUCE_START] type={pCmd.type}, use_time={pCmd.use_time}, count={pCmd.count}"); dlgProduce.OnProduceStart(pCmd); } break; case CommandID.PRODUCE_END: { Debug.Log("[PRODUCE_END] Production ended"); dlgProduce.OnProduceEnd(); } break; case CommandID.PRODUCE_NULL: { cmd_produce_null pCmd = GPDataTypeHelper.FromBytes(data); Debug.Log($"[PRODUCE_NULL] type={pCmd.type}"); dlgProduce.OnProduceNull(pCmd); } break; default: Debug.LogWarning($"[OnMsgHstProduceItem] Unknown command: {cmd}"); break; } } public void OnMsgHstEmbedItem(ECMSG Msg) { cmd_embed_item pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); EC_IvtrItem pEquip = m_pPack.GetItem(pCmd.equip_idx); EC_IvtrItem pTessera = m_pPack.GetItem(pCmd.chip_idx); if (pEquip == null || pTessera == null) { return; } m_pPack.RemoveItem(pCmd.chip_idx, 1); if (pTessera is EC_IvtrStone stone) { AddMoneyAmount(-(int)stone.GetDBEssence().install_price); } // Refresh equip's data // todo make receive request UnityGameSession.c2s_CmdGetItemInfo(Inventory_type.IVTRTYPE_PACK, pCmd.equip_idx); } public void OnMsgHstClearTessera(ECMSG Msg) { cmd_clear_tessera pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); AddMoneyAmount(-(int)pCmd.cost); // Refresh equip's data UnityGameSession.c2s_CmdGetItemInfo(Inventory_type.IVTRTYPE_PACK, (byte)pCmd.equip_idx); } // Add money amount private int AddMoneyAmount(int iAmount) { long next = (long)m_iMoneyCnt + iAmount; if (next < 0) { next = 0; } if(m_iMaxMoney > 0 && next > m_iMaxMoney) { next = m_iMaxMoney; } m_iMoneyCnt = (uint)next; ulong amount = m_iMoneyCnt; ulong maxAmount = m_iMaxMoney > 0 ? (ulong)m_iMaxMoney : amount; EC_InventoryUI ui = GameObject.FindFirstObjectByType(); if(ui != null && ui.gameObject.activeInHierarchy) { ui.UpdateMoney(amount, maxAmount); } else { EC_InventoryUI.CacheMoney(amount, maxAmount); } //m_iMoneyCnt += (uint)iAmount; return (int)m_iMoneyCnt; } public bool HaveHealthStones() { var pPack = GetPack(); var items = new int[] { 36764, 36765, 36766, 36767 }; for (int i = 0; i < items.Length; ++i) { if (pPack.FindItem(items[i]) >= 0) return true; } return false; } public bool UseItemInPack(int iPack, int iSlot, bool showMsg = true) { if (!CanDo(ActionCanDo.CANDO_USEITEM)) return false; EC_Inventory pPack = GetPack(iPack); if (pPack == null) return false; EC_IvtrItem pItem = pPack.GetItem(iSlot); if (pItem == null || pItem.IsFrozen()) return false; if (pItem.Use_Persist() && (IsJumping() || IsFalling())) return false; CECGameRun pGameRun = EC_Game.GetGameRun(); //CECGameSession pSession = g_pGame.GetGameSession(); if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_FIREWORK) { if (GetProfession() == (int)PROFESSION.PROF_GHOST && IsInvisible()) { if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_WHEN_INVISIBLE); return false; } } if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_INCSKILLABILITY) { EC_IvtrIncSkillAbility pIncSkill = pItem as EC_IvtrIncSkillAbility; //if (pIncSkill != null) //{ // var pDBEssence = pIncSkill.GetDBEssence(); // CECSkill pSkill = GetNormalSkill(pDBEssence.id_skill); // if (pSkill != null) // { // if (pSkill.GetSkillLevel() != pDBEssence.level_required) // { // if (showMsg) // pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_PRODUCE_LEVEL_INVALID); // return false; // } // if (GetSkillAbilityPercent(pDBEssence.id_skill) >= 100) // { // if (showMsg) // pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_PRODUCE_ABILITY_FULL); // return false; // } // } //} } if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TRANSMITSCROLL) { CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan(); if (pGameUI != null && !IsFighting()) { // TODO: Implement travel map dialog //CDlgWorldMap* pMap = (CDlgWorldMap*)pGameUI->GetDialog("Win_WorldMapTravel"); //pMap->BuildTravelMap(DT_TRANSMITSCROLL_ESSENCE, (void*)iSlot); //pMap->Show(true); } return true; } if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_SHOPTOKEN) { CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan(); if (pGameUI != null && !IsFighting()) { //CDlgTokenShop* pDlg = dynamic_cast(pGameUI->GetDialog("Win_TokenShop")); //if (pDlg) //{ // pDlg->InitTokenShopItem(pItem->GetTemplateID()); // pDlg->Show(!pDlg->IsShow()); //} } return true; } if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_UNIVERSAL_TOKEN) { // TODO: Implement universal token when available EC_IvtrUniversalToken pUniversalToken = pItem as EC_IvtrUniversalToken; //if (pUniversalToken != null && pUniversalToken.HasAnyUsage()) //{ // CECUseUniversalTokenCommandManager.Instance.Use(pUniversalToken, pUniversalToken.UsageIndexAt(0)); // return true; //} } if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TASKDICE) { EC_IvtrTaskDice pTaskDice = pItem as EC_IvtrTaskDice; if (pTaskDice != null) { if (pTaskDice != null) { if (IsFlying() && pTaskDice.GetDBEssence().no_use_in_combat == 1) { if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_BATTLE); return false; } } } } if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TARGETITEM) { EC_IvtrTargetItem pTargetItem = pItem as EC_IvtrTargetItem; if (pTargetItem == null) return false; var essence = pTargetItem.GetDBEssence(); if (!pTargetItem.IsEssenceLoaded()) return false; if (IsFighting() && essence.use_in_combat == 0) { if (showMsg) if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_BATTLE); return false; } if (essence.use_in_sanctuary_only != 0 && !IsInSanctuary()) { if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_USE_IN_SANCTUARY_ONLY); return false; } int iCurrMap = pGameRun.GetWorld().GetInstanceID(); if (pTargetItem.GetDBEssence().num_area != 0) { bool found = false; for (int i = 0; i < pTargetItem.GetDBEssence().num_area; i++) { if (pTargetItem.GetDBEssence().area_id[i] == iCurrMap) { found = true; break; } } if (!found) { if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_CURR_MAP); return false; } } if (!CanDo(ActionCanDo.CANDO_SPELLMAGIC)) return false; if (InSlidingState()) return false; if (m_idSelTarget == 0) return false; CECSkill pSkill = pTargetItem.GetTargetSkill(); if (pSkill == null) return false; if (IsSpellingMagic() && m_pCurSkill != null && m_pCurSkill.IsCharging() && m_pCurSkill.GetSkillID() == pSkill.GetSkillID()) { m_pCurSkill.EndCharging(); UnityGameSession.c2s_SendCmdContinueAction(); return true; } int iCon = CheckSkillCastCondition(pSkill); if (iCon != 0) { if (showMsg) ProcessSkillCondition(iCon); return false; } bool bForceAttack = glb_GetForceAttackFlag(0); if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_ATTACK || pSkill.GetType() == (int)CECSkill.SkillType.TYPE_CURSE) { if (m_idSelTarget == m_PlayerInfo.cid) { if (showMsg) pGameRun.AddFixedChannelMsg((int)FixedMsg.FIXMSG_TARGETWRONG, (int)ChatChannel.GP_CHAT_FIGHT); return false; } else if (m_idSelTarget != 0) { if (AttackableJudge(m_idSelTarget, bForceAttack) != 1) return false; } } int idCastTarget = m_idSelTarget; int iTargetType = pSkill.GetTargetType(); if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_BLESS || pSkill.GetType() == (int)CECSkill.SkillType.TYPE_NEUTRALBLESS) { if (iTargetType == 0 || !GPDataTypeHelper.ISPLAYERID(m_idSelTarget)) idCastTarget = m_PlayerInfo.cid; if (GPDataTypeHelper.ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid) { byte byBLSMask = EC_Utility.glb_BuildBLSMask(); if (pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_POINT) { if (!IsTeamMember(idCastTarget)) { if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_SELF) != 0) { idCastTarget = m_PlayerInfo.cid; } else { EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget) as EC_ElsePlayer; if (pPlayer == null) return false; if (pPlayer.IsInvader() || pPlayer.IsPariah()) { if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NORED) != 0) idCastTarget = m_PlayerInfo.cid; } if (!IsFactionMember(pPlayer.GetFactionID())) { if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOMAFIA) != 0) idCastTarget = m_PlayerInfo.cid; } if (!IsFactionAllianceMember(pPlayer.GetFactionID())) { if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOALLIANCE) != 0) idCastTarget = m_PlayerInfo.cid; } if (GetForce() != pPlayer.GetForce()) { if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOFORCE) != 0) idCastTarget = m_PlayerInfo.cid; } } } } // If host is in dule if (IsInDuel() && m_idSelTarget == m_pvp.idDuelOpp) idCastTarget = m_PlayerInfo.cid; // If host is in battle if (IsInBattle()) { EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget); if (!InSameBattleCamp(pPlayer)) idCastTarget = m_PlayerInfo.cid; } } } else if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_BLESS) { // TODO: Implement pet blessing when petsystem is available //CECSCPet pPet = EC_Game.GetGameRun().GetWorld().GetPetByID(m_idSelTarget); //if (pPet == null || pPet.GetMasterID() == GetCharacterID()) //{ // CECPetData pPetData = m_pPetCorral.GetActivePet(); // if (pPetData == null || // pPetData.GetClass() != GP_PET_TYPE.GP_PET_CLASS_COMBAT && // pPetData.GetClass() != GP_PET_TYPE.GP_PET_CLASS_SUMMON && // pPetData.GetClass() != GP_PET_TYPE.GP_PET_CLASS_EVOLUTION) // return false; // idCastTarget = m_pPetCorral.GetActivePetNPCID(); //} //if(iTargetType != 0 && idCastTarget == 0) // return false; } if (iTargetType != 0) { int iAliveFlag = 0; if (iTargetType == 1) iTargetType = 1; else if (iTargetType == 2) iTargetType = 2; CECObject pObject = EC_ManMessageMono.Instance.GetObject(idCastTarget, iAliveFlag); if (pObject == null) return false; } if (!IsMeleeing() && !IsSpellingMagic() && (iTargetType == 0 || idCastTarget == m_PlayerInfo.cid)) { if (!pSkill.ReadyToCast()) return false; if (!pSkill.IsInstant() && pSkill.GetType() != (int)CECSkill.SkillType.TYPE_FLASHMOVE) { if (!NaturallyStopMoving()) return false; } else if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_FLASHMOVE) { if (!CanDo(ActionCanDo.CANDO_FLASHMOVE)) return false; } m_pPrepSkill = pSkill; } else if (IsSpellingMagic() && m_pCurSkill == pSkill && !pSkill.ReadyToCast()) { return false; } } if (pItem.IsEquipment()) { if (iPack == Inventory_type.IVTRTYPE_EQUIPPACK) { // Take off equipment int iEmpty = m_pPack.SearchEmpty(); if (iEmpty < 0) return false; UnityGameSession.RequestEquipItemAsync((byte)iEmpty, (byte)iSlot, null); return true; } EC_IvtrEquip pEquip = pItem as EC_IvtrEquip; if (pEquip == null) return false; int iReason = 0; if (!CanUseEquipment(pEquip, ref iReason)) return false; int iFirstFree = -1, iFirstCan = -1; for (int i = 0; i < InventoryConst.SIZE_ALL_EQUIPIVTR; i++) { if (pItem.CanEquippedTo(i)) { if (iFirstCan < 0) iFirstCan = i; if (m_pEquipPack.GetItem(i) == null && iFirstFree < 0) { iFirstFree = i; break; } } } int iDst; if (iFirstFree >= 0) iDst = iFirstFree; else if (iFirstCan >= 0) iDst = iFirstCan; else { Debug.Assert(false); return false; } if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DYNSKILLEQUIP) { int iSameIDPos = m_pEquipPack.FindItem(pItem.GetTemplateID()); if (iSameIDPos >= 0) { iDst = iSameIDPos; } } if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_ARROW || pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DYNSKILLEQUIP) { EC_IvtrItem pDstItem = m_pEquipPack.GetItem(iDst); if (pDstItem == null || pItem.GetTemplateID() != pDstItem.GetTemplateID()) UnityGameSession.RequestEquipItemAsync((byte)iSlot, (byte)iDst, null); else { // TODO: Implement c2s_CmdMoveItemToEquip when available //UnityGameSession.c2s_CmdMoveItemToEquip((byte)iSlot, (byte)iDst); } } else { if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_GENERALCARD) { //TODO: Add general card equip request EC_IvtrGeneralCard pCard = pItem as EC_IvtrGeneralCard; if (pCard != null) { iDst = InventoryConst.EQUIPIVTR_GENERALCARD1 + pCard.GetEssence().type; } } UnityGameSession.RequestEquipItemAsync((byte)iSlot, (byte)iDst, null); } return true; } if (iPack != Inventory_type.IVTRTYPE_PACK) return false; if (!pItem.CheckUseCondition()) { if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_ITEM_CANNOTUSE); return false; } int piMax = -1; if (pItem.GetCoolTime(out piMax) > 0) { if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_ITEM_INCOOLTIME); return false; } if (pItem.Use_AtkTarget() || pItem.Use_Target()) { if (pItem.Use_AtkTarget() && CannotAttack()) return false; if (m_idSelTarget == 0 || m_idSelTarget == m_PlayerInfo.cid) { if (showMsg) { CECStringTab pStrTab = EC_Game.GetFixedMsgs(); pGameRun.AddChatMessage(pStrTab.GetWideString((int)FixedMsg.FIXMSG_NOTARGET), (int)ChatChannel.GP_CHAT_SYSTEM); } return false; } float fAattackRange = 10000.0f; if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TOSSMAT) { EC_IvtrTossMat pTossMat = pItem as EC_IvtrTossMat; if (pTossMat != null) fAattackRange = pTossMat.GetDBEssence().attack_range; } else if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TANKCALLIN) { fAattackRange = 5.0f; } else if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TARGETITEM) { EC_IvtrTargetItem pTargetItem = pItem as EC_IvtrTargetItem; if (pTargetItem != null && pTargetItem.GetTargetSkill() != null) { fAattackRange = pTargetItem.GetTargetSkill() .GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus()); } } float fDist = 0, fTargetRag = 0; CECObject pObject = null; if (CalcDist(m_idSelTarget, out fDist, out pObject)) { return false; } if (GPDataTypeHelper.ISNPCID(m_idSelTarget)) { pObject = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(m_idSelTarget); CECNPC pNPC = pObject as CECNPC; if (pNPC != null) fTargetRag = pNPC.GetTouchRadius(); } else if (GPDataTypeHelper.ISPLAYERID(m_idSelTarget)) { pObject = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(m_idSelTarget); EC_ElsePlayer pPlayer = pObject as EC_ElsePlayer; if (pPlayer != null) fTargetRag = pPlayer.GetTouchRadius(); } if (fDist - fTargetRag > fAattackRange * 0.8f) { if (showMsg) { CECStringTab pStrTab = EC_Game.GetFixedMsgs(); pGameRun.AddChatMessage(pStrTab.GetWideString((int)FixedMsg.FIXMSG_TARGETISFAR), (int)ChatChannel.GP_CHAT_SYSTEM); } return false; } byte byPVPMask = glb_BuildPVPMask(glb_GetForceAttackFlag(0)); UnityGameSession.c2s_SendCmdUseItemWithTarget((byte)iPack, (byte)iSlot, pItem.GetTemplateID(), byPVPMask); } else { if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DOUBLEEXP) { EC_IvtrDoubleExp pDoubleExp = pItem as EC_IvtrDoubleExp; if (pDoubleExp != null) { if (pDoubleExp.GetDBEssence().double_exp_time + pGameRun.GetRemainDblExpTime() > 3600 * 4) { if (showMsg) { CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan(); //pGameUI.MessageBox("", pGameUI.GetStringFromTable(828), MB_OK, new Color32(1, 1, 1, 0.6)); } return false; } } } if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_SHARPENER) { if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_SHARPEN_ON_DRAG); return false; } UnityGameSession.c2s_SendCmdUseItem((byte)iPack, (byte)iSlot, pItem.GetTemplateID(), 1); } return true; } public EC_Inventory GetPack(int iPack) { EC_Inventory pInventory = null; switch (iPack) { case Inventory_type.IVTRTYPE_PACK: pInventory = m_pPack; break; case Inventory_type.IVTRTYPE_EQUIPPACK: pInventory = m_pEquipPack; break; case Inventory_type.IVTRTYPE_TASKPACK: pInventory = m_pTaskPack; break; case Inventory_type.IVTRTYPE_TRASHBOX: pInventory = m_pTrashBoxPack; break; case Inventory_type.IVTRTYPE_TRASHBOX2: pInventory = m_pTrashBoxPack2; break; case Inventory_type.IVTRTYPE_TRASHBOX3: pInventory = m_pTrashBoxPack3; break; //case Inventory_type.IVTRTYPE_ACCOUNT_BOX: pInventory = m_pAccountBoxPack; break; //case Inventory_type.IVTRTYPE_GENERALCARD_BOX: pInventory = m_pGeneralCardPack; break; //case IVTRTYPE_PACK_CLIENT_GENERALCAR.IVTRTYPE_CLIENT_GENERALCARD_PACK: pInventory = m_pClientGenCardPack; break; default: return null; } return pInventory; } public int GetEquippedSuiteItem(int idSuite, ref int[] aItems) { int i, iItemCnt = 0; for (i = 0; i < m_pEquipPack.GetSize(); i++) { var pItem = m_pEquipPack.GetItem(i); if (pItem == null) { continue; } EC_IvtrEquip pEquip = (EC_IvtrEquip)pItem; if (pEquip == null) { continue; } if (pEquip.GetSuiteID() != idSuite) { continue; } int iReason = 0; if (!CanUseEquipment(pEquip, ref iReason)) { continue; } if (pEquip.CID == (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_GENERALCARD) { //TODO: Add general card Suite } if (aItems.Length > 0) { aItems[iItemCnt] = pEquip.GetTemplateID(); } iItemCnt++; } return iItemCnt; } public bool CanUseEquipment(EC_IvtrEquip pEquip, ref int piReason) { int iReason = 0; if (pEquip == null) { iReason = 1; goto End; } if (GetMaxLevelSofar() < pEquip.LevelReq || m_ExtProps.bs.strength < pEquip.StrengthReq || m_ExtProps.bs.agility < pEquip.AgilityReq || m_ExtProps.bs.vitality < pEquip.VitalityReq || m_ExtProps.bs.energy < pEquip.EnergyReq /*|| Reputation < pEquip.ReputationReq*/) //todo Add reputation check { iReason = 2; goto End; } switch (pEquip.CID) //class id { case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_ARROW: break; case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_WING: if (m_iProfession != (int)PROFESSION.PROF_ARCHOR && m_iProfession != (int)PROFESSION.PROF_ANGEL) iReason = 3; break; case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_FLYSWORD: //TODO: Add flysword check break; case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_FASHION: //TODO: Add fashion check break; case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_ARMOR: case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_DECORATION: if ((pEquip.ProfReq & (1 << m_iProfession)) == 0) iReason = 3; break; case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_WEAPON: if ((pEquip.ProfReq & (1 << m_iProfession)) == 0) iReason = 3; else { //TODO: check range weapon arrow } break; case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_GENERALCARD: // TODO: Add general card check break; default: break; } End: if (piReason > 0) { piReason = iReason; } return iReason == 0 ? true : false; } public bool CanTakeItem(int idItem, int iAmount) { bool bCanPick = false; if (GPDataTypeHelper.ISMONEYTID(idItem)) { if (GetMoneyAmount() < GetMaxMoneyAmount()) bCanPick = true; } else { if (IvtrPack.CanAddItem(idItem, iAmount, false) >= 0) bCanPick = true; } return bCanPick; } /// /// Consume money + SP for learning skill on client side after player confirms. /// Returns false if resources are not enough at commit time. /// public bool TryConsumeSkillLearnCost(int moneyCost, int spCost) { if (moneyCost < 0) moneyCost = 0; if (spCost < 0) spCost = 0; if ((long)GetMoneyAmount() < moneyCost) return false; if (m_BasicProps.iSP < spCost) return false; AddMoneyAmount(-moneyCost); m_BasicProps.iSP = Math.Max(0, m_BasicProps.iSP - spCost); return true; } } }