Core/Items: Implemented trading soulbound loot items
Core/DBLayer: Converted more more player-related queries into prepared statements Core/Items: Fixed loading of enchantments Closes issue #4130. --HG-- branch : trunk
This commit is contained in:
@@ -371,7 +371,9 @@ void Item::SaveToDB(SQLTransaction& trans)
|
||||
}break;
|
||||
case ITEM_REMOVED:
|
||||
{
|
||||
trans->PAppend("DELETE FROM item_instance WHERE guid = '%u'", guid);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||
stmt->setUInt32(0, guid);
|
||||
trans->Append(stmt);
|
||||
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))
|
||||
trans->PAppend("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
|
||||
delete this;
|
||||
@@ -437,7 +439,7 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, PreparedQueryResult result
|
||||
need_save = true;
|
||||
}
|
||||
|
||||
_LoadIntoDataField(result->GetCString(6), ITEM_FIELD_ENCHANTMENT_1_1, MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET);
|
||||
_LoadIntoDataField(result->GetString(6).c_str(), ITEM_FIELD_ENCHANTMENT_1_1, MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET);
|
||||
SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, result->GetInt32(7));
|
||||
// recalculate suffix factor
|
||||
if (GetItemRandomPropertyId() < 0)
|
||||
@@ -472,12 +474,16 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, PreparedQueryResult result
|
||||
|
||||
void Item::DeleteFromDB(SQLTransaction& trans)
|
||||
{
|
||||
trans->PAppend("DELETE FROM item_instance WHERE guid = '%u'", GetGUIDLow());
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||
stmt->setUInt32(0, GetGUIDLow());
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
void Item::DeleteFromInventoryDB(SQLTransaction& trans)
|
||||
{
|
||||
trans->PAppend("DELETE FROM character_inventory WHERE item = '%u'", GetGUIDLow());
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVENTORY_ITEM);
|
||||
stmt->setUInt32(0, GetGUIDLow());
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
ItemPrototype const *Item::GetProto() const
|
||||
@@ -736,12 +742,12 @@ bool Item::IsEquipped() const
|
||||
return !IsInBag() && m_slot < EQUIPMENT_SLOT_END;
|
||||
}
|
||||
|
||||
bool Item::CanBeTraded(bool mail) const
|
||||
bool Item::CanBeTraded(bool mail, bool trade) const
|
||||
{
|
||||
if (m_lootGenerated)
|
||||
return false;
|
||||
|
||||
if ((!mail || !IsBoundAccountWide()) && IsSoulBound())
|
||||
if ((!mail || !IsBoundAccountWide()) && (IsSoulBound() && !HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE) || !trade))
|
||||
return false;
|
||||
|
||||
if (IsBag() && (Player::IsBagPos(GetPos()) || !((Bag const*)this)->IsEmpty()))
|
||||
@@ -1067,6 +1073,10 @@ bool Item::IsBindedNotWith(Player const* player) const
|
||||
if (GetOwnerGUID() == player->GetGUID())
|
||||
return false;
|
||||
|
||||
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE))
|
||||
if (allowedGUIDs.find(player->GetGUIDLow()) != allowedGUIDs.end())
|
||||
return false;
|
||||
|
||||
// BOA item case
|
||||
if (IsBoundAccountWide())
|
||||
return false;
|
||||
@@ -1171,3 +1181,36 @@ bool Item::IsRefundExpired()
|
||||
{
|
||||
return (GetPlayedTime() > 2*HOUR);
|
||||
}
|
||||
|
||||
void Item::SetSoulboundTradeable(AllowedLooterSet* allowedLooters, Player* currentOwner, bool apply)
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE);
|
||||
allowedGUIDs = *allowedLooters;
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE);
|
||||
if (allowedGUIDs.empty())
|
||||
return;
|
||||
|
||||
allowedGUIDs.clear();
|
||||
SetState(ITEM_CHANGED, currentOwner);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_BOP_TRADE);
|
||||
stmt->setUInt32(0, GetGUIDLow());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
bool Item::CheckSoulboundTradeExpire()
|
||||
{
|
||||
// called from owner's update - GetOwner() MUST be valid
|
||||
if (GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME) + 2*HOUR < GetOwner()->GetTotalPlayedTime())
|
||||
{
|
||||
SetSoulboundTradeable(NULL, GetOwner(), false);
|
||||
return true; // remove from tradeable list
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ class Item : public Object
|
||||
bool IsLocked() const { return !HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED); }
|
||||
bool IsBag() const { return GetProto()->InventoryType == INVTYPE_BAG; }
|
||||
bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; }
|
||||
bool CanBeTraded(bool mail = false) const;
|
||||
bool CanBeTraded(bool mail = false, bool trade = false) const;
|
||||
void SetInTrade(bool b = true) { mb_in_trade = b; }
|
||||
bool IsInTrade() const { return mb_in_trade; }
|
||||
|
||||
@@ -345,6 +345,10 @@ class Item : public Object
|
||||
uint32 GetPlayedTime();
|
||||
bool IsRefundExpired();
|
||||
|
||||
// Soulbound trade system
|
||||
void SetSoulboundTradeable(AllowedLooterSet* allowedLooters, Player* currentOwner, bool apply);
|
||||
bool CheckSoulboundTradeExpire();
|
||||
|
||||
void BuildUpdate(UpdateDataMapType&);
|
||||
|
||||
uint32 GetScriptId() const { return GetProto()->ScriptId; }
|
||||
@@ -359,5 +363,6 @@ class Item : public Object
|
||||
uint32 m_refundRecipient;
|
||||
uint32 m_paidMoney;
|
||||
uint32 m_paidExtendedCost;
|
||||
AllowedLooterSet allowedGUIDs;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1301,6 +1301,9 @@ void Player::Update(uint32 p_time)
|
||||
if (now > m_Last_tick)
|
||||
UpdateItemDuration(uint32(now - m_Last_tick));
|
||||
|
||||
if (now > m_Last_tick + IN_MILLISECONDS)
|
||||
UpdateSoulboundTradeItems();
|
||||
|
||||
if (!m_timedquests.empty())
|
||||
{
|
||||
QuestSet::iterator iter = m_timedquests.begin();
|
||||
@@ -4503,7 +4506,9 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
|
||||
ItemPrototype const* itemProto = sObjectMgr.GetItemPrototype(item_template);
|
||||
if (!itemProto)
|
||||
{
|
||||
trans->PAppend("DELETE FROM item_instance WHERE guid = '%u'", item_guidlow);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||
stmt->setUInt32(0, item_guidlow);
|
||||
trans->Append(stmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -11437,7 +11442,7 @@ void Player::RemoveAmmo()
|
||||
}
|
||||
|
||||
// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
|
||||
Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update,int32 randomPropertyId)
|
||||
Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update, int32 randomPropertyId, AllowedLooterSet* allowedLooters)
|
||||
{
|
||||
uint32 count = 0;
|
||||
for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr)
|
||||
@@ -11451,6 +11456,23 @@ Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update
|
||||
if (randomPropertyId)
|
||||
pItem->SetItemRandomProperties(randomPropertyId);
|
||||
pItem = StoreItem(dest, pItem, update);
|
||||
|
||||
if (allowedLooters && pItem->GetProto()->GetMaxStackSize() == 1 && pItem->IsSoulBound())
|
||||
{
|
||||
pItem->SetSoulboundTradeable(allowedLooters, this, true);
|
||||
pItem->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, GetTotalPlayedTime());
|
||||
m_itemSoulboundTradeable.push_back(pItem);
|
||||
|
||||
// save data
|
||||
std::ostringstream ss;
|
||||
for (AllowedLooterSet::iterator itr = allowedLooters->begin(); itr != allowedLooters->end(); ++itr)
|
||||
ss << *itr << " ";
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_ITEM_BOP_TRADE);
|
||||
stmt->setUInt32(0, pItem->GetGUIDLow());
|
||||
stmt->setString(1, ss.str());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
}
|
||||
return pItem;
|
||||
}
|
||||
@@ -11574,6 +11596,8 @@ Item* Player::_StoreItem(uint16 pos, Item *pItem, uint32 count, bool clone, bool
|
||||
pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
|
||||
pItem->SetNotRefundable(this);
|
||||
pItem->SetState(ITEM_REMOVED, this);
|
||||
pItem->SetSoulboundTradeable(NULL, this, false);
|
||||
RemoveTradeableItem(pItem->GetGUIDLow());
|
||||
}
|
||||
|
||||
// AddItemDurations(pItem2); - pItem2 already have duration listed for player
|
||||
@@ -11691,6 +11715,8 @@ Item* Player::EquipItem(uint16 pos, Item *pItem, bool update)
|
||||
|
||||
pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
|
||||
pItem->SetNotRefundable(this);
|
||||
pItem->SetSoulboundTradeable(NULL, this, false);
|
||||
RemoveTradeableItem(pItem->GetGUIDLow());
|
||||
pItem->SetState(ITEM_REMOVED, this);
|
||||
pItem2->SetState(ITEM_CHANGED, this);
|
||||
|
||||
@@ -11862,6 +11888,15 @@ void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
|
||||
it->RemoveFromWorld();
|
||||
it->DestroyForPlayer(this);
|
||||
}
|
||||
for (ItemDurationList::iterator itr = m_itemSoulboundTradeable.begin(); itr != m_itemSoulboundTradeable.end();)
|
||||
{
|
||||
if ((*itr)->GetGUID() == it->GetGUID())
|
||||
{
|
||||
m_itemSoulboundTradeable.erase(itr++);
|
||||
break;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11886,6 +11921,9 @@ void Player::MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool
|
||||
// in case trade we already have item in other player inventory
|
||||
pLastItem->SetState(in_characterInventoryDB ? ITEM_CHANGED : ITEM_NEW, this);
|
||||
}
|
||||
|
||||
if (pLastItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE))
|
||||
m_itemSoulboundTradeable.push_back(pLastItem);
|
||||
}
|
||||
|
||||
void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
|
||||
@@ -11909,6 +11947,8 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
|
||||
RemoveItemDurations(pItem);
|
||||
|
||||
pItem->SetNotRefundable(this);
|
||||
pItem->SetSoulboundTradeable(NULL, this, false);
|
||||
RemoveTradeableItem(pItem->GetGUIDLow());
|
||||
|
||||
ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount());
|
||||
|
||||
@@ -12848,6 +12888,46 @@ void Player::TradeCancel(bool sendback)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateSoulboundTradeItems()
|
||||
{
|
||||
if (m_itemSoulboundTradeable.empty())
|
||||
return;
|
||||
|
||||
// also checks for garbage data
|
||||
for (ItemDurationList::iterator itr = m_itemSoulboundTradeable.begin(); itr != m_itemSoulboundTradeable.end();)
|
||||
{
|
||||
if (!*itr)
|
||||
{
|
||||
itr = m_itemSoulboundTradeable.erase(itr++);
|
||||
continue;
|
||||
}
|
||||
if ((*itr)->GetOwnerGUID() != GetGUID())
|
||||
{
|
||||
itr = m_itemSoulboundTradeable.erase(itr++);
|
||||
continue;
|
||||
}
|
||||
if ((*itr)->CheckSoulboundTradeExpire())
|
||||
{
|
||||
itr = m_itemSoulboundTradeable.erase(itr++);
|
||||
continue;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::RemoveTradeableItem(uint32 lowGuid)
|
||||
{
|
||||
for (ItemDurationList::iterator itr = m_itemSoulboundTradeable.begin(); itr != m_itemSoulboundTradeable.end();)
|
||||
{
|
||||
if ((*itr)->GetGUIDLow() == lowGuid)
|
||||
{
|
||||
m_itemSoulboundTradeable.erase(itr++);
|
||||
break;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateItemDuration(uint32 time, bool realtimeonly)
|
||||
{
|
||||
if (m_itemDuration.empty())
|
||||
@@ -15913,8 +15993,8 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
|
||||
SetUInt32Value(UNIT_FIELD_LEVEL, result->GetUInt8(6));
|
||||
SetUInt32Value(PLAYER_XP, result->GetUInt32(7));
|
||||
|
||||
_LoadIntoDataField(result->GetCString(61), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE);
|
||||
_LoadIntoDataField(result->GetCString(64), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE*2);
|
||||
_LoadIntoDataField(result->GetString(61).c_str(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE);
|
||||
_LoadIntoDataField(result->GetString(64).c_str(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE*2);
|
||||
|
||||
SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE);
|
||||
SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f);
|
||||
@@ -16261,7 +16341,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
|
||||
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM))
|
||||
SetUInt32Value(PLAYER_FLAGS, 0 | old_safe_flags);
|
||||
|
||||
m_taxi.LoadTaxiMask(result->GetCString(17)); // must be before InitTaxiNodesForLevel
|
||||
m_taxi.LoadTaxiMask(result->GetString(17).c_str()); // must be before InitTaxiNodesForLevel
|
||||
|
||||
uint32 extraflags = result->GetUInt32(31);
|
||||
|
||||
@@ -16707,8 +16787,12 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timediff)
|
||||
|
||||
if (!proto)
|
||||
{
|
||||
trans->PAppend("DELETE FROM character_inventory WHERE item = '%u'", item_guid);
|
||||
trans->PAppend("DELETE FROM item_instance WHERE guid = '%u'", item_guid);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVENTORY_ITEM);
|
||||
stmt->setUInt32(0, item_guid);
|
||||
trans->Append(stmt);
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||
stmt->setUInt32(0, item_guid);
|
||||
trans->Append(stmt);
|
||||
sLog.outError("Player::_LoadInventory: Player %s has an unknown item (id: #%u) in inventory, deleted.", GetName(),item_id);
|
||||
continue;
|
||||
}
|
||||
@@ -16718,7 +16802,9 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timediff)
|
||||
if (!item->LoadFromDB(item_guid, GetGUID(), result, item_id))
|
||||
{
|
||||
sLog.outError("Player::_LoadInventory: Player %s has broken item (id: #%u) in inventory, deleted.", GetName(),item_id);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVENTORY_ITEM);
|
||||
stmt->setUInt32(0, item_guid);
|
||||
trans->Append(stmt);
|
||||
item->FSetState(ITEM_REMOVED);
|
||||
item->SaveToDB(trans); // it also deletes item object !
|
||||
continue;
|
||||
@@ -16727,7 +16813,9 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timediff)
|
||||
// not allow have in alive state item limited to another map/zone
|
||||
if (isAlive() && item->IsLimitedToAnotherMapOrZone(GetMapId(), zone))
|
||||
{
|
||||
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVENTORY_ITEM);
|
||||
stmt->setUInt32(0, item_guid);
|
||||
trans->Append(stmt);
|
||||
item->FSetState(ITEM_REMOVED);
|
||||
item->SaveToDB(trans); // it also deletes item object !
|
||||
continue;
|
||||
@@ -16736,7 +16824,9 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timediff)
|
||||
// "Conjured items disappear if you are logged out for more than 15 minutes"
|
||||
if (timediff > 15*MINUTE && proto->Flags & ITEM_PROTO_FLAG_CONJURED)
|
||||
{
|
||||
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVENTORY_ITEM);
|
||||
stmt->setUInt32(0, item_guid);
|
||||
trans->Append(stmt);
|
||||
item->FSetState(ITEM_REMOVED);
|
||||
item->SaveToDB(trans); // it also deletes item object !
|
||||
continue;
|
||||
@@ -16752,26 +16842,45 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timediff)
|
||||
}
|
||||
else
|
||||
{
|
||||
QueryResult result2 = CharacterDatabase.PQuery(
|
||||
"SELECT player_guid,paidMoney,paidExtendedCost FROM `item_refund_instance` WHERE item_guid = '%u' AND player_guid = '%u' LIMIT 1",
|
||||
item->GetGUIDLow(), GetGUIDLow());
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_ITEM_REFUNDS);
|
||||
stmt->setUInt32(0, item->GetGUIDLow());
|
||||
stmt->setUInt32(1, GetGUIDLow());
|
||||
PreparedQueryResult result2 = CharacterDatabase.Query(stmt);
|
||||
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());
|
||||
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());
|
||||
item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
Field* fields2 = result2->Fetch();
|
||||
item->SetRefundRecipient(fields2[0].GetUInt32());
|
||||
item->SetPaidMoney(fields2[1].GetUInt32());
|
||||
item->SetPaidExtendedCost(fields2[2].GetUInt32());
|
||||
item->SetRefundRecipient(result2->GetUInt32(0));
|
||||
item->SetPaidMoney(result2->GetUInt32(1));
|
||||
item->SetPaidExtendedCost(result2->GetUInt32(2));
|
||||
AddRefundReference(item->GetGUIDLow());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE))
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_ITEM_BOP_TRADE);
|
||||
stmt->setUInt32(0, item->GetGUIDLow());
|
||||
PreparedQueryResult result2 = CharacterDatabase.Query(stmt);
|
||||
if (!result2)
|
||||
{
|
||||
sLog.outDebug("Item::LoadFromDB, Item GUID: %u has flag ITEM_FLAG_BOP_TRADEABLE but has no data in item_soulbound_trade_data, removing flag.", item->GetGUIDLow());
|
||||
item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string strGUID = result2->GetString(0);
|
||||
Tokens GUIDlist = StrSplit(strGUID, " ");
|
||||
AllowedLooterSet looters;
|
||||
for (Tokens::iterator itr = GUIDlist.begin(); itr != GUIDlist.end(); ++itr)
|
||||
looters.insert(atol((*itr).c_str()));
|
||||
item->SetSoulboundTradeable(&looters, this, true);
|
||||
m_itemSoulboundTradeable.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
@@ -16840,7 +16949,9 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timediff)
|
||||
else
|
||||
{
|
||||
sLog.outError("Player::_LoadInventory: Player %s has item (GUID: %u Entry: %u) can't be loaded to inventory (Bag GUID: %u Slot: %u) by some reason, will send by mail.", GetName(),item_guid, item_id, bag_guid, slot);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVENTORY_ITEM);
|
||||
stmt->setUInt32(0, item_guid);
|
||||
trans->Append(stmt);
|
||||
problematicItems.push_back(item);
|
||||
}
|
||||
} while (result->NextRow());
|
||||
@@ -16895,7 +17006,9 @@ void Player::_LoadMailedItems(Mail *mail)
|
||||
{
|
||||
sLog.outError("Player %u has unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID);
|
||||
trans->PAppend("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low);
|
||||
trans->PAppend("DELETE FROM item_instance WHERE guid = '%u'", item_guid_low);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||
stmt->setUInt32(0, item_guid_low);
|
||||
trans->Append(stmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -17870,7 +17983,9 @@ void Player::_SaveInventory(SQLTransaction& trans)
|
||||
if (!item || item->GetState() == ITEM_NEW)
|
||||
continue;
|
||||
trans->PAppend("DELETE FROM character_inventory WHERE item = '%u'", item->GetGUIDLow());
|
||||
trans->PAppend("DELETE FROM item_instance WHERE guid = '%u'", item->GetGUIDLow());
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||
stmt->setUInt32(0, item->GetGUIDLow());
|
||||
trans->Append(stmt);
|
||||
m_items[i]->FSetState(ITEM_NEW);
|
||||
}
|
||||
|
||||
@@ -17988,8 +18103,15 @@ void Player::_SaveMail(SQLTransaction& trans)
|
||||
else if (m->state == MAIL_STATE_DELETED)
|
||||
{
|
||||
if (m->HasItems())
|
||||
{
|
||||
PreparedStatement* stmt = NULL;
|
||||
for (std::vector<MailItemInfo>::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
|
||||
trans->PAppend("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid);
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||
stmt->setUInt32(0, itr2->item_guid);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
}
|
||||
trans->PAppend("DELETE FROM mail WHERE id = '%u'", m->messageID);
|
||||
trans->PAppend("DELETE FROM mail_items WHERE mail_id = '%u'", m->messageID);
|
||||
}
|
||||
@@ -22721,7 +22843,8 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot)
|
||||
uint8 msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
{
|
||||
Item * newitem = StoreNewItem(dest, item->itemid, true, item->randomPropertyId);
|
||||
AllowedLooterSet* looters = item->GetAllowedLooters();
|
||||
Item * newitem = StoreNewItem(dest, item->itemid, true, item->randomPropertyId, (looters->size() > 1) ? looters : NULL);
|
||||
|
||||
if (qitem)
|
||||
{
|
||||
|
||||
@@ -1187,7 +1187,7 @@ class Player : public Unit, public GridObject<Player>
|
||||
bool HasItemTotemCategory(uint32 TotemCategory) const;
|
||||
uint8 CanUseItem(ItemPrototype const *pItem) const;
|
||||
uint8 CanUseAmmo(uint32 item) const;
|
||||
Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update,int32 randomPropertyId = 0);
|
||||
Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update, int32 randomPropertyId = 0, AllowedLooterSet* allowedLooters = NULL);
|
||||
Item* StoreItem(ItemPosCountVec const& pos, Item *pItem, bool update);
|
||||
Item* EquipNewItem(uint16 pos, uint32 item, bool update);
|
||||
Item* EquipItem(uint16 pos, Item *pItem, bool update);
|
||||
@@ -1261,13 +1261,15 @@ class Player : public Unit, public GridObject<Player>
|
||||
void TradeCancel(bool sendback);
|
||||
|
||||
void UpdateEnchantTime(uint32 time);
|
||||
void UpdateItemDuration(uint32 time, bool realtimeonly=false);
|
||||
void UpdateSoulboundTradeItems();
|
||||
void RemoveTradeableItem(uint32 guid);
|
||||
void UpdateItemDuration(uint32 time, bool realtimeonly = false);
|
||||
void AddEnchantmentDurations(Item *item);
|
||||
void RemoveEnchantmentDurations(Item *item);
|
||||
void RemoveArenaEnchantments(EnchantmentSlot slot);
|
||||
void AddEnchantmentDuration(Item *item,EnchantmentSlot slot,uint32 duration);
|
||||
void ApplyEnchantment(Item *item,EnchantmentSlot slot,bool apply, bool apply_dur = true, bool ignore_condition = false);
|
||||
void ApplyEnchantment(Item *item,bool apply);
|
||||
void AddEnchantmentDuration(Item *item, EnchantmentSlot slot, uint32 duration);
|
||||
void ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool apply_dur = true, bool ignore_condition = false);
|
||||
void ApplyEnchantment(Item *item, bool apply);
|
||||
void UpdateSkillEnchantments(uint16 skill_id, uint16 curr_value, uint16 new_value);
|
||||
void SendEnchantmentDurations();
|
||||
void BuildEnchantmentsInfoData(WorldPacket *data);
|
||||
@@ -2535,6 +2537,7 @@ class Player : public Unit, public GridObject<Player>
|
||||
|
||||
EnchantDurationList m_enchantDuration;
|
||||
ItemDurationList m_itemDuration;
|
||||
ItemDurationList m_itemSoulboundTradeable;
|
||||
|
||||
void ResetTimeSync();
|
||||
void SendTimeSync();
|
||||
|
||||
Reference in New Issue
Block a user