diff options
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; }; |