bool CUser::GiveItem(uint32 itemid, uint16 count, bool send_packet /*= true*/) { int8 pos; bool bNewItem = true; _ITEM_TABLE* pTable = g_pMain->GetItemPtr( itemid ); if (pTable == nullptr) return false; pos = FindSlotForItem(itemid, count); if (pos < 0) return false; _ITEM_DATA *pItem = &m_sItemArray[pos]; if (pItem->nNum != 0) bNewItem = false; if (bNewItem) pItem->nSerialNum = g_pMain->GenerateItemSerial(); pItem->nNum = itemid; pItem->sCount += count; if (pItem->sCount > MAX_ITEM_COUNT) pItem->sCount = MAX_ITEM_COUNT; pItem->sDuration = pTable->m_sDuration; // This is really silly, but match the count up with the duration // for this special items that behave this way. if (pTable->m_bKind == 255) pItem->sCount = pItem->sDuration; if (send_packet) SendStackChange(itemid, m_sItemArray[pos].sCount, m_sItemArray[pos].sDuration, pos - SLOT_MAX, true); return true; }
bool CUser::RobItem(uint32 itemid, uint16 count) { // Allow unused exchanges. if (count == 0) return true; _ITEM_TABLE* pTable = g_pMain->GetItemPtr( itemid ); if (pTable == NULL) return false; // Search for the existance of all items in the player's inventory storage and onwards (includes magic bags) for (int i = SLOT_MAX; i < INVENTORY_TOTAL; i++) { _ITEM_DATA *pItem = &m_sItemArray[i]; if (pItem->nNum != itemid || m_sItemArray[i].sCount < count) continue; pItem->sCount -= count; // This is a hackfix to ensure the duration is tweaked as well as the count // for those special items that use this instead. // This may or may not be accurate. if (pTable->m_bKind == 255) pItem->sDuration = pItem->sCount; if (pItem->sCount == 0) memset(&m_sItemArray[i], 0, sizeof(_ITEM_DATA)); SendStackChange(itemid, pItem->sCount, pItem->sDuration, i - SLOT_MAX); return true; } return false; }
void CUser::GiveMerchantItems() { for (int i = 0; i < MAX_MERCH_ITEMS; i++) { _MERCH_DATA *pMerch = &m_arMerchantItems[i]; uint8 bOriginalSlot = pMerch->bOriginalSlot; _ITEM_DATA *pItem = &m_sItemArray[bOriginalSlot]; pItem->nNum = pMerch->nNum; pItem->nSerialNum = pMerch->nSerialNum; pItem->sCount = pMerch->sCount; pItem->sDuration = pMerch->sDuration; SendStackChange(pItem->nNum, pItem->sCount, pItem->sDuration, pMerch->bOriginalSlot, pItem->sCount == pMerch->sCount); // is it a new item? } // remove the items from the array now that they've been restored to the user memset(&m_arMerchantItems, 0, sizeof(m_arMerchantItems)); }
bool CUser::RobItem(uint32 itemid, uint16 count /*= 1*/) { // Allow unused exchanges. if (count == 0) return true; _ITEM_TABLE* pTable = g_pMain->GetItemPtr( itemid ); if (pTable == nullptr) return false; // Search for the existance of all items in the player's inventory storage and onwards (includes magic bags) for (int i = SLOT_MAX; i < INVENTORY_TOTAL; i++) { _ITEM_DATA *pItem = &m_sItemArray[i]; if (pItem->nNum != itemid || m_sItemArray[i].sCount < count) continue; // Consumable "scrolls" (with some exceptions) use the duration/durability as a usage count // instead of the stack size. Interestingly, the client shows this instead of the stack size in this case. bool bIsConsumableScroll = (pTable->m_bKind == 255); /* include 97? not sure how accurate this check is... */ if (bIsConsumableScroll) pItem->sDuration -= count; else pItem->sCount -= count; // Delete the item if the stack's now 0 // or if the item is a consumable scroll and its "duration"/use count is now 0. if (pItem->sCount == 0 || (bIsConsumableScroll && pItem->sDuration == 0)) memset(pItem, 0, sizeof(_ITEM_DATA)); SendStackChange(itemid, pItem->sCount, pItem->sDuration, i - SLOT_MAX); return true; } return false; }
void CUser::BuyingMerchantBuy(Packet & pkt) { uint32 nPrice; uint16 sStackSize, sRemainingStackSize; uint8 bSellerSrcSlot, bMerchantListSlot; CUser *pMerchant = g_pMain->GetUserPtr(m_sMerchantsSocketID); if (pMerchant == nullptr) return; pkt >> bSellerSrcSlot >> bMerchantListSlot >> sStackSize; if (bSellerSrcSlot >= HAVE_MAX || bMerchantListSlot >= MAX_MERCH_ITEMS) return; _MERCH_DATA *pWantedItem = &pMerchant->m_arMerchantItems[bMerchantListSlot]; _ITEM_DATA *pSellerItem = GetItem(SLOT_MAX + bSellerSrcSlot); // Make sure the merchant actually has that item in that slot // and that they want enough, and the selling user has enough if (pWantedItem->nNum != pSellerItem->nNum || pWantedItem->sCount < sStackSize || pSellerItem->sCount < sStackSize // For scrolls, this will ensure you can only sell a full stack of scrolls. // For everything else, this will ensure you cannot sell items that need repair. || pSellerItem->sDuration != pWantedItem->sDuration) 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(pWantedItem->nNum); if (proto == nullptr || !proto->m_bCountable && sStackSize != 1) return; // Do they have enough coins? nPrice = pWantedItem->nPrice * sStackSize; if (!pMerchant->hasCoins(nPrice)) return; // Now find the buyer a home for their item int8 bDstPos = pMerchant->FindSlotForItem(pWantedItem->nNum, sStackSize); if (bDstPos < 0) return; _ITEM_DATA *pMerchantItem = pMerchant->GetItem(bDstPos); // Take coins off the buying merchant if (!pMerchant->GoldLose(nPrice)) return; // and give them all to me, me, me! GoldGain(nPrice); // Get the remaining stack size after purchase. sRemainingStackSize = pSellerItem->sCount - sStackSize; // Now we give the buying merchant their wares. pMerchantItem->nNum = pSellerItem->nNum; pMerchantItem->sDuration = pSellerItem->sDuration; pSellerItem->sCount -= sStackSize; pMerchantItem->sCount += sStackSize; // Update how many items the buyer still needs. pWantedItem->sCount -= sStackSize; // If the buyer needs no more, remove this item from the wanted list. if (pWantedItem->sCount == 0) memset(pWantedItem, 0, sizeof(_MERCH_DATA)); // If the seller's all out, remove their item. if (pSellerItem->sCount == 0) memset(pSellerItem, 0, sizeof(_ITEM_DATA)); // TO-DO : Proper checks for the removal of the items in the array, we're now assuming everything gets bought // Update players SendStackChange(pSellerItem->nNum, pSellerItem->sCount, pSellerItem->sDuration, bSellerSrcSlot); pMerchant->SendStackChange(pMerchantItem->nNum, pMerchantItem->sCount, pMerchantItem->sDuration, bDstPos - SLOT_MAX, pMerchantItem->sCount == sStackSize); // if the buying merchant only has what they wanted, it's a new item. // (otherwise it was a stackable item that was merged into an existing slot) Packet result(WIZ_MERCHANT, uint8(MERCHANT_BUY_BOUGHT)); result << bMerchantListSlot << uint16(0) << GetName(); pMerchant->Send(&result); result.clear(); result << uint8(MERCHANT_BUY_SOLD) << uint8(1) << bMerchantListSlot << pWantedItem->sCount << bSellerSrcSlot << pSellerItem->sCount; Send(&result); result.clear(); result << uint8(MERCHANT_BUY_BUY) << uint8(1); Send(&result); if (bMerchantListSlot < 4 && pWantedItem->sCount == 0) { result.Initialize(WIZ_MERCHANT_INOUT); result << uint8(2) << m_sMerchantsSocketID << uint8(1) << uint8(0) << bMerchantListSlot; 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) pMerchant->BuyingMerchantClose(); }
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::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(); }