Core/Loot: implement Loot Item Storage

Port From (https://github.com/TrinityCore/TrinityCore/commit/090fd8304a7a6e2f7c233ac39c94ccc67cc816f8)
This commit is contained in:
hondacrx
2020-05-12 17:11:14 -04:00
parent 9f235e1659
commit 1315f2c7f5
11 changed files with 403 additions and 247 deletions
+2 -184
View File
@@ -366,7 +366,7 @@ namespace Game.Entities
// Delete the items if this is a container
if (!loot.IsLooted())
ItemContainerDeleteLootMoneyAndLootItemsFromDB();
Global.LootItemStorage.RemoveStoredLootForContainer(GetGUID().GetCounter());
Dispose();
return;
@@ -662,7 +662,7 @@ namespace Game.Entities
// Delete the items if this is a container
if (!loot.IsLooted())
ItemContainerDeleteLootMoneyAndLootItemsFromDB();
Global.LootItemStorage.RemoveStoredLootForContainer(GetGUID().GetCounter());
}
public static void DeleteFromInventoryDB(SQLTransaction trans, ulong itemGuid)
@@ -1744,188 +1744,6 @@ namespace Game.Entities
return proto.GetSellPrice();
}
public void ItemContainerSaveLootToDB()
{
// Saves the money and item loot associated with an openable item to the DB
if (loot.IsLooted()) // no money and no loot
return;
SQLTransaction trans = new SQLTransaction();
loot.containerID = GetGUID(); // Save this for when a LootItem is removed
// Save money
if (loot.gold > 0)
{
PreparedStatement stmt_money = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEMCONTAINER_MONEY);
stmt_money.AddValue(0, loot.containerID.GetCounter());
trans.Append(stmt_money);
stmt_money = DB.Characters.GetPreparedStatement(CharStatements.INS_ITEMCONTAINER_MONEY);
stmt_money.AddValue(0, loot.containerID.GetCounter());
stmt_money.AddValue(1, loot.gold);
trans.Append(stmt_money);
}
// Save items
if (!loot.IsLooted())
{
PreparedStatement stmt_items = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEMCONTAINER_ITEMS);
stmt_items.AddValue(0, loot.containerID.GetCounter());
trans.Append(stmt_items);
// Now insert the items
foreach (var _li in loot.items)
{
// 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;
Player guid = GetOwner();
if (!_li.AllowedForPlayer(guid))
continue;
stmt_items = DB.Characters.GetPreparedStatement(CharStatements.INS_ITEMCONTAINER_ITEMS);
// container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, context, bonus_list_ids
stmt_items.AddValue(0, loot.containerID.GetCounter());
stmt_items.AddValue(1, _li.itemid);
stmt_items.AddValue(2, _li.count);
stmt_items.AddValue(3, _li.follow_loot_rules);
stmt_items.AddValue(4, _li.freeforall);
stmt_items.AddValue(5, _li.is_blocked);
stmt_items.AddValue(6, _li.is_counted);
stmt_items.AddValue(7, _li.is_underthreshold);
stmt_items.AddValue(8, _li.needs_quest);
stmt_items.AddValue(9, _li.randomBonusListId);
stmt_items.AddValue(10, _li.context);
string bonusListIDs = "";
foreach (int bonusListID in _li.BonusListIDs)
bonusListIDs += bonusListID + ' ';
stmt_items.AddValue(11, bonusListIDs);
trans.Append(stmt_items);
}
}
DB.Characters.CommitTransaction(trans);
}
public bool 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;
// Save this for later use
loot.containerID = GetGUID();
// First, see if there was any money loot. This gets added directly to the container.
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_ITEMCONTAINER_MONEY);
stmt.AddValue(0, loot.containerID.GetCounter());
SQLResult money_result = DB.Characters.Query(stmt);
if (!money_result.IsEmpty())
{
loot.gold = money_result.Read<uint>(0);
}
// Next, load any items that were saved
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_ITEMCONTAINER_ITEMS);
stmt.AddValue(0, loot.containerID.GetCounter());
SQLResult item_result = DB.Characters.Query(stmt);
if (!item_result.IsEmpty())
{
// Get a LootTemplate for the container item. This is where
// the saved loot was originally rolled from, we will copy conditions from it
LootTemplate lt = LootStorage.Items.GetLootFor(GetEntry());
if (lt != null)
{
do
{
// Create an empty LootItem
LootItem loot_item = new LootItem();
// item_id, itm_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, context, bonus_list_ids
loot_item.itemid = item_result.Read<uint>(0);
loot_item.count = item_result.Read<byte>(1);
loot_item.follow_loot_rules = item_result.Read<bool>(2);
loot_item.freeforall = item_result.Read<bool>(3);
loot_item.is_blocked = item_result.Read<bool>(4);
loot_item.is_counted = item_result.Read<bool>(5);
loot_item.canSave = true;
loot_item.is_underthreshold = item_result.Read<bool>(6);
loot_item.needs_quest = item_result.Read<bool>(7);
loot_item.randomBonusListId = item_result.Read<uint>(8);
loot_item.context = (ItemContext)item_result.Read<byte>(9);
StringArray bonusLists = new StringArray(item_result.Read<string>(10), ' ');
if (!bonusLists.IsEmpty())
{
foreach (string line in bonusLists)
{
if (uint.TryParse(line, out uint id))
loot_item.BonusListIDs.Add(id);
}
}
// 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() != 0)
loot_item.AddAllowedLooter(GetOwner());
// Finally add the LootItem to the container
loot.items.Add(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 ItemContainerDeleteLootItemsFromDB()
{
// Deletes items associated with an openable item from the DB
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEMCONTAINER_ITEMS);
stmt.AddValue(0, GetGUID().GetCounter());
DB.Characters.Execute(stmt);
}
void ItemContainerDeleteLootItemFromDB(uint itemID)
{
// Deletes a single item associated with an openable item from the DB
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEMCONTAINER_ITEM);
stmt.AddValue(0, GetGUID().GetCounter());
stmt.AddValue(1, itemID);
DB.Characters.Execute(stmt);
}
void ItemContainerDeleteLootMoneyFromDB()
{
// Deletes the money loot associated with an openable item from the DB
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEMCONTAINER_MONEY);
stmt.AddValue(0, GetGUID().GetCounter());
DB.Characters.Execute(stmt);
}
public void ItemContainerDeleteLootMoneyAndLootItemsFromDB()
{
// Deletes money and items associated with an openable item from the DB
ItemContainerDeleteLootMoneyFromDB();
ItemContainerDeleteLootItemsFromDB();
}
public uint GetItemLevel(Player owner)
{
ItemTemplate itemTemplate = GetTemplate();
+16 -1
View File
@@ -1507,12 +1507,27 @@ namespace Game.Entities
for (var i = InventorySlots.BuyBackStart; i < InventorySlots.BuyBackEnd; ++i)
{
Item item = m_items[i];
if (item == null || item.GetState() == ItemUpdateState.New)
if (item == null)
continue;
ItemTemplate itemTemplate = item.GetTemplate();
if (item.GetState() == ItemUpdateState.New)
{
if (itemTemplate != null)
if (itemTemplate.GetFlags().HasAnyFlag(ItemFlags.HasLoot))
Global.LootItemStorage.RemoveStoredLootForContainer(item.GetGUID().GetCounter());
continue;
}
item.DeleteFromInventoryDB(trans);
item.DeleteFromDB(trans);
m_items[i].FSetState(ItemUpdateState.New);
if (itemTemplate != null)
if (itemTemplate.GetFlags().HasAnyFlag(ItemFlags.HasLoot))
Global.LootItemStorage.RemoveStoredLootForContainer(item.GetGUID().GetCounter());
}
// Updated played time for refundable items. We don't do this in Player.Update because there's simply no need for it,
+20 -12
View File
@@ -2449,7 +2449,7 @@ namespace Game.Entities
Item bagItem = bag.GetItemByPos(i);
if (bagItem != null)
{
if (bagItem.m_lootGenerated)
if (bagItem.GetGUID() == GetLootGUID())
{
GetSession().DoLootRelease(GetLootGUID());
released = true; // so we don't need to look at dstBag
@@ -2467,7 +2467,7 @@ namespace Game.Entities
Item bagItem = bag.GetItemByPos(i);
if (bagItem != null)
{
if (bagItem.m_lootGenerated)
if (bagItem.GetGUID() == GetLootGUID())
{
GetSession().DoLootRelease(GetLootGUID());
break;
@@ -3911,7 +3911,13 @@ namespace Game.Entities
{
pItem.RemoveFromWorld();
if (del)
{
pItem.SetState(ItemUpdateState.Removed, this);
ItemTemplate itemTemplate = pItem.GetTemplate();
if (itemTemplate != null)
if (itemTemplate.GetFlags().HasAnyFlag(ItemFlags.HasLoot))
Global.LootItemStorage.RemoveStoredLootForContainer(pItem.GetGUID().GetCounter());
}
}
m_items[slot] = null;
@@ -5811,7 +5817,10 @@ namespace Game.Entities
ApplyItemObtainSpells(pItem, false);
ItemRemovedQuestCheck(pItem.GetEntry(), pItem.GetCount());
Global.ScriptMgr.OnItemRemove(this, pItem);
Bag pBag;
ItemTemplate pProto = pItem.GetTemplate();
if (bag == InventorySlots.Bag0)
{
SetInvSlot(slot, ObjectGuid.Empty);
@@ -5819,8 +5828,6 @@ namespace Game.Entities
// equipment and equipped bags can have applied bonuses
if (slot < InventorySlots.BagEnd)
{
ItemTemplate pProto = pItem.GetTemplate();
// item set bonuses applied only at equip and removed at unequip, and still active for broken items
if (pProto != null && pProto.GetItemSet() != 0)
Item.RemoveItemsSetItem(this, pProto);
@@ -5856,10 +5863,8 @@ namespace Game.Entities
// Delete rolled money / loot from db.
// MUST be done before RemoveFromWorld() or GetTemplate() fails
ItemTemplate pTmp = pItem.GetTemplate();
if (pTmp != null)
if (Convert.ToBoolean(pTmp.GetFlags() & ItemFlags.HasLoot))
pItem.ItemContainerDeleteLootMoneyAndLootItemsFromDB();
if (pProto.GetFlags().HasAnyFlag(ItemFlags.HasLoot))
Global.LootItemStorage.RemoveStoredLootForContainer(pItem.GetGUID().GetCounter());
if (IsInWorld && update)
{
@@ -6325,7 +6330,7 @@ namespace Game.Entities
// LootItem is being removed (looted) from the container, delete it from the DB.
if (!loot.containerID.IsEmpty())
loot.DeleteLootItemFromContainerItemDB(item.itemid);
Global.LootItemStorage.RemoveStoredLootItemForContainer(loot.containerID.GetCounter(), item.itemid, item.count);
}
else
@@ -6517,9 +6522,12 @@ namespace Game.Entities
loot = item.loot;
// Store container id
loot.containerID = item.GetGUID();
// 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())
// fails then this is first time opening, generate loot
if (!item.m_lootGenerated && !Global.LootItemStorage.LoadStoredLoot(item, this))
{
item.m_lootGenerated = true;
loot.Clear();
@@ -6542,7 +6550,7 @@ namespace Game.Entities
// 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();
Global.LootItemStorage.AddNewStoredLoot(loot, this);
break;
}