Core/Loot: implement Loot Item Storage
Port From (https://github.com/TrinityCore/TrinityCore/commit/090fd8304a7a6e2f7c233ac39c94ccc67cc816f8)
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user