Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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));
}
Пример #4
0
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();
}