Skip to content

Commit

Permalink
Add stats support for 2 same item id in same loot entry.
Browse files Browse the repository at this point in the history
  • Loading branch information
cyberium committed Jan 31, 2024
1 parent 5373579 commit 8e76a71
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 18 deletions.
6 changes: 4 additions & 2 deletions src/game/Chat/Level2.cpp
Expand Up @@ -5547,7 +5547,7 @@ bool ChatHandler::LootStatsHelper(char* args, bool full)
" -> '.loot stats [#amountOfDropCheck]'\n"
" else you have to provide loot type and loot entry\n"
" -> '.loot stats lootType #lootEntry [#amountOfDropCheck]\n'"
" -> lootType can be 'creature', 'gameobject', 'fishing', 'item', 'pickpocketing', 'skinning', 'disenchanting', 'prospecting', 'mail', 'reference'\n"
" -> lootType can be 'creature', 'gameobject', 'fishing', 'item', 'pickpocketing', 'skinning', 'disenchanting', 'prospecting', 'milling', 'mail', 'spell', 'reference'\n"
" -> ex: '.loot stats c 448' will show Hogger loot table";

auto showError = [&]()
Expand Down Expand Up @@ -5591,8 +5591,10 @@ bool ChatHandler::LootStatsHelper(char* args, bool full)
lootStore = "item";
else if (lootType.rfind("pi", 0) == 0)
lootStore = "pickpocketing";
else if (lootType.rfind("s", 0) == 0)
else if (lootType.rfind("sk", 0) == 0)
lootStore = "skinning";
else if (lootType.rfind("sp", 0) == 0)
lootStore = "spell";
else if (lootType.rfind("dis", 0) == 0)
lootStore = "disenchanting";
else if (lootType.rfind("pr", 0) == 0)
Expand Down
28 changes: 18 additions & 10 deletions src/game/Loot/LootMgr.cpp
Expand Up @@ -128,6 +128,7 @@ void LootStore::LoadLootTable()
{
LootTemplateMap::const_iterator tplEntriesItr;
uint32 count = 0;
std::map<uint32, uint32> validItems;

// Clearing store (for reloading case)
Clear();
Expand Down Expand Up @@ -179,7 +180,8 @@ void LootStore::LoadLootTable()
continue;

// Add the item to the loot store
m_LootTemplates[entry].AddEntry(LootStoreItem(item, chanceOrQuestChance, group, conditionId, mincountOrRef, maxcount));
++validItems[entry];
m_LootTemplates[entry].AddEntry(LootStoreItem(validItems[entry], item, chanceOrQuestChance, group, conditionId, mincountOrRef, maxcount));
++count;
}
while (queryResult->NextRow());
Expand Down Expand Up @@ -343,7 +345,7 @@ bool LootStore::IsValidItemTemplate(uint32 entry, uint32 itemId, uint32 group, i
return false;
}

if (maxCount < mincountOrRef) // wrong max count
if (maxCount < uint32(mincountOrRef)) // wrong max count
{
sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", GetName(), entry, itemId, uint32(maxCount), mincountOrRef);
return false;
Expand Down Expand Up @@ -2603,7 +2605,7 @@ void LootTemplate::LootGroup::Process(Loot& loot, Player const* lootOwner, bool
loot.AddItem(*item);
// only used if we want some stats
if (groupStats)
groupStats->IncItemCount(item->group, item->itemid);
groupStats->IncItemCount(item->group, std::make_pair(item->itemid, item->itemIndex));
}
else
{
Expand All @@ -2619,7 +2621,7 @@ void LootTemplate::LootGroup::Process(Loot& loot, Player const* lootOwner, bool
lsData = std::make_unique<LootStatsData>(item->mincountOrRef, lootStatsData->stats);

// no need to check groupStats here, if we have a lootStatsPair->first, we have a lootStatsPair->second
groupStats->IncItemCount(item->group, item->mincountOrRef); // register the reference as a loot
groupStats->IncItemCount(item->group, std::make_pair(item->mincountOrRef, item->itemIndex)); // register the reference as a loot
}

for (uint32 loop = 0; loop < item->maxcount; ++loop)
Expand Down Expand Up @@ -2734,7 +2736,7 @@ void LootTemplate::Process(Loot& loot, Player const* lootOwner, bool rate, LootS
lsData = std::make_unique<LootStatsData>(Entrie.mincountOrRef, lootStatsData->stats);

// no need to check groupStats here, if we have a lootStatsPair->first, we have a lootStatsPair->second
groupStats->IncItemCount(0, Entrie.mincountOrRef); // register the reference as a loot
groupStats->IncItemCount(0, std::make_pair(Entrie.mincountOrRef, Entrie.itemIndex)); // register the reference as a loot
}

for (uint32 loop = 0; loop < Entrie.maxcount; ++loop) // Ref multiplicator
Expand All @@ -2745,7 +2747,7 @@ void LootTemplate::Process(Loot& loot, Player const* lootOwner, bool rate, LootS
loot.AddItem(Entrie); // Chance is already checked, just add
// only used if we want some stats
if (groupStats)
groupStats->IncItemCount(0, Entrie.itemid);
groupStats->IncItemCount(0, std::make_pair(Entrie.itemid, Entrie.itemIndex));
}
}

Expand Down Expand Up @@ -3361,17 +3363,23 @@ void LootMgr::CheckDropStats(ChatHandler& chat, uint32 amountOfCheck, uint32 loo

lootStatsInfo->lootIdOrRef = lootIdOrRef;

// for each group, set the items stats and sort them
// set the items stats and sort them for each group
for (auto& group : lootRef.second.groups)
{
uint32 groupId = group.first;
auto& groupStats = lootStatsInfo->groupStats[groupId];
auto& groupStats = group.second;
auto& fullGroupStats = lootStatsInfo->groupStats[groupId];

// fill the group stats with the items stats
groupStats.insert(groupStats.end(), group.second.begin(), group.second.end());
for (const auto& kv : groupStats)
{
const auto& itemId = kv.first;
const auto& count = kv.second;
fullGroupStats.emplace_back(itemId.first, count);
}

// sort the items stats
groupStats.sort(
fullGroupStats.sort(
[](LootStatsInfo::ItemStats const& a, LootStatsInfo::ItemStats const& b)
{ return a.second > b.second; }
);
Expand Down
14 changes: 8 additions & 6 deletions src/game/Loot/LootMgr.h
Expand Up @@ -129,14 +129,15 @@ struct LootStats
// itemId and count
struct GroupStats
{
using ItemStatsPair = std::map<int32, uint32>;
using GroupStatsMap = std::map<uint32, ItemStatsPair>;
using ItemIndex = std::pair<int32, uint32>;
using ItemStatsMap = std::map<ItemIndex, uint32>;
using GroupStatsMap = std::map<uint32, ItemStatsMap>;

GroupStatsMap groups;

void IncItemCount(uint32 group, int32 itemId)
void IncItemCount(uint32 group, ItemIndex itemIdx)
{
++groups[group][itemId];
++groups[group][itemIdx];
}
};

Expand Down Expand Up @@ -201,6 +202,7 @@ typedef std::unordered_map<uint32, GroupLootRoll> GroupLootRollMap;

struct LootStoreItem
{
uint32 itemIndex; // index in loot store
uint32 itemid; // id of the item
float chance; // always positive, chance to drop for both quest and non-quest items, chance to be used for refs
int32 mincountOrRef; // mincount for drop items (positive) or minus referenced TemplateleId (negative)
Expand All @@ -211,8 +213,8 @@ struct LootStoreItem

// Constructor, converting ChanceOrQuestChance -> (chance, needs_quest)
// displayid is filled in IsValid() which must be called after
LootStoreItem(uint32 _itemid, float _chanceOrQuestChance, int8 _group, uint16 _conditionId, int32 _mincountOrRef, uint8 _maxcount)
: itemid(_itemid), chance(fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef),
LootStoreItem(uint32 _itemIndex, uint32 _itemid, float _chanceOrQuestChance, int8 _group, uint16 _conditionId, int32 _mincountOrRef, uint8 _maxcount)
: itemIndex(_itemIndex), itemid(_itemid), chance(fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef),
group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount), conditionId(_conditionId)
{}

Expand Down

0 comments on commit 8e76a71

Please sign in to comment.