Implement vendor item refund system.

For info about this system, see: hxxp://us.blizzard.com/support/article.xml?locale=en_US&articleId=27351
Thanks to:
- Opterman, Malcrom, Xanadu + anonymous colleagues for aiding research on packet structure
- Aokromes and Svannon for testing

--HG--
branch : trunk
This commit is contained in:
Machiavelli
2010-03-18 17:27:40 +01:00
parent 72833e1584
commit 302af79bc2
6 changed files with 362 additions and 85 deletions
@@ -0,0 +1,19 @@
DROP TABLE IF EXISTS `item_refund_instance`;
CREATE TABLE `item_refund_instance` (
`item_guid` int(11) unsigned NOT NULL COMMENT 'Item GUID',
`player_guid` int(11) unsigned NOT NULL COMMENT 'Player GUID',
`paidMoney` int(11) unsigned NOT NULL DEFAULT '0',
`paidHonor` int(11) unsigned NOT NULL DEFAULT '0',
`paidArena` int(11) unsigned NOT NULL DEFAULT '0',
`paidItem_1` mediumint(6) unsigned NOT NULL DEFAULT '0' COMMENT 'item_template.entry',
`paidItemCount_1` mediumint(6) unsigned NOT NULL DEFAULT '0',
`paidItem_2` mediumint(6) unsigned NOT NULL DEFAULT '0',
`paidItemCount_2` mediumint(6) unsigned NOT NULL DEFAULT '0',
`paidItem_3` mediumint(6) unsigned NOT NULL DEFAULT '0',
`paidItemCount_3` mediumint(6) unsigned NOT NULL DEFAULT '0',
`paidItem_4` mediumint(6) unsigned NOT NULL DEFAULT '0',
`paidItemCount_4` mediumint(6) unsigned NOT NULL DEFAULT '0',
`paidItem_5` mediumint(6) unsigned NOT NULL DEFAULT '0',
`paidItemCount_5` mediumint(6) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`item_guid`, `player_guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
+68
View File
@@ -247,6 +247,8 @@ Item::Item( )
m_container = NULL; m_container = NULL;
m_lootGenerated = false; m_lootGenerated = false;
mb_in_trade = false; mb_in_trade = false;
m_lastPlayedTimeUpdate = time(NULL);
m_RefundData = NULL;
} }
bool Item::Create( uint32 guidlow, uint32 itemid, Player const* owner) bool Item::Create( uint32 guidlow, uint32 itemid, Player const* owner)
@@ -328,6 +330,8 @@ void Item::SaveToDB()
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid); CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid);
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow()); CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
DeleteRefundDataFromDB();
delete this; delete this;
return; return;
} }
@@ -1043,3 +1047,67 @@ void Item::BuildUpdate(UpdateDataMapType& data_map)
BuildFieldsUpdate(owner, data_map); BuildFieldsUpdate(owner, data_map);
ClearUpdateMask(false); ClearUpdateMask(false);
} }
void Item::SaveRefundDataToDB()
{
ItemRefund* RefundData = GetRefundData();
if (!RefundData)
return;
std::ostringstream ss;
ss << "INSERT INTO item_refund_instance VALUES(";
ss << GetGUIDLow() << ",";
ss << RefundData->eligibleFor << ",";
ss << RefundData->paidMoney << ",";
ss << RefundData->paidHonorPoints << ",";
ss << RefundData->paidArenaPoints << ",";
for (uint8 i=0; i<5; ++i)
{
ss << RefundData->paidItemId[i] << ",";
ss << RefundData->paidItemCount[i];
if (i < 4)
ss << ",";
}
ss << ")";
CharacterDatabase.Execute(ss.str().c_str());
}
void Item::DeleteRefundDataFromDB()
{
CharacterDatabase.PExecute("DELETE FROM item_refund_instance WHERE item_guid = '%u'", GetGUIDLow());
}
void Item::SetNotRefundable(Player *owner)
{
if (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
return;
if (m_RefundData)
delete m_RefundData;
RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE);
SetState(ITEM_CHANGED, owner);
DeleteRefundDataFromDB();
owner->DeleteRefundReference(this);
}
void Item::UpdatePlayedTime(Player *owner)
{
time_t curtime = time(NULL);
uint32 elapsed = curtime - m_lastPlayedTimeUpdate;
SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, GetPlayedTime(true) + elapsed);
SetState(ITEM_CHANGED, owner);
m_lastPlayedTimeUpdate = curtime;
}
uint32 Item::GetPlayedTime(bool raw)
{
if (raw)
return GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME);
time_t curtime = time(NULL);
uint32 elapsed = curtime - m_lastPlayedTimeUpdate;
return uint32(GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME) + elapsed);
}
+30 -19
View File
@@ -218,6 +218,27 @@ struct ItemRequiredTarget
bool ItemCanGoIntoBag(ItemPrototype const *proto, ItemPrototype const *pBagProto); bool ItemCanGoIntoBag(ItemPrototype const *proto, ItemPrototype const *pBagProto);
struct ItemRefund
{
ItemRefund()
{
paidMoney = 0;
paidHonorPoints = 0;
paidArenaPoints = 0;
for (uint8 i=0;i<5;++i)
{
paidItemId[i] = 0;
paidItemCount[i] = 0;
}
}
uint32 eligibleFor;
uint32 paidMoney;
uint32 paidHonorPoints;
uint32 paidArenaPoints;
uint32 paidItemId[5];
uint32 paidItemCount[5];
};
class Item : public Object class Item : public Object
{ {
public: public:
@@ -243,6 +264,8 @@ class Item : public Object
virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult_AutoPtr result = QueryResult_AutoPtr(NULL)); virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult_AutoPtr result = QueryResult_AutoPtr(NULL));
virtual void DeleteFromDB(); virtual void DeleteFromDB();
void DeleteFromInventoryDB(); void DeleteFromInventoryDB();
void SaveRefundDataToDB();
void DeleteRefundDataFromDB();
bool IsBag() const { return GetProto()->InventoryType == INVTYPE_BAG; } bool IsBag() const { return GetProto()->InventoryType == INVTYPE_BAG; }
bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; } bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; }
@@ -321,19 +344,11 @@ class Item : public Object
bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); } bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); }
// Item Refund system // Item Refund system
uint32 GetPaidHonorPoints() { return m_paidHonorPoints; } ItemRefund *GetRefundData() { return m_RefundData; }
uint32 GetPaidArenaPoints() { return m_paidArenaPoints; } void SetRefundData(ItemRefund *RefundData) { m_RefundData = RefundData; }
uint32 GetPaidExtendedCostId(uint32 pos) { return m_paidExtendedCostId[pos]; } void SetNotRefundable(Player *owner);
uint32 GetPaidExtendedCostCount(uint32 pos) { return m_paidExtendedCostCount[pos]; } void UpdatePlayedTime(Player *owner);
uint32 GetRefundExpiryTime() { return GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME); } uint32 GetPlayedTime(bool raw = false);
void SetRefundExpiryTime(uint32 timeval) { SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, timeval); }
void SetPaidHonorPoints(uint32 value) { m_paidHonorPoints = value; }
void SetPaidArenaPoints(uint32 value) { m_paidArenaPoints = value; }
void SetPaidExtendedCost(uint32 pos, uint32 entry, uint32 count)
{
m_paidExtendedCostId[pos] = entry;
m_paidExtendedCostCount[pos] = count;
}
void BuildUpdate(UpdateDataMapType& ); void BuildUpdate(UpdateDataMapType& );
@@ -343,11 +358,7 @@ class Item : public Object
ItemUpdateState uState; ItemUpdateState uState;
int16 uQueuePos; int16 uQueuePos;
bool mb_in_trade; // true if item is currently in trade-window bool mb_in_trade; // true if item is currently in trade-window
time_t m_lastPlayedTimeUpdate;
// refund system ItemRefund *m_RefundData;
uint32 m_paidHonorPoints;
uint32 m_paidArenaPoints;
uint32 m_paidExtendedCostId[5];
uint32 m_paidExtendedCostCount[5];
}; };
#endif #endif
+112 -44
View File
@@ -1350,36 +1350,53 @@ void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recv_data)
sLog.outDebug("WORLD: CMSG_ITEM_REFUND_INFO"); sLog.outDebug("WORLD: CMSG_ITEM_REFUND_INFO");
uint64 guid; uint64 guid;
recv_data >> guid; // item guid recv_data >> guid; // item guid
Item *item = _player->GetItemByGuid(guid); Item *item = _player->GetItemByGuid(guid);
if (!item)
if(!item)
{ {
sLog.outDebug("Item refund: item not found!"); sLog.outDebug("Item refund: item not found!");
return; return;
} }
if(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE)) if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
{ {
sLog.outDebug("Item refund: item not refundable!"); sLog.outDebug("Item refund: item not refundable!");
return; return;
} }
// item refund system not implemented yet if (item->GetPlayedTime() > (2*HOUR)) // item refund has expired
WorldPacket data(SMSG_ITEM_REFUND_INFO_RESPONSE, 8+4+4+4+4*4+4*4+4+4); // guess size item->SetNotRefundable(GetPlayer());
data << uint64(guid); // item guid
data << uint32(1); // unknown ItemRefund* RefundData = item->GetRefundData();
data << uint32(item->GetPaidHonorPoints()); // honor point cost if (!RefundData)
data << uint32(item->GetPaidArenaPoints()); // arena point cost
for(uint32 i = 0; i < 5; ++i) // extended cost data
{ {
data << uint32(item->GetPaidExtendedCostId(i)); sLog.outDebug("Item refund: cannot find refundable data.");
data << uint32(item->GetPaidExtendedCostCount(i)); item->SetNotRefundable(GetPlayer());
return;
}
if (GetPlayer()->GetGUIDLow() != RefundData->eligibleFor) // Formerly refundable item got traded
{
sLog.outDebug("Item refund: item was traded!");
item->SetNotRefundable(GetPlayer());
return;
}
item->UpdatePlayedTime(GetPlayer());
WorldPacket data(SMSG_ITEM_REFUND_INFO_RESPONSE, 8+4+4+4+4*4+4*4+4+4);
data << uint64(guid); // item guid
data << uint32(RefundData->paidMoney); // money cost
data << uint32(RefundData->paidHonorPoints); // honor point cost
data << uint32(RefundData->paidArenaPoints); // arena point cost
for (uint8 i = 0; i < 5; ++i) // item cost data
{
data << RefundData->paidItemId[i];
data << RefundData->paidItemCount[i];
} }
data << uint32(0); data << uint32(0);
data << uint32(0); data << uint32(GetPlayer()->GetTotalPlayedTime() - item->GetPlayedTime());
SendPacket(&data); SendPacket(&data);
} }
@@ -1390,67 +1407,118 @@ void WorldSession::HandleItemRefund(WorldPacket &recv_data)
recv_data >> guid; // item guid recv_data >> guid; // item guid
Item *item = _player->GetItemByGuid(guid); Item *item = _player->GetItemByGuid(guid);
if(!item) if (!item)
{ {
sLog.outDebug("Item refund: item not found!"); sLog.outDebug("Item refund: item not found!");
return; return;
} }
if(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE)) if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
{ {
sLog.outDebug("Item refund: item not refundable!"); sLog.outDebug("Item refund: item not refundable!");
return; return;
} }
if(item->GetRefundExpiryTime() <= time(NULL)) // item refund has expired if (item->GetPlayedTime() > (2*HOUR)) // item refund has expired
{ {
WorldPacket data(SMSG_ITEM_REFUND_RESULT); item->SetNotRefundable(GetPlayer());
data << uint64(guid); // guid WorldPacket data(SMSG_ITEM_REFUND_RESULT, 8+4);
data << uint32(1); // error, abort refund data << uint64(guid); // Guid
data << uint32(10); // Error!
SendPacket(&data);
return; return;
} }
WorldPacket data(SMSG_ITEM_REFUND_RESULT); ItemRefund* RefundData = item->GetRefundData();
data << uint64(guid); // guid? if (!RefundData)
data << uint32(0); // must be 0 or client side error in refund
data << uint32(0); // unk - message sent to client?
data << uint32(item->GetPaidHonorPoints()); // honor points refund
data << uint32(item->GetPaidArenaPoints()); // arena points refund
for(uint32 i = 0; i < 5; ++i) // extended cost?
{ {
data << uint32(item->GetPaidExtendedCostId(i)); sLog.outDebug("Item refund: cannot find refundable data.");
data << uint32(item->GetPaidExtendedCostCount(i)); item->SetNotRefundable(GetPlayer());
return;
} }
SendPacket(&data);
// Grant back extendedcost items if (GetPlayer()->GetGUIDLow() != RefundData->eligibleFor) // Formerly refundable item got traded
uint32 count = 0;
uint32 itemid = 0;
for(uint32 i = 0; i < 5; ++i)
{ {
count = item->GetPaidExtendedCostCount(i); sLog.outDebug("Item refund: item was traded!");
itemid = item->GetPaidExtendedCostId(i); item->SetNotRefundable(GetPlayer());
return;
}
bool store_error = false;
for (uint8 i = 0; i < 5; ++i)
{
uint32 count = RefundData->paidItemCount[i];
uint32 itemid = RefundData->paidItemId[i];
if (count && itemid) if (count && itemid)
{ {
ItemPosCountVec dest; ItemPosCountVec dest;
uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemid, count); uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemid, count);
if (msg == EQUIP_ERR_OK) if (msg != EQUIP_ERR_OK)
{ {
store_error = true;
break;
}
}
}
if (store_error)
{
WorldPacket data(SMSG_ITEM_REFUND_RESULT, 8+4);
data << uint64(guid); // Guid
data << uint32(10); // Error!
SendPacket(&data);
return;
}
WorldPacket data(SMSG_ITEM_REFUND_RESULT, 8+4+4+4+4+4*4+4*4);
data << uint64(guid); // item guid
data << uint32(0); // 0, or error code
data << uint32(RefundData->paidMoney); // money cost
data << uint32(RefundData->paidHonorPoints); // honor point cost
data << uint32(RefundData->paidArenaPoints); // arena point cost
for (uint8 i = 0; i < 5; ++i) // item cost data
{
data << RefundData->paidItemId[i];
data << RefundData->paidItemCount[i];
}
SendPacket(&data);
// Delete any references to the refund data
item->DeleteRefundDataFromDB();
GetPlayer()->DeleteRefundReference(item);
// Destroy item
_player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true);
// Grant back extendedcost items
for (uint8 i = 0; i < 5; ++i)
{
uint32 count = RefundData->paidItemCount[i];
uint32 itemid = RefundData->paidItemId[i];
if (count && itemid)
{
ItemPosCountVec dest;
uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemid, count);
ASSERT(msg == EQUIP_ERR_OK) /// Already checked before
Item* it = _player->StoreNewItem(dest, itemid, true); Item* it = _player->StoreNewItem(dest, itemid, true);
_player->SendNewItem(it, count, true, false, true); _player->SendNewItem(it, count, true, false, true);
} }
}
// Grant back money
uint32 moneyRefund = RefundData->paidMoney;
if (moneyRefund)
_player->ModifyMoney(moneyRefund);
// What to do if there's no space?
}
}
// Grant back Honor points // Grant back Honor points
if (uint32 honorRefund = item->GetPaidHonorPoints() > 0) uint32 honorRefund = RefundData->paidHonorPoints;
if (honorRefund)
_player->ModifyHonorPoints(honorRefund); _player->ModifyHonorPoints(honorRefund);
// Grant back Arena points // Grant back Arena points
if (uint32 arenaRefund = item->GetPaidArenaPoints() > 0) uint32 arenaRefund = RefundData->paidArenaPoints;
if (arenaRefund)
_player->ModifyArenaPoints(arenaRefund); _player->ModifyArenaPoints(arenaRefund);
// Destroy item delete RefundData;
_player->DestroyItemCount(item->GetEntry(), 1, true, true);
} }
+123 -17
View File
@@ -11561,6 +11561,9 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
RemoveEnchantmentDurations(pItem); RemoveEnchantmentDurations(pItem);
RemoveItemDurations(pItem); RemoveItemDurations(pItem);
if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
DeleteRefundReference(pItem);
ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount() ); ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount() );
if (bag == INVENTORY_SLOT_BAG_0) if (bag == INVENTORY_SLOT_BAG_0)
@@ -16366,6 +16369,47 @@ void Player::_LoadInventory(QueryResult_AutoPtr result, uint32 timediff)
continue; continue;
} }
if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
{
if (item->GetPlayedTime() > (2*HOUR))
{
sLog.outDebug("Item::LoadFromDB, Item GUID: %u: refund time expired, deleting refund data and removing refundable flag.", item->GetGUIDLow());
CharacterDatabase.PExecute("DELETE FROM item_refund_instance WHERE item_guid = '%u'", item->GetGUIDLow());
item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE);
}
else
{
QueryResult_AutoPtr result2 = CharacterDatabase.PQuery(
"SELECT player_guid,paidMoney,paidHonor,paidArena,"
"paidItem_1,paidItemCount_1,paidItem_2,paidItemCount_2,paidItem_3,paidItemCount_3,paidItem_4,paidItemCount_4,"
"paidItem_5,paidItemCount_5 FROM item_refund_instance WHERE item_guid = '%u' LIMIT 1",
item->GetGUIDLow());
if (!result2)
{
sLog.outDebug("Item::LoadFromDB, "
"Item GUID: %u has field flags & ITEM_FLAGS_REFUNDABLE but has no data in item_refund_instance, removing flag.",
item->GetGUIDLow());
RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE);
}
else
{
fields = result2->Fetch();
ItemRefund* RefundData = new ItemRefund();
RefundData->eligibleFor = fields[0].GetUInt32();
RefundData->paidMoney = fields[1].GetUInt32();
RefundData->paidHonorPoints = fields[2].GetUInt32();
RefundData->paidArenaPoints = fields[3].GetUInt32();
for (uint8 i=0, j=4; i<5; ++i, j+=2)
{
RefundData->paidItemId[i] = fields[j].GetUInt32();
RefundData->paidItemCount[i] = fields[j+1].GetUInt32();
}
item->SetRefundData(RefundData);
AddRefundReference(item);
}
}
}
bool success = true; bool success = true;
if (!bag_guid) if (!bag_guid)
@@ -17444,6 +17488,23 @@ void Player::_SaveInventory()
m_items[i]->FSetState(ITEM_NEW); m_items[i]->FSetState(ITEM_NEW);
} }
// Updated played time for refundable items
for (std::set<Item*>::iterator itr = m_refundableItems.begin(); itr!= m_refundableItems.end();)
{
// Item could be deleted, or traded.
// In the first case, DeleteRefundDataFromDB() was already called in Item::SaveToDB()
Item* iPtr = (*itr);
if (!iPtr || iPtr->GetOwner() != this)
m_refundableItems.erase(itr++);
else
{
iPtr->UpdatePlayedTime(this);
if (iPtr->GetPlayedTime() > (2*HOUR))
iPtr->SetNotRefundable(this);
++itr;
}
}
// update enchantment durations // update enchantment durations
for (EnchantDurationList::iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end(); ++itr) for (EnchantDurationList::iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end(); ++itr)
itr->item->SetEnchantmentDuration(itr->slot,itr->leftduration, this); itr->item->SetEnchantmentDuration(itr->slot,itr->leftduration, this);
@@ -19252,6 +19313,11 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
return false; return false;
} }
uint32 honorPoints = 0;
uint32 arenaPoints = 0;
uint32 itemCostId[5] = {0,0,0,0,0};
uint32 itemCostCount[5] = {0,0,0,0,0};
if ((bag == NULL_BAG && slot == NULL_SLOT) || IsInventoryPos(bag, slot)) if ((bag == NULL_BAG && slot == NULL_SLOT) || IsInventoryPos(bag, slot))
{ {
ItemPosCountVec dest; ItemPosCountVec dest;
@@ -19263,22 +19329,18 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
} }
ModifyMoney( -(int32)price ); ModifyMoney( -(int32)price );
uint32 arenaPoints = 0;
uint32 honorPoints = 0;
uint32 extendedCost[5] = {0,0,0,0,0};
uint32 extendedCostCount[5] = {0,0,0,0,0};
if (crItem->ExtendedCost) // case for new honor system if (crItem->ExtendedCost) // case for new honor system
{ {
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if (iece->reqhonorpoints) if (iece->reqhonorpoints)
{ {
honorPoints = iece->reqhonorpoints * count; honorPoints = iece->reqhonorpoints;
ModifyHonorPoints( - int32(honorPoints) ); ModifyHonorPoints( - int32(honorPoints) );
} }
if (iece->reqarenapoints) if (iece->reqarenapoints)
{ {
arenaPoints = iece->reqarenapoints * count; arenaPoints = iece->reqarenapoints;
ModifyArenaPoints( - int32(arenaPoints) ); ModifyArenaPoints( - int32(arenaPoints) );
} }
for (uint8 i = 0; i < 5; ++i) for (uint8 i = 0; i < 5; ++i)
@@ -19286,8 +19348,8 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
if (iece->reqitem[i]) if (iece->reqitem[i])
{ {
DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true); DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true);
extendedCost[i] = iece->reqitem[i]; itemCostId[i] = iece->reqitem[i];
extendedCostCount[i] = iece->reqitemcount[i]; itemCostCount[i] = iece->reqitemcount[i];
} }
} }
} }
@@ -19304,14 +19366,21 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
SendNewItem(it, pProto->BuyCount*count, true, false, false); SendNewItem(it, pProto->BuyCount*count, true, false, false);
// Item Refund system, only works for non stackable items with extendedcost if (it->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
if(count == 1 && crItem->ExtendedCost )
{ {
it->SetPaidArenaPoints(arenaPoints); ItemRefund* RefundData = new ItemRefund();
it->SetPaidHonorPoints(honorPoints); RefundData->eligibleFor = GetGUIDLow();
it->SetRefundExpiryTime( time(NULL)+(HOUR*2) ); RefundData->paidMoney = price;
for (uint8 i = 0; i < 5; ++i) RefundData->paidHonorPoints = honorPoints;
it->SetPaidExtendedCost(i, extendedCost[i], extendedCostCount[i]); RefundData->paidArenaPoints = arenaPoints;
for (uint8 i=0; i<5; ++i)
{
RefundData->paidItemId[i] = itemCostId[i];
RefundData->paidItemCount[i] = itemCostCount[i] ;
}
it->SetRefundData(RefundData);
it->SaveRefundDataToDB();
AddRefundReference(it);
} }
} }
} }
@@ -19336,13 +19405,23 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
{ {
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if (iece->reqhonorpoints) if (iece->reqhonorpoints)
ModifyHonorPoints( - int32(iece->reqhonorpoints)); {
honorPoints = iece->reqhonorpoints;
ModifyHonorPoints( - int32(honorPoints) );
}
if (iece->reqarenapoints) if (iece->reqarenapoints)
ModifyArenaPoints( - int32(iece->reqarenapoints)); {
arenaPoints = iece->reqarenapoints;
ModifyArenaPoints( - int32(arenaPoints));
}
for (uint8 i = 0; i < 5; ++i) for (uint8 i = 0; i < 5; ++i)
{ {
if(iece->reqitem[i]) if(iece->reqitem[i])
{
DestroyItemCount(iece->reqitem[i], iece->reqitemcount[i], true); DestroyItemCount(iece->reqitem[i], iece->reqitemcount[i], true);
itemCostId[i] = iece->reqitem[i];
itemCostCount[i] = iece->reqitemcount[i];
}
} }
} }
@@ -19360,6 +19439,23 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
SendNewItem(it, pProto->BuyCount*count, true, false, false); SendNewItem(it, pProto->BuyCount*count, true, false, false);
AutoUnequipOffhandIfNeed(); AutoUnequipOffhandIfNeed();
if (it->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
{
ItemRefund* RefundData = new ItemRefund();
RefundData->eligibleFor = GetGUIDLow();
RefundData->paidMoney = price;
RefundData->paidHonorPoints = honorPoints;
RefundData->paidArenaPoints = arenaPoints;
for (uint8 i=0; i<5; ++i)
{
RefundData->paidItemId[i] = itemCostId[i];
RefundData->paidItemCount[i] = itemCostCount[i] ;
}
it->SetRefundData(RefundData);
it->SaveRefundDataToDB();
AddRefundReference(it);
}
} }
} }
else else
@@ -23284,3 +23380,13 @@ void Player::SendDuelCountdown(uint32 counter)
data << uint32(counter); // seconds data << uint32(counter); // seconds
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
} }
void Player::AddRefundReference(Item* it)
{
m_refundableItems.insert(it);
}
void Player::DeleteRefundReference(Item* it)
{
m_refundableItems.erase(it);
}
+5
View File
@@ -1190,6 +1190,9 @@ class Player : public Unit, public GridObject<Player>
uint8 _CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL) const; uint8 _CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL) const;
uint8 _CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item *pItem = NULL, bool swap = false, uint32* no_space_count = NULL ) const; uint8 _CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item *pItem = NULL, bool swap = false, uint32* no_space_count = NULL ) const;
void AddRefundReference(Item* it);
void DeleteRefundReference(Item* it);
void ApplyEquipCooldown( Item * pItem ); void ApplyEquipCooldown( Item * pItem );
void SetAmmo( uint32 item ); void SetAmmo( uint32 item );
void RemoveAmmo(); void RemoveAmmo();
@@ -2554,6 +2557,8 @@ class Player : public Unit, public GridObject<Player>
uint8 _CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool merge, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot ) const; uint8 _CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool merge, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot ) const;
Item* _StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update ); Item* _StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update );
std::set<Item*> m_refundableItems;
void UpdateKnownCurrencies(uint32 itemId, bool apply); void UpdateKnownCurrencies(uint32 itemId, bool apply);
int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest); int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest);
void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData ); void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData );