/* Regular merchants */ void CUser::MerchantOpen() { int16 errorCode = 0; if (isDead()) errorCode = MERCHANT_OPEN_DEAD; else if (isStoreOpen()) errorCode = MERCHANT_OPEN_SHOPPING; else if (isTrading()) errorCode = MERCHANT_OPEN_TRADING; else if (GetZoneID() > 21 || GetZoneID() <= ELMORAD) errorCode = MERCHANT_OPEN_INVALID_ZONE; else if (GetLevel() < 30) errorCode = MERCHANT_OPEN_UNDERLEVELED; else if (isMerchanting()) errorCode = MERCHANT_OPEN_MERCHANTING; else errorCode = MERCHANT_OPEN_SUCCESS; Packet result(WIZ_MERCHANT, uint8(MERCHANT_OPEN)); result << errorCode; Send(&result); // If we're already merchanting, user may be desynced // so we need to close our current merchant first. if (errorCode == MERCHANT_OPEN_MERCHANTING) MerchantClose(); }
void CUser::MerchantItemBuy(Packet & pkt) { uint32 itemid, req_gold; uint16 item_count, leftover_count; uint8 item_slot, dest_slot; CUser *pMerchant = g_pMain->GetUserPtr(m_sMerchantsSocketID); if (pMerchant == nullptr) return; pkt >> itemid >> item_count >> item_slot >> dest_slot; // Make sure the slots are correct and that we're actually buying at least 1 item. if (item_slot >= MAX_MERCH_ITEMS || dest_slot >= HAVE_MAX || item_count == 0) return; // Grab pointers to the items. _MERCH_DATA *pMerch = &pMerchant->m_arMerchantItems[item_slot]; _ITEM_DATA *pItem = GetItem(SLOT_MAX + dest_slot); // Make sure the merchant actually has that item in that slot // and that they have enough if (pMerch->nNum != itemid || pMerch->sCount < item_count) return; // If it's not stackable, and we're specifying something other than 1 // we really don't care to handle this request... _ITEM_TABLE *proto = g_pMain->GetItemPtr(itemid); if (proto == nullptr || !proto->m_bCountable && item_count != 1) return; // Do we have enough coins? req_gold = pMerch->nPrice * item_count; if (m_iGold < req_gold) return; // If the slot's not empty if (pItem->nNum != 0 // and we already have an item that isn't the same item // or it's the same item but the item's not stackable... && (pItem->nNum != itemid || !proto->m_bCountable)) return; leftover_count = pMerch->sCount - item_count; pMerchant->GoldChange(GetSocketID(), req_gold); pItem->nNum = itemid; pItem->sCount += item_count; pItem->sDuration = pMerch->sDuration; pItem->nSerialNum = pMerch->nSerialNum; pMerch->sCount -= item_count; // TO-DO : Proper checks for the removal of the items in the array, we're now assuming everything gets bought if (pMerch->sCount == 0) memset(pMerch, 0, sizeof(_MERCH_DATA)); SetSlotItemValue(); pMerchant->SetSlotItemValue(); SetUserAbility(); pMerchant->SetUserAbility(); SendStackChange(itemid, pItem->sCount, pItem->sDuration, dest_slot, (pItem->sCount == item_count)); // is it a new item? pMerchant->SendStackChange(itemid, leftover_count, pMerch->sDuration, pMerch->bOriginalSlot - SLOT_MAX); Packet result(WIZ_MERCHANT, uint8(MERCHANT_ITEM_PURCHASED)); result << itemid << GetName(); pMerchant->Send(&result); result.clear(); result << uint8(MERCHANT_ITEM_BUY) << uint16(1) << itemid << leftover_count << item_slot << dest_slot; Send(&result); if (item_slot < 4 && leftover_count == 0) { result.Initialize(WIZ_MERCHANT_INOUT); result << uint8(2) << m_sMerchantsSocketID << uint16(item_slot); pMerchant->SendToRegion(&result); } int nItemsRemaining = 0; for (int i = 0; i < MAX_MERCH_ITEMS; i++) { if (pMerchant->m_arMerchantItems[i].nNum != 0) nItemsRemaining++; } if (nItemsRemaining == 0) MerchantClose(); }
void CUser::MerchantProcess(char *pBuf) { int index = 0; BYTE subcommand = GetByte(pBuf, index); switch (subcommand) { // Regular merchants case MERCHANT_OPEN: MerchantOpen(pBuf+index); break; case MERCHANT_CLOSE: MerchantClose(); break; case MERCHANT_ITEM_ADD: MerchantItemAdd(pBuf+index); break; case MERCHANT_ITEM_CANCEL: MerchantItemCancel(pBuf+index); break; case MERCHANT_ITEM_LIST: MerchantItemList(pBuf+index); break; case MERCHANT_ITEM_BUY: MerchantItemBuy(pBuf+index); break; case MERCHANT_INSERT: MerchantInsert(pBuf+index); break; case MERCHANT_TRADE_CANCEL: CancelMerchant(); break; #if __VERSION >= 1700 // Buying merchants case MERCHANT_BUY_OPEN: BuyingMerchantOpen(pBuf+index); break; case MERCHANT_BUY_CLOSE: BuyingMerchantClose(); break; case MERCHANT_BUY_LIST: BuyingMerchantList(pBuf+index); break; case MERCHANT_BUY_INSERT: BuyingMerchantInsert(pBuf+index); break; case MERCHANT_BUY_BUY: // seeya! BuyingMerchantBuy(pBuf+index); break; #endif } }
void CUser::MerchantProcess(Packet & pkt) { uint8 opcode = pkt.read<uint8>(); switch (opcode) { // Regular merchants case MERCHANT_OPEN: MerchantOpen(); break; case MERCHANT_CLOSE: MerchantClose(); break; case MERCHANT_ITEM_ADD: MerchantItemAdd(pkt); break; case MERCHANT_ITEM_CANCEL: MerchantItemCancel(pkt); break; case MERCHANT_ITEM_LIST: MerchantItemList(pkt); break; case MERCHANT_ITEM_BUY: MerchantItemBuy(pkt); break; case MERCHANT_INSERT: MerchantInsert(pkt); break; case MERCHANT_TRADE_CANCEL: CancelMerchant(); break; #if __VERSION >= 1700 // Buying merchants case MERCHANT_BUY_OPEN: BuyingMerchantOpen(pkt); break; case MERCHANT_BUY_CLOSE: BuyingMerchantClose(); break; case MERCHANT_BUY_LIST: BuyingMerchantList(pkt); break; case MERCHANT_BUY_INSERT: BuyingMerchantInsert(pkt); break; case MERCHANT_BUY_BUY: // seeya! BuyingMerchantBuy(pkt); break; #endif } }
void CUser::MerchantItemBuy(Packet & pkt) { uint32 itemid, req_gold; uint16 item_count, leftover_count; uint8 item_slot, dest_slot; CUser * m_MerchantUser = NULL; if (m_sMerchantsSocketID < 0 || m_sMerchantsSocketID > MAX_USER) return; m_MerchantUser = g_pMain->GetUserPtr(m_sMerchantsSocketID); if (m_MerchantUser == NULL) return; pkt >> itemid >> item_count >> item_slot >> dest_slot; if (item_slot < 0 || item_slot > MAX_MERCH_ITEMS || item_count == 0) return; if (m_MerchantUser->m_arSellingItems[item_slot].nNum != itemid ||m_MerchantUser->m_arSellingItems[item_slot].sCount < item_count) return; req_gold = m_MerchantUser->m_arSellingItems[item_slot].nPrice * item_count; if (m_pUserData->m_iGold < req_gold) return; if (m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].nNum != 0 && m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].nNum != itemid) return; leftover_count = m_MerchantUser->m_arSellingItems[item_slot].sCount - item_count; m_MerchantUser->GoldChange(GetSocketID(), req_gold); m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].nNum = itemid; m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].sCount += item_count; m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].sDuration = m_MerchantUser->m_arSellingItems[item_slot].sDuration; m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].nSerialNum = m_MerchantUser->m_arSellingItems[item_slot].nSerialNum; //TO-DO : Proper checks for the removal of the items in the array, we're now assuming everything gets bought if(item_count == m_MerchantUser->m_arSellingItems[item_slot].sCount) memset(&m_MerchantUser->m_arSellingItems[item_slot], 0, sizeof(_MERCH_DATA)); //Remove the item from the arSellingItems array. else m_MerchantUser->m_arSellingItems[item_slot].sCount -= item_count; SetSlotItemValue(); m_MerchantUser->SetSlotItemValue(); SetUserAbility(); m_MerchantUser->SetUserAbility(); if (m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].sCount == item_count) SendStackChange(itemid, m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].sCount, m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].sDuration, dest_slot, true); else SendStackChange(itemid, m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].sCount, m_pUserData->m_sItemArray[SLOT_MAX+dest_slot].sDuration, dest_slot); m_MerchantUser->SendStackChange(itemid, leftover_count, m_MerchantUser->m_arSellingItems[item_slot].sDuration, m_MerchantUser->m_arSellingItems[item_slot].bOriginalSlot - SLOT_MAX); Packet result(WIZ_MERCHANT, uint8(MERCHANT_ITEM_PURCHASED)); result << itemid << m_pUserData->m_id; m_MerchantUser->Send(&result); result.clear(); result << uint8(MERCHANT_ITEM_BUY) << uint16(1) << itemid << leftover_count << item_slot << dest_slot; Send(&result); if(item_slot < 4 && leftover_count == 0) { result.Initialize(WIZ_MERCHANT_INOUT); result << uint8(2) << m_sMerchantsSocketID << uint16(item_slot); m_MerchantUser->SendToRegion(&result); } int n = 0; for(int i = 0; i < MAX_MERCH_ITEMS; i++) if(m_MerchantUser->m_arSellingItems[i].nNum == 0) n++; if(n == 0) MerchantClose(); }