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:
@@ -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
|
||||||
@@ -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
@@ -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
|
||||||
|
|||||||
+108
-40
@@ -1350,11 +1350,9 @@ 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!");
|
||||||
@@ -1367,19 +1365,38 @@ void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recv_data)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1402,55 +1419,106 @@ void WorldSession::HandleItemRefund(WorldPacket &recv_data)
|
|||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+122
-16
@@ -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;
|
||||||
|
RefundData->paidHonorPoints = honorPoints;
|
||||||
|
RefundData->paidArenaPoints = arenaPoints;
|
||||||
for (uint8 i=0; i<5; ++i)
|
for (uint8 i=0; i<5; ++i)
|
||||||
it->SetPaidExtendedCost(i, extendedCost[i], extendedCostCount[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);
|
||||||
|
}
|
||||||
@@ -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 );
|
||||||
|
|||||||
Reference in New Issue
Block a user