Core/Loot: Implemented currency loot
Port From (https://github.com/TrinityCore/TrinityCore/commit/3e28ee080a1cf3c7cd332a8d1e0808505b4ea9d4)
This commit is contained in:
@@ -1454,5 +1454,6 @@ namespace Framework.Constants
|
|||||||
{
|
{
|
||||||
Item = 0,
|
Item = 0,
|
||||||
Reference = 1,
|
Reference = 1,
|
||||||
|
Currency = 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ namespace Framework.Constants
|
|||||||
CommandNpcShowlootLabel2 = 293,
|
CommandNpcShowlootLabel2 = 293,
|
||||||
CommandNpcShowlootSublabel = 294,
|
CommandNpcShowlootSublabel = 294,
|
||||||
CommandNpcShowlootEntry2 = 295,
|
CommandNpcShowlootEntry2 = 295,
|
||||||
// 296 Free
|
CommandNpcShowLootCurrency = 296,
|
||||||
|
|
||||||
// End
|
// End
|
||||||
CommandWanderDistance = 297,
|
CommandWanderDistance = 297,
|
||||||
|
|||||||
@@ -663,10 +663,10 @@ namespace Framework.Database
|
|||||||
PrepareStatement(CharStatements.DEL_CHAR_CUF_PROFILES, "DELETE FROM character_cuf_profiles WHERE guid = ?");
|
PrepareStatement(CharStatements.DEL_CHAR_CUF_PROFILES, "DELETE FROM character_cuf_profiles WHERE guid = ?");
|
||||||
|
|
||||||
// Items that hold loot or money
|
// Items that hold loot or money
|
||||||
PrepareStatement(CharStatements.SEL_ITEMCONTAINER_ITEMS, "SELECT container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_bonus, context, bonus_list_ids FROM item_loot_items");
|
PrepareStatement(CharStatements.SEL_ITEMCONTAINER_ITEMS, "SELECT container_id, item_type, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_bonus, context, bonus_list_ids FROM item_loot_items");
|
||||||
PrepareStatement(CharStatements.DEL_ITEMCONTAINER_ITEMS, "DELETE FROM item_loot_items WHERE container_id = ?");
|
PrepareStatement(CharStatements.DEL_ITEMCONTAINER_ITEMS, "DELETE FROM item_loot_items WHERE container_id = ?");
|
||||||
PrepareStatement(CharStatements.DEL_ITEMCONTAINER_ITEM, "DELETE FROM item_loot_items WHERE container_id = ? AND item_id = ? AND item_count = ? AND item_index = ?");
|
PrepareStatement(CharStatements.DEL_ITEMCONTAINER_ITEM, "DELETE FROM item_loot_items WHERE container_id = ? AND item_type = ? AND item_id = ? AND item_count = ? AND item_index = ?");
|
||||||
PrepareStatement(CharStatements.INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_bonus, context, bonus_list_ids) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
PrepareStatement(CharStatements.INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_type, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_bonus, context, bonus_list_ids) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||||
PrepareStatement(CharStatements.SEL_ITEMCONTAINER_MONEY, "SELECT container_id, money FROM item_loot_money");
|
PrepareStatement(CharStatements.SEL_ITEMCONTAINER_MONEY, "SELECT container_id, money FROM item_loot_money");
|
||||||
PrepareStatement(CharStatements.DEL_ITEMCONTAINER_MONEY, "DELETE FROM item_loot_money WHERE container_id = ?");
|
PrepareStatement(CharStatements.DEL_ITEMCONTAINER_MONEY, "DELETE FROM item_loot_money WHERE container_id = ?");
|
||||||
PrepareStatement(CharStatements.INS_ITEMCONTAINER_MONEY, "INSERT INTO item_loot_money (container_id, money) VALUES (?, ?)");
|
PrepareStatement(CharStatements.INS_ITEMCONTAINER_MONEY, "INSERT INTO item_loot_money (container_id, money) VALUES (?, ?)");
|
||||||
|
|||||||
@@ -611,11 +611,8 @@ namespace Game.Chat
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Command("currency", RBACPermissions.CommandModifyCurrency)]
|
[Command("currency", RBACPermissions.CommandModifyCurrency)]
|
||||||
static bool HandleModifyCurrencyCommand(CommandHandler handler, StringArguments args)
|
static bool HandleModifyCurrencyCommand(CommandHandler handler, CurrencyTypesRecord currency, int amount)
|
||||||
{
|
{
|
||||||
if (args.Empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Player target = handler.GetSelectedPlayerOrSelf();
|
Player target = handler.GetSelectedPlayerOrSelf();
|
||||||
if (target == null)
|
if (target == null)
|
||||||
{
|
{
|
||||||
@@ -624,15 +621,7 @@ namespace Game.Chat
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint currencyId = args.NextUInt32();
|
target.ModifyCurrency(currency.Id, amount, CurrencyGainSource.Cheat, CurrencyDestroyReason.Cheat);
|
||||||
if (!CliDB.CurrencyTypesStorage.ContainsKey(currencyId))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint amount = args.NextUInt32();
|
|
||||||
if (amount == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
target.ModifyCurrency(currencyId, (int)amount, CurrencyGainSource.Cheat, CurrencyDestroyReason.Cheat);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,23 +316,23 @@ namespace Game.Chat
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!creatureTarget.IsDead())
|
||||||
|
{
|
||||||
|
handler.SendSysMessage(CypherStrings.CommandNotDeadOrNoLoot, creatureTarget.GetName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Loot loot = creatureTarget._loot;
|
Loot loot = creatureTarget._loot;
|
||||||
if (creatureTarget.IsDead() || loot == null || loot.IsLooted())
|
if ((loot == null || loot.IsLooted()) && creatureTarget.m_personalLoot.Count(p => p.Value.IsLooted()) == 0)
|
||||||
{
|
{
|
||||||
handler.SendSysMessage(CypherStrings.CommandNotDeadOrNoLoot, creatureTarget.GetName());
|
handler.SendSysMessage(CypherStrings.CommandNotDeadOrNoLoot, creatureTarget.GetName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.SendSysMessage(CypherStrings.CommandNpcShowlootHeader, creatureTarget.GetName(), creatureTarget.GetEntry());
|
handler.SendSysMessage(CypherStrings.CommandNpcShowlootHeader, creatureTarget.GetName(), creatureTarget.GetEntry());
|
||||||
handler.SendSysMessage(CypherStrings.CommandNpcShowlootMoney, loot.gold / MoneyConstants.Gold, (loot.gold % MoneyConstants.Gold) / MoneyConstants.Silver, loot.gold % MoneyConstants.Silver);
|
|
||||||
|
|
||||||
if (all.Equals("all", StringComparison.OrdinalIgnoreCase)) // nonzero from strcmp <. not equal
|
if (loot != null)
|
||||||
{
|
_ShowLootContents(handler, all == "all", loot);
|
||||||
handler.SendSysMessage(CypherStrings.CommandNpcShowlootLabel, "Standard items", loot.items.Count);
|
|
||||||
foreach (LootItem item in loot.items)
|
|
||||||
if (!item.is_looted)
|
|
||||||
_ShowLootEntry(handler, item.itemid, item.count);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
handler.SendSysMessage(CypherStrings.CommandNpcShowlootLabel, "Standard items", loot.items.Count);
|
handler.SendSysMessage(CypherStrings.CommandNpcShowlootLabel, "Standard items", loot.items.Count);
|
||||||
@@ -340,10 +340,11 @@ namespace Game.Chat
|
|||||||
if (!item.is_looted && !item.freeforall && item.conditions.IsEmpty())
|
if (!item.is_looted && !item.freeforall && item.conditions.IsEmpty())
|
||||||
_ShowLootEntry(handler, item.itemid, item.count);
|
_ShowLootEntry(handler, item.itemid, item.count);
|
||||||
|
|
||||||
if (!loot.GetPlayerFFAItems().Empty())
|
foreach (var (lootOwner, personalLoot) in creatureTarget.m_personalLoot)
|
||||||
{
|
{
|
||||||
handler.SendSysMessage(CypherStrings.CommandNpcShowlootLabel2, "FFA items per allowed player");
|
var character = Global.CharacterCacheStorage.GetCharacterCacheByGuid(lootOwner);
|
||||||
_IterateNotNormalLootMap(handler, loot.GetPlayerFFAItems(), loot.items);
|
handler.SendSysMessage(CypherStrings.CommandNpcShowlootLabel2, $"Personal loot for {(character != null ? character.Name : "")}");
|
||||||
|
_ShowLootContents(handler, all == "all", personalLoot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,7 +516,7 @@ namespace Game.Chat
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _ShowLootEntry(CommandHandler handler, uint itemId, byte itemCount, bool alternateString = false)
|
static void _ShowLootEntry(CommandHandler handler, uint itemId, uint itemCount, bool alternateString = false)
|
||||||
{
|
{
|
||||||
string name = "Unknown item";
|
string name = "Unknown item";
|
||||||
|
|
||||||
@@ -526,6 +527,18 @@ namespace Game.Chat
|
|||||||
handler.SendSysMessage(alternateString ? CypherStrings.CommandNpcShowlootEntry2 : CypherStrings.CommandNpcShowlootEntry,
|
handler.SendSysMessage(alternateString ? CypherStrings.CommandNpcShowlootEntry2 : CypherStrings.CommandNpcShowlootEntry,
|
||||||
itemCount, ItemConst.ItemQualityColors[(int)(itemTemplate != null ? itemTemplate.GetQuality() : ItemQuality.Poor)], itemId, name, itemId);
|
itemCount, ItemConst.ItemQualityColors[(int)(itemTemplate != null ? itemTemplate.GetQuality() : ItemQuality.Poor)], itemId, name, itemId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _ShowLootCurrencyEntry(CommandHandler handler, uint currencyId, uint count, bool alternateString = false)
|
||||||
|
{
|
||||||
|
CurrencyTypesRecord currency = CliDB.CurrencyTypesStorage.LookupByKey(currencyId);
|
||||||
|
string name = "Unknown currency";
|
||||||
|
if (currency != null)
|
||||||
|
name = currency.Name;
|
||||||
|
|
||||||
|
handler.SendSysMessage(CypherStrings.CommandNpcShowLootCurrency, alternateString ? 6 : 3 /*number of bytes from following string*/, "\u2500\u2500",
|
||||||
|
count, ItemConst.ItemQualityColors[currency != null ? currency.Quality : (int)ItemQuality.Poor], currencyId, count, name, currencyId);
|
||||||
|
}
|
||||||
|
|
||||||
static void _IterateNotNormalLootMap(CommandHandler handler, MultiMap<ObjectGuid, NotNormalLootItem> map, List<LootItem> items)
|
static void _IterateNotNormalLootMap(CommandHandler handler, MultiMap<ObjectGuid, NotNormalLootItem> map, List<LootItem> items)
|
||||||
{
|
{
|
||||||
foreach (var key in map.Keys)
|
foreach (var key in map.Keys)
|
||||||
@@ -542,7 +555,67 @@ namespace Game.Chat
|
|||||||
{
|
{
|
||||||
LootItem item = items[it.LootListId];
|
LootItem item = items[it.LootListId];
|
||||||
if (!it.is_looted && !item.is_looted)
|
if (!it.is_looted && !item.is_looted)
|
||||||
_ShowLootEntry(handler, item.itemid, item.count, true);
|
{
|
||||||
|
switch (item.type)
|
||||||
|
{
|
||||||
|
case LootItemType.Item:
|
||||||
|
_ShowLootEntry(handler, item.itemid, item.count, true);
|
||||||
|
break;
|
||||||
|
case LootItemType.Currency:
|
||||||
|
_ShowLootCurrencyEntry(handler, item.itemid, item.count, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ShowLootContents(CommandHandler handler, bool all, Loot loot)
|
||||||
|
{
|
||||||
|
handler.SendSysMessage(CypherStrings.CommandNpcShowlootMoney, loot.gold / MoneyConstants.Gold, (loot.gold % MoneyConstants.Gold) / MoneyConstants.Silver, loot.gold % MoneyConstants.Silver);
|
||||||
|
|
||||||
|
if (!all)
|
||||||
|
{
|
||||||
|
handler.SendSysMessage(CypherStrings.CommandNpcShowlootLabel, "Standard items", loot.items.Count);
|
||||||
|
foreach (LootItem item in loot.items)
|
||||||
|
{
|
||||||
|
if (!item.is_looted)
|
||||||
|
{
|
||||||
|
switch (item.type)
|
||||||
|
{
|
||||||
|
case LootItemType.Item:
|
||||||
|
_ShowLootEntry(handler, item.itemid, item.count);
|
||||||
|
break;
|
||||||
|
case LootItemType.Currency:
|
||||||
|
_ShowLootCurrencyEntry(handler, item.itemid, item.count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handler.SendSysMessage(CypherStrings.CommandNpcShowlootLabel, "Standard items", loot.items.Count);
|
||||||
|
foreach (LootItem item in loot.items)
|
||||||
|
{
|
||||||
|
if (!item.is_looted && !item.freeforall && item.conditions.IsEmpty())
|
||||||
|
{
|
||||||
|
switch (item.type)
|
||||||
|
{
|
||||||
|
case LootItemType.Item:
|
||||||
|
_ShowLootEntry(handler, item.itemid, item.count);
|
||||||
|
break;
|
||||||
|
case LootItemType.Currency:
|
||||||
|
_ShowLootCurrencyEntry(handler, item.itemid, item.count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loot.GetPlayerFFAItems().Empty())
|
||||||
|
{
|
||||||
|
handler.SendSysMessage(CypherStrings.CommandNpcShowlootLabel2, "FFA items per allowed player");
|
||||||
|
_IterateNotNormalLootMap(handler, loot.GetPlayerFFAItems(), loot.items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6066,55 +6066,64 @@ namespace Game.Entities
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ItemPosCount> dest = new();
|
switch (item.type)
|
||||||
InventoryResult msg = CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item.itemid, item.count);
|
|
||||||
if (msg == InventoryResult.Ok)
|
|
||||||
{
|
{
|
||||||
Item newitem = StoreNewItem(dest, item.itemid, true, item.randomBonusListId, item.GetAllowedLooters(), item.context);
|
case LootItemType.Item:
|
||||||
if (ffaItem != null)
|
List<ItemPosCount> dest = new();
|
||||||
{
|
InventoryResult msg = CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item.itemid, item.count);
|
||||||
//freeforall case, notify only one player of the removal
|
if (msg != InventoryResult.Ok)
|
||||||
ffaItem.is_looted = true;
|
{
|
||||||
SendNotifyLootItemRemoved(loot.GetGUID(), loot.GetOwnerGUID(), lootSlot);
|
SendEquipError(msg, null, null, item.itemid);
|
||||||
}
|
return;
|
||||||
else //not freeforall, notify everyone
|
}
|
||||||
loot.NotifyItemRemoved(lootSlot, GetMap());
|
|
||||||
|
|
||||||
//if only one person is supposed to loot the item, then set it to looted
|
Item newitem = StoreNewItem(dest, item.itemid, true, item.randomBonusListId, item.GetAllowedLooters(), item.context);
|
||||||
if (!item.freeforall)
|
if (newitem != null && (newitem.GetQuality() > ItemQuality.Epic || (newitem.GetQuality() == ItemQuality.Epic && newitem.GetItemLevel(this) >= GuildConst.MinNewsItemLevel)))
|
||||||
item.is_looted = true;
|
{
|
||||||
|
Guild guild = GetGuild();
|
||||||
|
if (guild != null)
|
||||||
|
guild.AddGuildNews(GuildNews.ItemLooted, GetGUID(), 0, item.itemid);
|
||||||
|
}
|
||||||
|
|
||||||
--loot.unlootedCount;
|
// if aeLooting then we must delay sending out item so that it appears properly stacked in chat
|
||||||
|
if (aeResult == null || newitem == null)
|
||||||
|
{
|
||||||
|
SendNewItem(newitem, item.count, false, false, true, loot.GetDungeonEncounterId());
|
||||||
|
UpdateCriteria(CriteriaType.LootItem, item.itemid, item.count);
|
||||||
|
UpdateCriteria(CriteriaType.GetLootByType, item.itemid, item.count, (uint)SharedConst.GetLootTypeForClient(loot.loot_type));
|
||||||
|
UpdateCriteria(CriteriaType.LootAnyItem, item.itemid, item.count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aeResult.Add(newitem, (byte)item.count, SharedConst.GetLootTypeForClient(loot.loot_type), loot.GetDungeonEncounterId());
|
||||||
|
|
||||||
if (newitem != null && (newitem.GetQuality() > ItemQuality.Epic || (newitem.GetQuality() == ItemQuality.Epic && newitem.GetItemLevel(this) >= GuildConst.MinNewsItemLevel)))
|
if (newitem != null)
|
||||||
{
|
ApplyItemLootedSpell(newitem, true);
|
||||||
Guild guild = GetGuild();
|
else
|
||||||
if (guild != null)
|
ApplyItemLootedSpell(Global.ObjectMgr.GetItemTemplate(item.itemid));
|
||||||
guild.AddGuildNews(GuildNews.ItemLooted, GetGUID(), 0, item.itemid);
|
break;
|
||||||
}
|
case LootItemType.Currency:
|
||||||
|
ModifyCurrency(item.itemid, (int)item.count, CurrencyGainSource.Loot);
|
||||||
// if aeLooting then we must delay sending out item so that it appears properly stacked in chat
|
break;
|
||||||
if (aeResult == null || newitem == null)
|
|
||||||
{
|
|
||||||
SendNewItem(newitem, item.count, false, false, true, loot.GetDungeonEncounterId());
|
|
||||||
UpdateCriteria(CriteriaType.LootItem, item.itemid, item.count);
|
|
||||||
UpdateCriteria(CriteriaType.GetLootByType, item.itemid, item.count, (uint)SharedConst.GetLootTypeForClient(loot.loot_type));
|
|
||||||
UpdateCriteria(CriteriaType.LootAnyItem, item.itemid, item.count);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
aeResult.Add(newitem, item.count, SharedConst.GetLootTypeForClient(loot.loot_type), loot.GetDungeonEncounterId());
|
|
||||||
|
|
||||||
// LootItem is being removed (looted) from the container, delete it from the DB.
|
|
||||||
if (loot.loot_type == LootType.Item)
|
|
||||||
Global.LootItemStorage.RemoveStoredLootItemForContainer(lootWorldObjectGuid.GetCounter(), item.itemid, item.count, item.LootListId);
|
|
||||||
|
|
||||||
if (newitem != null)
|
|
||||||
ApplyItemLootedSpell(newitem, true);
|
|
||||||
else
|
|
||||||
ApplyItemLootedSpell(Global.ObjectMgr.GetItemTemplate(item.itemid));
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
SendEquipError(msg, null, null, item.itemid);
|
if (ffaItem != null)
|
||||||
|
{
|
||||||
|
//freeforall case, notify only one player of the removal
|
||||||
|
ffaItem.is_looted = true;
|
||||||
|
SendNotifyLootItemRemoved(loot.GetGUID(), loot.GetOwnerGUID(), lootSlot);
|
||||||
|
}
|
||||||
|
else //not freeforall, notify everyone
|
||||||
|
loot.NotifyItemRemoved(lootSlot, GetMap());
|
||||||
|
|
||||||
|
//if only one person is supposed to loot the item, then set it to looted
|
||||||
|
if (!item.freeforall)
|
||||||
|
item.is_looted = true;
|
||||||
|
|
||||||
|
--loot.unlootedCount;
|
||||||
|
|
||||||
|
// LootItem is being removed (looted) from the container, delete it from the DB.
|
||||||
|
if (loot.loot_type == LootType.Item)
|
||||||
|
Global.LootItemStorage.RemoveStoredLootItemForContainer(lootWorldObjectGuid.GetCounter(), item.type, item.itemid, item.count, item.LootListId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<ObjectGuid, Loot> GetAELootView() { return m_AELootView; }
|
public Dictionary<ObjectGuid, Loot> GetAELootView() { return m_AELootView; }
|
||||||
|
|||||||
@@ -2873,6 +2873,39 @@ namespace Game.Entities
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HasQuestForCurrency(uint currencyId)
|
||||||
|
{
|
||||||
|
bool isCompletableObjective(QuestObjectiveStatusData objectiveStatus)
|
||||||
|
{
|
||||||
|
Quest qInfo = Global.ObjectMgr.GetQuestTemplate(objectiveStatus.QuestStatusPair.QuestID);
|
||||||
|
QuestObjective objective = Global.ObjectMgr.GetQuestObjective(objectiveStatus.ObjectiveId);
|
||||||
|
if (qInfo == null || objective == null || !IsQuestObjectiveCompletable(objectiveStatus.QuestStatusPair.Status.Slot, qInfo, objective))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// hide quest if player is in raid-group and quest is no raid quest
|
||||||
|
if (GetGroup() != null && GetGroup().IsRaidGroup() && !qInfo.IsAllowedInRaid(GetMap().GetDifficultyID()))
|
||||||
|
if (!InBattleground()) //there are two ways.. we can make every bg-quest a raidquest, or add this code here.. i don't know if this can be exploited by other quests, but i think all other quests depend on a specific area.. but keep this in mind, if something strange happens later
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!IsQuestObjectiveComplete(objectiveStatus.QuestStatusPair.Status.Slot, qInfo, objective))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool hasObjectiveTypeForCurrency(QuestObjectiveType type) => m_questObjectiveStatus.LookupByKey((type, currencyId)).Any(isCompletableObjective);
|
||||||
|
if (hasObjectiveTypeForCurrency(QuestObjectiveType.Currency))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hasObjectiveTypeForCurrency(QuestObjectiveType.HaveCurrency))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hasObjectiveTypeForCurrency(QuestObjectiveType.ObtainCurrency))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public int GetQuestObjectiveData(QuestObjective objective)
|
public int GetQuestObjectiveData(QuestObjective objective)
|
||||||
{
|
{
|
||||||
ushort slot = FindQuestSlot(objective.QuestID);
|
ushort slot = FindQuestSlot(objective.QuestID);
|
||||||
|
|||||||
@@ -427,11 +427,17 @@ namespace Game
|
|||||||
|
|
||||||
if (req.LootListID >= loot.items.Count)
|
if (req.LootListID >= loot.items.Count)
|
||||||
{
|
{
|
||||||
|
_player.SendLootError(req.Object, loot.GetOwnerGUID(), LootError.MasterOther);
|
||||||
Log.outDebug(LogFilter.Loot, $"MasterLootItem: Player {GetPlayer().GetName()} might be using a hack! (slot {req.LootListID}, size {loot.items.Count})");
|
Log.outDebug(LogFilter.Loot, $"MasterLootItem: Player {GetPlayer().GetName()} might be using a hack! (slot {req.LootListID}, size {loot.items.Count})");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LootItem item = loot.items[req.LootListID];
|
LootItem item = loot.items[req.LootListID];
|
||||||
|
if (item.type != LootItemType.Item)
|
||||||
|
{
|
||||||
|
_player.SendLootError(req.Object, loot.GetOwnerGUID(), LootError.MasterOther);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List<ItemPosCount> dest = new();
|
List<ItemPosCount> dest = new();
|
||||||
InventoryResult msg = target.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item.itemid, item.count);
|
InventoryResult msg = target.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item.itemid, item.count);
|
||||||
@@ -452,7 +458,7 @@ namespace Game
|
|||||||
// now move item from loot to target inventory
|
// now move item from loot to target inventory
|
||||||
Item newitem = target.StoreNewItem(dest, item.itemid, true, item.randomBonusListId, item.GetAllowedLooters(), item.context, item.BonusListIDs);
|
Item newitem = target.StoreNewItem(dest, item.itemid, true, item.randomBonusListId, item.GetAllowedLooters(), item.context, item.BonusListIDs);
|
||||||
if (newitem != null)
|
if (newitem != null)
|
||||||
aeResult.Add(newitem, item.count, loot.loot_type, loot.GetDungeonEncounterId());
|
aeResult.Add(newitem, (byte)item.count, loot.loot_type, loot.GetDungeonEncounterId());
|
||||||
else
|
else
|
||||||
target.ApplyItemLootedSpell(Global.ObjectMgr.GetItemTemplate(item.itemid));
|
target.ApplyItemLootedSpell(Global.ObjectMgr.GetItemTemplate(item.itemid));
|
||||||
|
|
||||||
|
|||||||
+177
-74
@@ -16,19 +16,47 @@ namespace Game.Loots
|
|||||||
{
|
{
|
||||||
public class LootItem
|
public class LootItem
|
||||||
{
|
{
|
||||||
|
public uint itemid;
|
||||||
|
public uint LootListId;
|
||||||
|
public uint randomBonusListId;
|
||||||
|
public List<uint> BonusListIDs = new();
|
||||||
|
public ItemContext context;
|
||||||
|
public ConditionsReference conditions; // additional loot condition
|
||||||
|
public List<ObjectGuid> allowedGUIDs = new();
|
||||||
|
public ObjectGuid rollWinnerGUID; // Stores the guid of person who won loot, if his bags are full only he can see the item in loot list!
|
||||||
|
public uint count;
|
||||||
|
public LootItemType type;
|
||||||
|
public bool is_looted;
|
||||||
|
public bool is_blocked;
|
||||||
|
public bool freeforall; // free for all
|
||||||
|
public bool is_underthreshold;
|
||||||
|
public bool is_counted;
|
||||||
|
public bool needs_quest; // quest drop
|
||||||
|
public bool follow_loot_rules;
|
||||||
|
|
||||||
public LootItem() { }
|
public LootItem() { }
|
||||||
public LootItem(LootStoreItem li)
|
public LootItem(LootStoreItem li)
|
||||||
{
|
{
|
||||||
itemid = li.itemid;
|
itemid = li.itemid;
|
||||||
conditions = li.conditions;
|
conditions = li.conditions;
|
||||||
|
|
||||||
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(itemid);
|
|
||||||
freeforall = proto != null && proto.HasFlag(ItemFlags.MultiDrop);
|
|
||||||
follow_loot_rules = !li.needs_quest || (proto != null && proto.FlagsCu.HasAnyFlag(ItemFlagsCustom.FollowLootRules));
|
|
||||||
|
|
||||||
needs_quest = li.needs_quest;
|
needs_quest = li.needs_quest;
|
||||||
|
|
||||||
randomBonusListId = ItemEnchantmentManager.GenerateItemRandomBonusListId(itemid);
|
switch (li.type)
|
||||||
|
{
|
||||||
|
case LootStoreItemType.Item:
|
||||||
|
randomBonusListId = ItemEnchantmentManager.GenerateItemRandomBonusListId(itemid);
|
||||||
|
type = LootItemType.Item;
|
||||||
|
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(itemid);
|
||||||
|
freeforall = proto != null && proto.HasFlag(ItemFlags.MultiDrop);
|
||||||
|
follow_loot_rules = !li.needs_quest || (proto != null && proto.HasFlag(ItemFlagsCustom.FollowLootRules));
|
||||||
|
break;
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
|
type = LootItemType.Currency;
|
||||||
|
freeforall = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -39,10 +67,35 @@ namespace Game.Loots
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool AllowedForPlayer(Player player, Loot loot)
|
public bool AllowedForPlayer(Player player, Loot loot)
|
||||||
{
|
{
|
||||||
return AllowedForPlayer(player, loot, itemid, needs_quest, follow_loot_rules, false, conditions);
|
switch (type)
|
||||||
|
{
|
||||||
|
case LootItemType.Item:
|
||||||
|
return ItemAllowedForPlayer(player, loot, itemid, needs_quest, follow_loot_rules, false, conditions);
|
||||||
|
case LootItemType.Currency:
|
||||||
|
return CurrencyAllowedForPlayer(player, itemid, needs_quest, conditions);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool AllowedForPlayer(Player player, Loot loot, uint itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck, ConditionsReference conditions)
|
public static bool AllowedForPlayer(Player player, LootStoreItem lootStoreItem, bool strictUsabilityCheck)
|
||||||
|
{
|
||||||
|
switch (lootStoreItem.type)
|
||||||
|
{
|
||||||
|
case LootStoreItemType.Item:
|
||||||
|
return ItemAllowedForPlayer(player, null, lootStoreItem.itemid, lootStoreItem.needs_quest,
|
||||||
|
!lootStoreItem.needs_quest || Global.ObjectMgr.GetItemTemplate(lootStoreItem.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
||||||
|
strictUsabilityCheck, lootStoreItem.conditions);
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
|
return CurrencyAllowedForPlayer(player, lootStoreItem.itemid, lootStoreItem.needs_quest, lootStoreItem.conditions);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ItemAllowedForPlayer(Player player, Loot loot, uint itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck, ConditionsReference conditions)
|
||||||
{
|
{
|
||||||
// DB conditions check
|
// DB conditions check
|
||||||
if (!conditions.Meets(player))
|
if (!conditions.Meets(player))
|
||||||
@@ -96,6 +149,30 @@ namespace Game.Loots
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool CurrencyAllowedForPlayer(Player player, uint currencyId, bool needs_quest, ConditionsReference conditions)
|
||||||
|
{
|
||||||
|
// DB conditions check
|
||||||
|
if (!conditions.Meets(player))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CurrencyTypesRecord currency = CliDB.CurrencyTypesStorage.LookupByKey(currencyId);
|
||||||
|
if (currency == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// not show loot for not own team
|
||||||
|
if (currency.HasFlag(CurrencyTypesFlags.IsHordeOnly) && player.GetTeam() != Team.Horde)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (currency.HasFlag(CurrencyTypesFlags.IsAllianceOnly) && player.GetTeam() != Team.Alliance)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check quest requirements
|
||||||
|
if (needs_quest && !player.HasQuestForCurrency(currencyId))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddAllowedLooter(Player player)
|
public void AddAllowedLooter(Player player)
|
||||||
{
|
{
|
||||||
allowedGUIDs.Add(player.GetGUID());
|
allowedGUIDs.Add(player.GetGUID());
|
||||||
@@ -174,23 +251,6 @@ namespace Game.Loots
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<ObjectGuid> GetAllowedLooters() { return allowedGUIDs; }
|
public List<ObjectGuid> GetAllowedLooters() { return allowedGUIDs; }
|
||||||
|
|
||||||
public uint itemid;
|
|
||||||
public uint LootListId;
|
|
||||||
public uint randomBonusListId;
|
|
||||||
public List<uint> BonusListIDs = new();
|
|
||||||
public ItemContext context;
|
|
||||||
public ConditionsReference conditions; // additional loot condition
|
|
||||||
public List<ObjectGuid> allowedGUIDs = new();
|
|
||||||
public ObjectGuid rollWinnerGUID; // Stores the guid of person who won loot, if his bags are full only he can see the item in loot list!
|
|
||||||
public byte count;
|
|
||||||
public bool is_looted;
|
|
||||||
public bool is_blocked;
|
|
||||||
public bool freeforall; // free for all
|
|
||||||
public bool is_underthreshold;
|
|
||||||
public bool is_counted;
|
|
||||||
public bool needs_quest; // quest drop
|
|
||||||
public bool follow_loot_rules;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NotNormalLootItem
|
public class NotNormalLootItem
|
||||||
@@ -630,7 +690,7 @@ namespace Game.Loots
|
|||||||
for (uint i = 0; i < loot.items.Count; ++i)
|
for (uint i = 0; i < loot.items.Count; ++i)
|
||||||
{
|
{
|
||||||
LootItem disenchantLoot = loot.LootItemInSlot(i, player);
|
LootItem disenchantLoot = loot.LootItemInSlot(i, player);
|
||||||
if (disenchantLoot != null)
|
if (disenchantLoot != null && disenchantLoot.type == LootItemType.Item)
|
||||||
player.SendItemRetrievalMail(disenchantLoot.itemid, disenchantLoot.count, disenchantLoot.context);
|
player.SendItemRetrievalMail(disenchantLoot.itemid, disenchantLoot.count, disenchantLoot.context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -660,23 +720,40 @@ namespace Game.Loots
|
|||||||
// Inserts the item into the loot (called by LootTemplate processors)
|
// Inserts the item into the loot (called by LootTemplate processors)
|
||||||
public void AddItem(LootStoreItem item)
|
public void AddItem(LootStoreItem item)
|
||||||
{
|
{
|
||||||
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item.itemid);
|
switch (item.type)
|
||||||
if (proto == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint count = RandomHelper.URand(item.mincount, item.maxcount);
|
|
||||||
uint stacks = (uint)(count / proto.GetMaxStackSize() + (Convert.ToBoolean(count % proto.GetMaxStackSize()) ? 1 : 0));
|
|
||||||
|
|
||||||
for (uint i = 0; i < stacks && items.Count < SharedConst.MaxNRLootItems; ++i)
|
|
||||||
{
|
{
|
||||||
LootItem generatedLoot = new(item);
|
case LootStoreItemType.Item:
|
||||||
generatedLoot.context = _itemContext;
|
{
|
||||||
generatedLoot.count = (byte)Math.Min(count, proto.GetMaxStackSize());
|
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item.itemid);
|
||||||
generatedLoot.LootListId = (uint)items.Count;
|
if (proto == null)
|
||||||
generatedLoot.BonusListIDs = ItemBonusMgr.GetBonusListsForItem(generatedLoot.itemid, new(_itemContext));
|
return;
|
||||||
|
|
||||||
items.Add(generatedLoot);
|
uint count = RandomHelper.URand(item.mincount, item.maxcount);
|
||||||
count -= proto.GetMaxStackSize();
|
uint stacks = (uint)(count / proto.GetMaxStackSize() + (Convert.ToBoolean(count % proto.GetMaxStackSize()) ? 1 : 0));
|
||||||
|
|
||||||
|
for (uint i = 0; i < stacks && items.Count < SharedConst.MaxNRLootItems; ++i)
|
||||||
|
{
|
||||||
|
LootItem generatedLoot = new(item);
|
||||||
|
generatedLoot.context = _itemContext;
|
||||||
|
generatedLoot.count = (byte)Math.Min(count, proto.GetMaxStackSize());
|
||||||
|
generatedLoot.LootListId = (uint)items.Count;
|
||||||
|
generatedLoot.BonusListIDs = ItemBonusMgr.GetBonusListsForItem(generatedLoot.itemid, new(_itemContext));
|
||||||
|
|
||||||
|
items.Add(generatedLoot);
|
||||||
|
count -= proto.GetMaxStackSize();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
|
{
|
||||||
|
LootItem generatedLoot = new(item);
|
||||||
|
generatedLoot.count = RandomHelper.URand(item.mincount, item.maxcount);
|
||||||
|
generatedLoot.LootListId = (uint)items.Count;
|
||||||
|
items.Add(generatedLoot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,19 +776,36 @@ namespace Game.Loots
|
|||||||
if (!lootItem.rollWinnerGUID.IsEmpty() && lootItem.rollWinnerGUID != GetGUID())
|
if (!lootItem.rollWinnerGUID.IsEmpty() && lootItem.rollWinnerGUID != GetGUID())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
List<ItemPosCount> dest = new();
|
switch (lootItem.type)
|
||||||
InventoryResult msg = player.CanStoreNewItem(bag, slot, dest, lootItem.itemid, lootItem.count);
|
|
||||||
if (msg != InventoryResult.Ok && slot != ItemConst.NullSlot)
|
|
||||||
msg = player.CanStoreNewItem(bag, ItemConst.NullSlot, dest, lootItem.itemid, lootItem.count);
|
|
||||||
if (msg != InventoryResult.Ok && bag != ItemConst.NullBag)
|
|
||||||
msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, lootItem.itemid, lootItem.count);
|
|
||||||
if (msg != InventoryResult.Ok)
|
|
||||||
{
|
{
|
||||||
player.SendEquipError(msg, null, null, lootItem.itemid);
|
case LootItemType.Item:
|
||||||
allLooted = false;
|
List<ItemPosCount> dest = new();
|
||||||
continue;
|
InventoryResult msg = player.CanStoreNewItem(bag, slot, dest, lootItem.itemid, lootItem.count);
|
||||||
}
|
if (msg != InventoryResult.Ok && slot != ItemConst.NullSlot)
|
||||||
|
msg = player.CanStoreNewItem(bag, ItemConst.NullSlot, dest, lootItem.itemid, lootItem.count);
|
||||||
|
if (msg != InventoryResult.Ok && bag != ItemConst.NullBag)
|
||||||
|
msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, lootItem.itemid, lootItem.count);
|
||||||
|
if (msg != InventoryResult.Ok)
|
||||||
|
{
|
||||||
|
player.SendEquipError(msg, null, null, lootItem.itemid);
|
||||||
|
allLooted = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item pItem = player.StoreNewItem(dest, lootItem.itemid, true, lootItem.randomBonusListId, null, lootItem.context, lootItem.BonusListIDs);
|
||||||
|
if (pItem != null)
|
||||||
|
{
|
||||||
|
player.SendNewItem(pItem, lootItem.count, false, createdByPlayer, broadcast, GetDungeonEncounterId());
|
||||||
|
player.ApplyItemLootedSpell(pItem, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
player.ApplyItemLootedSpell(Global.ObjectMgr.GetItemTemplate(lootItem.itemid));
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LootItemType.Currency:
|
||||||
|
player.ModifyCurrency(lootItem.itemid, (int)lootItem.count, CurrencyGainSource.Loot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (ffaitem != null)
|
if (ffaitem != null)
|
||||||
ffaitem.is_looted = true;
|
ffaitem.is_looted = true;
|
||||||
|
|
||||||
@@ -719,15 +813,6 @@ namespace Game.Loots
|
|||||||
lootItem.is_looted = true;
|
lootItem.is_looted = true;
|
||||||
|
|
||||||
--unlootedCount;
|
--unlootedCount;
|
||||||
|
|
||||||
Item pItem = player.StoreNewItem(dest, lootItem.itemid, true, lootItem.randomBonusListId, null, lootItem.context, lootItem.BonusListIDs);
|
|
||||||
if (pItem != null)
|
|
||||||
{
|
|
||||||
player.SendNewItem(pItem, lootItem.count, false, createdByPlayer, broadcast, GetDungeonEncounterId());
|
|
||||||
player.ApplyItemLootedSpell(pItem, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
player.ApplyItemLootedSpell(Global.ObjectMgr.GetItemTemplate(lootItem.itemid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return allLooted;
|
return allLooted;
|
||||||
@@ -783,7 +868,7 @@ namespace Game.Loots
|
|||||||
|
|
||||||
foreach (LootItem item in items)
|
foreach (LootItem item in items)
|
||||||
{
|
{
|
||||||
if (!item.follow_loot_rules || item.freeforall)
|
if (!item.follow_loot_rules || item.freeforall || item.type != LootItemType.Item)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item.itemid);
|
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item.itemid);
|
||||||
@@ -1014,12 +1099,8 @@ namespace Game.Loots
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
var ffaItems = GetPlayerFFAItems().LookupByKey(player.GetGUID());
|
var ffaItems = GetPlayerFFAItems().LookupByKey(player.GetGUID());
|
||||||
if (ffaItems != null)
|
if (ffaItems != null && ffaItems.Any(ffaItem => !ffaItem.is_looted))
|
||||||
{
|
return true;
|
||||||
bool hasFfaItem = ffaItems.Any(ffaItem => !ffaItem.is_looted);
|
|
||||||
if (hasFfaItem)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1046,12 +1127,34 @@ namespace Game.Loots
|
|||||||
if (!uiType.HasValue)
|
if (!uiType.HasValue)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LootItemData lootItem = new();
|
switch (item.type)
|
||||||
lootItem.LootListID = (byte)item.LootListId;
|
{
|
||||||
lootItem.UIType = uiType.Value;
|
case LootItemType.Item:
|
||||||
lootItem.Quantity = item.count;
|
{
|
||||||
lootItem.Loot = new(item);
|
LootItemData lootItem = new();
|
||||||
packet.Items.Add(lootItem);
|
lootItem.LootListID = (byte)item.LootListId;
|
||||||
|
lootItem.UIType = uiType.Value;
|
||||||
|
lootItem.Quantity = item.count;
|
||||||
|
lootItem.Loot = new(item);
|
||||||
|
packet.Items.Add(lootItem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LootItemType.Currency:
|
||||||
|
{
|
||||||
|
LootCurrency lootCurrency = new();
|
||||||
|
lootCurrency.CurrencyID = item.itemid;
|
||||||
|
lootCurrency.Quantity = item.count;
|
||||||
|
lootCurrency.LootListID = (byte)item.LootListId;
|
||||||
|
lootCurrency.UIType = (byte)uiType.Value;
|
||||||
|
|
||||||
|
// fake visible quantity for SPELL_AURA_MOD_CURRENCY_CATEGORY_GAIN_PCT - handled in Player::ModifyCurrency
|
||||||
|
lootCurrency.Quantity = (uint)((float)lootCurrency.Quantity * viewer.GetTotalAuraMultiplierByMiscValue(AuraType.ModCurrencyCategoryGainPct, CliDB.CurrencyTypesStorage.LookupByKey(item.itemid).CategoryID));
|
||||||
|
packet.Currencies.Add(lootCurrency);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,18 +35,19 @@ namespace Game.Loots
|
|||||||
StoredLootContainer storedContainer = _lootItemStorage[key];
|
StoredLootContainer storedContainer = _lootItemStorage[key];
|
||||||
|
|
||||||
LootItem lootItem = new();
|
LootItem lootItem = new();
|
||||||
lootItem.itemid = result.Read<uint>(1);
|
lootItem.type = (LootItemType)result.Read<sbyte>(1);
|
||||||
lootItem.count = result.Read<byte>(2);
|
lootItem.itemid = result.Read<uint>(2);
|
||||||
lootItem.LootListId = result.Read<uint>(3);
|
lootItem.count = result.Read<byte>(3);
|
||||||
lootItem.follow_loot_rules = result.Read<bool>(4);
|
lootItem.LootListId = result.Read<uint>(4);
|
||||||
lootItem.freeforall = result.Read<bool>(5);
|
lootItem.follow_loot_rules = result.Read<bool>(5);
|
||||||
lootItem.is_blocked = result.Read<bool>(6);
|
lootItem.freeforall = result.Read<bool>(6);
|
||||||
lootItem.is_counted = result.Read<bool>(7);
|
lootItem.is_blocked = result.Read<bool>(7);
|
||||||
lootItem.is_underthreshold = result.Read<bool>(8);
|
lootItem.is_counted = result.Read<bool>(8);
|
||||||
lootItem.needs_quest = result.Read<bool>(9);
|
lootItem.is_underthreshold = result.Read<bool>(9);
|
||||||
lootItem.randomBonusListId = result.Read<uint>(10);
|
lootItem.needs_quest = result.Read<bool>(10);
|
||||||
lootItem.context = (ItemContext)result.Read<byte>(11);
|
lootItem.randomBonusListId = result.Read<uint>(11);
|
||||||
StringArray bonusLists = new(result.Read<string>(12), ' ');
|
lootItem.context = (ItemContext)result.Read<byte>(12);
|
||||||
|
StringArray bonusLists = new(result.Read<string>(13), ' ');
|
||||||
|
|
||||||
foreach (string str in bonusLists)
|
foreach (string str in bonusLists)
|
||||||
lootItem.BonusListIDs.Add(uint.Parse(str));
|
lootItem.BonusListIDs.Add(uint.Parse(str));
|
||||||
@@ -177,12 +178,12 @@ namespace Game.Loots
|
|||||||
DB.Characters.CommitTransaction(trans);
|
DB.Characters.CommitTransaction(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveStoredLootItemForContainer(ulong containerId, uint itemId, uint count, uint itemIndex)
|
public void RemoveStoredLootItemForContainer(ulong containerId, LootItemType type, uint itemId, uint count, uint itemIndex)
|
||||||
{
|
{
|
||||||
if (!_lootItemStorage.ContainsKey(containerId))
|
if (!_lootItemStorage.ContainsKey(containerId))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_lootItemStorage[containerId].RemoveItem(itemId, count, itemIndex);
|
_lootItemStorage[containerId].RemoveItem(type, itemId, count, itemIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddNewStoredLoot(ulong containerId, Loot loot, Player player)
|
public void AddNewStoredLoot(ulong containerId, Loot loot, Player player)
|
||||||
@@ -248,25 +249,26 @@ namespace Game.Loots
|
|||||||
|
|
||||||
PreparedStatement stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_ITEMCONTAINER_ITEMS);
|
PreparedStatement stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_ITEMCONTAINER_ITEMS);
|
||||||
|
|
||||||
// container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix
|
// container_id, item_type, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix
|
||||||
stmt.AddValue(0, _containerId);
|
stmt.AddValue(0, _containerId);
|
||||||
stmt.AddValue(1, lootItem.itemid);
|
stmt.AddValue(1, (sbyte)lootItem.type);
|
||||||
stmt.AddValue(2, lootItem.count);
|
stmt.AddValue(2, lootItem.itemid);
|
||||||
stmt.AddValue(3, lootItem.LootListId);
|
stmt.AddValue(3, lootItem.count);
|
||||||
stmt.AddValue(4, lootItem.follow_loot_rules);
|
stmt.AddValue(4, lootItem.LootListId);
|
||||||
stmt.AddValue(5, lootItem.freeforall);
|
stmt.AddValue(5, lootItem.follow_loot_rules);
|
||||||
stmt.AddValue(6, lootItem.is_blocked);
|
stmt.AddValue(6, lootItem.freeforall);
|
||||||
stmt.AddValue(7, lootItem.is_counted);
|
stmt.AddValue(7, lootItem.is_blocked);
|
||||||
stmt.AddValue(8, lootItem.is_underthreshold);
|
stmt.AddValue(8, lootItem.is_counted);
|
||||||
stmt.AddValue(9, lootItem.needs_quest);
|
stmt.AddValue(9, lootItem.is_underthreshold);
|
||||||
stmt.AddValue(10, lootItem.randomBonusListId);
|
stmt.AddValue(10, lootItem.needs_quest);
|
||||||
stmt.AddValue(11, (uint)lootItem.context);
|
stmt.AddValue(11, lootItem.randomBonusListId);
|
||||||
|
stmt.AddValue(12, (uint)lootItem.context);
|
||||||
|
|
||||||
StringBuilder bonusListIDs = new();
|
StringBuilder bonusListIDs = new();
|
||||||
foreach (int bonusListID in lootItem.BonusListIDs)
|
foreach (int bonusListID in lootItem.BonusListIDs)
|
||||||
bonusListIDs.Append(bonusListID + ' ');
|
bonusListIDs.Append(bonusListID + ' ');
|
||||||
|
|
||||||
stmt.AddValue(12, bonusListIDs.ToString());
|
stmt.AddValue(13, bonusListIDs.ToString());
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +297,7 @@ namespace Game.Loots
|
|||||||
DB.Characters.Execute(stmt);
|
DB.Characters.Execute(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveItem(uint itemId, uint count, uint itemIndex)
|
public void RemoveItem(LootItemType type, uint itemId, uint count, uint itemIndex)
|
||||||
{
|
{
|
||||||
var bounds = _lootItems.LookupByKey(itemId);
|
var bounds = _lootItems.LookupByKey(itemId);
|
||||||
foreach (var itr in bounds)
|
foreach (var itr in bounds)
|
||||||
@@ -310,9 +312,10 @@ namespace Game.Loots
|
|||||||
// Deletes a single item associated with an openable item from the DB
|
// Deletes a single item associated with an openable item from the DB
|
||||||
PreparedStatement stmt = CharacterDatabase.GetPreparedStatement(CharStatements.DEL_ITEMCONTAINER_ITEM);
|
PreparedStatement stmt = CharacterDatabase.GetPreparedStatement(CharStatements.DEL_ITEMCONTAINER_ITEM);
|
||||||
stmt.AddValue(0, _containerId);
|
stmt.AddValue(0, _containerId);
|
||||||
stmt.AddValue(1, itemId);
|
stmt.AddValue(1, (sbyte)type);
|
||||||
stmt.AddValue(2, count);
|
stmt.AddValue(2, itemId);
|
||||||
stmt.AddValue(3, itemIndex);
|
stmt.AddValue(3, count);
|
||||||
|
stmt.AddValue(4, itemIndex);
|
||||||
DB.Characters.Execute(stmt);
|
DB.Characters.Execute(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -512,6 +512,14 @@ namespace Game.Loots
|
|||||||
}
|
}
|
||||||
case LootStoreItemType.Reference:
|
case LootStoreItemType.Reference:
|
||||||
return RandomHelper.randChance(chance * (rate ? WorldConfig.GetFloatValue(WorldCfg.RateDropItemReferenced) : 1.0f));
|
return RandomHelper.randChance(chance * (rate ? WorldConfig.GetFloatValue(WorldCfg.RateDropItemReferenced) : 1.0f));
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
|
{
|
||||||
|
CurrencyTypesRecord currency = CliDB.CurrencyTypesStorage.LookupByKey(itemid);
|
||||||
|
|
||||||
|
float qualityModifier = currency != null && rate && QualityToRate[currency.Quality] != WorldCfg.Max ? WorldConfig.GetFloatValue(QualityToRate[currency.Quality]) : 1.0f;
|
||||||
|
|
||||||
|
return RandomHelper.randChance(chance * qualityModifier);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -523,7 +531,7 @@ namespace Game.Loots
|
|||||||
{
|
{
|
||||||
if (mincount == 0)
|
if (mincount == 0)
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Sql, "Table '{0}' entry {1} item {2}: wrong mincount ({3}) - skipped", store.GetName(), entry, itemid, mincount);
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: wrong mincount ({mincount}) - skipped");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,38 +541,64 @@ namespace Game.Loots
|
|||||||
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(itemid);
|
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(itemid);
|
||||||
if (proto == null)
|
if (proto == null)
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Sql, "Table '{0}' entry {1} item {2}: item does not exist - skipped", store.GetName(), entry, itemid);
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: item does not exist - skipped");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chance == 0 && groupid == 0) // Zero chance is allowed for grouped entries only
|
if (chance == 0 && groupid == 0) // Zero chance is allowed for grouped entries only
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Sql, "Table '{0}' entry {1} item {2}: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: equal-chanced grouped entry, but group not defined - skipped");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chance != 0 && chance < 0.000001f) // loot with low chance
|
if (chance != 0 && chance < 0.000001f) // loot with low chance
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Sql, "Table '{0}' entry {1} item {2}: low chance ({3}) - skipped",
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: low chance ({chance}) - skipped");
|
||||||
store.GetName(), entry, itemid, chance);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxcount < mincount) // wrong max count
|
if (maxcount < mincount) // wrong max count
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Sql, "Table '{0}' entry {1} item {2}: max count ({3}) less that min count ({4}) - skipped", store.GetName(), entry, itemid, maxcount, mincount);
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: max count ({maxcount}) less that min count ({mincount}) - skipped");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LootStoreItemType.Reference:
|
case LootStoreItemType.Reference:
|
||||||
if (needs_quest)
|
if (needs_quest)
|
||||||
Log.outError(LogFilter.Sql, "Table '{0}' entry {1} item {2}: quest chance will be treated as non-quest chance", store.GetName(), entry, itemid);
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: quest chance will be treated as non-quest chance");
|
||||||
else if (chance == 0) // no chance for the reference
|
else if (chance == 0) // no chance for the reference
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Sql, "Table '{0}' entry {1} item {2}: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: zero chance is specified for a reference, skipped");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
|
{
|
||||||
|
if (!CliDB.CurrencyTypesStorage.HasRecord(itemid))
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: currency does not exist - skipped");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chance == 0 && groupid == 0) // Zero chance is allowed for grouped entries only
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: equal-chanced grouped entry, but group not defined - skipped");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chance != 0 && chance < 0.0001f) // loot with low chance
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: low chance ({chance}) - skipped");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxcount < mincount) // wrong max count
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} ItemType {type} Item {itemid}: MaxCount ({maxcount}) less that MinCount ({mincount}) - skipped");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} Item {itemid}: invalid ItemType {type}, skipped");
|
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} Item {itemid}: invalid ItemType {type}, skipped");
|
||||||
return false;
|
return false;
|
||||||
@@ -757,12 +791,10 @@ namespace Game.Loots
|
|||||||
switch (item.type)
|
switch (item.type)
|
||||||
{
|
{
|
||||||
case LootStoreItemType.Item:
|
case LootStoreItemType.Item:
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
// Plain entries (not a reference, not grouped)
|
// Plain entries (not a reference, not grouped)
|
||||||
// Chance is already checked, just add
|
// Chance is already checked, just add
|
||||||
if (personalLooter == null
|
if (personalLooter == null || LootItem.AllowedForPlayer(personalLooter, item, true))
|
||||||
|| LootItem.AllowedForPlayer(personalLooter, null, item.itemid, item.needs_quest,
|
|
||||||
!item.needs_quest || Global.ObjectMgr.GetItemTemplate(item.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
|
||||||
true, item.conditions))
|
|
||||||
loot.AddItem(item);
|
loot.AddItem(item);
|
||||||
break;
|
break;
|
||||||
case LootStoreItemType.Reference:
|
case LootStoreItemType.Reference:
|
||||||
@@ -813,13 +845,7 @@ namespace Game.Loots
|
|||||||
{
|
{
|
||||||
// Plain entries (not a reference, not grouped)
|
// Plain entries (not a reference, not grouped)
|
||||||
// Chance is already checked, just add
|
// Chance is already checked, just add
|
||||||
var lootersForItem = getLootersForItem(looter =>
|
var lootersForItem = getLootersForItem(looter => LootItem.AllowedForPlayer(looter, item, true));
|
||||||
{
|
|
||||||
return LootItem.AllowedForPlayer(looter, null, item.itemid, item.needs_quest,
|
|
||||||
!item.needs_quest || Global.ObjectMgr.GetItemTemplate(item.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
|
||||||
true, item.conditions);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!lootersForItem.Empty())
|
if (!lootersForItem.Empty())
|
||||||
{
|
{
|
||||||
Player chosenLooter = lootersForItem.SelectRandom();
|
Player chosenLooter = lootersForItem.SelectRandom();
|
||||||
@@ -860,6 +886,16 @@ namespace Game.Loots
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
|
{
|
||||||
|
// Plain entries (not a reference, not grouped)
|
||||||
|
// Chance is already checked, just add
|
||||||
|
var lootersForItem = getLootersForItem(looter => LootItem.AllowedForPlayer(looter, item, true));
|
||||||
|
|
||||||
|
foreach (Player looter in lootersForItem)
|
||||||
|
personalLoot[looter].AddItem(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -901,9 +937,7 @@ namespace Game.Loots
|
|||||||
switch (lootStoreItem.type)
|
switch (lootStoreItem.type)
|
||||||
{
|
{
|
||||||
case LootStoreItemType.Item:
|
case LootStoreItemType.Item:
|
||||||
if (LootItem.AllowedForPlayer(player, null, lootStoreItem.itemid, lootStoreItem.needs_quest,
|
if (LootItem.AllowedForPlayer(player, lootStoreItem, strictUsabilityCheck))
|
||||||
!lootStoreItem.needs_quest || Global.ObjectMgr.GetItemTemplate(lootStoreItem.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
|
||||||
strictUsabilityCheck, lootStoreItem.conditions))
|
|
||||||
return true; // active quest drop found
|
return true; // active quest drop found
|
||||||
break;
|
break;
|
||||||
case LootStoreItemType.Reference:
|
case LootStoreItemType.Reference:
|
||||||
@@ -931,6 +965,22 @@ namespace Game.Loots
|
|||||||
// Copies the conditions list from a template item to a LootItem
|
// Copies the conditions list from a template item to a LootItem
|
||||||
foreach (var item in Entries)
|
foreach (var item in Entries)
|
||||||
{
|
{
|
||||||
|
switch (item.type)
|
||||||
|
{
|
||||||
|
case LootStoreItemType.Item:
|
||||||
|
if (li.type != LootItemType.Item)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case LootStoreItemType.Reference:
|
||||||
|
continue;
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
|
if (li.type != LootItemType.Currency)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.itemid != li.itemid)
|
if (item.itemid != li.itemid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -957,6 +1007,7 @@ namespace Game.Loots
|
|||||||
switch (item.type)
|
switch (item.type)
|
||||||
{
|
{
|
||||||
case LootStoreItemType.Item:
|
case LootStoreItemType.Item:
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
if (item.needs_quest)
|
if (item.needs_quest)
|
||||||
return true; // quest drop found
|
return true; // quest drop found
|
||||||
break;
|
break;
|
||||||
@@ -1009,6 +1060,10 @@ namespace Game.Loots
|
|||||||
if (Referenced.HasQuestDropForPlayer(store, player, item.groupid))
|
if (Referenced.HasQuestDropForPlayer(store, player, item.groupid))
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
|
if (player.HasQuestForCurrency(item.itemid))
|
||||||
|
return true; // active quest drop found
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1124,10 +1179,24 @@ namespace Game.Loots
|
|||||||
|
|
||||||
public bool HasQuestDropForPlayer(Player player)
|
public bool HasQuestDropForPlayer(Player player)
|
||||||
{
|
{
|
||||||
if (ExplicitlyChanced.Any(item => player.HasQuestForItem(item.itemid)))
|
var hasQuestForLootItem = (LootStoreItem item) =>
|
||||||
|
{
|
||||||
|
switch (item.type)
|
||||||
|
{
|
||||||
|
case LootStoreItemType.Item:
|
||||||
|
return player.HasQuestForItem(item.itemid);
|
||||||
|
case LootStoreItemType.Currency:
|
||||||
|
return player.HasQuestForCurrency(item.itemid);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ExplicitlyChanced.Any(hasQuestForLootItem))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (EqualChanced.Any(item => player.HasQuestForItem(item.itemid)))
|
if (EqualChanced.Any(hasQuestForLootItem))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1239,15 +1308,11 @@ namespace Game.Loots
|
|||||||
public bool HasDropForPlayer(Player player, bool strictUsabilityCheck)
|
public bool HasDropForPlayer(Player player, bool strictUsabilityCheck)
|
||||||
{
|
{
|
||||||
foreach (LootStoreItem lootStoreItem in ExplicitlyChanced)
|
foreach (LootStoreItem lootStoreItem in ExplicitlyChanced)
|
||||||
if (LootItem.AllowedForPlayer(player, null, lootStoreItem.itemid, lootStoreItem.needs_quest,
|
if (LootItem.AllowedForPlayer(player, lootStoreItem, strictUsabilityCheck))
|
||||||
!lootStoreItem.needs_quest || Global.ObjectMgr.GetItemTemplate(lootStoreItem.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
|
||||||
strictUsabilityCheck, lootStoreItem.conditions))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
foreach (LootStoreItem lootStoreItem in EqualChanced)
|
foreach (LootStoreItem lootStoreItem in EqualChanced)
|
||||||
if (LootItem.AllowedForPlayer(player, null, lootStoreItem.itemid, lootStoreItem.needs_quest,
|
if (LootItem.AllowedForPlayer(player, lootStoreItem, strictUsabilityCheck))
|
||||||
!lootStoreItem.needs_quest || Global.ObjectMgr.GetItemTemplate(lootStoreItem.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
|
||||||
strictUsabilityCheck, lootStoreItem.conditions))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1268,9 +1333,7 @@ namespace Game.Loots
|
|||||||
if ((item.lootmode & _lootMode) == 0)
|
if ((item.lootmode & _lootMode) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (_personalLooter != null && !LootItem.AllowedForPlayer(_personalLooter, null, item.itemid, item.needs_quest,
|
if (_personalLooter != null && !LootItem.AllowedForPlayer(_personalLooter, item, true))
|
||||||
!item.needs_quest || Global.ObjectMgr.GetItemTemplate(item.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
|
||||||
true, item.conditions))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user