Merge pull request #8662 from MrSmite/ItemContainer_1.1

Item Loot Saving
This commit is contained in:
Subv committed 2012-12-20 07:00:29 -08:00
commit 957571e18c
10 files changed
+398 -5

No files matched your search

+35
View File
@@ -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 */;
+196
View File
@@ -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();
}
+9
View File
@@ -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);
+20 -1
View File
@@ -8850,7 +8850,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();
@@ -8869,6 +8871,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;
}
}
@@ -12621,6 +12629,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();
@@ -24062,6 +24076,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);
+14 -2
View File
@@ -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
+41
View File
@@ -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
{
+14 -2
View File
@@ -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
};