Core/Loot: Implemented currency loot
Port From (https://github.com/TrinityCore/TrinityCore/commit/3e28ee080a1cf3c7cd332a8d1e0808505b4ea9d4)
This commit is contained in:
+177
-74
@@ -16,19 +16,47 @@ namespace Game.Loots
|
||||
{
|
||||
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(LootStoreItem li)
|
||||
{
|
||||
itemid = li.itemid;
|
||||
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;
|
||||
|
||||
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>
|
||||
@@ -39,10 +67,35 @@ namespace Game.Loots
|
||||
/// <returns></returns>
|
||||
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
|
||||
if (!conditions.Meets(player))
|
||||
@@ -96,6 +149,30 @@ namespace Game.Loots
|
||||
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)
|
||||
{
|
||||
allowedGUIDs.Add(player.GetGUID());
|
||||
@@ -174,23 +251,6 @@ namespace Game.Loots
|
||||
}
|
||||
|
||||
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
|
||||
@@ -630,7 +690,7 @@ namespace Game.Loots
|
||||
for (uint i = 0; i < loot.items.Count; ++i)
|
||||
{
|
||||
LootItem disenchantLoot = loot.LootItemInSlot(i, player);
|
||||
if (disenchantLoot != null)
|
||||
if (disenchantLoot != null && disenchantLoot.type == LootItemType.Item)
|
||||
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)
|
||||
public void AddItem(LootStoreItem item)
|
||||
{
|
||||
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item.itemid);
|
||||
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)
|
||||
switch (item.type)
|
||||
{
|
||||
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));
|
||||
case LootStoreItemType.Item:
|
||||
{
|
||||
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item.itemid);
|
||||
if (proto == null)
|
||||
return;
|
||||
|
||||
items.Add(generatedLoot);
|
||||
count -= proto.GetMaxStackSize();
|
||||
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);
|
||||
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())
|
||||
continue;
|
||||
|
||||
List<ItemPosCount> dest = new();
|
||||
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)
|
||||
switch (lootItem.type)
|
||||
{
|
||||
player.SendEquipError(msg, null, null, lootItem.itemid);
|
||||
allLooted = false;
|
||||
continue;
|
||||
}
|
||||
case LootItemType.Item:
|
||||
List<ItemPosCount> dest = new();
|
||||
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)
|
||||
ffaitem.is_looted = true;
|
||||
|
||||
@@ -719,15 +813,6 @@ namespace Game.Loots
|
||||
lootItem.is_looted = true;
|
||||
|
||||
--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;
|
||||
@@ -783,7 +868,7 @@ namespace Game.Loots
|
||||
|
||||
foreach (LootItem item in items)
|
||||
{
|
||||
if (!item.follow_loot_rules || item.freeforall)
|
||||
if (!item.follow_loot_rules || item.freeforall || item.type != LootItemType.Item)
|
||||
continue;
|
||||
|
||||
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item.itemid);
|
||||
@@ -1014,12 +1099,8 @@ namespace Game.Loots
|
||||
return true;
|
||||
|
||||
var ffaItems = GetPlayerFFAItems().LookupByKey(player.GetGUID());
|
||||
if (ffaItems != null)
|
||||
{
|
||||
bool hasFfaItem = ffaItems.Any(ffaItem => !ffaItem.is_looted);
|
||||
if (hasFfaItem)
|
||||
return true;
|
||||
}
|
||||
if (ffaItems != null && ffaItems.Any(ffaItem => !ffaItem.is_looted))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1046,12 +1127,34 @@ namespace Game.Loots
|
||||
if (!uiType.HasValue)
|
||||
continue;
|
||||
|
||||
LootItemData lootItem = new();
|
||||
lootItem.LootListID = (byte)item.LootListId;
|
||||
lootItem.UIType = uiType.Value;
|
||||
lootItem.Quantity = item.count;
|
||||
lootItem.Loot = new(item);
|
||||
packet.Items.Add(lootItem);
|
||||
switch (item.type)
|
||||
{
|
||||
case LootItemType.Item:
|
||||
{
|
||||
LootItemData lootItem = new();
|
||||
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];
|
||||
|
||||
LootItem lootItem = new();
|
||||
lootItem.itemid = result.Read<uint>(1);
|
||||
lootItem.count = result.Read<byte>(2);
|
||||
lootItem.LootListId = result.Read<uint>(3);
|
||||
lootItem.follow_loot_rules = result.Read<bool>(4);
|
||||
lootItem.freeforall = result.Read<bool>(5);
|
||||
lootItem.is_blocked = result.Read<bool>(6);
|
||||
lootItem.is_counted = result.Read<bool>(7);
|
||||
lootItem.is_underthreshold = result.Read<bool>(8);
|
||||
lootItem.needs_quest = result.Read<bool>(9);
|
||||
lootItem.randomBonusListId = result.Read<uint>(10);
|
||||
lootItem.context = (ItemContext)result.Read<byte>(11);
|
||||
StringArray bonusLists = new(result.Read<string>(12), ' ');
|
||||
lootItem.type = (LootItemType)result.Read<sbyte>(1);
|
||||
lootItem.itemid = result.Read<uint>(2);
|
||||
lootItem.count = result.Read<byte>(3);
|
||||
lootItem.LootListId = result.Read<uint>(4);
|
||||
lootItem.follow_loot_rules = result.Read<bool>(5);
|
||||
lootItem.freeforall = result.Read<bool>(6);
|
||||
lootItem.is_blocked = result.Read<bool>(7);
|
||||
lootItem.is_counted = result.Read<bool>(8);
|
||||
lootItem.is_underthreshold = result.Read<bool>(9);
|
||||
lootItem.needs_quest = result.Read<bool>(10);
|
||||
lootItem.randomBonusListId = result.Read<uint>(11);
|
||||
lootItem.context = (ItemContext)result.Read<byte>(12);
|
||||
StringArray bonusLists = new(result.Read<string>(13), ' ');
|
||||
|
||||
foreach (string str in bonusLists)
|
||||
lootItem.BonusListIDs.Add(uint.Parse(str));
|
||||
@@ -177,12 +178,12 @@ namespace Game.Loots
|
||||
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))
|
||||
return;
|
||||
|
||||
_lootItemStorage[containerId].RemoveItem(itemId, count, itemIndex);
|
||||
_lootItemStorage[containerId].RemoveItem(type, itemId, count, itemIndex);
|
||||
}
|
||||
|
||||
public void AddNewStoredLoot(ulong containerId, Loot loot, Player player)
|
||||
@@ -248,25 +249,26 @@ namespace Game.Loots
|
||||
|
||||
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(1, lootItem.itemid);
|
||||
stmt.AddValue(2, lootItem.count);
|
||||
stmt.AddValue(3, lootItem.LootListId);
|
||||
stmt.AddValue(4, lootItem.follow_loot_rules);
|
||||
stmt.AddValue(5, lootItem.freeforall);
|
||||
stmt.AddValue(6, lootItem.is_blocked);
|
||||
stmt.AddValue(7, lootItem.is_counted);
|
||||
stmt.AddValue(8, lootItem.is_underthreshold);
|
||||
stmt.AddValue(9, lootItem.needs_quest);
|
||||
stmt.AddValue(10, lootItem.randomBonusListId);
|
||||
stmt.AddValue(11, (uint)lootItem.context);
|
||||
stmt.AddValue(1, (sbyte)lootItem.type);
|
||||
stmt.AddValue(2, lootItem.itemid);
|
||||
stmt.AddValue(3, lootItem.count);
|
||||
stmt.AddValue(4, lootItem.LootListId);
|
||||
stmt.AddValue(5, lootItem.follow_loot_rules);
|
||||
stmt.AddValue(6, lootItem.freeforall);
|
||||
stmt.AddValue(7, lootItem.is_blocked);
|
||||
stmt.AddValue(8, lootItem.is_counted);
|
||||
stmt.AddValue(9, lootItem.is_underthreshold);
|
||||
stmt.AddValue(10, lootItem.needs_quest);
|
||||
stmt.AddValue(11, lootItem.randomBonusListId);
|
||||
stmt.AddValue(12, (uint)lootItem.context);
|
||||
|
||||
StringBuilder bonusListIDs = new();
|
||||
foreach (int bonusListID in lootItem.BonusListIDs)
|
||||
bonusListIDs.Append(bonusListID + ' ');
|
||||
|
||||
stmt.AddValue(12, bonusListIDs.ToString());
|
||||
stmt.AddValue(13, bonusListIDs.ToString());
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
@@ -295,7 +297,7 @@ namespace Game.Loots
|
||||
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);
|
||||
foreach (var itr in bounds)
|
||||
@@ -310,9 +312,10 @@ namespace Game.Loots
|
||||
// Deletes a single item associated with an openable item from the DB
|
||||
PreparedStatement stmt = CharacterDatabase.GetPreparedStatement(CharStatements.DEL_ITEMCONTAINER_ITEM);
|
||||
stmt.AddValue(0, _containerId);
|
||||
stmt.AddValue(1, itemId);
|
||||
stmt.AddValue(2, count);
|
||||
stmt.AddValue(3, itemIndex);
|
||||
stmt.AddValue(1, (sbyte)type);
|
||||
stmt.AddValue(2, itemId);
|
||||
stmt.AddValue(3, count);
|
||||
stmt.AddValue(4, itemIndex);
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
|
||||
|
||||
@@ -512,6 +512,14 @@ namespace Game.Loots
|
||||
}
|
||||
case LootStoreItemType.Reference:
|
||||
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:
|
||||
break;
|
||||
}
|
||||
@@ -523,7 +531,7 @@ namespace Game.Loots
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -533,38 +541,64 @@ namespace Game.Loots
|
||||
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(itemid);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (chance != 0 && chance < 0.000001f) // loot with low chance
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Table '{0}' entry {1} item {2}: low chance ({3}) - skipped",
|
||||
store.GetName(), entry, itemid, 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 '{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;
|
||||
}
|
||||
break;
|
||||
case LootStoreItemType.Reference:
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
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:
|
||||
Log.outError(LogFilter.Sql, $"Table '{store.GetName()}' Entry {entry} Item {itemid}: invalid ItemType {type}, skipped");
|
||||
return false;
|
||||
@@ -757,12 +791,10 @@ namespace Game.Loots
|
||||
switch (item.type)
|
||||
{
|
||||
case LootStoreItemType.Item:
|
||||
case LootStoreItemType.Currency:
|
||||
// Plain entries (not a reference, not grouped)
|
||||
// Chance is already checked, just add
|
||||
if (personalLooter == null
|
||||
|| LootItem.AllowedForPlayer(personalLooter, null, item.itemid, item.needs_quest,
|
||||
!item.needs_quest || Global.ObjectMgr.GetItemTemplate(item.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
||||
true, item.conditions))
|
||||
if (personalLooter == null || LootItem.AllowedForPlayer(personalLooter, item, true))
|
||||
loot.AddItem(item);
|
||||
break;
|
||||
case LootStoreItemType.Reference:
|
||||
@@ -813,13 +845,7 @@ namespace Game.Loots
|
||||
{
|
||||
// Plain entries (not a reference, not grouped)
|
||||
// Chance is already checked, just add
|
||||
var lootersForItem = getLootersForItem(looter =>
|
||||
{
|
||||
return LootItem.AllowedForPlayer(looter, null, item.itemid, item.needs_quest,
|
||||
!item.needs_quest || Global.ObjectMgr.GetItemTemplate(item.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
||||
true, item.conditions);
|
||||
});
|
||||
|
||||
var lootersForItem = getLootersForItem(looter => LootItem.AllowedForPlayer(looter, item, true));
|
||||
if (!lootersForItem.Empty())
|
||||
{
|
||||
Player chosenLooter = lootersForItem.SelectRandom();
|
||||
@@ -860,6 +886,16 @@ namespace Game.Loots
|
||||
}
|
||||
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:
|
||||
break;
|
||||
}
|
||||
@@ -901,9 +937,7 @@ namespace Game.Loots
|
||||
switch (lootStoreItem.type)
|
||||
{
|
||||
case LootStoreItemType.Item:
|
||||
if (LootItem.AllowedForPlayer(player, null, lootStoreItem.itemid, lootStoreItem.needs_quest,
|
||||
!lootStoreItem.needs_quest || Global.ObjectMgr.GetItemTemplate(lootStoreItem.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
||||
strictUsabilityCheck, lootStoreItem.conditions))
|
||||
if (LootItem.AllowedForPlayer(player, lootStoreItem, strictUsabilityCheck))
|
||||
return true; // active quest drop found
|
||||
break;
|
||||
case LootStoreItemType.Reference:
|
||||
@@ -931,6 +965,22 @@ namespace Game.Loots
|
||||
// Copies the conditions list from a template item to a LootItem
|
||||
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)
|
||||
continue;
|
||||
|
||||
@@ -957,6 +1007,7 @@ namespace Game.Loots
|
||||
switch (item.type)
|
||||
{
|
||||
case LootStoreItemType.Item:
|
||||
case LootStoreItemType.Currency:
|
||||
if (item.needs_quest)
|
||||
return true; // quest drop found
|
||||
break;
|
||||
@@ -1009,6 +1060,10 @@ namespace Game.Loots
|
||||
if (Referenced.HasQuestDropForPlayer(store, player, item.groupid))
|
||||
return true;
|
||||
break;
|
||||
case LootStoreItemType.Currency:
|
||||
if (player.HasQuestForCurrency(item.itemid))
|
||||
return true; // active quest drop found
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1124,10 +1179,24 @@ namespace Game.Loots
|
||||
|
||||
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;
|
||||
|
||||
if (EqualChanced.Any(item => player.HasQuestForItem(item.itemid)))
|
||||
if (EqualChanced.Any(hasQuestForLootItem))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -1239,15 +1308,11 @@ namespace Game.Loots
|
||||
public bool HasDropForPlayer(Player player, bool strictUsabilityCheck)
|
||||
{
|
||||
foreach (LootStoreItem lootStoreItem in ExplicitlyChanced)
|
||||
if (LootItem.AllowedForPlayer(player, null, lootStoreItem.itemid, lootStoreItem.needs_quest,
|
||||
!lootStoreItem.needs_quest || Global.ObjectMgr.GetItemTemplate(lootStoreItem.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
||||
strictUsabilityCheck, lootStoreItem.conditions))
|
||||
if (LootItem.AllowedForPlayer(player, lootStoreItem, strictUsabilityCheck))
|
||||
return true;
|
||||
|
||||
foreach (LootStoreItem lootStoreItem in EqualChanced)
|
||||
if (LootItem.AllowedForPlayer(player, null, lootStoreItem.itemid, lootStoreItem.needs_quest,
|
||||
!lootStoreItem.needs_quest || Global.ObjectMgr.GetItemTemplate(lootStoreItem.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
||||
strictUsabilityCheck, lootStoreItem.conditions))
|
||||
if (LootItem.AllowedForPlayer(player, lootStoreItem, strictUsabilityCheck))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -1268,9 +1333,7 @@ namespace Game.Loots
|
||||
if ((item.lootmode & _lootMode) == 0)
|
||||
return true;
|
||||
|
||||
if (_personalLooter != null && !LootItem.AllowedForPlayer(_personalLooter, null, item.itemid, item.needs_quest,
|
||||
!item.needs_quest || Global.ObjectMgr.GetItemTemplate(item.itemid).HasFlag(ItemFlagsCustom.FollowLootRules),
|
||||
true, item.conditions))
|
||||
if (_personalLooter != null && !LootItem.AllowedForPlayer(_personalLooter, item, true))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user