fix(Core/Loot): properly save and load from DB loot from items (#6151)
- Closes #5472 - Closes https://github.com/chromiecraft/chromiecraft/issues/456
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
INSERT INTO `version_db_characters` (`sql_rev`) VALUES ('1622403654219554600');
|
||||||
|
|
||||||
|
ALTER TABLE `item_loot_storage`
|
||||||
|
ADD COLUMN `follow_loot_rules` TINYINT UNSIGNED NOT NULL AFTER `randomSuffix`,
|
||||||
|
ADD COLUMN `freeforall` TINYINT UNSIGNED NOT NULL AFTER `follow_loot_rules`,
|
||||||
|
ADD COLUMN `is_blocked` TINYINT UNSIGNED NOT NULL AFTER `freeforall`,
|
||||||
|
ADD COLUMN `is_counted` TINYINT UNSIGNED NOT NULL AFTER `is_blocked`,
|
||||||
|
ADD COLUMN `is_underthreshold` TINYINT UNSIGNED NOT NULL AFTER `is_counted`,
|
||||||
|
ADD COLUMN `needs_quest` TINYINT UNSIGNED NOT NULL AFTER `is_underthreshold`;
|
||||||
@@ -509,9 +509,9 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
|||||||
PrepareStatement(CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC, "DELETE FROM character_action WHERE spec<>? AND guid = ?", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC, "DELETE FROM character_action WHERE spec<>? AND guid = ?", CONNECTION_ASYNC);
|
||||||
|
|
||||||
// Items that hold loot or money
|
// Items that hold loot or money
|
||||||
PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT containerGUID, itemid, count, randomPropertyId, randomSuffix FROM item_loot_storage", CONNECTION_SYNCH);
|
PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT containerGUID, itemid, count, randomPropertyId, randomSuffix, follow_loot_rules, freeforall, is_blocked, is_counted, is_underthreshold, needs_quest FROM item_loot_storage", CONNECTION_SYNCH);
|
||||||
PrepareStatement(CHAR_DEL_ITEMCONTAINER_SINGLE_ITEM, "DELETE FROM item_loot_storage WHERE containerGUID = ? AND itemid = ? AND count = ? LIMIT 1", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_DEL_ITEMCONTAINER_SINGLE_ITEM, "DELETE FROM item_loot_storage WHERE containerGUID = ? AND itemid = ? AND count = ? LIMIT 1", CONNECTION_ASYNC);
|
||||||
PrepareStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM, "INSERT INTO item_loot_storage (containerGUID, itemid, count, randomPropertyId, randomSuffix) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM, "INSERT INTO item_loot_storage (containerGUID, itemid, count, randomPropertyId, randomSuffix, follow_loot_rules, freeforall, is_blocked, is_counted, is_underthreshold, needs_quest) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||||
PrepareStatement(CHAR_DEL_ITEMCONTAINER_CONTAINER, "DELETE FROM item_loot_storage WHERE containerGUID = ?", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_DEL_ITEMCONTAINER_CONTAINER, "DELETE FROM item_loot_storage WHERE containerGUID = ?", CONNECTION_ASYNC);
|
||||||
|
|
||||||
// Calendar
|
// Calendar
|
||||||
|
|||||||
@@ -9379,7 +9379,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
|||||||
// Xinef: Store container id
|
// Xinef: Store container id
|
||||||
loot->containerGUID = item->GetGUID();
|
loot->containerGUID = item->GetGUID();
|
||||||
|
|
||||||
if (!item->m_lootGenerated && !sLootItemStorage->LoadStoredLoot(item))
|
if (!item->m_lootGenerated && !sLootItemStorage->LoadStoredLoot(item, this))
|
||||||
{
|
{
|
||||||
item->m_lootGenerated = true;
|
item->m_lootGenerated = true;
|
||||||
loot->clear();
|
loot->clear();
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ void LootItemStorage::LoadStorageFromDB()
|
|||||||
Field* fields = result->Fetch();
|
Field* fields = result->Fetch();
|
||||||
|
|
||||||
StoredLootItemList& itemList = lootItemStore[ObjectGuid::Create<HighGuid::Item>(fields[0].GetUInt32())];
|
StoredLootItemList& itemList = lootItemStore[ObjectGuid::Create<HighGuid::Item>(fields[0].GetUInt32())];
|
||||||
itemList.push_back(StoredLootItem(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[3].GetInt32(), fields[4].GetUInt32()));
|
itemList.push_back(StoredLootItem(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[3].GetInt32(), fields[4].GetUInt32(), fields[5].GetBool(),
|
||||||
|
fields[6].GetBool(), fields[7].GetBool(), fields[8].GetBool(), fields[9].GetBool(), fields[10].GetBool()));
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
} while (result->NextRow());
|
} while (result->NextRow());
|
||||||
@@ -79,14 +80,21 @@ void LootItemStorage::AddNewStoredLoot(Loot* loot, Player* /*player*/)
|
|||||||
// Gold at first
|
// Gold at first
|
||||||
if (loot->gold)
|
if (loot->gold)
|
||||||
{
|
{
|
||||||
itemList.push_back(StoredLootItem(0, loot->gold, 0, 0));
|
itemList.push_back(StoredLootItem(0, loot->gold, 0, 0, false, false, false, false, false, false));
|
||||||
|
|
||||||
|
uint8 index = 0;
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM);
|
||||||
stmt->setUInt32(0, loot->containerGUID.GetCounter());
|
stmt->setUInt32(index++, loot->containerGUID.GetCounter());
|
||||||
stmt->setUInt32(1, 0);
|
stmt->setUInt32(index++, 0);
|
||||||
stmt->setUInt32(2, loot->gold);
|
stmt->setUInt32(index++, loot->gold);
|
||||||
stmt->setInt32(3, 0);
|
stmt->setInt32(index++, 0);
|
||||||
stmt->setUInt32(4, 0);
|
stmt->setUInt32(index++, 0);
|
||||||
|
stmt->setBool(index++, false);
|
||||||
|
stmt->setBool(index++, false);
|
||||||
|
stmt->setBool(index++, false);
|
||||||
|
stmt->setBool(index++, false);
|
||||||
|
stmt->setBool(index++, false);
|
||||||
|
stmt->setBool(index++, false);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,22 +112,36 @@ void LootItemStorage::AddNewStoredLoot(Loot* loot, Player* /*player*/)
|
|||||||
if (!itemTemplate || itemTemplate->IsCurrencyToken())
|
if (!itemTemplate || itemTemplate->IsCurrencyToken())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
itemList.push_back(StoredLootItem(li->itemid, li->count, li->randomPropertyId, li->randomSuffix));
|
itemList.push_back(StoredLootItem(li->itemid, li->count, li->randomPropertyId, li->randomSuffix, li->follow_loot_rules, li->freeforall, li->is_blocked, li->is_counted,
|
||||||
|
li->is_underthreshold, li->needs_quest));
|
||||||
|
|
||||||
|
uint8 index = 0;
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM);
|
||||||
stmt->setUInt32(0, loot->containerGUID.GetCounter());
|
stmt->setUInt32(index++, loot->containerGUID.GetCounter());
|
||||||
stmt->setUInt32(1, li->itemid);
|
stmt->setUInt32(index++, li->itemid);
|
||||||
stmt->setUInt32(2, li->count);
|
stmt->setUInt32(index++, li->count);
|
||||||
stmt->setInt32 (3, li->randomPropertyId);
|
stmt->setInt32 (index++, li->randomPropertyId);
|
||||||
stmt->setUInt32(4, li->randomSuffix);
|
stmt->setUInt32(index++, li->randomSuffix);
|
||||||
|
stmt->setBool(index++, li->follow_loot_rules);
|
||||||
|
stmt->setBool(index++, li->freeforall);
|
||||||
|
stmt->setBool(index++, li->is_blocked);
|
||||||
|
stmt->setBool(index++, li->is_counted);
|
||||||
|
stmt->setBool(index++, li->is_underthreshold);
|
||||||
|
stmt->setBool(index++, li->needs_quest);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterDatabase.CommitTransaction(trans);
|
CharacterDatabase.CommitTransaction(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LootItemStorage::LoadStoredLoot(Item* item)
|
bool LootItemStorage::LoadStoredLoot(Item* item, Player* player)
|
||||||
{
|
{
|
||||||
|
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item->GetEntry());
|
||||||
|
if (!proto)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Loot* loot = &item->loot;
|
Loot* loot = &item->loot;
|
||||||
LootItemContainer::iterator itr = lootItemStore.find(loot->containerGUID);
|
LootItemContainer::iterator itr = lootItemStore.find(loot->containerGUID);
|
||||||
if (itr == lootItemStore.end())
|
if (itr == lootItemStore.end())
|
||||||
@@ -134,22 +156,47 @@ bool LootItemStorage::LoadStoredLoot(Item* item)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LootItem li;
|
if (LootTemplate const* lt = LootTemplates_Item.GetLootFor(item->GetEntry()))
|
||||||
li.itemid = it2->itemid;
|
{
|
||||||
li.count = it2->count;
|
LootItem li;
|
||||||
li.follow_loot_rules = false;
|
li.itemid = it2->itemid;
|
||||||
li.freeforall = false;
|
li.count = it2->count;
|
||||||
li.is_blocked = false;
|
li.follow_loot_rules = it2->follow_loot_rules;
|
||||||
li.is_counted = false;
|
li.freeforall = it2->freeforall;
|
||||||
li.is_underthreshold = false;
|
li.is_blocked = it2->is_blocked;
|
||||||
li.is_looted = false;
|
li.is_counted = it2->is_counted;
|
||||||
li.needs_quest = false;
|
li.is_underthreshold = it2->is_underthreshold;
|
||||||
li.randomPropertyId = it2->randomPropertyId;
|
li.is_looted = false;
|
||||||
li.randomSuffix = it2->randomSuffix;
|
li.needs_quest = it2->needs_quest;
|
||||||
li.rollWinnerGUID = ObjectGuid::Empty;
|
li.randomPropertyId = it2->randomPropertyId;
|
||||||
|
li.randomSuffix = it2->randomSuffix;
|
||||||
|
li.rollWinnerGUID = ObjectGuid::Empty;
|
||||||
|
|
||||||
loot->items.push_back(li);
|
// Copy the extra loot conditions from the item in the loot template
|
||||||
loot->unlootedCount++;
|
lt->CopyConditions(&li);
|
||||||
|
|
||||||
|
if (li.needs_quest)
|
||||||
|
{
|
||||||
|
loot->quest_items.push_back(li);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loot->items.push_back(li);
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-conditional one-player only items are counted here,
|
||||||
|
// free for all items are counted in FillFFALoot(),
|
||||||
|
// non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
|
||||||
|
if ((!li.needs_quest && li.conditions.empty() && !(proto->Flags & ITEM_FLAG_MULTI_DROP)) || li.is_counted)
|
||||||
|
{
|
||||||
|
++loot->unlootedCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loot->unlootedCount)
|
||||||
|
{
|
||||||
|
loot->FillNotNormalLootFor(player, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the item if it has loot so it won't be generated again on open
|
// Mark the item if it has loot so it won't be generated again on open
|
||||||
|
|||||||
@@ -13,14 +13,21 @@ Xinef
|
|||||||
|
|
||||||
struct StoredLootItem
|
struct StoredLootItem
|
||||||
{
|
{
|
||||||
StoredLootItem(uint32 i, uint32 c, int32 ri, uint32 rs) :
|
StoredLootItem(uint32 i, uint32 c, int32 ri, uint32 rs, bool follow_loot_rules, bool freeforall, bool is_blocked, bool is_counted, bool is_underthreshold, bool needs_quest) :
|
||||||
itemid(i), count(c), randomPropertyId(ri), randomSuffix(rs) { }
|
itemid(i), count(c), randomPropertyId(ri), randomSuffix(rs), follow_loot_rules(follow_loot_rules), freeforall(freeforall), is_blocked(is_blocked),
|
||||||
|
is_counted(is_counted), is_underthreshold(is_underthreshold), needs_quest(needs_quest) { }
|
||||||
|
|
||||||
// If itemid == 0 - money amount is stored in count value
|
// If itemid == 0 - money amount is stored in count value
|
||||||
uint32 itemid;
|
uint32 itemid;
|
||||||
uint32 count;
|
uint32 count;
|
||||||
int32 randomPropertyId;
|
int32 randomPropertyId;
|
||||||
uint32 randomSuffix;
|
uint32 randomSuffix;
|
||||||
|
bool follow_loot_rules;
|
||||||
|
bool freeforall;
|
||||||
|
bool is_blocked;
|
||||||
|
bool is_counted;
|
||||||
|
bool is_underthreshold;
|
||||||
|
bool needs_quest;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::list<StoredLootItem> StoredLootItemList;
|
typedef std::list<StoredLootItem> StoredLootItemList;
|
||||||
@@ -39,7 +46,7 @@ public:
|
|||||||
void RemoveEntryFromDB(ObjectGuid containerGUID, uint32 itemid, uint32 count);
|
void RemoveEntryFromDB(ObjectGuid containerGUID, uint32 itemid, uint32 count);
|
||||||
|
|
||||||
void AddNewStoredLoot(Loot* loot, Player* player);
|
void AddNewStoredLoot(Loot* loot, Player* player);
|
||||||
bool LoadStoredLoot(Item* item);
|
bool LoadStoredLoot(Item* item, Player* player);
|
||||||
|
|
||||||
void RemoveStoredLootItem(ObjectGuid containerGUID, uint32 itemid, uint32 count, Loot* loot);
|
void RemoveStoredLootItem(ObjectGuid containerGUID, uint32 itemid, uint32 count, Loot* loot);
|
||||||
void RemoveStoredLootMoney(ObjectGuid containerGUID, Loot* loot);
|
void RemoveStoredLootMoney(ObjectGuid containerGUID, Loot* loot);
|
||||||
|
|||||||
@@ -1375,18 +1375,93 @@ void LootTemplate::CopyConditions(ConditionList conditions)
|
|||||||
group->CopyConditions(conditions);
|
group->CopyConditions(conditions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LootTemplate::CopyConditions(LootItem* li) const
|
bool 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)
|
for (LootStoreItemList::const_iterator _iter = Entries.begin(); _iter != Entries.end(); ++_iter)
|
||||||
{
|
{
|
||||||
LootStoreItem* item = *_iter;
|
LootStoreItem* item = *_iter;
|
||||||
if (item->itemid != li->itemid)
|
if (item->reference)
|
||||||
|
{
|
||||||
|
if (LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(item->reference))
|
||||||
|
{
|
||||||
|
if (Referenced->CopyConditions(li))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (item->itemid != li->itemid)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
li->conditions = item->conditions;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (LootGroups::const_iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr)
|
||||||
|
{
|
||||||
|
LootGroup* group = *groupItr;
|
||||||
|
if (!group)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
li->conditions = item->conditions;
|
LootStoreItemList* itemList = group->GetExplicitlyChancedItemList();
|
||||||
break;
|
for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
|
||||||
|
{
|
||||||
|
LootStoreItem* item = *i;
|
||||||
|
if (item->reference)
|
||||||
|
{
|
||||||
|
if (LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(item->reference))
|
||||||
|
{
|
||||||
|
if (Referenced->CopyConditions(li))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (item->itemid != li->itemid)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
li->conditions = item->conditions;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
itemList = group->GetEqualChancedItemList();
|
||||||
|
for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
|
||||||
|
{
|
||||||
|
LootStoreItem* item = *i;
|
||||||
|
if (item->reference)
|
||||||
|
{
|
||||||
|
if (LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(item->reference))
|
||||||
|
{
|
||||||
|
if (Referenced->CopyConditions(li))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (item->itemid != li->itemid)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
li->conditions = item->conditions;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rolls for every item in the template and adds the rolled items the the loot
|
// Rolls for every item in the template and adds the rolled items the the loot
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ public:
|
|||||||
// Rolls for every item in the template and adds the rolled items the the loot
|
// Rolls for every item in the template and adds the rolled items the the loot
|
||||||
void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0) const;
|
void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0) const;
|
||||||
void CopyConditions(ConditionList conditions);
|
void CopyConditions(ConditionList conditions);
|
||||||
void CopyConditions(LootItem* li) const;
|
bool CopyConditions(LootItem* li) const;
|
||||||
|
|
||||||
// True if template includes at least 1 quest drop entry
|
// True if template includes at least 1 quest drop entry
|
||||||
[[nodiscard]] bool HasQuestDrop(LootTemplateMap const& store, uint8 groupId = 0) const;
|
[[nodiscard]] bool HasQuestDrop(LootTemplateMap const& store, uint8 groupId = 0) const;
|
||||||
@@ -371,9 +371,9 @@ struct Loot
|
|||||||
bool hasItemForAll() const;
|
bool hasItemForAll() const;
|
||||||
bool hasItemFor(Player* player) const;
|
bool hasItemFor(Player* player) const;
|
||||||
[[nodiscard]] bool hasOverThresholdItem() const;
|
[[nodiscard]] bool hasOverThresholdItem() const;
|
||||||
|
void FillNotNormalLootFor(Player* player, bool presentAtLooting);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void FillNotNormalLootFor(Player* player, bool presentAtLooting);
|
|
||||||
QuestItemList* FillFFALoot(Player* player);
|
QuestItemList* FillFFALoot(Player* player);
|
||||||
QuestItemList* FillQuestLoot(Player* player);
|
QuestItemList* FillQuestLoot(Player* player);
|
||||||
QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting);
|
QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting);
|
||||||
|
|||||||
Reference in New Issue
Block a user