Files
test/Assets/Scripts/CECHostPlayer.Inventory.cs
T
2026-04-26 16:37:34 +07:00

1760 lines
70 KiB
C#

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 PerfectWorld.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();
}
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
ui?.RefreshAll();
}
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();
}
}
break;
}
case CommandID.CHANGE_IVTR_SIZE:
{
// C++: resize pack (normal inventory)
if (data != null && data.Length >= 4)
{
int newSize = BitConverter.ToInt32(data, 0);
if (m_pPack != null)
m_pPack.Resize(newSize);
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
ui?.RefreshAll();
}
break;
}
case CommandID.GET_OWN_MONEY:
{
//if (data != null)
//{
// try
// {
// var money = GPDataTypeHelper.FromBytes<CSNetwork.GPDataType.cmd_get_own_money>(data);
// SetMoneyAmount(money.amount);
// var ui = GameObject.FindFirstObjectByType<BrewMonster.Scripts.Managers.EC_InventoryUI>();
// if (ui == null)
// {
// var all = Resources.FindObjectsOfTypeAll<BrewMonster.Scripts.Managers.EC_InventoryUI>();
// 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<CSNetwork.GPDataType.cmd_get_own_money>(data);
SetMoneyAmount(money.amount);
m_iMaxMoney = (int)money.max_amount;
EC_InventoryUI ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
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<CSNetwork.GPDataType.player_cash>(data);
var ui = GameObject.FindFirstObjectByType<BrewMonster.Scripts.Managers.EC_InventoryUI>();
if (ui == null)
{
var all = Resources.FindObjectsOfTypeAll<BrewMonster.Scripts.Managers.EC_InventoryUI>();
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<EC_InventoryUI>();
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<cmd_empty_item_slot>(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<EC_InventoryUI>();
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<EC_InventoryUI>();
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<EC_InventoryUI>();
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<EC_InventoryUI>();
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<EC_InventoryUI>();
if (ui != null)
{
ui.RefreshAll();
ui.RefreshCharacterModelPreview();
}
UpdateEquipSkins();
break;
}
}
}
/// <summary>
/// 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.
/// </summary>
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<cmd_pickup_item>(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<cmd_host_obtain_item>(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<cmd_produce_once>(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>();
dlgProduce?.OnProduceOnce(pCmdProduce);
break;
}
case CommandID.TASK_DELIVER_ITEM:
{
var pCmdTask = GPDataTypeHelper.FromBytes<cmd_task_deliver_item>(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<pickupItem>();
pickupScript?.OnPickupSuccess(idItem);
}
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
ui?.RefreshAll();
UpdateEquipSkins();
}
/// <summary>
/// Buy from NPC/booth: S2C PURCHASE_ITEM (<c>cmd_purchase_item</c>).
/// Port of <c>CECHostPlayer::OnMsgHstPurchaseItems</c> (EC_HostMsg.cpp): prefer <c>MergeItem</c> like the C++ client.
/// If merge lands on a different slot than <c>inv_index</c> (common when stacking into an earlier pile), we still accept
/// the merged slot—the strict C++ <c>iLastSlot == inv_index</c> check would skip updates and break buy/stack UI here.
/// Fallback: <c>PutItemInSlot(inv_index)</c> then <c>MergeItem</c> when merge alone fails.
/// </summary>
public void OnMsgHstPurchaseItems(ECMSG Msg)
{
var data = Msg.dwParam1 as byte[];
if (data == null || data.Length < 11)
return;
var header = GPDataTypeHelper.FromBytes<cmd_purchase_item_header>(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<byte>();
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<EC_InventoryUI>();
ui?.RefreshAll();
if (purchaseSlotMismatch)
{
UnityGameSession.RequestInventoryAsync(0, () =>
{
var ui2 = GameObject.FindFirstObjectByType<EC_InventoryUI>();
ui2?.RefreshAll();
});
}
}
UpdateEquipSkins();
}
/// <summary>
/// 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.
/// </summary>
// 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<EC_InventoryUI>();
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<EC_InventoryUI>();
invUi?.RefreshAll();
UpdateEquipSkins();
}
private void OnMsgHstUseItem(ECMSG Msg)
{
cmd_host_use_item pCmd = GPDataTypeHelper.FromBytes<cmd_host_use_item>((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<EC_InventoryUI>();
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<DlgProduce>();
if (dlgProduce == null)
{
Debug.LogWarning("[OnMsgHstProduceItem] DlgProduce not found");
return;
}
switch (cmd)
{
case CommandID.PRODUCE_START:
{
cmd_produce_start pCmd = GPDataTypeHelper.FromBytes<cmd_produce_start>(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<cmd_produce_null>(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<cmd_embed_item>((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<cmd_clear_tessera>((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<EC_InventoryUI>();
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<CDlgTokenShop*>(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;
}
/// <summary>
/// Consume money + SP for learning skill on client side after player confirms.
/// Returns false if resources are not enough at commit time.
/// </summary>
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;
}
}
}