Implements saving of loot (items / money) contained inside lootable inventory items.
* Unlooted items / money persist across player sessions
* Loot inside items is tied to the item rather than the player so if trading
partially looted items becomes possible, this implementation will still work
* New tables added:
characters_database.sql (first time users)
characters_create_item_loot.sql (existing users)
Implementation Can be tested with:
Watertight Trunk [21113]
Bulging Sack of Gems [25422]
Fat Sack of Coins [11937]
Closes #2048
This commit is contained in:
1 parent
1f869ce3a5
commit
04f08d26a7
10 files changed
+398
-5
No files matched your search
@@ -1954,6 +1954,41 @@ LOCK TABLES `item_instance` WRITE;
|
||||
/*!40000 ALTER TABLE `item_instance` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `item_loot_items`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `item_loot_items`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `item_loot_items` (
|
||||
`container_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'guid of container (item_instance.guid)',
|
||||
`item_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'loot item entry (item_instance.itemEntry)',
|
||||
`item_count` int(10) NOT NULL DEFAULT '0' COMMENT 'stack size',
|
||||
`follow_rules` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'follow loot rules',
|
||||
`ffa` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'free-for-all',
|
||||
`blocked` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`counted` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`under_threshold` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`needs_quest` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'quest drop',
|
||||
`rnd_prop` int(10) NOT NULL DEFAULT '0' COMMENT 'random enchantment added when originally rolled',
|
||||
`rnd_suffix` int(10) NOT NULL DEFAULT '0' COMMENT 'random suffix added when originally rolled'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `item_loot_money`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `item_loot_money`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `item_loot_money` (
|
||||
`container_id` int(10) NOT NULL DEFAULT '0' COMMENT 'guid of container (item_instance.guid)',
|
||||
`money` int(10) NOT NULL DEFAULT '0' COMMENT 'money loot (in copper)'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `item_refund_instance`
|
||||
--
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
SQLyog Ultimate v9.63
|
||||
MySQL - 5.5.21 : Database - characters
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
/*!40101 SET NAMES utf8 */;
|
||||
|
||||
/*!40101 SET SQL_MODE=''*/;
|
||||
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `item_loot_items`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `item_loot_items`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `item_loot_items` (
|
||||
`container_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'guid of container (item_instance.guid)',
|
||||
`item_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'loot item entry (item_instance.itemEntry)',
|
||||
`item_count` int(10) NOT NULL DEFAULT '0' COMMENT 'stack size',
|
||||
`follow_rules` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'follow loot rules',
|
||||
`ffa` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'free-for-all',
|
||||
`blocked` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`counted` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`under_threshold` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`needs_quest` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'quest drop',
|
||||
`rnd_prop` int(10) NOT NULL DEFAULT '0' COMMENT 'random enchantment added when originally rolled',
|
||||
`rnd_suffix` int(10) NOT NULL DEFAULT '0' COMMENT 'random suffix added when originally rolled'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `item_loot_money`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `item_loot_money`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `item_loot_money` (
|
||||
`container_id` int(10) NOT NULL DEFAULT '0' COMMENT 'guid of container (item_instance.guid)',
|
||||
`money` int(10) NOT NULL DEFAULT '0' COMMENT 'money loot (in copper)'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
@@ -378,6 +378,10 @@ void Item::SaveToDB(SQLTransaction& trans)
|
||||
if (!isInTransaction)
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
// Delete the items if this is a container
|
||||
if (!loot.isLooted())
|
||||
ItemContainerDeleteLootMoneyAndLootItemsFromDB();
|
||||
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
@@ -483,6 +487,10 @@ void Item::DeleteFromDB(SQLTransaction& trans, uint32 itemGuid)
|
||||
void Item::DeleteFromDB(SQLTransaction& trans)
|
||||
{
|
||||
DeleteFromDB(trans, GetGUIDLow());
|
||||
|
||||
// Delete the items if this is a container
|
||||
if (!loot.isLooted())
|
||||
ItemContainerDeleteLootMoneyAndLootItemsFromDB();
|
||||
}
|
||||
|
||||
/*static*/
|
||||
@@ -1198,3 +1206,191 @@ bool Item::CheckSoulboundTradeExpire()
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Item::ItemContainerSaveLootToDB()
|
||||
{
|
||||
// Saves the money and item loot associated with an openable item to the DB
|
||||
|
||||
if (loot.isLooted()) // no money and no loot
|
||||
return;
|
||||
|
||||
uint32 container_id = GetGUIDLow();
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
loot.containerID = container_id; // Save this for when a LootItem is removed
|
||||
|
||||
// Save money
|
||||
if (loot.gold > 0)
|
||||
{
|
||||
PreparedStatement* stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
|
||||
stmt_money->setUInt32(0, container_id);
|
||||
trans->Append(stmt_money);
|
||||
|
||||
stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_MONEY);
|
||||
stmt_money->setUInt32(0, container_id);
|
||||
stmt_money->setUInt32(1, loot.gold);
|
||||
trans->Append(stmt_money);
|
||||
}
|
||||
|
||||
// Save items
|
||||
if (!loot.isLooted())
|
||||
{
|
||||
|
||||
PreparedStatement* stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
|
||||
stmt_items->setUInt32(0, container_id);
|
||||
trans->Append(stmt_items);
|
||||
|
||||
// Now insert the items
|
||||
for (LootItemList::const_iterator _li = loot.items.begin(); _li != loot.items.end(); _li++)
|
||||
{
|
||||
// When an item is looted, it doesn't get removed from the items collection
|
||||
// but we don't want to resave it.
|
||||
if (!_li->canSave)
|
||||
continue;
|
||||
|
||||
stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_ITEMS);
|
||||
|
||||
// container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix
|
||||
stmt_items->setUInt32(0, container_id);
|
||||
stmt_items->setUInt32(1, _li->itemid);
|
||||
stmt_items->setUInt32(2, _li->count);
|
||||
stmt_items->setBool(3, _li->follow_loot_rules);
|
||||
stmt_items->setBool(4, _li->freeforall);
|
||||
stmt_items->setBool(5, _li->is_blocked);
|
||||
stmt_items->setBool(6, _li->is_counted);
|
||||
stmt_items->setBool(7, _li->is_underthreshold);
|
||||
stmt_items->setBool(8, _li->needs_quest);
|
||||
stmt_items->setUInt32(9, _li->randomPropertyId);
|
||||
stmt_items->setUInt32(10, _li->randomSuffix);
|
||||
trans->Append(stmt_items);
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
bool Item::ItemContainerLoadLootFromDB()
|
||||
{
|
||||
// Loads the money and item loot associated with an openable item from the DB
|
||||
|
||||
// Default. If there are no records for this item then it will be rolled for in Player::SendLoot()
|
||||
m_lootGenerated = false;
|
||||
|
||||
uint32 container_id = GetGUIDLow();
|
||||
|
||||
// Save this for later use
|
||||
loot.containerID = container_id;
|
||||
|
||||
// First, see if there was any money loot. This gets added directly to the container.
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt32(0, container_id);
|
||||
PreparedQueryResult money_result = CharacterDatabase.Query(stmt);
|
||||
|
||||
if (money_result)
|
||||
{
|
||||
Field* fields = money_result->Fetch();
|
||||
loot.gold = fields[0].GetUInt32();
|
||||
}
|
||||
|
||||
// Next, load any items that were saved
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_ITEMS);
|
||||
stmt->setUInt32(0, container_id);
|
||||
PreparedQueryResult item_result = CharacterDatabase.Query(stmt);
|
||||
|
||||
if (item_result)
|
||||
{
|
||||
// Get a LootTemplate for the container item. This is where
|
||||
// the saved loot was originally rolled from, we will copy conditions from it
|
||||
LootTemplate const* lt = LootTemplates_Item.GetLootFor(GetEntry());
|
||||
|
||||
if (lt)
|
||||
{
|
||||
do
|
||||
{
|
||||
// Create an empty LootItem
|
||||
LootItem loot_item = LootItem();
|
||||
|
||||
// Fill in the rest of the LootItem from the DB
|
||||
Field* fields = item_result->Fetch();
|
||||
|
||||
// item_id, itm_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix
|
||||
loot_item.itemid = fields[0].GetUInt32();
|
||||
loot_item.count = fields[1].GetUInt32();
|
||||
loot_item.follow_loot_rules = fields[2].GetBool();
|
||||
loot_item.freeforall = fields[3].GetBool();
|
||||
loot_item.is_blocked = fields[4].GetBool();
|
||||
loot_item.is_counted = fields[5].GetBool();
|
||||
loot_item.canSave = true;
|
||||
loot_item.is_underthreshold = fields[6].GetBool();
|
||||
loot_item.needs_quest = fields[7].GetBool();
|
||||
loot_item.randomPropertyId = fields[8].GetUInt32();
|
||||
loot_item.randomSuffix = fields[9].GetUInt32();
|
||||
|
||||
// Copy the extra loot conditions from the item in the loot template
|
||||
lt->CopyConditions(&loot_item);
|
||||
|
||||
// If container item is in a bag, add that player as an allowed looter
|
||||
if (GetBagSlot())
|
||||
loot_item.allowedGUIDs.insert(GetOwner()->GetGUIDLow());
|
||||
|
||||
// Finally add the LootItem to the container
|
||||
loot.items.push_back(loot_item);
|
||||
|
||||
// Increment unlooted count
|
||||
loot.unlootedCount++;
|
||||
|
||||
} while (item_result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the item if it has loot so it won't be generated again on open
|
||||
m_lootGenerated = !loot.isLooted();
|
||||
|
||||
return m_lootGenerated;
|
||||
}
|
||||
|
||||
void Item::ItemContainerDeleteLootItemsFromDB()
|
||||
{
|
||||
// Deletes items associated with an openable item from the DB
|
||||
|
||||
uint32 containerId = GetGUIDLow();
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
|
||||
stmt->setUInt32(0, containerId);
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
trans->Append(stmt);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void Item::ItemContainerDeleteLootItemFromDB(uint32 itemID)
|
||||
{
|
||||
// Deletes a single item associated with an openable item from the DB
|
||||
|
||||
uint32 containerId = GetGUIDLow();
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
|
||||
stmt->setUInt32(0, containerId);
|
||||
stmt->setUInt32(1, itemID);
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
trans->Append(stmt);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void Item::ItemContainerDeleteLootMoneyFromDB()
|
||||
{
|
||||
// Deletes the money loot associated with an openable item from the DB
|
||||
|
||||
uint32 containerId = GetGUIDLow();
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt32(0, containerId);
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
trans->Append(stmt);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void Item::ItemContainerDeleteLootMoneyAndLootItemsFromDB()
|
||||
{
|
||||
// Deletes money and items associated with an openable item from the DB
|
||||
|
||||
ItemContainerDeleteLootMoneyFromDB();
|
||||
ItemContainerDeleteLootItemsFromDB();
|
||||
}
|
||||
|
||||
@@ -231,6 +231,15 @@ class Item : public Object
|
||||
static void DeleteFromDB(SQLTransaction& trans, uint32 itemGuid);
|
||||
virtual void DeleteFromDB(SQLTransaction& trans);
|
||||
static void DeleteFromInventoryDB(SQLTransaction& trans, uint32 itemGuid);
|
||||
|
||||
// Lootable items and their contents
|
||||
void ItemContainerSaveLootToDB();
|
||||
bool ItemContainerLoadLootFromDB();
|
||||
void ItemContainerDeleteLootItemsFromDB();
|
||||
void ItemContainerDeleteLootItemFromDB(uint32 itemID);
|
||||
void ItemContainerDeleteLootMoneyFromDB();
|
||||
void ItemContainerDeleteLootMoneyAndLootItemsFromDB();
|
||||
|
||||
void DeleteFromInventoryDB(SQLTransaction& trans);
|
||||
void SaveRefundDataToDB();
|
||||
void DeleteRefundDataFromDB(SQLTransaction* trans);
|
||||
|
||||
@@ -8903,7 +8903,9 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
|
||||
|
||||
loot = &item->loot;
|
||||
|
||||
if (!item->m_lootGenerated)
|
||||
// If item doesn't already have loot, attempt to load it. If that
|
||||
// fails then this is first time opening, generate loot
|
||||
if (!item->m_lootGenerated && !item->ItemContainerLoadLootFromDB())
|
||||
{
|
||||
item->m_lootGenerated = true;
|
||||
loot->clear();
|
||||
@@ -8922,6 +8924,12 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
|
||||
default:
|
||||
loot->generateMoneyLoot(item->GetTemplate()->MinMoneyLoot, item->GetTemplate()->MaxMoneyLoot);
|
||||
loot->FillLoot(item->GetEntry(), LootTemplates_Item, this, true, loot->gold != 0);
|
||||
|
||||
// Force save the loot and money items that were just rolled
|
||||
// Also saves the container item ID in Loot struct (not to DB)
|
||||
if (loot->gold > 0 || loot->unlootedCount > 0)
|
||||
item->ItemContainerSaveLootToDB();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -12675,6 +12683,12 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
|
||||
else if (Bag* pBag = GetBagByPos(bag))
|
||||
pBag->RemoveItem(slot, update);
|
||||
|
||||
// Delete rolled money / loot from db.
|
||||
// MUST be done before RemoveFromWorld() or GetTemplate() fails
|
||||
if (ItemTemplate const* pTmp = pItem->GetTemplate())
|
||||
if (pTmp->Flags & ITEM_PROTO_FLAG_OPENABLE)
|
||||
pItem->ItemContainerDeleteLootMoneyAndLootItemsFromDB();
|
||||
|
||||
if (IsInWorld() && update)
|
||||
{
|
||||
pItem->RemoveFromWorld();
|
||||
@@ -24055,6 +24069,11 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot)
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count);
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count);
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count);
|
||||
|
||||
// LootItem is being removed (looted) from the container, delete it from the DB.
|
||||
if (loot->containerID > 0)
|
||||
loot->DeleteLootItemFromContainerItemDB(item->itemid);
|
||||
|
||||
}
|
||||
else
|
||||
SendEquipError(msg, NULL, NULL, item->itemid);
|
||||
|
||||
@@ -93,6 +93,10 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
player->StoreLootItem(lootSlot, loot);
|
||||
|
||||
// If player is removing the last LootItem, delete the empty container.
|
||||
if (loot->isLooted() && IS_ITEM_GUID(lguid))
|
||||
player->GetSession()->DoLootRelease(lguid);
|
||||
}
|
||||
|
||||
void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recvData*/)
|
||||
@@ -200,6 +204,14 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recvData*/)
|
||||
}
|
||||
|
||||
loot->gold = 0;
|
||||
|
||||
// Delete the money loot record from the DB
|
||||
if (loot->containerID > 0)
|
||||
loot->DeleteLootMoneyFromContainerItemDB();
|
||||
|
||||
// Delete container if empty
|
||||
if (loot->isLooted() && IS_ITEM_GUID(guid))
|
||||
player->GetSession()->DoLootRelease(guid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,8 +393,8 @@ void WorldSession::DoLootRelease(uint64 lguid)
|
||||
player->DestroyItemCount(pItem, count, true);
|
||||
}
|
||||
else
|
||||
// FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible.
|
||||
player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
|
||||
if (pItem->loot.isLooted()) // Only delete item if no loot or money (unlooted loot is saved to db)
|
||||
player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
|
||||
return; // item can be looted only single player
|
||||
}
|
||||
else
|
||||
|
||||
@@ -334,6 +334,7 @@ LootItem::LootItem(LootStoreItem const& li)
|
||||
is_blocked = 0;
|
||||
is_underthreshold = 0;
|
||||
is_counted = 0;
|
||||
canSave = true;
|
||||
}
|
||||
|
||||
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
|
||||
@@ -654,6 +655,33 @@ void Loot::generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
|
||||
}
|
||||
}
|
||||
|
||||
void Loot::DeleteLootItemFromContainerItemDB(uint32 itemID)
|
||||
{
|
||||
// Deletes a single item associated with an openable item from the DB
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
|
||||
stmt->setUInt32(0, containerID);
|
||||
stmt->setUInt32(1, itemID);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
// Mark the item looted to prevent resaving
|
||||
for (LootItemList::iterator _itr = items.begin(); _itr != items.end(); _itr++)
|
||||
{
|
||||
if (!_itr->itemid == itemID)
|
||||
continue;
|
||||
|
||||
_itr->canSave = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Loot::DeleteLootMoneyFromContainerItemDB()
|
||||
{
|
||||
// Deletes money loot associated with an openable item from the DB
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt32(0, containerID);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qitem, QuestItem* *ffaitem, QuestItem* *conditem)
|
||||
{
|
||||
LootItem* item = NULL;
|
||||
@@ -1239,6 +1267,19 @@ void LootTemplate::CopyConditions(ConditionList conditions)
|
||||
i->CopyConditions(conditions);
|
||||
}
|
||||
|
||||
void LootTemplate::CopyConditions(LootItem* li) const
|
||||
{
|
||||
// Copies the conditions list from a template item to a LootItem
|
||||
for (LootStoreItemList::const_iterator _iter = Entries.begin(); _iter != Entries.end(); ++_iter)
|
||||
{
|
||||
if (!_iter->itemid == li->itemid)
|
||||
continue;
|
||||
|
||||
li->conditions = _iter->conditions;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Rolls for every item in the template and adds the rolled items the the loot
|
||||
void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId) const
|
||||
{
|
||||
|
||||
@@ -141,14 +141,17 @@ struct LootItem
|
||||
bool is_counted : 1;
|
||||
bool needs_quest : 1; // quest drop
|
||||
bool follow_loot_rules : 1;
|
||||
bool canSave;
|
||||
|
||||
// Constructor, copies most fields from LootStoreItem, generates random count and random suffixes/properties
|
||||
// Should be called for non-reference LootStoreItem entries only (mincountOrRef > 0)
|
||||
explicit LootItem(LootStoreItem const& li);
|
||||
|
||||
// Empty constructor for creating an empty LootItem to be filled in with DB data
|
||||
LootItem() : canSave(true){};
|
||||
|
||||
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
|
||||
bool AllowedForPlayer(Player const* player) const;
|
||||
|
||||
void AddAllowedLooter(Player const* player);
|
||||
const AllowedLooterSet & GetAllowedLooters() const { return allowedGUIDs; }
|
||||
};
|
||||
@@ -223,6 +226,7 @@ class LootTemplate
|
||||
// Rolls for every item in the template and adds the rolled items the the loot
|
||||
void Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId = 0) const;
|
||||
void CopyConditions(ConditionList conditions);
|
||||
void CopyConditions(LootItem* li) const;
|
||||
|
||||
// True if template includes at least 1 quest drop entry
|
||||
bool HasQuestDrop(LootTemplateMap const& store, uint8 groupId = 0) const;
|
||||
@@ -286,10 +290,18 @@ struct Loot
|
||||
uint8 unlootedCount;
|
||||
uint64 roundRobinPlayer; // GUID of the player having the Round-Robin ownership for the loot. If 0, round robin owner has released.
|
||||
LootType loot_type; // required for achievement system
|
||||
|
||||
// GUIDLow of container that holds this loot (item_instance.entry)
|
||||
// Only set for inventory items that can be right-click looted
|
||||
uint32 containerID;
|
||||
|
||||
Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), loot_type(LOOT_CORPSE) {}
|
||||
Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), loot_type(LOOT_CORPSE), containerID(0) {}
|
||||
~Loot() { clear(); }
|
||||
|
||||
// For deleting items at loot removal since there is no backward interface to the Item()
|
||||
void DeleteLootItemFromContainerItemDB(uint32 itemID);
|
||||
void DeleteLootMoneyFromContainerItemDB();
|
||||
|
||||
// if loot becomes invalid this reference is used to inform the listener
|
||||
void addLootValidatorRef(LootValidatorRef* pLootValidatorRef)
|
||||
{
|
||||
|
||||
@@ -540,6 +540,15 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PREPARE_STATEMENT(CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC, "DELETE FROM character_action WHERE spec<>? AND guid = ?", CONNECTION_ASYNC);
|
||||
PREPARE_STATEMENT(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND slot = ?", CONNECTION_SYNCH);
|
||||
|
||||
// Items that hold loot or money
|
||||
PREPARE_STATEMENT(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix FROM item_loot_items WHERE container_id = ?", CONNECTION_SYNCH);
|
||||
PREPARE_STATEMENT(CHAR_DEL_ITEMCONTAINER_ITEMS, "DELETE FROM item_loot_items WHERE container_id = ?", CONNECTION_ASYNC);
|
||||
PREPARE_STATEMENT(CHAR_DEL_ITEMCONTAINER_ITEM, "DELETE FROM item_loot_items WHERE container_id = ? AND item_id = ?", CONNECTION_ASYNC);
|
||||
PREPARE_STATEMENT(CHAR_INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix) VALUES (?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC);
|
||||
PREPARE_STATEMENT(CHAR_SEL_ITEMCONTAINER_MONEY, "SELECT money FROM item_loot_money WHERE container_id = ?", CONNECTION_SYNCH);
|
||||
PREPARE_STATEMENT(CHAR_DEL_ITEMCONTAINER_MONEY, "DELETE FROM item_loot_money WHERE container_id = ?", CONNECTION_ASYNC);
|
||||
PREPARE_STATEMENT(CHAR_INS_ITEMCONTAINER_MONEY," INSERT INTO item_loot_money (container_id, money) VALUES (?,?)", CONNECTION_ASYNC);
|
||||
|
||||
// Calendar
|
||||
PREPARE_STATEMENT(CHAR_REP_CALENDAR_EVENT, "REPLACE INTO calendar_events (id, creator, title, description, type, dungeon, eventtime, flags, time2) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PREPARE_STATEMENT(CHAR_DEL_CALENDAR_EVENT, "DELETE FROM calendar_events WHERE id = ?", CONNECTION_ASYNC);
|
||||
|
||||
@@ -505,6 +505,14 @@ enum CharacterDatabaseStatements
|
||||
CHAR_REP_CALENDAR_INVITE,
|
||||
CHAR_DEL_CALENDAR_INVITE,
|
||||
|
||||
CHAR_SEL_ITEMCONTAINER_ITEMS,
|
||||
CHAR_DEL_ITEMCONTAINER_ITEMS,
|
||||
CHAR_DEL_ITEMCONTAINER_ITEM,
|
||||
CHAR_INS_ITEMCONTAINER_ITEMS,
|
||||
CHAR_SEL_ITEMCONTAINER_MONEY,
|
||||
CHAR_DEL_ITEMCONTAINER_MONEY,
|
||||
CHAR_INS_ITEMCONTAINER_MONEY,
|
||||
|
||||
MAX_CHARACTERDATABASE_STATEMENTS
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user