aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp42
-rw-r--r--src/server/game/DataStores/DB2Stores.h5
-rw-r--r--src/server/game/DataStores/DB2Structure.h16
-rw-r--r--src/server/game/DataStores/DB2fmt.h2
-rw-r--r--src/server/game/DataStores/DBCStores.cpp19
-rw-r--r--src/server/game/DataStores/DBCStores.h8
-rw-r--r--src/server/game/DataStores/DBCStructure.h19
-rw-r--r--src/server/game/DataStores/DBCfmt.h4
-rw-r--r--src/server/game/Entities/Item/Item.cpp13
-rw-r--r--src/server/game/Entities/Item/Item.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp50
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Groups/Group.cpp6
-rw-r--r--src/server/game/Handlers/LootHandler.cpp2
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp4
-rw-r--r--src/server/game/Instances/InstanceSaveMgr.cpp14
-rw-r--r--src/server/game/Loot/LootMgr.cpp14
-rw-r--r--src/server/game/Loot/LootMgr.h5
-rw-r--r--src/server/game/Maps/Map.cpp24
-rw-r--r--src/server/game/Maps/Map.h3
-rw-r--r--src/server/game/Maps/MapManager.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.h2
22 files changed, 177 insertions, 82 deletions
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index d6560e6679a..ee3becd0c28 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -29,11 +29,13 @@ DB2Storage<HolidaysEntry> sHolidaysStore(HolidaysEntryfmt);
DB2Storage<ItemEntry> sItemStore(Itemfmt);
DB2Storage<ItemAppearanceEntry> sItemAppearanceStore(ItemAppearanceEntryfmt);
DB2Storage<ItemBonusEntry> sItemBonusStore(ItemBonusEntryfmt);
+DB2Storage<ItemBonusTreeNodeEntry> sItemBonusTreeNodeStore(ItemBonusTreeNodeEntryfmt);
DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore(ItemCurrencyCostfmt);
DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
DB2Storage<ItemEffectEntry> sItemEffectStore(ItemEffectEntryfmt);
DB2Storage<ItemModifiedAppearanceEntry> sItemModifiedAppearanceStore(ItemModifiedAppearanceEntryfmt);
DB2Storage<ItemSparseEntry> sItemSparseStore(ItemSparsefmt);
+DB2Storage<ItemXBonusTreeEntry> sItemXBonusTreeStore(ItemXBonusTreeEntryfmt);
DB2Storage<KeyChainEntry> sKeyChainStore(KeyChainfmt);
DB2Storage<OverrideSpellDataEntry> sOverrideSpellDataStore(OverrideSpellDataEntryfmt);
DB2Storage<PhaseGroupEntry> sPhaseGroupStore(PhaseGroupEntryfmt);
@@ -127,11 +129,13 @@ void DB2Manager::LoadStores(std::string const& dataPath)
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemStore, db2Path, "Item.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemAppearanceStore, db2Path, "ItemAppearance.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemBonusStore, db2Path, "ItemBonus.db2");
+ LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemBonusTreeNodeStore, db2Path, "ItemBonusTreeNode.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemCurrencyCostStore, db2Path, "ItemCurrencyCost.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemExtendedCostStore, db2Path, "ItemExtendedCost.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemEffectStore, db2Path, "ItemEffect.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemModifiedAppearanceStore, db2Path, "ItemModifiedAppearance.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemSparseStore, db2Path, "Item-sparse.db2");
+ LoadDB2(availableDb2Locales, bad_db2_files, _stores, sItemXBonusTreeStore, db2Path, "ItemXBonusTree.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sKeyChainStore, db2Path, "KeyChain.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sOverrideSpellDataStore, db2Path, "OverrideSpellData.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sPhaseGroupStore, db2Path, "PhaseXPhaseGroup.db2");
@@ -151,11 +155,28 @@ void DB2Manager::LoadStores(std::string const& dataPath)
if (ItemBonusEntry const* bonus = sItemBonusStore.LookupEntry(i))
_itemBonusLists[bonus->BonusListID].push_back(bonus);
+ for (uint32 i = 0; i < sItemBonusTreeNodeStore.GetNumRows(); ++i)
+ {
+ if (ItemBonusTreeNodeEntry const* bonusTreeNode = sItemBonusTreeNodeStore.LookupEntry(i))
+ {
+ uint32 bonusTreeId = bonusTreeNode->BonusTreeID;
+ while (bonusTreeNode)
+ {
+ _itemBonusTrees[bonusTreeId].insert(bonusTreeNode);
+ bonusTreeNode = sItemBonusTreeNodeStore.LookupEntry(bonusTreeNode->SubTreeID);
+ }
+ }
+ }
+
for (uint32 i = 0; i < sItemModifiedAppearanceStore.GetNumRows(); ++i)
if (ItemModifiedAppearanceEntry const* appearanceMod = sItemModifiedAppearanceStore.LookupEntry(i))
if (ItemAppearanceEntry const* appearance = sItemAppearanceStore.LookupEntry(appearanceMod->AppearanceID))
_itemDisplayIDs[appearanceMod->ItemID | (appearanceMod->AppearanceModID << 24)] = appearance->DisplayID;
+ for (uint32 i = 0; i < sItemXBonusTreeStore.GetNumRows(); ++i)
+ if (ItemXBonusTreeEntry const* itemBonusTreeAssignment = sItemXBonusTreeStore.LookupEntry(i))
+ _itemToBonusTree.insert({ itemBonusTreeAssignment->ItemID, itemBonusTreeAssignment->BonusTreeID });
+
{
std::set<uint32> scalingCurves;
for (uint32 i = 0; i < sScalingStatDistributionStore.GetNumRows(); ++i)
@@ -395,6 +416,27 @@ uint32 DB2Manager::GetItemDisplayId(uint32 itemId, uint32 appearanceModId) const
return 0;
}
+std::set<uint32> DB2Manager::GetItemBonusTree(uint32 itemId, uint32 itemBonusTreeMod) const
+{
+ std::set<uint32> bonusListIDs;
+ auto itemIdRange = _itemToBonusTree.equal_range(itemId);
+ if (itemIdRange.first == itemIdRange.second)
+ return bonusListIDs;
+
+ for (auto itemTreeItr = itemIdRange.first; itemTreeItr != itemIdRange.second; ++itemTreeItr)
+ {
+ auto treeItr = _itemBonusTrees.find(itemTreeItr->second);
+ if (treeItr == _itemBonusTrees.end())
+ continue;
+
+ for (ItemBonusTreeNodeEntry const* bonusTreeNode : treeItr->second)
+ if (bonusTreeNode->BonusTreeModID == itemBonusTreeMod)
+ bonusListIDs.insert(bonusTreeNode->BonusListID);
+ }
+
+ return bonusListIDs;
+}
+
DB2Manager::ItemBonusList DB2Manager::GetItemBonusList(uint32 bonusListId) const
{
auto itr = _itemBonusLists.find(bonusListId);
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index d901082b69f..0f89ab919e0 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -69,6 +69,8 @@ public:
typedef std::unordered_map<uint32 /*itemId | appearanceMod << 24*/, uint32> ItemDisplayIdContainer;
typedef std::vector<ItemBonusEntry const*> ItemBonusList;
typedef std::unordered_map<uint32 /*bonusListId*/, ItemBonusList> ItemBonusListContainer;
+ typedef std::unordered_multimap<uint32 /*itemId*/, uint32 /*bonusTreeId*/> ItemToBonusTreeContainer;
+ typedef std::unordered_map<uint32, std::set<ItemBonusTreeNodeEntry const*>> ItemBonusTreeContainer;
typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer;
static DB2Manager& Instance()
@@ -87,6 +89,7 @@ public:
static char const* GetBroadcastTextValue(BroadcastTextEntry const* broadcastText, LocaleConstant locale = DEFAULT_LOCALE, uint8 gender = GENDER_MALE, bool forceGender = false);
uint32 GetHeirloomItemLevel(uint32 curveId, uint32 level) const;
uint32 GetItemDisplayId(uint32 itemId, uint32 appearanceModId) const;
+ std::set<uint32> GetItemBonusTree(uint32 itemId, uint32 itemBonusTreeMod) const;
ItemBonusList GetItemBonusList(uint32 bonusListId) const;
std::set<uint32> GetPhasesForGroup(uint32 group) const;
@@ -97,6 +100,8 @@ private:
HeirloomCurvesContainer _heirloomCurvePoints;
ItemDisplayIdContainer _itemDisplayIDs;
ItemBonusListContainer _itemBonusLists;
+ ItemToBonusTreeContainer _itemToBonusTree;
+ ItemBonusTreeContainer _itemBonusTrees;
PhaseGroupContainer _phasesByGroup;
};
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index cdc83b70b2b..2fa04ac20b1 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -99,6 +99,15 @@ struct ItemBonusEntry
uint32 Index; // 5
};
+struct ItemBonusTreeNodeEntry
+{
+ uint32 ID; // 0
+ uint32 BonusTreeID; // 1
+ uint32 BonusTreeModID; // 2
+ uint32 SubTreeID; // 3
+ uint32 BonusListID; // 4
+};
+
struct ItemCurrencyCostEntry
{
//uint32 ID; // 0
@@ -215,6 +224,13 @@ struct ItemSparseEntry
uint32 ItemNameDescriptionID; // 101
};
+struct ItemXBonusTreeEntry
+{
+ uint32 ID; // 0
+ uint32 ItemID; // 1
+ uint32 BonusTreeID; // 2
+};
+
#define KEYCHAIN_SIZE 32
struct KeyChainEntry
diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h
index d789f4a6622..9c8563eb720 100644
--- a/src/server/game/DataStores/DB2fmt.h
+++ b/src/server/game/DataStores/DB2fmt.h
@@ -24,11 +24,13 @@ char const HolidaysEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix";
char const Itemfmt[] = "niiiiiiii";
char const ItemAppearanceEntryfmt[] = "nii";
char const ItemBonusEntryfmt[] = "niiiii";
+char const ItemBonusTreeNodeEntryfmt[] = "niiii";
char const ItemCurrencyCostfmt[] = "xn";
char const ItemExtendedCostEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
char const ItemEffectEntryfmt[] = "niiiiiiii";
char const ItemModifiedAppearanceEntryfmt[] = "niiiii";
char const ItemSparsefmt[] = "niiiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffffffiiifisssssiiiiiiiiiiiiiiiiiiifiiifiii";
+char const ItemXBonusTreeEntryfmt[] = "nii";
char const KeyChainfmt[] = "nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
char const OverrideSpellDataEntryfmt[] = "niiiiiiiiiixx";
char const PhaseGroupEntryfmt[] = "nii";
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 066d5e20934..bea9a882215 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -501,11 +501,10 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sMapStore, dbcPath, "Map.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sMapDifficultyStore, dbcPath, "MapDifficulty.dbc");//19116
// fill data
- sMapDifficultyMap[0][0] = MapDifficulty(DIFFICULTY_NONE, 0, 0, false);//map 0 is missingg from MapDifficulty.dbc use this till its ported to sql
for (uint32 i = 0; i < sMapDifficultyStore.GetNumRows(); ++i)
if (MapDifficultyEntry const* entry = sMapDifficultyStore.LookupEntry(i))
- sMapDifficultyMap[entry->MapID][entry->DifficultyID] = MapDifficulty(entry->DifficultyID, entry->RaidDuration, entry->MaxPlayers, entry->Message_lang[0] > 0);
- sMapDifficultyStore.Clear();
+ sMapDifficultyMap[entry->MapID][entry->DifficultyID] = entry;
+ sMapDifficultyMap[0][0] = sMapDifficultyMap[1][0]; //map 0 is missing from MapDifficulty.dbc use this till its ported to sql
LoadDBC(availableDbcLocales, bad_dbc_files, sModifierTreeStore, dbcPath, "ModifierTree.dbc");//19342
LoadDBC(availableDbcLocales, bad_dbc_files, sMountCapabilityStore, dbcPath, "MountCapability.dbc");//19116
@@ -961,7 +960,7 @@ void Map2ZoneCoordinates(float& x, float& y, uint32 zone)
std::swap(x, y); // client have map coords swapped
}
-MapDifficulty const* GetDefaultMapDifficulty(uint32 mapID)
+MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapID)
{
auto itr = sMapDifficultyMap.find(mapID);
if (itr == sMapDifficultyMap.end())
@@ -977,13 +976,13 @@ MapDifficulty const* GetDefaultMapDifficulty(uint32 mapID)
continue;
if (difficulty->Flags & DIFFICULTY_FLAG_DEFAULT)
- return &p.second;
+ return p.second;
}
- return &itr->second.begin()->second;
+ return itr->second.begin()->second;
}
-MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty)
+MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty)
{
auto itr = sMapDifficultyMap.find(mapId);
if (itr == sMapDifficultyMap.end())
@@ -993,17 +992,17 @@ MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty)
if (diffItr == itr->second.end())
return nullptr;
- return &diffItr->second;
+ return diffItr->second;
}
-MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty)
+MapDifficultyEntry const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty)
{
DifficultyEntry const* diffEntry = sDifficultyStore.LookupEntry(difficulty);
if (!diffEntry)
return GetDefaultMapDifficulty(mapId);
uint32 tmpDiff = difficulty;
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff));
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff));
while (!mapDiff)
{
tmpDiff = diffEntry->FallbackDifficultyID;
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index 8f21d07eb1a..87a519c8c01 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -71,10 +71,10 @@ uint32 GetClassBySkillId(uint32 skillId);
uint32 GetSkillIdByClass(uint32 classId);
std::list<uint32> GetSpellsForLevels(uint32 classId, uint32 raceMask, uint32 specializationId, uint32 minLevel, uint32 maxLevel);
-typedef std::unordered_map<uint32, std::unordered_map<uint32, MapDifficulty>> MapDifficultyMap;
-MapDifficulty const* GetDefaultMapDifficulty(uint32 mapID);
-MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty);
-MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty);
+typedef std::unordered_map<uint32, std::unordered_map<uint32, MapDifficultyEntry const*>> MapDifficultyMap;
+MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapID);
+MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty);
+MapDifficultyEntry const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty);
uint32 GetLiquidFlags(uint32 liquidType);
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 15a2f537547..97481616225 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -634,7 +634,7 @@ struct DifficultyEntry
//uint32 GroupSizeDmgCurveID; // 9
//uint32 GroupSizeSpellPointsCurveID; // 10
//char const* NameLang; // 11
- //uint32 Unk; // 12
+ uint32 ItemBonusTreeModID; // 12
};
struct DungeonEncounterEntry
@@ -1266,7 +1266,9 @@ struct MapDifficultyEntry
uint32 RaidDuration; // 4 m_raidDuration in secs, 0 if no fixed reset time
uint32 MaxPlayers; // 5 m_maxPlayers some heroic versions have 0 when expected same amount as in normal version
uint32 LockID; // 6
- //uint32 Unk2; // 7
+ uint32 ItemBonusTreeModID; // 7
+
+ bool HasMessage() const { return Message_lang[0] != '\0'; }
};
struct MinorTalentEntry
@@ -2076,18 +2078,5 @@ struct VectorArray
typedef std::map<uint32, VectorArray> NameGenContainer;
-// Structures not used for casting to loaded DBC data and not required then packing
-struct MapDifficulty
-{
- MapDifficulty() : DifficultyID(0), resetTime(0), maxPlayers(0), hasErrorMessage(false) { }
- MapDifficulty(uint32 difficultyID, uint32 _resetTime, uint32 _maxPlayers, bool _hasErrorMessage)
- : DifficultyID(difficultyID), resetTime(_resetTime), maxPlayers(_maxPlayers), hasErrorMessage(_hasErrorMessage) { }
-
- uint32 DifficultyID;
- uint32 resetTime;
- uint32 maxPlayers;
- bool hasErrorMessage;
-};
-
typedef std::map<uint32, uint32> TalentSpellPosMap;
#endif
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index ef707738fd9..1d404d66311 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -52,7 +52,7 @@ char const Criteriafmt[] = "niiiiiiiixii";
char const CriteriaTreefmt[] = "niliixxx";
char const CurrencyTypesfmt[] = "nixxxxxiiixx";
char const DestructibleModelDatafmt[] = "nixxxixxxxixxxxixxxxxxxx";
-char const DifficultyFmt[] = "niiiixiixxxxx";
+char const DifficultyFmt[] = "niiiixiixxxxi";
char const DungeonEncounterfmt[] = "niiixsxxx";
char const DurabilityCostsfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
char const DurabilityQualityfmt[] = "nf";
@@ -114,7 +114,7 @@ char const LockEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
char const PhaseEntryfmt[] = "ni";
char const MailTemplateEntryfmt[] = "nxs";
char const MapEntryfmt[] = "nxiixxsixxixiffxiiiixx";
-char const MapDifficultyEntryfmt[] = "diisiiix";
+char const MapDifficultyEntryfmt[] = "diisiiii";
char const MinorTalentEntryfmt[] = "niii";
char const MovieEntryfmt[] = "nxxxx";
char const ModifierTreefmt[] = "niiiiii";
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index 5aa196e9fbc..b36948ffe19 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -503,10 +503,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi
for (char const* token : bonusListIDs)
{
uint32 bonusListID = atoul(token);
- DB2Manager::ItemBonusList bonuses = sDB2Manager.GetItemBonusList(bonusListID);
- AddDynamicValue(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS, bonusListID);
- for (ItemBonusEntry const* bonus : bonuses)
- _bonusData.AddBonus(bonus->Type, bonus->Value);
+ AddBonuses(bonusListID);
}
if (need_save) // normal item changed state set not work at loading
@@ -1797,6 +1794,14 @@ uint32 Item::GetVisibleAppearanceModId() const
return GetAppearanceModId();
}
+void Item::AddBonuses(uint32 bonusListID)
+{
+ DB2Manager::ItemBonusList bonuses = sDB2Manager.GetItemBonusList(bonusListID);
+ AddDynamicValue(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS, bonusListID);
+ for (ItemBonusEntry const* bonus : bonuses)
+ _bonusData.AddBonus(bonus->Type, bonus->Value);
+}
+
void BonusData::Initialize(ItemTemplate const* proto)
{
Quality = proto->GetQuality();
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 2188e582e0a..f687dae23da 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -261,6 +261,9 @@ class Item : public Object
bool IsBoundByEnchant() const;
virtual void SaveToDB(SQLTransaction& trans);
virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fields, uint32 entry);
+
+ void AddBonuses(uint32 bonusListID);
+
static void DeleteFromDB(SQLTransaction& trans, ObjectGuid::LowType itemGuid);
virtual void DeleteFromDB(SQLTransaction& trans);
static void DeleteFromInventoryDB(SQLTransaction& trans, ObjectGuid::LowType itemGuid);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 1116cdfcb98..7595757531b 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -11636,27 +11636,31 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje
}
// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
-Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update, int32 randomPropertyId, GuidSet const& allowedLooters)
+Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, int32 randomPropertyId /*= 0*/, GuidSet const& allowedLooters /*= GuidSet()*/, std::vector<int32> const& bonusListIDs /*= std::vector<int32>()*/)
{
uint32 count = 0;
- for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr)
+ for (ItemPosCountVec::const_iterator itr = pos.begin(); itr != pos.end(); ++itr)
count += itr->count;
- Item* pItem = Item::CreateItem(item, count, this);
- if (pItem)
+ Item* item = Item::CreateItem(itemId, count, this);
+ if (item)
{
- ItemAddedQuestCheck(item, count);
- UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, item, count);
- UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, item, 1);
+ ItemAddedQuestCheck(itemId, count);
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, itemId, count);
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, itemId, 1);
if (randomPropertyId)
- pItem->SetItemRandomProperties(randomPropertyId);
- pItem = StoreItem(dest, pItem, update);
+ item->SetItemRandomProperties(randomPropertyId);
+
+ for (int32 bonusListID : bonusListIDs)
+ item->AddBonuses(bonusListID);
+
+ item = StoreItem(pos, item, update);
- if (allowedLooters.size() > 1 && pItem->GetTemplate()->GetMaxStackSize() == 1 && pItem->IsSoulBound())
+ if (allowedLooters.size() > 1 && item->GetTemplate()->GetMaxStackSize() == 1 && item->IsSoulBound())
{
- pItem->SetSoulboundTradeable(allowedLooters);
- pItem->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, GetTotalPlayedTime());
- AddTradeableItem(pItem);
+ item->SetSoulboundTradeable(allowedLooters);
+ item->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, GetTotalPlayedTime());
+ AddTradeableItem(item);
// save data
std::ostringstream ss;
@@ -11666,12 +11670,12 @@ Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update
ss << ' ' << *itr;
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_BOP_TRADE);
- stmt->setUInt64(0, pItem->GetGUID().GetCounter());
+ stmt->setUInt64(0, item->GetGUID().GetCounter());
stmt->setString(1, ss.str());
CharacterDatabase.Execute(stmt);
}
}
- return pItem;
+ return item;
}
Item* Player::StoreItem(ItemPosCountVec const& dest, Item* pItem, bool update)
@@ -18403,7 +18407,7 @@ void Player::_LoadBoundInstances(PreparedQueryResult result)
}
else
{
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapId, Difficulty(difficulty));
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapId, Difficulty(difficulty));
if (!mapDiff)
{
TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%s) has bind to not existed difficulty %d instance for map %u (%s)", GetName().c_str(), GetGUID().ToString().c_str(), difficulty, mapId, mapname.c_str());
@@ -18439,7 +18443,7 @@ void Player::_LoadBoundInstances(PreparedQueryResult result)
InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty)
{
// some instances only have one difficulty
- MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(mapid, difficulty);
+ MapDifficultyEntry const* mapDiff = GetDownscaledMapDifficultyData(mapid, difficulty);
if (!mapDiff)
return NULL;
@@ -18726,14 +18730,14 @@ bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, bool report
missingAchievement = ar->achievement;
Difficulty target_difficulty = GetDifficultyID(mapEntry);
- MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(target_map, target_difficulty);
+ MapDifficultyEntry const* mapDiff = GetDownscaledMapDifficultyData(target_map, target_difficulty);
if (LevelMin || LevelMax || missingItem || missingQuest || missingAchievement)
{
if (report)
{
if (missingQuest && !ar->questFailedText.empty())
ChatHandler(GetSession()).PSendSysMessage("%s", ar->questFailedText.c_str());
- else if (mapDiff->hasErrorMessage) // if (missingAchievement) covered by this case
+ else if (mapDiff->HasMessage()) // if (missingAchievement) covered by this case
SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY, target_difficulty);
else if (missingItem)
GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, sObjectMgr->GetItemTemplate(missingItem)->GetName(GetSession()->GetSessionDbcLocale()));
@@ -22926,7 +22930,7 @@ void Player::SendInitialPacketsBeforeAddToMap()
WorldPackets::Misc::WorldServerInfo worldServerInfo;
worldServerInfo.IneligibleForLootMask.Clear(); /// @todo
worldServerInfo.WeeklyReset = sWorld->GetNextWeeklyQuestsResetTime() - WEEK;
- worldServerInfo.InstanceGroupSize.Set(GetMap()->GetMapDifficulty()->maxPlayers);
+ worldServerInfo.InstanceGroupSize.Set(GetMap()->GetMapDifficulty()->MaxPlayers);
worldServerInfo.IsTournamentRealm = 0; /// @todo
worldServerInfo.RestrictedAccountMaxLevel.Clear(); /// @todo
worldServerInfo.RestrictedAccountMaxMoney.Clear(); /// @todo
@@ -25014,7 +25018,7 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons
continue;
}
- Item* pItem = StoreNewItem(dest, lootItem->itemid, true, lootItem->randomPropertyId);
+ Item* pItem = StoreNewItem(dest, lootItem->itemid, true, lootItem->randomPropertyId, GuidSet(), lootItem->BonusListIDs);
SendNewItem(pItem, lootItem->count, false, false, broadcast);
}
}
@@ -25050,7 +25054,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot)
InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count);
if (msg == EQUIP_ERR_OK)
{
- Item* newitem = StoreNewItem(dest, item->itemid, true, item->randomPropertyId, item->GetAllowedLooters());
+ Item* newitem = StoreNewItem(dest, item->itemid, true, item->randomPropertyId, item->GetAllowedLooters(), item->BonusListIDs);
if (qitem)
{
@@ -27197,7 +27201,7 @@ Difficulty Player::GetDifficultyID(MapEntry const* mapEntry) const
if (!mapEntry->IsRaid())
return m_dungeonDifficulty;
- MapDifficulty const* defaultDifficulty = GetDefaultMapDifficulty(mapEntry->ID);
+ MapDifficultyEntry const* defaultDifficulty = GetDefaultMapDifficulty(mapEntry->ID);
if (!defaultDifficulty)
return m_legacyRaidDifficulty;
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index f38b8363615..7f95209a6eb 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1455,7 +1455,7 @@ class Player : public Unit, public GridObject<Player>
InventoryResult CanUseItem(ItemTemplate const* pItem) const;
InventoryResult CanUseAmmo(uint32 item) const;
InventoryResult CanRollForItemInLFG(ItemTemplate const* item, WorldObject const* lootedObject) const;
- Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update, int32 randomPropertyId = 0, GuidSet const& allowedLooters = GuidSet());
+ Item* StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, int32 randomPropertyId = 0, GuidSet const& allowedLooters = GuidSet(), std::vector<int32> const& bonusListIDs = std::vector<int32>());
Item* StoreItem(ItemPosCountVec const& pos, Item* pItem, bool update);
Item* EquipNewItem(uint16 pos, uint32 item, bool update);
Item* EquipItem(uint16 pos, Item* pItem, bool update);
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index c8a069a71df..f4a884f4e26 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1388,7 +1388,7 @@ void Group::CountTheRoll(Rolls::iterator rollI)
item->is_looted = true;
roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
roll->getLoot()->unlootedCount--;
- player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, item->GetAllowedLooters());
+ player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, item->GetAllowedLooters(), item->BonusListIDs);
}
else
{
@@ -1440,7 +1440,7 @@ void Group::CountTheRoll(Rolls::iterator rollI)
item->is_looted = true;
roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
roll->getLoot()->unlootedCount--;
- player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, item->GetAllowedLooters());
+ player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, item->GetAllowedLooters(), item->BonusListIDs);
}
else
{
@@ -2003,7 +2003,7 @@ Difficulty Group::GetDifficultyID(MapEntry const* mapEntry) const
if (!mapEntry->IsRaid())
return m_dungeonDifficulty;
- MapDifficulty const* defaultDifficulty = GetDefaultMapDifficulty(mapEntry->ID);
+ MapDifficultyEntry const* defaultDifficulty = GetDefaultMapDifficulty(mapEntry->ID);
if (!defaultDifficulty)
return m_legacyRaidDifficulty;
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index 61e63311910..5e318219336 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -478,7 +478,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData)
}
// now move item from loot to target inventory
- Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, item.GetAllowedLooters());
+ Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, item.GetAllowedLooters(), item.BonusListIDs);
target->SendNewItem(newitem, uint32(item.count), false, false, true);
target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count);
target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, item.itemid, item.count, loot->loot_type);
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index e48bb514ba8..447d8e065f1 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -159,9 +159,9 @@ void WorldSession::HandleMoveWorldportAckOpcode()
if (mInstance)
{
Difficulty diff = GetPlayer()->GetDifficultyID(mEntry);
- if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->ID, diff))
+ if (MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mEntry->ID, diff))
{
- if (mapDiff->resetTime)
+ if (mapDiff->RaidDuration)
{
if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->ID, diff))
{
diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp
index 9423cd78aa3..c45358efa11 100644
--- a/src/server/game/Instances/InstanceSaveMgr.cpp
+++ b/src/server/game/Instances/InstanceSaveMgr.cpp
@@ -373,7 +373,7 @@ void InstanceSaveManager::LoadResetTimes()
Difficulty difficulty = Difficulty(fields[1].GetUInt8());
uint64 oldresettime = fields[2].GetUInt32();
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty);
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid, difficulty);
if (!mapDiff)
{
TC_LOG_ERROR("misc", "InstanceSaveManager::LoadResetTimes: invalid mapid(%u)/difficulty(%u) pair in instance_reset!", mapid, difficulty);
@@ -399,12 +399,12 @@ void InstanceSaveManager::LoadResetTimes()
for (auto& difficultyPair : mapDifficultyPair.second)
{
Difficulty difficulty = Difficulty(difficultyPair.first);
- MapDifficulty const* mapDiff = &difficultyPair.second;
- if (!mapDiff->resetTime)
+ MapDifficultyEntry const* mapDiff = difficultyPair.second;
+ if (!mapDiff->RaidDuration)
continue;
// the reset_delay must be at least one day
- uint32 period = uint32(((mapDiff->resetTime * sWorld->getRate(RATE_INSTANCE_RESET_TIME)) / DAY) * DAY);
+ uint32 period = uint32(((mapDiff->RaidDuration * sWorld->getRate(RATE_INSTANCE_RESET_TIME)) / DAY) * DAY);
if (period < DAY)
period = DAY;
@@ -577,8 +577,8 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b
if (!warn)
{
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty);
- if (!mapDiff || !mapDiff->resetTime)
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid, difficulty);
+ if (!mapDiff || !mapDiff->RaidDuration)
{
TC_LOG_ERROR("misc", "InstanceSaveManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
return;
@@ -616,7 +616,7 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b
// calculate the next reset time
uint32 diff = sWorld->getIntConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR;
- uint32 period = uint32(((mapDiff->resetTime * sWorld->getRate(RATE_INSTANCE_RESET_TIME))/DAY) * DAY);
+ uint32 period = uint32(((mapDiff->RaidDuration * sWorld->getRate(RATE_INSTANCE_RESET_TIME))/DAY) * DAY);
if (period < DAY)
period = DAY;
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index 487454c6e2f..b6a3cc3dd5e 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -419,6 +419,12 @@ void LootItem::BuildItemInstance(WorldPackets::Item::ItemInstance& instance) con
instance.ItemID = itemid;
instance.RandomPropertiesSeed = randomSuffix;
instance.RandomPropertiesID = randomPropertyId;
+ if (!BonusListIDs.empty())
+ {
+ WorldPackets::Item::ItemBonusInstanceData bonusData;
+ instance.ItemBonus.Value.BonusListIDs = BonusListIDs;
+ instance.ItemBonus.HasValue = true;
+ }
}
//
@@ -442,6 +448,12 @@ void Loot::AddItem(LootStoreItem const& item)
{
LootItem generatedLoot(item);
generatedLoot.count = std::min(count, proto->GetMaxStackSize());
+ if (_difficultyBonusTreeMod)
+ {
+ std::set<uint32> bonusListIDs = sDB2Manager.GetItemBonusTree(generatedLoot.itemid, _difficultyBonusTreeMod);
+ generatedLoot.BonusListIDs.insert(generatedLoot.BonusListIDs.end(), bonusListIDs.begin(), bonusListIDs.end());
+ }
+
lootItems.push_back(generatedLoot);
count -= proto->GetMaxStackSize();
@@ -469,6 +481,8 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
return false;
}
+ _difficultyBonusTreeMod = lootOwner->GetMap()->GetDifficultyLootBonusTreeMod();
+
items.reserve(MAX_NR_LOOT_ITEMS);
quest_items.reserve(MAX_NR_QUEST_ITEMS);
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index e6f48b45c28..105a44f76d5 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -164,6 +164,7 @@ struct LootItem
uint32 itemid;
uint32 randomSuffix;
int32 randomPropertyId;
+ std::vector<int32> BonusListIDs;
ConditionList conditions; // additional loot condition
GuidSet allowedGUIDs;
uint8 count : 8;
@@ -335,7 +336,7 @@ struct Loot
// Only set for inventory items that can be right-click looted
ObjectGuid containerID;
- Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_CORPSE), maxDuplicates(1) { }
+ Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_CORPSE), maxDuplicates(1), _difficultyBonusTreeMod(0){ }
~Loot() { clear(); }
ObjectGuid const& GetGUID() const { return _GUID; }
@@ -374,6 +375,7 @@ struct Loot
roundRobinPlayer.Clear();
loot_type = LOOT_NONE;
i_LootValidatorRefManager.clearReferences();
+ _difficultyBonusTreeMod = 0;
}
bool empty() const { return items.empty() && gold == 0; }
@@ -416,6 +418,7 @@ private:
// Loot GUID
ObjectGuid _GUID;
+ uint32 _difficultyBonusTreeMod;
};
extern LootStore LootTemplates_Creature;
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 29041b5bccb..41594ad7d94 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -3201,11 +3201,23 @@ void InstanceMap::SetResetSchedule(bool on)
}
}
-MapDifficulty const* Map::GetMapDifficulty() const
+MapDifficultyEntry const* Map::GetMapDifficulty() const
{
return GetMapDifficultyData(GetId(), GetDifficultyID());
}
+uint32 Map::GetDifficultyLootBonusTreeMod() const
+{
+ if (MapDifficultyEntry const* mapDifficulty = GetMapDifficulty())
+ if (mapDifficulty->ItemBonusTreeModID)
+ return mapDifficulty->ItemBonusTreeModID;
+
+ if (DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(GetDifficultyID()))
+ return difficulty->ItemBonusTreeModID;
+
+ return 0;
+}
+
bool Map::IsHeroic() const
{
if (DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(i_spawnMode))
@@ -3215,17 +3227,17 @@ bool Map::IsHeroic() const
uint32 InstanceMap::GetMaxPlayers() const
{
- MapDifficulty const* mapDiff = GetMapDifficulty();
- if (mapDiff && mapDiff->maxPlayers)
- return mapDiff->maxPlayers;
+ MapDifficultyEntry const* mapDiff = GetMapDifficulty();
+ if (mapDiff && mapDiff->MaxPlayers)
+ return mapDiff->MaxPlayers;
return GetEntry()->MaxPlayers;
}
uint32 InstanceMap::GetMaxResetDelay() const
{
- MapDifficulty const* mapDiff = GetMapDifficulty();
- return mapDiff ? mapDiff->resetTime : 0;
+ MapDifficultyEntry const* mapDiff = GetMapDifficulty();
+ return mapDiff ? mapDiff->RaidDuration : 0;
}
/* ******* Battleground Instance Maps ******* */
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 94b89484e15..d38852e50c9 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -386,7 +386,8 @@ class Map : public GridRefManager<NGridType>
// have meaning only for instanced map (that have set real difficulty)
Difficulty GetDifficultyID() const { return Difficulty(GetSpawnMode()); }
- MapDifficulty const* GetMapDifficulty() const;
+ MapDifficultyEntry const* GetMapDifficulty() const;
+ uint32 GetDifficultyLootBonusTreeMod() const;
bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); }
bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); }
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index 8c4dd2e0c65..89ca656675b 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -136,7 +136,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
Difficulty targetDifficulty, requestedDifficulty;
targetDifficulty = requestedDifficulty = player->GetDifficultyID(entry);
// Get the highest available difficulty if current setting is higher than the instance allows
- MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(entry->ID, targetDifficulty);
+ MapDifficultyEntry const* mapDiff = GetDownscaledMapDifficultyData(entry->ID, targetDifficulty);
if (!mapDiff)
{
player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, requestedDifficulty);
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 7e60e11448d..5b9cfacb56b 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -574,7 +574,7 @@ public:
SpellEffectInfoVector GetEffectsForDifficulty(uint32 difficulty) const;
SpellEffectInfo const* GetEffect(uint32 difficulty, uint32 index) const;
SpellEffectInfo const* GetEffect(uint32 index) const { return GetEffect(DIFFICULTY_NONE, index); }
- SpellEffectInfo const* GetEffect(WorldObject* obj, uint32 index) const { return GetEffect(obj->GetMap()->GetDifficultyID(), index); }
+ SpellEffectInfo const* GetEffect(WorldObject const* obj, uint32 index) const { return GetEffect(obj->GetMap()->GetDifficultyID(), index); }
SpellEffectInfoMap _effects;
};