diff options
Diffstat (limited to 'src')
60 files changed, 1382 insertions, 567 deletions
diff --git a/src/common/GitRevision.cpp b/src/common/GitRevision.cpp index 2b4537db448..1f4c28cd310 100644 --- a/src/common/GitRevision.cpp +++ b/src/common/GitRevision.cpp @@ -46,19 +46,30 @@ char const* GitRevision::GetHotfixesDatabase() return _HOTFIXES_DATABASE; } -#define _PACKAGENAME "TrinityCore" - -char const* GitRevision::GetFullVersion() -{ #if PLATFORM == PLATFORM_WINDOWS -# ifdef _WIN64 - return _PACKAGENAME " rev. " VER_PRODUCTVERSION_STR " (Win64, " _BUILD_DIRECTIVE ")"; -# else - return _PACKAGENAME " rev. " VER_PRODUCTVERSION_STR " (Win32, " _BUILD_DIRECTIVE ")"; -# endif +# ifdef _WIN64 +# define TRINITY_PLATFORM_STR "Win64" +# else +# define TRINITY_PLATFORM_STR "Win32" +# endif +#elif PLATFORM == PLATFORM_APPLE +# define TRINITY_PLATFORM_STR "MacOSX" +#elif PLATFORM == PLATFORM_INTEL +# define TRINITY_PLATFORM_STR "Intel" +#else // PLATFORM_UNIX +# define TRINITY_PLATFORM_STR "Unix" +#endif + +#ifndef TRINITY_API_USE_DYNAMIC_LINKING +# define TRINITY_LINKAGE_TYPE_STR "Static" #else - return _PACKAGENAME " rev. " VER_PRODUCTVERSION_STR " (Unix, " _BUILD_DIRECTIVE ")"; +# define TRINITY_LINKAGE_TYPE_STR "Dynamic" #endif + +char const* GitRevision::GetFullVersion() +{ + return "TrinityCore rev. " VER_PRODUCTVERSION_STR + " (" TRINITY_PLATFORM_STR ", " _BUILD_DIRECTIVE ", " TRINITY_LINKAGE_TYPE_STR ")"; } char const* GitRevision::GetCompanyNameStr() diff --git a/src/common/Utilities/EventProcessor.cpp b/src/common/Utilities/EventProcessor.cpp index be74d58b790..2341d0a0872 100644 --- a/src/common/Utilities/EventProcessor.cpp +++ b/src/common/Utilities/EventProcessor.cpp @@ -17,11 +17,20 @@ */ #include "EventProcessor.h" +#include "Errors.h" -EventProcessor::EventProcessor() +void BasicEvent::ScheduleAbort() { - m_time = 0; - m_aborting = false; + ASSERT(IsRunning() + && "Tried to scheduled the abortion of an event twice!"); + m_abortState = AbortState::STATE_ABORT_SCHEDULED; +} + +void BasicEvent::SetAborted() +{ + ASSERT(!IsAborted() + && "Tried to abort an already aborted event!"); + m_abortState = AbortState::STATE_ABORTED; } EventProcessor::~EventProcessor() @@ -39,55 +48,73 @@ void EventProcessor::Update(uint32 p_time) while (((i = m_events.begin()) != m_events.end()) && i->first <= m_time) { // get and remove event from queue - BasicEvent* Event = i->second; + BasicEvent* event = i->second; m_events.erase(i); - if (!Event->to_Abort) + if (event->IsRunning()) { - if (Event->Execute(m_time, p_time)) + if (event->Execute(m_time, p_time)) { // completely destroy event if it is not re-added - delete Event; + delete event; } + continue; } - else + + if (event->IsAbortScheduled()) { - Event->Abort(m_time); - delete Event; + event->Abort(m_time); + // Mark the event as aborted + event->SetAborted(); } + + if (event->IsDeletable()) + { + delete event; + continue; + } + + // Reschedule non deletable events to be checked at + // the next update tick + AddEvent(event, CalculateTime(1), false); } } void EventProcessor::KillAllEvents(bool force) { - // prevent event insertions - m_aborting = true; - - // first, abort all existing events - for (EventList::iterator i = m_events.begin(); i != m_events.end();) + for (auto itr = m_events.begin(); itr != m_events.end();) { - EventList::iterator i_old = i; - ++i; - - i_old->second->to_Abort = true; - i_old->second->Abort(m_time); - if (force || i_old->second->IsDeletable()) + // Abort events which weren't aborted already + if (!itr->second->IsAborted()) { - delete i_old->second; + itr->second->SetAborted(); + itr->second->Abort(m_time); + } - if (!force) // need per-element cleanup - m_events.erase (i_old); + // Skip non-deletable events when we are + // not forcing the event cancellation. + if (!force && !itr->second->IsDeletable()) + { + ++itr; + continue; } + + delete itr->second; + + if (force) + ++itr; // Clear the whole container when forcing + else + itr = m_events.erase(itr); } - // fast clear event list (in force case) if (force) m_events.clear(); } void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime) { - if (set_addtime) Event->m_addTime = m_time; + if (set_addtime) + Event->m_addTime = m_time; Event->m_execTime = e_time; m_events.insert(std::pair<uint64, BasicEvent*>(e_time, Event)); } @@ -96,4 +123,3 @@ uint64 EventProcessor::CalculateTime(uint64 t_offset) const { return(m_time + t_offset); } - diff --git a/src/common/Utilities/EventProcessor.h b/src/common/Utilities/EventProcessor.h index e10558e6a21..57f3065f323 100644 --- a/src/common/Utilities/EventProcessor.h +++ b/src/common/Utilities/EventProcessor.h @@ -20,20 +20,27 @@ #define __EVENTPROCESSOR_H #include "Define.h" - #include <map> +class EventProcessor; + // Note. All times are in milliseconds here. class TC_COMMON_API BasicEvent { + friend class EventProcessor; + + enum class AbortState : uint8 + { + STATE_RUNNING, + STATE_ABORT_SCHEDULED, + STATE_ABORTED + }; + public: BasicEvent() - { - to_Abort = false; - m_addTime = 0; - m_execTime = 0; - } + : m_abortState(AbortState::STATE_RUNNING), m_addTime(0), m_execTime(0) { } + virtual ~BasicEvent() { } // override destructor to perform some actions on event removal // this method executes when the event is triggered @@ -45,8 +52,16 @@ class TC_COMMON_API BasicEvent virtual void Abort(uint64 /*e_time*/) { } // this method executes when the event is aborted - bool to_Abort; // set by externals when the event is aborted, aborted events don't execute - // and get Abort call when deleted + // Aborts the event at the next update tick + void ScheduleAbort(); + + private: + void SetAborted(); + bool IsRunning() const { return (m_abortState == AbortState::STATE_RUNNING); } + bool IsAbortScheduled() const { return (m_abortState == AbortState::STATE_ABORT_SCHEDULED); } + bool IsAborted() const { return (m_abortState == AbortState::STATE_ABORTED); } + + AbortState m_abortState; // set by externals when the event is aborted, aborted events don't execute // these can be used for time offset control uint64 m_addTime; // time when the event was added to queue, filled by event handler @@ -58,16 +73,17 @@ typedef std::multimap<uint64, BasicEvent*> EventList; class TC_COMMON_API EventProcessor { public: - EventProcessor(); + EventProcessor() : m_time(0) { } ~EventProcessor(); void Update(uint32 p_time); void KillAllEvents(bool force); void AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime = true); uint64 CalculateTime(uint64 t_offset) const; + protected: uint64 m_time; EventList m_events; - bool m_aborting; }; + #endif diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index fc729e04e5b..f88307db19c 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -167,7 +167,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_REP_INVENTORY_ITEM, "REPLACE INTO character_inventory (guid, bag, slot, item) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_REP_ITEM_INSTANCE, "REPLACE INTO item_instance (itemEntry, owner_guid, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, upgradeId, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, bonusListIDs, guid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, randomPropertyId = ?, durability = ?, playedTime = ?, text = ?, upgradeId = ?, battlePetSpeciesId = ?, battlePetBreedData = ?, battlePetLevel = ?, battlePetDisplayId = ?, bonusListIDs = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD, "UPDATE item_instance SET duration = ?, flags = ?, durability = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD, "UPDATE item_instance SET duration = ?, flags = ?, durability = ?, upgradeId = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE, "DELETE FROM item_instance WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER, "DELETE FROM item_instance WHERE owner_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_INSTANCE_GEMS, "INSERT INTO item_instance_gems (itemGuid, gemItemId1, gemItemId2, gemItemId3) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 210516eaf7c..524392fb474 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -481,6 +481,10 @@ void HotfixDatabaseConnection::DoPrepareStatements() // ItemSpecOverride.db2 PrepareStatement(HOTFIX_SEL_ITEM_SPEC_OVERRIDE, "SELECT ID, ItemID, SpecID FROM item_spec_override ORDER BY ID DESC", CONNECTION_SYNCH); + // ItemUpgrade.db2 + PrepareStatement(HOTFIX_SEL_ITEM_UPGRADE, "SELECT ID, CurrencyCost, PrevItemUpgradeID, CurrencyID, ItemUpgradePathID, ItemLevelBonus" + " FROM item_upgrade ORDER BY ID DESC", CONNECTION_SYNCH); + // ItemXBonusTree.db2 PrepareStatement(HOTFIX_SEL_ITEM_X_BONUS_TREE, "SELECT ID, ItemID, BonusTreeID FROM item_x_bonus_tree ORDER BY ID DESC", CONNECTION_SYNCH); @@ -623,6 +627,9 @@ void HotfixDatabaseConnection::DoPrepareStatements() "RarePropertiesPoints5, UncommonPropertiesPoints1, UncommonPropertiesPoints2, UncommonPropertiesPoints3, UncommonPropertiesPoints4, " "UncommonPropertiesPoints5 FROM rand_prop_points ORDER BY ID DESC", CONNECTION_SYNCH); + // RulesetItemUpgrade.db2 + PrepareStatement(HOTFIX_SEL_RULESET_ITEM_UPGRADE, "SELECT ID, ItemID, ItemUpgradeID FROM ruleset_item_upgrade ORDER BY ID DESC", CONNECTION_SYNCH); + // ScalingStatDistribution.db2 PrepareStatement(HOTFIX_SEL_SCALING_STAT_DISTRIBUTION, "SELECT ID, ItemLevelCurveID, MinLevel, MaxLevel FROM scaling_stat_distribution" " ORDER BY ID DESC", CONNECTION_SYNCH); @@ -635,7 +642,7 @@ void HotfixDatabaseConnection::DoPrepareStatements() // SkillLineAbility.db2 PrepareStatement(HOTFIX_SEL_SKILL_LINE_ABILITY, "SELECT ID, SpellID, RaceMask, SupercedesSpell, Unknown703, SkillLine, MinSkillLineRank, " - "TrivialSkillLineRankHigh, TrivialSkillLineRankLow, UniqueBit, TradeSkillCategoryID, AquireMethod, NumSkillUps, ClassMask" + "TrivialSkillLineRankHigh, TrivialSkillLineRankLow, UniqueBit, TradeSkillCategoryID, AcquireMethod, NumSkillUps, ClassMask" " FROM skill_line_ability ORDER BY ID DESC", CONNECTION_SYNCH); // SkillRaceClassInfo.db2 diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index f49e28b8de2..4221e05f0cc 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -264,6 +264,8 @@ enum HotfixDatabaseStatements HOTFIX_SEL_ITEM_SPEC_OVERRIDE, + HOTFIX_SEL_ITEM_UPGRADE, + HOTFIX_SEL_ITEM_X_BONUS_TREE, HOTFIX_SEL_KEY_CHAIN, @@ -335,6 +337,8 @@ enum HotfixDatabaseStatements HOTFIX_SEL_RAND_PROP_POINTS, + HOTFIX_SEL_RULESET_ITEM_UPGRADE, + HOTFIX_SEL_SCALING_STAT_DISTRIBUTION, HOTFIX_SEL_SKILL_LINE, diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 9c95eca9db1..1d0d061a6db 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -85,7 +85,7 @@ bool AchievementMgr::CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTre return false; } - return true; + return CriteriaHandler::CanUpdateCriteriaTree(criteria, tree, referencePlayer); } bool AchievementMgr::CanCompleteCriteriaTree(CriteriaTree const* tree) diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index 3c8a5241809..c8acd18671e 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -935,37 +935,80 @@ bool CriteriaHandler::IsCompletedCriteriaTree(CriteriaTree const* tree) return false; uint64 requiredCount = tree->Entry->Amount; - uint64 completedCount = 0; - uint32 op = tree->Entry->Operator; - bool hasAll = true; - - // Check criteria we depend on first - for (CriteriaTree const* node : tree->Children) + switch (tree->Entry->Operator) { - if (IsCompletedCriteriaTree(node)) - ++completedCount; - else - hasAll = false; + case CRITERIA_TREE_OPERATOR_SINGLE: + return tree->Criteria && IsCompletedCriteria(tree->Criteria, requiredCount); + case CRITERIA_TREE_OPERATOR_SINGLE_NOT_COMPLETED: + return !tree->Criteria || !IsCompletedCriteria(tree->Criteria, requiredCount); + case CRITERIA_TREE_OPERATOR_ALL: + for (CriteriaTree const* node : tree->Children) + if (!IsCompletedCriteriaTree(node)) + return false; + return true; + case CRITERIA_TREE_OPERAROR_SUM_CHILDREN: + { + uint64 progress = 0; + CriteriaMgr::WalkCriteriaTree(tree, [this, &progress](CriteriaTree const* criteriaTree) + { + if (criteriaTree->Criteria) + if (CriteriaProgress const* criteriaProgress = GetCriteriaProgress(criteriaTree->Criteria)) + progress += criteriaProgress->Counter; + }); + return progress >= requiredCount; + } + case CRITERIA_TREE_OPERATOR_MAX_CHILD: + { + uint64 progress = 0; + CriteriaMgr::WalkCriteriaTree(tree, [this, &progress](CriteriaTree const* criteriaTree) + { + if (criteriaTree->Criteria) + if (CriteriaProgress const* criteriaProgress = GetCriteriaProgress(criteriaTree->Criteria)) + if (criteriaProgress->Counter > progress) + progress = criteriaProgress->Counter; + }); + return progress >= requiredCount; + } + case CRITERIA_TREE_OPERATOR_COUNT_DIRECT_CHILDREN: + { + uint64 progress = 0; + for (CriteriaTree const* node : tree->Children) + if (node->Criteria) + if (CriteriaProgress const* criteriaProgress = GetCriteriaProgress(node->Criteria)) + if (criteriaProgress->Counter >= 1) + if (++progress >= requiredCount) + return true; - if (op & CRITERIA_TREE_OPERATOR_ANY && completedCount >= requiredCount) + return false; + } + case CRITERIA_TREE_OPERATOR_ANY: { - if (!tree->Criteria) - return true; + uint64 progress = 0; + for (CriteriaTree const* node : tree->Children) + if (IsCompletedCriteriaTree(node)) + if (++progress >= requiredCount) + return true; - break; + return false; } + default: + break; } - if (op & CRITERIA_TREE_OPERATOR_ANY && completedCount < requiredCount) - return false; + return false; +} - if (op & CRITERIA_TREE_OPERATOR_ALL && !hasAll) +bool CriteriaHandler::CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const +{ + if ((tree->Entry->Flags & CRITERIA_TREE_FLAG_HORDE_ONLY && referencePlayer->GetTeam() != HORDE) || + (tree->Entry->Flags & CRITERIA_TREE_FLAG_ALLIANCE_ONLY && referencePlayer->GetTeam() != ALLIANCE)) + { + TC_LOG_TRACE("criteria", "CriteriaHandler::CanUpdateCriteriaTree: (Id: %u Type %s CriteriaTree %u) Wrong faction", + criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Entry->ID); return false; + } - if (!tree->Criteria) - return true; - - return IsCompletedCriteria(tree->Criteria, requiredCount); + return true; } bool CriteriaHandler::CanCompleteCriteriaTree(CriteriaTree const* /*tree*/) diff --git a/src/server/game/Achievements/CriteriaHandler.h b/src/server/game/Achievements/CriteriaHandler.h index 4d269a894bd..adabca54ac9 100644 --- a/src/server/game/Achievements/CriteriaHandler.h +++ b/src/server/game/Achievements/CriteriaHandler.h @@ -273,7 +273,7 @@ protected: virtual void SendCriteriaProgressRemoved(uint32 criteriaId) = 0; bool IsCompletedCriteriaTree(CriteriaTree const* tree); - virtual bool CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const = 0; + virtual bool CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const; virtual bool CanCompleteCriteriaTree(CriteriaTree const* tree); virtual void CompletedCriteriaTree(CriteriaTree const* tree, Player* referencePlayer) = 0; virtual void AfterCriteriaTreeUpdate(CriteriaTree const* /*tree*/, Player* /*referencePlayer*/) { } diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 449e614a900..147070f98af 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1870,7 +1870,7 @@ uint32 Battleground::GetAlivePlayersCountByTeam(uint32 Team) const if (itr->second.Team == Team) { Player* player = ObjectAccessor::FindPlayer(itr->first); - if (player && player->IsAlive() && !player->HasByteFlag(UNIT_FIELD_BYTES_2, 3, FORM_SPIRITOFREDEMPTION)) + if (player && player->IsAlive() && !player->HasByteFlag(UNIT_FIELD_BYTES_2, 3, FORM_SPIRIT_OF_REDEMPTION)) ++count; } } diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 2acf3205ddc..2d7c3003688 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -122,6 +122,7 @@ DB2Storage<ItemSetSpellEntry> sItemSetSpellStore("ItemSetSpell DB2SparseStorage<ItemSparseEntry> sItemSparseStore("Item-sparse.db2", ItemSparseMeta::Instance(), HOTFIX_SEL_ITEM_SPARSE); DB2Storage<ItemSpecEntry> sItemSpecStore("ItemSpec.db2", ItemSpecMeta::Instance(), HOTFIX_SEL_ITEM_SPEC); DB2Storage<ItemSpecOverrideEntry> sItemSpecOverrideStore("ItemSpecOverride.db2", ItemSpecOverrideMeta::Instance(), HOTFIX_SEL_ITEM_SPEC_OVERRIDE); +DB2Storage<ItemUpgradeEntry> sItemUpgradeStore("ItemUpgrade.db2", ItemUpgradeMeta::Instance(), HOTFIX_SEL_ITEM_UPGRADE); DB2Storage<ItemXBonusTreeEntry> sItemXBonusTreeStore("ItemXBonusTree.db2", ItemXBonusTreeMeta::Instance(), HOTFIX_SEL_ITEM_X_BONUS_TREE); DB2Storage<KeyChainEntry> sKeyChainStore("KeyChain.db2", KeyChainMeta::Instance(), HOTFIX_SEL_KEY_CHAIN); DB2Storage<LfgDungeonsEntry> sLfgDungeonsStore("LfgDungeons.db2", LfgDungeonsMeta::Instance(), HOTFIX_SEL_LFG_DUNGEONS); @@ -153,6 +154,7 @@ DB2Storage<QuestSortEntry> sQuestSortStore("QuestSort.db2", DB2Storage<QuestV2Entry> sQuestV2Store("QuestV2.db2", QuestV2Meta::Instance(), HOTFIX_SEL_QUEST_V2); DB2Storage<QuestXPEntry> sQuestXPStore("QuestXP.db2", QuestXPMeta::Instance(), HOTFIX_SEL_QUEST_XP); DB2Storage<RandPropPointsEntry> sRandPropPointsStore("RandPropPoints.db2", RandPropPointsMeta::Instance(), HOTFIX_SEL_RAND_PROP_POINTS); +DB2Storage<RulesetItemUpgradeEntry> sRulesetItemUpgradeStore("RulesetItemUpgrade.db2", RulesetItemUpgradeMeta::Instance(), HOTFIX_SEL_RULESET_ITEM_UPGRADE); DB2Storage<ScalingStatDistributionEntry> sScalingStatDistributionStore("ScalingStatDistribution.db2", ScalingStatDistributionMeta::Instance(), HOTFIX_SEL_SCALING_STAT_DISTRIBUTION); DB2Storage<SkillLineEntry> sSkillLineStore("SkillLine.db2", SkillLineMeta::Instance(), HOTFIX_SEL_SKILL_LINE); DB2Storage<SkillLineAbilityEntry> sSkillLineAbilityStore("SkillLineAbility.db2", SkillLineAbilityMeta::Instance(), HOTFIX_SEL_SKILL_LINE_ABILITY); @@ -381,6 +383,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) LOAD_DB2(sItemSparseStore); LOAD_DB2(sItemSpecStore); LOAD_DB2(sItemSpecOverrideStore); + LOAD_DB2(sItemUpgradeStore); LOAD_DB2(sItemXBonusTreeStore); LOAD_DB2(sKeyChainStore); LOAD_DB2(sLfgDungeonsStore); @@ -412,6 +415,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) LOAD_DB2(sQuestV2Store); LOAD_DB2(sQuestXPStore); LOAD_DB2(sRandPropPointsStore); + LOAD_DB2(sRulesetItemUpgradeStore); LOAD_DB2(sScalingStatDistributionStore); LOAD_DB2(sSkillLineStore); LOAD_DB2(sSkillLineAbilityStore); @@ -683,6 +687,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) for (QuestPackageItemEntry const* questPackageItem : sQuestPackageItemStore) _questPackages[questPackageItem->QuestPackageID].push_back(questPackageItem); + for (RulesetItemUpgradeEntry const* rulesetItemUpgrade : sRulesetItemUpgradeStore) + _rulesetItemUpgrade[rulesetItemUpgrade->ItemID] = rulesetItemUpgrade->ItemUpgradeID; + for (SkillRaceClassInfoEntry const* entry : sSkillRaceClassInfoStore) if (sSkillLineStore.LookupEntry(entry->SkillID)) _skillRaceClassInfoBySkill.insert(SkillRaceClassInfoContainer::value_type(entry->SkillID, entry)); @@ -1312,6 +1319,15 @@ std::set<uint32> DB2Manager::GetPhasesForGroup(uint32 group) const return std::set<uint32>(); } +uint32 DB2Manager::GetRulesetItemUpgrade(uint32 itemId) const +{ + auto itr = _rulesetItemUpgrade.find(itemId); + if (itr != _rulesetItemUpgrade.end()) + return itr->second; + + return 0; +} + SkillRaceClassInfoEntry const* DB2Manager::GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_) { auto bounds = _skillRaceClassInfoBySkill.equal_range(skill); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index fc8407eb96b..9ee2bb3b553 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -112,6 +112,7 @@ TC_GAME_API extern DB2Storage<ItemSetSpellEntry> sItemSetSpel TC_GAME_API extern DB2SparseStorage<ItemSparseEntry> sItemSparseStore; TC_GAME_API extern DB2Storage<ItemSpecEntry> sItemSpecStore; TC_GAME_API extern DB2Storage<ItemSpecOverrideEntry> sItemSpecOverrideStore; +TC_GAME_API extern DB2Storage<ItemUpgradeEntry> sItemUpgradeStore; TC_GAME_API extern DB2Storage<LfgDungeonsEntry> sLfgDungeonsStore; TC_GAME_API extern DB2Storage<LiquidTypeEntry> sLiquidTypeStore; TC_GAME_API extern DB2Storage<LockEntry> sLockStore; @@ -246,6 +247,7 @@ public: typedef std::array<std::vector<boost::regex>, TOTAL_LOCALES + 1> NameValidationRegexContainer; typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer; typedef std::unordered_map<uint32, std::vector<QuestPackageItemEntry const*>> QuestPackageItemContainer; + typedef std::unordered_map<uint32, uint32> RulesetItemUpgradeContainer; typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRaceClassInfoContainer; typedef std::unordered_map<uint32, std::vector<SpecializationSpellsEntry const*>> SpecializationSpellsContainer; typedef std::unordered_map<uint32, std::vector<SpellPowerEntry const*>> SpellPowerContainer; @@ -298,13 +300,13 @@ public: MountEntry const* GetMountById(uint32 id) const; MountTypeXCapabilitySet const* GetMountCapabilities(uint32 mountType) const; ResponseCodes ValidateName(std::string const& name, LocaleConstant locale) const; - std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const; - uint32 GetQuestUniqueBitFlag(uint32 questId); std::set<uint32> GetPhasesForGroup(uint32 group) const; static PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level); static PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id); - SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); - std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId) const; + std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const; + uint32 GetQuestUniqueBitFlag(uint32 questId); + uint32 GetRulesetItemUpgrade(uint32 itemId) const; + SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId) const; std::vector<SpellPowerEntry const*> GetSpellPowers(uint32 spellId, Difficulty difficulty = DIFFICULTY_NONE, bool* hasDifficultyPowers = nullptr) const; std::vector<SpellProcsPerMinuteModEntry const*> GetSpellProcsPerMinuteMods(uint32 spellprocsPerMinuteId) const; std::vector<TalentEntry const*> const& GetTalentsByPosition(uint32 class_, uint32 tier, uint32 column) const; @@ -343,6 +345,7 @@ private: NameValidationRegexContainer _nameValidators; PhaseGroupContainer _phasesByGroup; QuestPackageItemContainer _questPackages; + RulesetItemUpgradeContainer _rulesetItemUpgrade; SkillRaceClassInfoContainer _skillRaceClassInfoBySkill; SpecializationSpellsContainer _specializationSpellsBySpec; SpellPowerContainer _spellPowers; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 47e54d1f7af..f9a7c7116d8 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -1446,6 +1446,16 @@ struct ItemSpecOverrideEntry uint16 SpecID; }; +struct ItemUpgradeEntry +{ + uint32 ID; + uint32 CurrencyCost; + uint16 PrevItemUpgradeID; + uint16 CurrencyID; + uint8 ItemUpgradePathID; + uint8 ItemLevelBonus; +}; + struct ItemXBonusTreeEntry { uint32 ID; @@ -1887,6 +1897,13 @@ struct RandPropPointsEntry uint32 UncommonPropertiesPoints[5]; }; +struct RulesetItemUpgradeEntry +{ + uint32 ID; + uint32 ItemID; + uint16 ItemUpgradeID; +}; + struct ScalingStatDistributionEntry { uint32 ID; @@ -1921,7 +1938,7 @@ struct SkillLineAbilityEntry uint16 TrivialSkillLineRankLow; uint16 UniqueBit; uint16 TradeSkillCategoryID; - uint8 AquireMethod; + uint8 AcquireMethod; uint8 NumSkillUps; uint32 ClassMask; }; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index dd29591e22f..3159039d6cd 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -407,10 +407,25 @@ enum CriteriaTypes #define CRITERIA_TYPE_TOTAL 190 -enum CriteriaTreeOperator +enum CriteriaTreeFlags : uint16 { - CRITERIA_TREE_OPERATOR_ALL = 4, - CRITERIA_TREE_OPERATOR_ANY = 8 + CRITERIA_TREE_FLAG_PROGRESS_BAR = 0x0001, + CRITERIA_TREE_FLAG_PROGRESS_IS_DATE = 0x0004, + CRITERIA_TREE_FLAG_SHOW_CURRENCY_ICON = 0x0008, + CRITERIA_TREE_FLAG_ALLIANCE_ONLY = 0x0200, + CRITERIA_TREE_FLAG_HORDE_ONLY = 0x0400, + CRITERIA_TREE_FLAG_SHOW_REQUIRED_COUNT = 0x0800 +}; + +enum CriteriaTreeOperator : uint8 +{ + CRITERIA_TREE_OPERATOR_SINGLE = 0, + CRITERIA_TREE_OPERATOR_SINGLE_NOT_COMPLETED = 1, + CRITERIA_TREE_OPERATOR_ALL = 4, + CRITERIA_TREE_OPERAROR_SUM_CHILDREN = 5, + CRITERIA_TREE_OPERATOR_MAX_CHILD = 6, + CRITERIA_TREE_OPERATOR_COUNT_DIRECT_CHILDREN = 7, + CRITERIA_TREE_OPERATOR_ANY = 8 }; enum CharSectionFlags diff --git a/src/server/game/DataStores/GameTables.h b/src/server/game/DataStores/GameTables.h index 1d4e9126955..c9b9547847c 100644 --- a/src/server/game/DataStores/GameTables.h +++ b/src/server/game/DataStores/GameTables.h @@ -196,7 +196,7 @@ TC_GAME_API extern GameTable<GtXpEntry> sXpGameTable; TC_GAME_API void LoadGameTables(std::string const& dataPath); template<class T> -inline float GetGameTableColumnForClass(T const* row, uint32 class_) +inline float GetGameTableColumnForClass(T const* row, int32 class_) { switch (class_) { @@ -231,4 +231,51 @@ inline float GetGameTableColumnForClass(T const* row, uint32 class_) return 0.0f; } +inline float GetSpellScalingColumnForClass(GtSpellScalingEntry const* row, int32 class_) +{ + switch (class_) + { + case CLASS_WARRIOR: + return row->Warrior; + case CLASS_PALADIN: + return row->Paladin; + case CLASS_HUNTER: + return row->Hunter; + case CLASS_ROGUE: + return row->Rogue; + case CLASS_PRIEST: + return row->Priest; + case CLASS_DEATH_KNIGHT: + return row->DeathKnight; + case CLASS_SHAMAN: + return row->Shaman; + case CLASS_MAGE: + return row->Mage; + case CLASS_WARLOCK: + return row->Warlock; + case CLASS_MONK: + return row->Monk; + case CLASS_DRUID: + return row->Druid; + case CLASS_DEMON_HUNTER: + return row->DemonHunter; + case -1: + return row->Item; + case -2: + return row->Consumable; + case -3: + return row->Gem1; + case -4: + return row->Gem2; + case -5: + return row->Gem3; + case -6: + return row->Health; + default: + break; + } + + return 0.0f; +} + #endif // GameTables_h__ diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index 68ee386be3f..568c0e39469 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -15,13 +15,14 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "Unit.h" -#include "SpellInfo.h" +#include "AreaTrigger.h" +#include "DB2Stores.h" #include "Log.h" +#include "SpellInfo.h" +#include "Unit.h" #include "UpdateData.h" -#include "AreaTrigger.h" -AreaTrigger::AreaTrigger() : WorldObject(false), _duration(0) +AreaTrigger::AreaTrigger() : WorldObject(false), _duration(0), _spellXSpellVisualId(0) { m_objectType |= TYPEMASK_AREATRIGGER; m_objectTypeId = TYPEID_AREATRIGGER; @@ -56,8 +57,9 @@ void AreaTrigger::RemoveFromWorld() } } -bool AreaTrigger::CreateAreaTrigger(ObjectGuid::LowType guidlow, uint32 triggerEntry, Unit* caster, SpellInfo const* spell, Position const& pos) +bool AreaTrigger::CreateAreaTrigger(ObjectGuid::LowType guidlow, uint32 triggerEntry, Unit* caster, SpellInfo const* spell, Position const& pos, uint32 spellXSpellVisualId) { + _spellXSpellVisualId = spellXSpellVisualId; SetMap(caster->GetMap()); Relocate(pos); if (!IsPositionValid()) @@ -69,13 +71,17 @@ bool AreaTrigger::CreateAreaTrigger(ObjectGuid::LowType guidlow, uint32 triggerE Object::_Create(ObjectGuid::Create<HighGuid::AreaTrigger>(GetMapId(), triggerEntry, guidlow)); SetPhaseMask(caster->GetPhaseMask(), false); + uint32 spellVisual = 0; + if (SpellXSpellVisualEntry const* visual = sSpellXSpellVisualStore.LookupEntry(spellXSpellVisualId)) + spellVisual = visual->SpellVisualID[0]; + SetEntry(triggerEntry); SetDuration(spell->GetDuration()); SetObjectScale(1); SetGuidValue(AREATRIGGER_CASTER, caster->GetGUID()); SetUInt32Value(AREATRIGGER_SPELLID, spell->Id); - SetUInt32Value(AREATRIGGER_SPELLVISUALID, spell->GetSpellVisual(GetMap()->GetDifficultyID())); + SetUInt32Value(AREATRIGGER_SPELLVISUALID, spellVisual); SetUInt32Value(AREATRIGGER_DURATION, spell->GetDuration()); CopyPhaseFrom(caster); diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.h b/src/server/game/Entities/AreaTrigger/AreaTrigger.h index e3caa6d2e95..1b3e6f02a3e 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.h +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.h @@ -32,7 +32,7 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge void AddToWorld() override; void RemoveFromWorld() override; - bool CreateAreaTrigger(ObjectGuid::LowType guidlow, uint32 triggerEntry, Unit* caster, SpellInfo const* spell, Position const& pos); + bool CreateAreaTrigger(ObjectGuid::LowType guidlow, uint32 triggerEntry, Unit* caster, SpellInfo const* spell, Position const& pos, uint32 spellXSpellVisualId); void Update(uint32 p_time) override; void Remove(); uint32 GetSpellId() const { return GetUInt32Value(AREATRIGGER_SPELLID); } @@ -42,5 +42,6 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge protected: int32 _duration; + uint32 _spellXSpellVisualId; }; #endif diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 679238ecb17..ab5db4c0b04 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1893,9 +1893,9 @@ SpellInfo const* Creature::reachWithSpellAttack(Unit* victim) float dist = GetDistance(victim); if (dist > range || dist < minrange) continue; - if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) + if (spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) continue; - if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) + if (spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) continue; return spellInfo; } @@ -1943,9 +1943,9 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim) // continue; if (dist > range || dist < minrange) continue; - if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) + if (spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) continue; - if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) + if (spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) continue; return spellInfo; } diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index ea925148084..25684b44db6 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -28,7 +28,7 @@ #include "Transport.h" DynamicObject::DynamicObject(bool isWorldObject) : WorldObject(isWorldObject), - _aura(NULL), _removedAura(NULL), _caster(NULL), _duration(0), _isViewpoint(false) + _aura(NULL), _removedAura(NULL), _caster(NULL), _duration(0), _spellXSpellVisualId(0), _isViewpoint(false) { m_objectType |= TYPEMASK_DYNAMICOBJECT; m_objectTypeId = TYPEID_DYNAMICOBJECT; @@ -80,8 +80,9 @@ void DynamicObject::RemoveFromWorld() } } -bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caster, SpellInfo const* spell, Position const& pos, float radius, DynamicObjectType type) +bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caster, SpellInfo const* spell, Position const& pos, float radius, DynamicObjectType type, uint32 spellXSpellVisualId) { + _spellXSpellVisualId = spellXSpellVisualId; SetMap(caster->GetMap()); Relocate(pos); if (!IsPositionValid()) @@ -93,10 +94,14 @@ bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caste WorldObject::_Create(ObjectGuid::Create<HighGuid::DynamicObject>(GetMapId(), spell->Id, guidlow)); SetPhaseMask(caster->GetPhaseMask(), false); + uint32 spellVisual = 0; + if (SpellXSpellVisualEntry const* visual = sSpellXSpellVisualStore.LookupEntry(spellXSpellVisualId)) + spellVisual = visual->SpellVisualID[0]; + SetEntry(spell->Id); SetObjectScale(1.0f); SetGuidValue(DYNAMICOBJECT_CASTER, caster->GetGUID()); - SetUInt32Value(DYNAMICOBJECT_BYTES, spell->GetSpellVisual(GetMap()->GetDifficultyID()) | (type << 28)); + SetUInt32Value(DYNAMICOBJECT_BYTES, spellVisual | (type << 28)); SetUInt32Value(DYNAMICOBJECT_SPELLID, spell->Id); SetFloatValue(DYNAMICOBJECT_RADIUS, radius); SetUInt32Value(DYNAMICOBJECT_CASTTIME, getMSTime()); diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h index 09426a3c044..4d1cdefdd48 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.h +++ b/src/server/game/Entities/DynamicObject/DynamicObject.h @@ -41,7 +41,7 @@ class TC_GAME_API DynamicObject : public WorldObject, public GridObject<DynamicO void AddToWorld() override; void RemoveFromWorld() override; - bool CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caster, SpellInfo const* spell, Position const& pos, float radius, DynamicObjectType type); + bool CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caster, SpellInfo const* spell, Position const& pos, float radius, DynamicObjectType type, uint32 spellXSpellVisualId); void Update(uint32 p_time) override; void Remove(); void SetDuration(int32 newDuration); @@ -63,6 +63,7 @@ class TC_GAME_API DynamicObject : public WorldObject, public GridObject<DynamicO Aura* _removedAura; Unit* _caster; int32 _duration; // for non-aura dynobjects + uint32 _spellXSpellVisualId; bool _isViewpoint; }; #endif diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 9bb17ec1fa5..103eee0d1f0 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -577,7 +577,23 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, fields[11].GetUInt32()); SetText(fields[12].GetString()); - SetModifier(ITEM_MODIFIER_UPGRADE_ID, fields[13].GetUInt32()); + SetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID, fields[19].GetUInt32()); + uint32 upgradeId = fields[14].GetUInt32(); + ItemUpgradeEntry const* rulesetUpgrade = sItemUpgradeStore.LookupEntry(sDB2Manager.GetRulesetItemUpgrade(entry)); + ItemUpgradeEntry const* upgrade = sItemUpgradeStore.LookupEntry(upgradeId); + if (!rulesetUpgrade || !upgrade || rulesetUpgrade->ItemUpgradePathID != upgrade->ItemUpgradePathID) + { + upgradeId = 0; + need_save = true; + } + + if (rulesetUpgrade && !upgradeId) + { + upgradeId = rulesetUpgrade->ID; + need_save = true; + } + + SetModifier(ITEM_MODIFIER_UPGRADE_ID, upgradeId); SetModifier(ITEM_MODIFIER_BATTLE_PET_SPECIES_ID, fields[14].GetUInt32()); SetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA, fields[15].GetUInt32()); SetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL, fields[16].GetUInt16()); @@ -615,11 +631,13 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie if (need_save) // normal item changed state set not work at loading { + uint8 index = 0; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD); - stmt->setUInt32(0, GetUInt32Value(ITEM_FIELD_DURATION)); - stmt->setUInt32(1, GetUInt32Value(ITEM_FIELD_FLAGS)); - stmt->setUInt32(2, GetUInt32Value(ITEM_FIELD_DURABILITY)); - stmt->setUInt64(3, guid); + stmt->setUInt32(index++, GetUInt32Value(ITEM_FIELD_DURATION)); + stmt->setUInt32(index++, GetUInt32Value(ITEM_FIELD_FLAGS)); + stmt->setUInt32(index++, GetUInt32Value(ITEM_FIELD_DURABILITY)); + stmt->setUInt32(index++, GetModifier(ITEM_MODIFIER_UPGRADE_ID)); + stmt->setUInt64(index++, guid); CharacterDatabase.Execute(stmt); } @@ -1897,6 +1915,9 @@ uint32 Item::GetItemLevel(Player const* owner) const if (uint32 heirloomIlvl = sDB2Manager.GetHeirloomItemLevel(ssd->ItemLevelCurveID, owner->getLevel())) itemLevel = heirloomIlvl; + if (ItemUpgradeEntry const* upgrade = sItemUpgradeStore.LookupEntry(GetModifier(ITEM_MODIFIER_UPGRADE_ID))) + itemLevel += upgrade->ItemLevelBonus; + return std::min(std::max(itemLevel + _bonusData.ItemLevel, uint32(MIN_ITEM_LEVEL)), uint32(MAX_ITEM_LEVEL)); } @@ -1935,6 +1956,12 @@ ItemModifiedAppearanceEntry const* Item::GetItemModifiedAppearance() const void Item::SetModifier(ItemModifier modifier, uint32 value) { + if (_modifiers[modifier] != value) + { + _dynamicChangesMask.SetBit(ITEM_DYNAMIC_FIELD_MODIFIERS); + AddToObjectUpdateIfNeeded(); + } + _modifiers[modifier] = value; ApplyModFlag(ITEM_FIELD_MODIFIERS_MASK, 1 << modifier, value != 0); } diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index 756d21e7856..cacea73bf87 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -733,6 +733,7 @@ struct TC_GAME_API ItemTemplate uint32 GetScalingStatDistribution() const { return ExtendedData->ScalingStatDistribution; } uint32 GetDamageType() const { return ExtendedData->DamageType; } uint32 GetDelay() const { return ExtendedData->Delay; } + float GetRangedModRange() const { return ExtendedData->RangedModRange; } ItemBondingType GetBonding() const { return ItemBondingType(ExtendedData->Bonding); } char const* GetName(LocaleConstant locale) const; uint32 GetPageText() const { return ExtendedData->PageText; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a59624515dd..8ac7e909471 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2917,7 +2917,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent { uint32 next_active_spell_id = 0; // fix activate state for non-stackable low rank (and find next spell for !active case) - if (!spellInfo->IsStackableWithRanks() && spellInfo->IsRanked()) + if (spellInfo->IsRanked()) { if (uint32 next = sSpellMgr->GetNextSpellInChain(spellId)) { @@ -3030,7 +3030,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent newspell->disabled = disabled; // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible - if (newspell->active && !newspell->disabled && !spellInfo->IsStackableWithRanks() && spellInfo->IsRanked() != 0) + if (newspell->active && !newspell->disabled && spellInfo->IsRanked()) { for (PlayerSpellMap::iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2) { @@ -3138,7 +3138,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent continue; // Runeforging special case - if ((_spell_idx->second->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(_spell_idx->second->SkillLine)) || ((_spell_idx->second->SkillLine == SKILL_RUNEFORGING) && _spell_idx->second->TrivialSkillLineRankHigh == 0)) + if ((_spell_idx->second->AcquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(_spell_idx->second->SkillLine)) || ((_spell_idx->second->SkillLine == SKILL_RUNEFORGING) && _spell_idx->second->TrivialSkillLineRankHigh == 0)) if (SkillRaceClassInfoEntry const* rcInfo = sDB2Manager.GetSkillRaceClassInfo(_spell_idx->second->SkillLine, getRace(), getClass())) LearnDefaultSkill(rcInfo); } @@ -3380,7 +3380,7 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank) { // if ranked non-stackable spell: need activate lesser rank and update dendence state /// No need to check for spellInfo != NULL here because if cur_active is true, then that means that the spell was already in m_spells, and only valid spells can be pushed there. - if (cur_active && !spellInfo->IsStackableWithRanks() && spellInfo->IsRanked()) + if (cur_active && spellInfo->IsRanked()) { // need manually update dependence state (learn spell ignore like attempts) PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id); @@ -7960,11 +7960,10 @@ void Player::_ApplyAllLevelScaleItemMods(bool apply) { if (m_items[i]) { - if (m_items[i]->IsBroken() || !CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType()))) + if (!CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType()))) continue; - _ApplyItemBonuses(m_items[i], i, apply); - ApplyItemEquipSpell(m_items[i], apply); + _ApplyItemMods(m_items[i], i, apply); } } } @@ -11075,6 +11074,9 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat if (randomPropertyId) item->SetItemRandomProperties(randomPropertyId); + if (uint32 upgradeID = sDB2Manager.GetRulesetItemUpgrade(itemId)) + item->SetModifier(ITEM_MODIFIER_UPGRADE_ID, upgradeID); + for (int32 bonusListID : bonusListIDs) item->AddBonuses(bonusListID); @@ -12877,6 +12879,25 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool } break; case ITEM_ENCHANTMENT_TYPE_RESISTANCE: + if (pEnchant->ScalingClass) + { + int32 scalingClass = pEnchant->ScalingClass; + if ((GetUInt32Value(UNIT_FIELD_MIN_ITEM_LEVEL) || GetUInt32Value(UNIT_FIELD_MAXITEMLEVEL)) && pEnchant->ScalingClassRestricted) + scalingClass = pEnchant->ScalingClassRestricted; + + uint8 minLevel = pEnchant->Flags & 0x20 ? 1 : 60; + uint8 scalingLevel = getLevel(); + uint8 maxLevel = uint8(pEnchant->MaxLevel ? pEnchant->MaxLevel : sSpellScalingGameTable.GetTableRowCount() - 1); + + if (minLevel > getLevel()) + scalingLevel = minLevel; + else if (maxLevel < getLevel()) + scalingLevel = maxLevel; + + if (GtSpellScalingEntry const* spellScaling = sSpellScalingGameTable.GetRow(scalingLevel)) + enchant_amount = uint32(pEnchant->EffectScalingPoints[s] * GetSpellScalingColumnForClass(spellScaling, scalingClass)); + } + if (!enchant_amount) { ItemRandomSuffixEntry const* item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); @@ -12897,6 +12918,25 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool break; case ITEM_ENCHANTMENT_TYPE_STAT: { + if (pEnchant->ScalingClass) + { + int32 scalingClass = pEnchant->ScalingClass; + if ((GetUInt32Value(UNIT_FIELD_MIN_ITEM_LEVEL) || GetUInt32Value(UNIT_FIELD_MAXITEMLEVEL)) && pEnchant->ScalingClassRestricted) + scalingClass = pEnchant->ScalingClassRestricted; + + uint8 minLevel = pEnchant->Flags & 0x20 ? 1 : 60; + uint8 scalingLevel = getLevel(); + uint8 maxLevel = uint8(pEnchant->MaxLevel ? pEnchant->MaxLevel : sSpellScalingGameTable.GetTableRowCount() - 1); + + if (minLevel > getLevel()) + scalingLevel = minLevel; + else if (maxLevel < getLevel()) + scalingLevel = maxLevel; + + if (GtSpellScalingEntry const* spellScaling = sSpellScalingGameTable.GetRow(scalingLevel)) + enchant_amount = uint32(pEnchant->EffectScalingPoints[s] * GetSpellScalingColumnForClass(spellScaling, scalingClass)); + } + if (!enchant_amount) { ItemRandomSuffixEntry const* item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); @@ -17818,7 +17858,6 @@ void Player::_LoadQuestStatus(PreparedQueryResult result) void Player::_LoadQuestStatusObjectives(PreparedQueryResult result) { - uint16 slot = 0; //// 0 1 2 //QueryResult* result = CharacterDatabase.PQuery("SELECT quest, objective, data WHERE guid = '%u'", GetGUIDLow()); @@ -17831,8 +17870,9 @@ void Player::_LoadQuestStatusObjectives(PreparedQueryResult result) uint32 questID = fields[0].GetUInt32(); + uint16 slot = FindQuestSlot(questID); auto itr = m_QuestStatus.find(questID); - if (itr != m_QuestStatus.end()) + if (itr != m_QuestStatus.end() && slot < MAX_QUEST_LOG_SIZE) { QuestStatusData& questStatusData = itr->second; uint8 objectiveIndex = fields[1].GetUInt8(); @@ -20935,13 +20975,13 @@ void Player::InitDataForForm(bool reapplyMods) switch (form) { case FORM_GHOUL: - case FORM_CAT: + case FORM_CAT_FORM: { if (getPowerType() != POWER_ENERGY) setPowerType(POWER_ENERGY); break; } - case FORM_BEAR: + case FORM_BEAR_FORM: { if (getPowerType() != POWER_RAGE) setPowerType(POWER_RAGE); @@ -22678,6 +22718,11 @@ void Player::LearnQuestRewardedSpells() void Player::LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue) { + // bad hack to work around data being suited only for the client - AcquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN for riding + // client uses it to show riding in spellbook as trainable + if (skillId == SKILL_RIDING) + return; + uint32 raceMask = getRaceMask(); uint32 classMask = getClassMask(); for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) @@ -22690,7 +22735,7 @@ void Player::LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue) if (!spellInfo) continue; - if (ability->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE && ability->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) + if (ability->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE && ability->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) continue; // Check race if set @@ -22706,7 +22751,7 @@ void Player::LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue) continue; // need unlearn spell - if (skillValue < ability->MinSkillLineRank && ability->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE) + if (skillValue < ability->MinSkillLineRank && ability->AcquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE) RemoveSpell(ability->SpellID); // need learn else if (!IsInWorld()) @@ -25266,11 +25311,11 @@ void Player::SendTimeSync() GetName().c_str(), GetGUID().ToString().c_str()); } -void Player::SetReputation(uint32 factionentry, uint32 value) +void Player::SetReputation(uint32 factionentry, int32 value) { GetReputationMgr().SetReputation(sFactionStore.LookupEntry(factionentry), value); } -uint32 Player::GetReputation(uint32 factionentry) const +int32 Player::GetReputation(uint32 factionentry) const { return GetReputationMgr().GetReputation(sFactionStore.LookupEntry(factionentry)); } @@ -25969,9 +26014,10 @@ void Player::SendUpdatePhasing() void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) const { - WorldPacket data(SMSG_SUPERCEDED_SPELLS, 8); - data << uint32(newSpell) << uint32(oldSpell); - GetSession()->SendPacket(&data); + WorldPackets::Spells::SupercededSpells supercededSpells; + supercededSpells.SpellID.push_back(newSpell); + supercededSpells.Superceded.push_back(oldSpell); + GetSession()->SendPacket(supercededSpells.Write()); } uint32 Player::CalculateTalentsTiers() const diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 4f2df580d54..1c4c1d57dd4 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1746,8 +1746,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void RemoveSpecializationSpells(); void SendSpellCategoryCooldowns() const; - void SetReputation(uint32 factionentry, uint32 value); - uint32 GetReputation(uint32 factionentry) const; + void SetReputation(uint32 factionentry, int32 value); + int32 GetReputation(uint32 factionentry) const; std::string GetGuildName() const; // Loot Spec diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 035bc4d8703..2c9da5cf672 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -163,7 +163,10 @@ void Player::ApplySpellPowerBonus(int32 amount, bool apply) ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, amount, apply); if (HasAuraType(SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT)) + { UpdateAttackPowerAndDamage(); + UpdateAttackPowerAndDamage(true); + } } void Player::UpdateSpellDamageAndHealingBonus() @@ -177,7 +180,10 @@ void Player::UpdateSpellDamageAndHealingBonus() SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i))); if (HasAuraType(SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT)) + { UpdateAttackPowerAndDamage(); + UpdateAttackPowerAndDamage(true); + } } bool Player::UpdateAllStats() @@ -313,19 +319,24 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) index = UNIT_FIELD_RANGED_ATTACK_POWER; index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MOD_POS; index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; - val2 = (level + std::max(GetStat(STAT_AGILITY), 0.0f)) * entry->RangedAttackPowerPerAgility; } - else if (!HasAuraType(SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT)) + + if (!HasAuraType(SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT)) { - float strengthValue = std::max(GetStat(STAT_STRENGTH) * entry->AttackPowerPerStrength, 0.0f); - float agilityValue = std::max(GetStat(STAT_AGILITY) * entry->AttackPowerPerAgility, 0.0f); + if (!ranged) + { + float strengthValue = std::max(GetStat(STAT_STRENGTH) * entry->AttackPowerPerStrength, 0.0f); + float agilityValue = std::max(GetStat(STAT_AGILITY) * entry->AttackPowerPerAgility, 0.0f); - SpellShapeshiftFormEntry const* form = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm()); - // Directly taken from client, SHAPESHIFT_FLAG_AP_FROM_STRENGTH ? - if (form && form->Flags & 0x20) - agilityValue += std::max(GetStat(STAT_AGILITY) * entry->AttackPowerPerStrength, 0.0f); + SpellShapeshiftFormEntry const* form = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm()); + // Directly taken from client, SHAPESHIFT_FLAG_AP_FROM_STRENGTH ? + if (form && form->Flags & 0x20) + agilityValue += std::max(GetStat(STAT_AGILITY) * entry->AttackPowerPerStrength, 0.0f); - val2 = strengthValue + agilityValue; + val2 = strengthValue + agilityValue; + } + else + val2 = (level + std::max(GetStat(STAT_AGILITY), 0.0f)) * entry->RangedAttackPowerPerAgility; } else { @@ -416,12 +427,12 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo if (Item* weapon = GetWeaponForAttack(BASE_ATTACK, true)) weaponSpeed = weapon->GetTemplate()->GetDelay() / 1000; - if (GetShapeshiftForm() == FORM_CAT) + if (GetShapeshiftForm() == FORM_CAT_FORM) { weaponMinDamage = weaponMinDamage / weaponSpeed; weaponMaxDamage = weaponMaxDamage / weaponSpeed; } - else if (GetShapeshiftForm() == FORM_BEAR) + else if (GetShapeshiftForm() == FORM_BEAR_FORM) { weaponMinDamage = weaponMinDamage / weaponSpeed + weaponMinDamage / 2.5; weaponMaxDamage = weaponMinDamage / weaponSpeed + weaponMaxDamage / 2.5; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e117a859da6..abb2f8a9d07 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -484,12 +484,6 @@ void Unit::resetAttackTimer(WeaponAttackType type) m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]); } -float Unit::GetMeleeReach() const -{ - float reach = m_floatValues[UNIT_FIELD_COMBATREACH]; - return reach > MIN_MELEE_REACH ? reach : MIN_MELEE_REACH; -} - bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const { if (!obj || !IsInMap(obj) || !IsInPhase(obj)) @@ -516,7 +510,7 @@ bool Unit::IsWithinMeleeRange(const Unit* obj, float dist) const float dz = GetPositionZMinusOffset() - obj->GetPositionZMinusOffset(); float distsq = dx*dx + dy*dy + dz*dz; - float sizefactor = GetMeleeReach() + obj->GetMeleeReach(); + float sizefactor = GetCombatReach() + obj->GetCombatReach() + 4.0f / 3.0f; float maxdist = dist + sizefactor; return distsq < maxdist * maxdist; @@ -3308,7 +3302,7 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura) { Unit* caster = aura->GetCaster(); if (caster && caster->GetTypeId() == TYPEID_PLAYER) - Spell::SendCastResult(caster->ToPlayer(), aura->GetSpellInfo(), aura->GetSpellInfo()->GetSpellXSpellVisualId(caster->GetMap()->GetDifficultyID()), aura->GetCastGUID(), SPELL_FAILED_AURA_BOUNCED); + Spell::SendCastResult(caster->ToPlayer(), aura->GetSpellInfo(), aura->GetSpellXSpellVisualId(), aura->GetCastGUID(), SPELL_FAILED_AURA_BOUNCED); } aura->Remove(); @@ -6183,10 +6177,10 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg switch (GetShapeshiftForm()) { case FORM_NONE: trigger_spell_id = 37344; break; - case FORM_CAT: trigger_spell_id = 37341; break; - case FORM_BEAR: trigger_spell_id = 37340; break; - case FORM_TREE: trigger_spell_id = 37342; break; - case FORM_MOONKIN: trigger_spell_id = 37343; break; + case FORM_CAT_FORM: trigger_spell_id = 37341; break; + case FORM_BEAR_FORM: trigger_spell_id = 37340; break; + case FORM_TREE_OF_LIFE: trigger_spell_id = 37342; break; + case FORM_MOONKIN_FORM: trigger_spell_id = 37343; break; default: return false; } @@ -6197,8 +6191,8 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg { switch (GetShapeshiftForm()) { - case FORM_CAT: trigger_spell_id = 67355; break; - case FORM_BEAR: trigger_spell_id = 67354; break; + case FORM_CAT_FORM: trigger_spell_id = 67355; break; + case FORM_BEAR_FORM: trigger_spell_id = 67354; break; default: return false; } @@ -10660,7 +10654,7 @@ void Unit::SetShapeshiftForm(ShapeshiftForm form) bool Unit::IsInFeralForm() const { ShapeshiftForm form = GetShapeshiftForm(); - return form == FORM_CAT || form == FORM_BEAR; + return form == FORM_CAT_FORM || form == FORM_BEAR_FORM; } bool Unit::IsInDisallowedMountForm() const @@ -11582,6 +11576,7 @@ bool InitTriggerAuraData() isAlwaysTriggeredAura[i] = false; } isTriggerAura[SPELL_AURA_PROC_ON_POWER_AMOUNT] = true; + isTriggerAura[SPELL_AURA_PROC_ON_POWER_AMOUNT_2] = true; isTriggerAura[SPELL_AURA_DUMMY] = true; isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; isTriggerAura[SPELL_AURA_MOD_THREAT] = true; @@ -11906,6 +11901,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u break; } case SPELL_AURA_PROC_ON_POWER_AMOUNT: + case SPELL_AURA_PROC_ON_POWER_AMOUNT_2: { triggeredByAura->HandleProcTriggerSpellOnPowerAmountAuraProc(aurApp, eventInfo); takeCharges = true; @@ -13106,7 +13102,7 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) // restore for use at real death victim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); - // FORM_SPIRITOFREDEMPTION and related auras + // FORM_SPIRIT_OF_REDEMPTION and related auras victim->CastSpell(victim, 27827, true, NULL, aurEff); spiritOfRedemption = true; break; @@ -14195,7 +14191,7 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const { switch (form) { - case FORM_CAT: + case FORM_CAT_FORM: // Based on Hair color if (getRace() == RACE_NIGHTELF) { @@ -14343,7 +14339,7 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const return 892; else return 8571; - case FORM_BEAR: + case FORM_BEAR_FORM: // Based on Hair color if (getRace() == RACE_NIGHTELF) { @@ -14491,17 +14487,17 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const return 2281; else return 2289; - case FORM_FLIGHT: + case FORM_FLIGHT_FORM: if (Player::TeamForRace(getRace()) == ALLIANCE) return 20857; return 20872; - case FORM_FLIGHT_EPIC: + case FORM_FLIGHT_FORM_EPIC: if (Player::TeamForRace(getRace()) == ALLIANCE) return (getRace() == RACE_WORGEN ? 37729 : 21243); if (getRace() == RACE_TROLL) return 37730; return 21244; - case FORM_MOONKIN: + case FORM_MOONKIN_FORM: switch (getRace()) { case RACE_NIGHTELF: @@ -14516,7 +14512,7 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const break; } break; - case FORM_GHOSTWOLF: + case FORM_GHOST_WOLF: if (HasAura(58135)) //! Glyph of Arctic Wolf return 27312; default: @@ -16038,6 +16034,24 @@ SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo) const return spellInfo; } +uint32 Unit::GetCastSpellXSpellVisualId(SpellInfo const* spellInfo) const +{ + Unit::AuraEffectList const& visualOverrides = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_SPELL_VISUAL); + for (AuraEffect const* effect : visualOverrides) + { + if (uint32(effect->GetMiscValue()) == spellInfo->Id) + { + if (SpellInfo const* visualSpell = sSpellMgr->GetSpellInfo(effect->GetMiscValueB())) + { + spellInfo = visualSpell; + break; + } + } + } + + return spellInfo->GetSpellXSpellVisualId(this); +} + struct CombatLogSender { WorldObject const* i_source; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 209958f430b..8dbe00d54c2 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -259,37 +259,40 @@ enum UnitBytes1_Flags // high byte (3 from 0..3) of UNIT_FIELD_BYTES_2 enum ShapeshiftForm { - FORM_NONE = 0x00, - FORM_CAT = 0x01, - FORM_TREE = 0x02, - FORM_TRAVEL = 0x03, - FORM_AQUA = 0x04, - FORM_BEAR = 0x05, - FORM_AMBIENT = 0x06, - FORM_GHOUL = 0x07, - FORM_DIREBEAR = 0x08, // Removed in 4.0.1 - FORM_STEVES_GHOUL = 0x09, - FORM_THARONJA_SKELETON = 0x0A, - FORM_TEST_OF_STRENGTH = 0x0B, - FORM_BLB_PLAYER = 0x0C, - FORM_SHADOW_DANCE = 0x0D, - FORM_CREATUREBEAR = 0x0E, - FORM_CREATURECAT = 0x0F, - FORM_GHOSTWOLF = 0x10, - FORM_BATTLESTANCE = 0x11, - FORM_DEFENSIVESTANCE = 0x12, - FORM_BERSERKERSTANCE = 0x13, - FORM_TEST = 0x14, - FORM_ZOMBIE = 0x15, - FORM_METAMORPHOSIS = 0x16, - FORM_UNDEAD = 0x19, - FORM_MASTER_ANGLER = 0x1A, - FORM_FLIGHT_EPIC = 0x1B, - FORM_SHADOW = 0x1C, - FORM_FLIGHT = 0x1D, - FORM_STEALTH = 0x1E, - FORM_MOONKIN = 0x1F, - FORM_SPIRITOFREDEMPTION = 0x20 + FORM_NONE = 0, + FORM_CAT_FORM = 1, + FORM_TREE_OF_LIFE = 2, + FORM_TRAVEL_FORM = 3, + FORM_AQUATIC_FORM = 4, + FORM_BEAR_FORM = 5, + FORM_AMBIENT = 6, + FORM_GHOUL = 7, + FORM_DIRE_BEAR_FORM = 8, + FORM_CRANE_STANCE = 9, + FORM_THARONJA_SKELETON = 10, + FORM_DARKMOON_TEST_OF_STRENGTH = 11, + FORM_BLB_PLAYER = 12, + FORM_SHADOW_DANCE = 13, + FORM_CREATURE_BEAR = 14, + FORM_CREATURE_CAT = 15, + FORM_GHOST_WOLF = 16, + FORM_BATTLE_STANCE = 17, + FORM_DEFENSIVE_STANCE = 18, + FORM_BERSERKER_STANCE = 19, + FORM_SERPENT_STANCE = 20, + FORM_ZOMBIE = 21, + FORM_METAMORPHOSIS = 22, + FORM_OX_STANCE = 23, + FORM_TIGER_STANCE = 24, + FORM_UNDEAD = 25, + FORM_FRENZY = 26, + FORM_FLIGHT_FORM_EPIC = 27, + FORM_SHADOWFORM = 28, + FORM_FLIGHT_FORM = 29, + FORM_STEALTH = 30, + FORM_MOONKIN_FORM = 31, + FORM_SPIRIT_OF_REDEMPTION = 32, + FORM_GLADIATOR_STANCE = 33 }; // low byte (0 from 0..3) of UNIT_FIELD_BYTES_2 @@ -734,7 +737,8 @@ enum UnitFlags2 UNIT_FLAG2_DISABLE_TURN = 0x00008000, UNIT_FLAG2_UNK2 = 0x00010000, UNIT_FLAG2_PLAY_DEATH_ANIM = 0x00020000, // Plays special death animation upon death - UNIT_FLAG2_ALLOW_CHEAT_SPELLS = 0x00040000 // Allows casting spells with AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL + UNIT_FLAG2_ALLOW_CHEAT_SPELLS = 0x00040000, // Allows casting spells with AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL + UNIT_FLAG2_NO_ACTIONS = 0x00800000 }; /// Non Player Character flags @@ -1370,7 +1374,6 @@ class TC_GAME_API Unit : public WorldObject bool CanDualWield() const { return m_canDualWield; } virtual void SetCanDualWield(bool value) { m_canDualWield = value; } float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; } - float GetMeleeReach() const; bool IsWithinCombatRange(const Unit* obj, float dist2compare) const; bool IsWithinMeleeRange(const Unit* obj, float dist = MELEE_RANGE) const; void GetRandomContactPoint(const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const; @@ -1936,6 +1939,7 @@ class TC_GAME_API Unit : public WorldObject Spell* FindCurrentSpellBySpellId(uint32 spell_id) const; int32 GetCurrentSpellCastTime(uint32 spell_id) const; virtual SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const; + uint32 GetCastSpellXSpellVisualId(SpellInfo const* spellInfo) const; SpellHistory* GetSpellHistory() { return _spellHistory; } SpellHistory const* GetSpellHistory() const { return _spellHistory; } diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index a1523db5d62..9f3c91f2e35 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -232,7 +232,7 @@ void Vehicle::RemoveAllPassengers() while (!_pendingJoinEvents.empty()) { VehicleJoinEvent* e = _pendingJoinEvents.front(); - e->to_Abort = true; + e->ScheduleAbort(); e->Target = eventVehicle; _pendingJoinEvents.pop_front(); } @@ -421,7 +421,7 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId) if (seat == Seats.end()) // no available seat { - e->to_Abort = true; + e->ScheduleAbort(); return false; } @@ -433,7 +433,7 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId) seat = Seats.find(seatId); if (seat == Seats.end()) { - e->to_Abort = true; + e->ScheduleAbort(); return false; } @@ -691,7 +691,7 @@ void Vehicle::RemovePendingEventsForSeat(int8 seatId) { if ((*itr)->Seat->first == seatId) { - (*itr)->to_Abort = true; + (*itr)->ScheduleAbort(); _pendingJoinEvents.erase(itr++); } else @@ -716,7 +716,7 @@ void Vehicle::RemovePendingEventsForPassenger(Unit* passenger) { if ((*itr)->Passenger == passenger) { - (*itr)->to_Abort = true; + (*itr)->ScheduleAbort(); _pendingJoinEvents.erase(itr++); } else diff --git a/src/server/game/Handlers/BattlenetHandler.cpp b/src/server/game/Handlers/BattlenetHandler.cpp index 1f968c3b423..2324ae51959 100644 --- a/src/server/game/Handlers/BattlenetHandler.cpp +++ b/src/server/game/Handlers/BattlenetHandler.cpp @@ -31,6 +31,7 @@ void WorldSession::HandleBattlenetRequestRealmListTicket(WorldPackets::Battlenet WorldPackets::Battlenet::RealmListTicket realmListTicket; realmListTicket.Token = requestRealmListTicket.Token; + realmListTicket.Allow = true; realmListTicket.Ticket << "WorldserverRealmListTicket"; SendPacket(realmListTicket.Write()); diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 938523afb8a..91a8eee27e6 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -1136,3 +1136,65 @@ void WorldSession::HandleUseCritterItem(WorldPackets::Item::UseCritterItem& useC _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); } + +void WorldSession::HandleUpgradeItem(WorldPackets::Item::UpgradeItem& upgradeItem) +{ + WorldPackets::Item::ItemUpgradeResult itemUpgradeResult; + if (!_player->GetNPCIfCanInteractWith(upgradeItem.ItemMaster, UNIT_NPC_FLAG_ITEM_UPGRADE_MASTER)) + { + TC_LOG_DEBUG("network", "WORLD: HandleUpgradeItems - %s not found or player can't interact with it.", upgradeItem.ItemMaster.ToString().c_str()); + itemUpgradeResult.Success = false; + SendPacket(itemUpgradeResult.Write()); + return; + } + + Item* item = _player->GetItemByGuid(upgradeItem.ItemGUID); + if (!item) + { + TC_LOG_DEBUG("network", "WORLD: HandleUpgradeItems: Item %s not found!", upgradeItem.ItemGUID.ToString().c_str()); + itemUpgradeResult.Success = false; + SendPacket(itemUpgradeResult.Write()); + return; + } + + ItemUpgradeEntry const* itemUpgradeEntry = sItemUpgradeStore.LookupEntry(upgradeItem.UpgradeID); + if (!itemUpgradeEntry) + { + TC_LOG_DEBUG("network", "WORLD: HandleUpgradeItems - ItemUpgradeEntry (%u) not found.", upgradeItem.UpgradeID); + itemUpgradeResult.Success = false; + SendPacket(itemUpgradeResult.Write()); + return; + } + + // Check if player has enough currency + if (!_player->HasCurrency(itemUpgradeEntry->CurrencyID, itemUpgradeEntry->CurrencyCost)) + { + TC_LOG_DEBUG("network", "WORLD: HandleUpgradeItems - Player has not enougth currency (ID: %u, Cost: %u) not found.", itemUpgradeEntry->CurrencyID, itemUpgradeEntry->CurrencyCost); + itemUpgradeResult.Success = false; + SendPacket(itemUpgradeResult.Write()); + return; + } + + uint32 currentUpgradeId = item->GetModifier(ITEM_MODIFIER_UPGRADE_ID); + if (currentUpgradeId != itemUpgradeEntry->PrevItemUpgradeID) + { + TC_LOG_DEBUG("network", "WORLD: HandleUpgradeItems - ItemUpgradeEntry (%u) is not related to this ItemUpgradePath (%u).", itemUpgradeEntry->ID, currentUpgradeId); + itemUpgradeResult.Success = false; + SendPacket(itemUpgradeResult.Write()); + return; + } + + itemUpgradeResult.Success = true; + SendPacket(itemUpgradeResult.Write()); + + if (item->IsEquipped()) + _player->_ApplyItemBonuses(item, item->GetSlot(), false); + + item->SetModifier(ITEM_MODIFIER_UPGRADE_ID, itemUpgradeEntry->ID); + + if (item->IsEquipped()) + _player->_ApplyItemBonuses(item, item->GetSlot(), true); + + item->SetState(ITEM_CHANGED, _player); + _player->ModifyCurrency(itemUpgradeEntry->CurrencyID, -int32(itemUpgradeEntry->CurrencyCost)); +} diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index f110425c1a4..abf20d1920a 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -366,6 +366,7 @@ LootItem::LootItem(LootStoreItem const& li) randomSuffix = GenerateEnchSuffixFactor(itemid); randomPropertyId = Item::GenerateItemRandomPropertyId(itemid); + upgradeId = sDB2Manager.GetRulesetItemUpgrade(itemid); count = 0; is_looted = 0; is_blocked = 0; diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 006edab70a6..f7c1085eaad 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -159,6 +159,7 @@ struct TC_GAME_API LootItem uint32 itemid; uint32 randomSuffix; int32 randomPropertyId; + int32 upgradeId; std::vector<int32> BonusListIDs; ConditionContainer conditions; // additional loot condition GuidSet allowedGUIDs; @@ -177,7 +178,7 @@ struct TC_GAME_API LootItem explicit LootItem(LootStoreItem const& li); // Empty constructor for creating an empty LootItem to be filled in with DB data - LootItem() : itemid(0), randomSuffix(0), randomPropertyId(0), count(0), is_looted(false), is_blocked(false), + LootItem() : itemid(0), randomSuffix(0), randomPropertyId(0), upgradeId(0), count(0), is_looted(false), is_blocked(false), freeforall(false), is_underthreshold(false), is_counted(false), needs_quest(false), follow_loot_rules(false), canSave(true){ }; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 54461828da4..b76281ffeac 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -2254,10 +2254,9 @@ enum SpellDmgClass enum SpellPreventionType { - SPELL_PREVENTION_TYPE_NONE = 0, - SPELL_PREVENTION_TYPE_SILENCE = 1, - SPELL_PREVENTION_TYPE_PACIFY = 2, - SPELL_PREVENTION_TYPE_UNK = 3 // Only a few spells have this, but most of the should be interruptable. + SPELL_PREVENTION_TYPE_SILENCE = 1, + SPELL_PREVENTION_TYPE_PACIFY = 2, + SPELL_PREVENTION_TYPE_NO_ACTIONS = 4 }; enum GameobjectTypes : uint8 // (6.0.3.19103) diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 70f0e717e7c..5fe41518cbc 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -367,7 +367,9 @@ class CreatureGameObjectScriptRegistrySwapHooks // Hook which is called before a creature is swapped static void UnloadStage1(Creature* creature) { - creature->m_Events.KillAllEvents(true); + // Remove deletable events only, + // otherwise it causes crashes with non-deletable spell events. + creature->m_Events.KillAllEvents(false); if (creature->IsCharmed()) creature->RemoveCharmedBy(nullptr); diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp index 3ae94dfb84a..c6609812af5 100644 --- a/src/server/game/Server/Packets/ItemPackets.cpp +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -293,7 +293,11 @@ void WorldPackets::Item::ItemInstance::Initialize(::LootItem const& lootItem) ItemBonus->Context = 0; /// @todo } - /// no Modifications + if (lootItem.upgradeId) + { + Modifications = boost::in_place(); + Modifications->Insert(ITEM_MODIFIER_UPGRADE_ID, lootItem.upgradeId); + } } void WorldPackets::Item::ItemInstance::Initialize(::VoidStorageItem const* voidItem) @@ -508,6 +512,15 @@ void WorldPackets::Item::UseCritterItem::Read() _worldPacket >> ItemGuid; } +void WorldPackets::Item::UpgradeItem::Read() +{ + _worldPacket >> ItemMaster; + _worldPacket >> ItemGUID; + _worldPacket >> UpgradeID; + _worldPacket >> ContainerSlot; + _worldPacket >> Slot; +} + void WorldPackets::Item::SocketGems::Read() { _worldPacket >> ItemGuid; @@ -521,3 +534,11 @@ WorldPacket const* WorldPackets::Item::SocketGemsResult::Write() return &_worldPacket; } + +WorldPacket const* WorldPackets::Item::ItemUpgradeResult::Write() +{ + _worldPacket.WriteBit(Success); + _worldPacket.FlushBits(); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/ItemPackets.h b/src/server/game/Server/Packets/ItemPackets.h index 384ba7eea5b..aef6060b260 100644 --- a/src/server/game/Server/Packets/ItemPackets.h +++ b/src/server/game/Server/Packets/ItemPackets.h @@ -484,6 +484,30 @@ namespace WorldPackets ObjectGuid ItemGuid; }; + class UpgradeItem final : public ClientPacket + { + public: + UpgradeItem(WorldPacket&& packet) : ClientPacket(CMSG_UPGRADE_ITEM, std::move(packet)) { } + + void Read() override; + + ObjectGuid ItemMaster; + ObjectGuid ItemGUID; + int32 ContainerSlot = 0; + int32 UpgradeID = 0; + int32 Slot = 0; + }; + + class ItemUpgradeResult final : public ServerPacket + { + public: + ItemUpgradeResult() : ServerPacket(SMSG_ITEM_UPGRADE_RESULT, 1) { } + + WorldPacket const* Write() override; + + bool Success = false; + }; + class SocketGems final : public ClientPacket { public: diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index 599d07e0d87..be57dc2ab9d 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -480,6 +480,24 @@ WorldPacket const* WorldPackets::Spells::LearnedSpells::Write() return &_worldPacket; } +WorldPacket const* WorldPackets::Spells::SupercededSpells::Write() +{ + _worldPacket << uint32(SpellID.size()); + _worldPacket << uint32(Superceded.size()); + _worldPacket << uint32(FavoriteSpellID.size()); + + if (!SpellID.empty()) + _worldPacket.append(SpellID.data(), SpellID.size()); + + if (!Superceded.empty()) + _worldPacket.append(Superceded.data(), Superceded.size()); + + if (!FavoriteSpellID.empty()) + _worldPacket.append(FavoriteSpellID.data(), FavoriteSpellID.size()); + + return &_worldPacket; +} + WorldPacket const* WorldPackets::Spells::SpellFailure::Write() { _worldPacket << CasterUnit; diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index a3a68c8e194..60299e06c4d 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -422,6 +422,18 @@ namespace WorldPackets bool SuppressMessaging = false; }; + class SupercededSpells final : public ServerPacket + { + public: + SupercededSpells() : ServerPacket(SMSG_SUPERCEDED_SPELLS, 4 + 4 + 4 + 4) { } + + WorldPacket const* Write() override; + + std::vector<int32> SpellID; + std::vector<int32> Superceded; + std::vector<int32> FavoriteSpellID; + }; + class SpellFailure final : public ServerPacket { public: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 777f69c1c17..3dbd9a60ad9 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -796,7 +796,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_UPDATE_WOW_TOKEN_AUCTIONABLE_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Token::UpdateListedAuctionableTokens, &WorldSession::HandleUpdateListedAuctionableTokens); DEFINE_HANDLER(CMSG_UPDATE_WOW_TOKEN_COUNT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_UPGRADE_GARRISON, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_UPGRADE_ITEM, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_UPGRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::UpgradeItem, &WorldSession::HandleUpgradeItem); DEFINE_HANDLER(CMSG_USED_FOLLOW, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_USE_CRITTER_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::UseCritterItem, &WorldSession::HandleUseCritterItem); DEFINE_HANDLER(CMSG_USE_EQUIPMENT_SET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::EquipmentSet::UseEquipmentSet, &WorldSession::HandleUseEquipmentSet); @@ -1261,6 +1261,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_PURCHASE_REFUND_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_PUSH_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TIME_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_UPGRADE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_KICK_REASON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARNED_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARN_PVP_TALENTS_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1689,7 +1690,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUMMON_CANCEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUMMON_RAID_MEMBER_VALIDATE_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUMMON_REQUEST, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPERCEDED_SPELLS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPERCEDED_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_COMMS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INVOLUNTARILY_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 87a9f180a4a..dbd448e1bba 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -1694,6 +1694,7 @@ enum OpcodeServer : uint32 // Opcodes that are not generated automatically SMSG_ACCOUNT_HEIRLOOM_UPDATE = 0xBADD, // no client handler + SMSG_ITEM_UPGRADE_RESULT = 0xBADD, // no client handler SMSG_COMPRESSED_PACKET = 0x3052, SMSG_MULTIPLE_PACKETS = 0x3051, diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 02ba3d182ec..757ea968ed1 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -367,6 +367,7 @@ namespace WorldPackets class WrapItem; class CancelTempEnchantment; class UseCritterItem; + class UpgradeItem; class SocketGems; struct ItemInstance; } @@ -1420,6 +1421,7 @@ class TC_GAME_API WorldSession void HandleBuybackItem(WorldPackets::Item::BuyBackItem& packet); void HandleWrapItem(WorldPackets::Item::WrapItem& packet); void HandleUseCritterItem(WorldPackets::Item::UseCritterItem& packet); + void HandleUpgradeItem(WorldPackets::Item::UpgradeItem& packet); void HandleAttackSwingOpcode(WorldPackets::Combat::AttackSwing& packet); void HandleAttackStopOpcode(WorldPackets::Combat::AttackStop& packet); diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 9eb6ad5c864..34023c16d1b 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -378,7 +378,7 @@ enum AuraType SPELL_AURA_MASTERY = 318, SPELL_AURA_MOD_MELEE_HASTE_3 = 319, SPELL_AURA_MOD_RANGED_HASTE_2 = 320, - SPELL_AURA_321 = 321, + SPELL_AURA_MOD_NO_ACTIONS = 321, SPELL_AURA_INTERFERE_TARGETTING = 322, // NYI SPELL_AURA_323 = 323, // Not used in 4.3.4 SPELL_AURA_324 = 324, // spell critical chance (probably by school mask) @@ -453,13 +453,13 @@ enum AuraType SPELL_AURA_393 = 393, SPELL_AURA_SHOW_CONFIRMATION_PROMPT = 394, SPELL_AURA_AREA_TRIGGER = 395, // NYI - SPELL_AURA_396 = 396, + SPELL_AURA_PROC_ON_POWER_AMOUNT_2 = 396, // missing MicValueB handling, probably OnAmountReach ascending/descending or spell/stack add/remove SPELL_AURA_397 = 397, SPELL_AURA_398 = 398, SPELL_AURA_399 = 399, SPELL_AURA_MOD_SKILL_2 = 400, SPELL_AURA_401 = 401, - SPELL_AURA_402 = 402, + SPELL_AURA_MOD_POWER_DISPLAY = 402, SPELL_AURA_OVERRIDE_SPELL_VISUAL = 403, SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT = 404, SPELL_AURA_MOD_RATING_PCT = 405, // NYI @@ -515,17 +515,17 @@ enum AuraType SPELL_AURA_455 = 455, SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE = 456, SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE_REGEN = 457, - SPELL_AURA_IGNORE_DUAL_WIELD_HIT_PENALTY = 458, // NYI - SPELL_AURA_459 = 459, - SPELL_AURA_460 = 460, + SPELL_AURA_IGNORE_DUAL_WIELD_HIT_PENALTY = 458, // NYI + SPELL_AURA_IGNORE_MOVEMENT_FORCES = 459, // NYI + SPELL_AURA_RESET_COOLDOWNS_ON_DUEL_START = 460, // NYI SPELL_AURA_461 = 461, - SPELL_AURA_462 = 462, - SPELL_AURA_CONVER_CRIT_RATING_PCT_TO_PARRY_RATING = 463, // NYI - SPELL_AURA_464 = 464, - SPELL_AURA_465 = 465, - SPELL_AURA_MOD_BONUS_ARMOR_PCT = 466, // Affects bonus armor gain from all sources except base stats - SPELL_AURA_MOD_STAT_BONUS_PCT = 467, // Affects stat gain from all sources except base stats - SPELL_AURA_468 = 468, + SPELL_AURA_MOD_HEALING_AND_ABSORB_FROM_CASTER = 462, // NYI + SPELL_AURA_CONVERT_CRIT_RATING_PCT_TO_PARRY_RATING = 463, // NYI + SPELL_AURA_MOD_ATTACK_POWER_OF_BONUS_ARMOR = 464, // NYI + SPELL_AURA_MOD_BONUS_ARMOR = 465, // NYI + SPELL_AURA_MOD_BONUS_ARMOR_PCT = 466, // Affects bonus armor gain from all sources except base stats + SPELL_AURA_MOD_STAT_BONUS_PCT = 467, // Affects stat gain from all sources except base stats + SPELL_AURA_TRIGGER_SPELL_ON_HEALTH_BELOW_PCT = 468, // Triggers spell when health falls below specified percent value (once, not every time damage is taken below threshold) SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY = 469, SPELL_AURA_470 = 470, SPELL_AURA_MOD_VERSATILITY = 471, // NYI diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a6ab82e2211..21eb48c3fa5 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -380,7 +380,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleMastery, //318 SPELL_AURA_MASTERY &AuraEffect::HandleModMeleeSpeedPct, //319 SPELL_AURA_MOD_MELEE_HASTE_3 &AuraEffect::HandleAuraModRangedHaste, //320 SPELL_AURA_MOD_RANGED_HASTE_2 - &AuraEffect::HandleNULL, //321 SPELL_AURA_321 + &AuraEffect::HandleAuraModNoActions, //321 SPELL_AURA_MOD_NO_ACTIONS &AuraEffect::HandleNULL, //322 SPELL_AURA_INTERFERE_TARGETTING &AuraEffect::HandleUnused, //323 unused (4.3.4) &AuraEffect::HandleNULL, //324 SPELL_AURA_324 @@ -455,14 +455,14 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //393 &AuraEffect::HandleShowConfirmationPrompt, //394 SPELL_AURA_SHOW_CONFIRMATION_PROMPT &AuraEffect::HandleNULL, //395 SPELL_AURA_AREA_TRIGGER - &AuraEffect::HandleNULL, //396 + &AuraEffect::HandleNoImmediateEffect, //396 SPELL_AURA_PROC_ON_POWER_AMOUNT_2 implemented in Unit::HandleAuraProcOnPowerAmount &AuraEffect::HandleNULL, //397 &AuraEffect::HandleNULL, //398 &AuraEffect::HandleNULL, //399 &AuraEffect::HandleAuraModSkill, //400 SPELL_AURA_MOD_SKILL_2 &AuraEffect::HandleNULL, //401 - &AuraEffect::HandleNULL, //402 - &AuraEffect::HandleNULL, //403 + &AuraEffect::HandleModPowerDisplay, //402 SPELL_AURA_MOD_POWER_DISPLAY + &AuraEffect::HandleNoImmediateEffect, //403 SPELL_AURA_OVERRIDE_SPELL_VISUAL implemented in Unit::GetCastSpellXSpellVisualId &AuraEffect::HandleOverrideAttackPowerBySpellPower, //404 SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT &AuraEffect::HandleNULL, //405 SPELL_AURA_MOD_RATING_PCT &AuraEffect::HandleNULL, //406 @@ -518,16 +518,16 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //456 SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleNoImmediateEffect, //457 SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE_REGEN implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleNULL, //458 SPELL_AURA_IGNORE_DUAL_WIELD_HIT_PENALTY - &AuraEffect::HandleNULL, //459 - &AuraEffect::HandleNULL, //460 + &AuraEffect::HandleNULL, //459 SPELL_AURA_IGNORE_MOVEMENT_FORCES + &AuraEffect::HandleNULL, //460 SPELL_AURA_RESET_COOLDOWNS_ON_DUEL_START &AuraEffect::HandleNULL, //461 - &AuraEffect::HandleNULL, //462 - &AuraEffect::HandleNULL, //463 SPELL_AURA_CRIT_RATING_AFFECTS_PARRY used by Riposte - &AuraEffect::HandleNULL, //464 - &AuraEffect::HandleNULL, //465 + &AuraEffect::HandleNULL, //462 SPELL_AURA_MOD_HEALING_AND_ABSORB_FROM_CASTER + &AuraEffect::HandleNULL, //463 SPELL_AURA_CONVERT_CRIT_RATING_PCT_TO_PARRY_RATING used by Riposte + &AuraEffect::HandleNULL, //464 SPELL_AURA_MOD_ATTACK_POWER_OF_BONUS_ARMOR + &AuraEffect::HandleNULL, //465 SPELL_AURA_MOD_BONUS_ARMOR &AuraEffect::HandleNULL, //466 SPELL_AURA_MOD_BONUS_ARMOR_PCT &AuraEffect::HandleModStatBonusPercent, //467 SPELL_AURA_MOD_STAT_BONUS_PCT - &AuraEffect::HandleNULL, //468 + &AuraEffect::HandleNULL, //468 SPELL_AURA_TRIGGER_SPELL_ON_HEALTH_BELOW_PCT &AuraEffect::HandleShowConfirmationPrompt, //469 SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY &AuraEffect::HandleNULL, //470 &AuraEffect::HandleNULL, //471 SPELL_AURA_MOD_VERSATILITY @@ -1236,6 +1236,7 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) HandleRaidProcFromChargeWithValueAuraProc(aurApp, eventInfo); break; case SPELL_AURA_PROC_ON_POWER_AMOUNT: + case SPELL_AURA_PROC_ON_POWER_AMOUNT_2: HandleProcTriggerSpellOnPowerAmountAuraProc(aurApp, eventInfo); break; default: @@ -1274,40 +1275,40 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const switch (GetMiscValue()) { - case FORM_CAT: + case FORM_CAT_FORM: spellId = 3025; break; - case FORM_TREE: + case FORM_TREE_OF_LIFE: spellId = 34123; break; - case FORM_TRAVEL: + case FORM_TRAVEL_FORM: spellId = 5419; break; - case FORM_AQUA: + case FORM_AQUATIC_FORM: spellId = 5421; break; - case FORM_BEAR: + case FORM_BEAR_FORM: spellId = 1178; spellId2 = 21178; break; - case FORM_BATTLESTANCE: + case FORM_BATTLE_STANCE: spellId = 21156; break; - case FORM_DEFENSIVESTANCE: + case FORM_DEFENSIVE_STANCE: spellId = 7376; break; - case FORM_BERSERKERSTANCE: + case FORM_BERSERKER_STANCE: spellId = 7381; break; - case FORM_MOONKIN: + case FORM_MOONKIN_FORM: spellId = 24905; spellId2 = 24907; break; - case FORM_FLIGHT: + case FORM_FLIGHT_FORM: spellId = 33948; spellId2 = 34764; break; - case FORM_FLIGHT_EPIC: + case FORM_FLIGHT_FORM_EPIC: spellId = 40122; spellId2 = 40121; break; @@ -1315,21 +1316,19 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const spellId = 54817; spellId2 = 54879; break; - case FORM_SPIRITOFREDEMPTION: + case FORM_SPIRIT_OF_REDEMPTION: spellId = 27792; spellId2 = 27795; // must be second, this important at aura remove to prevent to early iterator invalidation. break; - case FORM_SHADOW: + case FORM_SHADOWFORM: spellId = 49868; break; - case FORM_GHOSTWOLF: + case FORM_GHOST_WOLF: spellId = 67116; break; case FORM_GHOUL: case FORM_AMBIENT: case FORM_STEALTH: - case FORM_CREATURECAT: - case FORM_CREATUREBEAR: break; default: break; @@ -1377,7 +1376,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const switch (GetMiscValue()) { - case FORM_CAT: + case FORM_CAT_FORM: // Savage Roar if (target->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_DRUID, flag128(0, 0x10000000, 0))) target->CastSpell(target, 62071, true); @@ -1403,7 +1402,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const target->CastCustomSpell(target, 48420, &bp, NULL, NULL, true); } break; - case FORM_BEAR: + case FORM_BEAR_FORM: // Master Shapeshifter - Bear if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_HEALING_DONE_PERCENT, SPELLFAMILY_GENERIC, 2851, EFFECT_0)) { @@ -1411,7 +1410,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const target->CastCustomSpell(target, 48418, &bp, NULL, NULL, true); } break; - case FORM_MOONKIN: + case FORM_MOONKIN_FORM: // Master Shapeshifter - Moonkin if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_HEALING_DONE_PERCENT, SPELLFAMILY_GENERIC, 2851, EFFECT_0)) { @@ -1766,44 +1765,43 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo switch (form) { - case FORM_CAT: // 0x01 - case FORM_GHOUL: // 0x07 + case FORM_CAT_FORM: + case FORM_GHOUL: + case FORM_TIGER_STANCE: + case FORM_OX_STANCE: PowerType = POWER_ENERGY; break; - case FORM_BEAR: // 0x05 + case FORM_BEAR_FORM: - case FORM_BATTLESTANCE: // 0x11 - case FORM_DEFENSIVESTANCE: // 0x12 - case FORM_BERSERKERSTANCE: // 0x13 + case FORM_BATTLE_STANCE: + case FORM_DEFENSIVE_STANCE: + case FORM_BERSERKER_STANCE: PowerType = POWER_RAGE; break; - case FORM_TREE: // 0x02 - case FORM_TRAVEL: // 0x03 - case FORM_AQUA: // 0x04 - case FORM_AMBIENT: // 0x06 - - case FORM_STEVES_GHOUL: // 0x09 - case FORM_THARONJA_SKELETON: // 0x0A - case FORM_TEST_OF_STRENGTH: // 0x0B - case FORM_BLB_PLAYER: // 0x0C - case FORM_SHADOW_DANCE: // 0x0D - case FORM_CREATUREBEAR: // 0x0E - case FORM_CREATURECAT: // 0x0F - case FORM_GHOSTWOLF: // 0x10 - - case FORM_TEST: // 0x14 - case FORM_ZOMBIE: // 0x15 - case FORM_METAMORPHOSIS: // 0x16 - case FORM_UNDEAD: // 0x19 - case FORM_MASTER_ANGLER: // 0x1A - case FORM_FLIGHT_EPIC: // 0x1B - case FORM_SHADOW: // 0x1C - case FORM_FLIGHT: // 0x1D - case FORM_STEALTH: // 0x1E - case FORM_MOONKIN: // 0x1F - case FORM_SPIRITOFREDEMPTION: // 0x20 + case FORM_TREE_OF_LIFE: + case FORM_TRAVEL_FORM: + case FORM_AQUATIC_FORM: + case FORM_AMBIENT: + + case FORM_THARONJA_SKELETON: + case FORM_DARKMOON_TEST_OF_STRENGTH: + case FORM_BLB_PLAYER: + case FORM_SHADOW_DANCE: + case FORM_CRANE_STANCE: + case FORM_GHOST_WOLF: + + case FORM_SERPENT_STANCE: + case FORM_ZOMBIE: + case FORM_METAMORPHOSIS: + case FORM_UNDEAD: + case FORM_FLIGHT_FORM_EPIC: + case FORM_SHADOWFORM: + case FORM_FLIGHT_FORM: + case FORM_STEALTH: + case FORM_MOONKIN_FORM: + case FORM_SPIRIT_OF_REDEMPTION: break; default: TC_LOG_ERROR("spells", "Auras: Unknown Shapeshift Type: %u", GetMiscValue()); @@ -1816,14 +1814,14 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo // remove polymorph before changing display id to keep new display id switch (form) { - case FORM_CAT: - case FORM_TREE: - case FORM_TRAVEL: - case FORM_AQUA: - case FORM_BEAR: - case FORM_FLIGHT_EPIC: - case FORM_FLIGHT: - case FORM_MOONKIN: + case FORM_CAT_FORM: + case FORM_TREE_OF_LIFE: + case FORM_TRAVEL_FORM: + case FORM_AQUATIC_FORM: + case FORM_BEAR_FORM: + case FORM_FLIGHT_FORM_EPIC: + case FORM_FLIGHT_FORM: + case FORM_MOONKIN_FORM: { // remove movement affects target->RemoveMovementImpairingAuras(); @@ -1851,14 +1849,14 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo if (target->getPowerType() != PowerType) target->setPowerType(PowerType); - if (form == FORM_CAT || form == FORM_BEAR) + if (form == FORM_CAT_FORM || form == FORM_BEAR_FORM) { // get furor proc chance int32 FurorChance = 0; if (AuraEffect const* dummy = target->GetDummyAuraEffect(SPELLFAMILY_DRUID, 238, 0)) FurorChance = std::max(dummy->GetAmount(), 0); - if (form == FORM_CAT) + if (form == FORM_CAT_FORM) { int32 basePoints = std::min<int32>(oldPower, FurorChance); target->SetPower(POWER_ENERGY, 0); @@ -1901,19 +1899,19 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo switch (form) { // Nordrassil Harness - bonus - case FORM_BEAR: - case FORM_CAT: + case FORM_BEAR_FORM: + case FORM_CAT_FORM: if (AuraEffect* dummy = target->GetAuraEffect(37315, 0)) target->CastSpell(target, 37316, true, NULL, dummy); break; // Nordrassil Regalia - bonus - case FORM_MOONKIN: + case FORM_MOONKIN_FORM: if (AuraEffect* dummy = target->GetAuraEffect(37324, 0)) target->CastSpell(target, 37325, true, NULL, dummy); break; - case FORM_BATTLESTANCE: - case FORM_DEFENSIVESTANCE: - case FORM_BERSERKERSTANCE: + case FORM_BATTLE_STANCE: + case FORM_DEFENSIVE_STANCE: + case FORM_BERSERKER_STANCE: { int32 Rage_val = 0; // Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch) @@ -2409,10 +2407,10 @@ void AuraEffect::HandleAuraModSilence(AuraApplication const* aurApp, uint8 mode, target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED); // call functions which may have additional effects after chainging state of unit - // Stop cast only spells vs PreventionType == SPELL_PREVENTION_TYPE_SILENCE + // Stop cast only spells vs PreventionType & SPELL_PREVENTION_TYPE_SILENCE for (uint32 i = CURRENT_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) if (Spell* spell = target->GetCurrentSpell(CurrentSpellTypes(i))) - if (spell->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + if (spell->m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE) // Stop spells on prepare or casting state target->InterruptSpell(CurrentSpellTypes(i), false); } @@ -2494,6 +2492,35 @@ void AuraEffect::HandleAuraAllowOnlyAbility(AuraApplication const* aurApp, uint8 } } +void AuraEffect::HandleAuraModNoActions(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit* target = aurApp->GetTarget(); + + if (apply) + { + target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_NO_ACTIONS); + + // call functions which may have additional effects after chainging state of unit + // Stop cast only spells vs PreventionType & SPELL_PREVENTION_TYPE_SILENCE + for (uint32 i = CURRENT_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) + if (Spell* spell = target->GetCurrentSpell(CurrentSpellTypes(i))) + if (spell->m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_NO_ACTIONS) + // Stop spells on prepare or casting state + target->InterruptSpell(CurrentSpellTypes(i), false); + } + else + { + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(SPELL_AURA_MOD_NO_ACTIONS)) + return; + + target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_NO_ACTIONS); + } +} + /****************************/ /*** TRACKING ***/ /****************************/ @@ -3981,6 +4008,7 @@ void AuraEffect::HandleOverrideAttackPowerBySpellPower(AuraApplication const* au target->ApplyModSignedFloatValue(PLAYER_FIELD_OVERRIDE_AP_BY_SPELL_POWER_PERCENT, float(m_amount), apply); target->UpdateAttackPowerAndDamage(); + target->UpdateAttackPowerAndDamage(true); } /********************************/ @@ -4151,6 +4179,28 @@ void AuraEffect::HandleAuraModIncreaseBaseManaPercent(AuraApplication const* aur aurApp->GetTarget()->HandleStatModifier(UNIT_MOD_MANA, BASE_PCT, float(GetAmount()), apply); } +void AuraEffect::HandleModPowerDisplay(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(GetMiscValue()); + if (!powerDisplay) + return; + + Unit* target = aurApp->GetTarget(); + if (target->GetPowerIndex(powerDisplay->PowerType) == MAX_POWERS) + return; + + if (apply) + { + target->RemoveAurasByType(GetAuraType(), ObjectGuid::Empty, GetBase()); + target->SetUInt32Value(UNIT_FIELD_OVERRIDE_DISPLAY_POWER_ID, powerDisplay->ID); + } + else + target->SetUInt32Value(UNIT_FIELD_OVERRIDE_DISPLAY_POWER_ID, 0); +} + /********************************/ /*** FIGHT ***/ /********************************/ diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 8df069df7f3..b599fe1df28 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -167,6 +167,7 @@ class TC_GAME_API AuraEffect void HandleAuraModPacify(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModPacifyAndSilence(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraAllowOnlyAbility(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleAuraModNoActions(AuraApplication const* aurApp, uint8 mode, bool apply) const; // tracking void HandleAuraTrackResources(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraTrackCreatures(AuraApplication const* aurApp, uint8 mode, bool apply) const; @@ -247,6 +248,7 @@ class TC_GAME_API AuraEffect void HandleAuraModIncreaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModIncreaseBaseManaPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleModPowerDisplay(AuraApplication const* aurApp, uint8 mode, bool apply) const; // fight void HandleAuraModParryPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModDodgePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index d0af2af8f97..0aa5d752c60 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -205,7 +205,7 @@ void AuraApplication::BuildUpdatePacket(WorldPackets::Spells::AuraInfo& auraInfo WorldPackets::Spells::AuraDataInfo& auraData = auraInfo.AuraData.get(); auraData.CastID = aura->GetCastGUID(); auraData.SpellID = aura->GetId(); - auraData.SpellXSpellVisualID = aura->GetSpellInfo()->GetSpellXSpellVisualId(_target->GetMap()->GetDifficultyID()); + auraData.SpellXSpellVisualID = aura->GetSpellXSpellVisualId(); auraData.Flags = GetFlags(); if (aura->GetMaxDuration() > 0 && !(aura->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_HIDE_DURATION)) auraData.Flags |= AFLAG_DURATION; @@ -366,7 +366,7 @@ Aura* Aura::Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMas Aura::Aura(SpellInfo const* spellproto, ObjectGuid castId, WorldObject* owner, Unit* caster, Item* castItem, ObjectGuid casterGUID, int32 castItemLevel) : m_spellInfo(spellproto), m_castGuid(castId), m_casterGuid(!casterGUID.IsEmpty() ? casterGUID : caster->GetGUID()), -m_castItemGuid(castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_castItemLevel(castItemLevel), +m_castItemGuid(castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_castItemLevel(castItemLevel), m_spellXSpellVisualId(caster ? caster->GetCastSpellXSpellVisualId(spellproto) : spellproto->GetSpellXSpellVisualId()), m_applyTime(time(NULL)), m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1), m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr), @@ -525,7 +525,7 @@ void Aura::_Remove(AuraRemoveMode removeMode) if (m_dropEvent) { - m_dropEvent->to_Abort = true; + m_dropEvent->ScheduleAbort(); m_dropEvent = nullptr; } } diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 253b07768f0..83b6343ceef 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -134,6 +134,7 @@ class TC_GAME_API Aura ObjectGuid GetCasterGUID() const { return m_casterGuid; } ObjectGuid GetCastItemGUID() const { return m_castItemGuid; } int32 GetCastItemLevel() const { return m_castItemLevel; } + uint32 GetSpellXSpellVisualId() const { return m_spellXSpellVisualId; } Unit* GetCaster() const; WorldObject* GetOwner() const { return m_owner; } Unit* GetUnitOwner() const { ASSERT(GetType() == UNIT_AURA_TYPE); return (Unit*)m_owner; } @@ -302,6 +303,7 @@ class TC_GAME_API Aura ObjectGuid const m_casterGuid; ObjectGuid const m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted int32 m_castItemLevel; + uint32 const m_spellXSpellVisualId; time_t const m_applyTime; WorldObject* const m_owner; @@ -315,7 +317,6 @@ class TC_GAME_API Aura uint8 m_procCharges; // Aura charges (0 for infinite) uint8 m_stackAmount; // Aura stack amount - //AuraEffect* m_effects[3]; ApplicationMap m_applications; bool m_isRemoved; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index c69c2ebea5f..de5d96f9894 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -591,7 +591,7 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo)), focusObject = NULL; m_castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, m_caster->GetMapId(), m_spellInfo->Id, m_caster->GetMap()->GenerateLowGuid<HighGuid::Cast>()); memset(m_misc.Raw.Data, 0, sizeof(m_misc.Raw.Data)); - m_SpellVisual = m_spellInfo->GetSpellXSpellVisualId(caster->GetMap()->GetDifficultyID()); + m_SpellVisual = caster->GetCastSpellXSpellVisualId(m_spellInfo); m_preCastSpell = 0; m_triggeredByAuraSpell = NULL; m_spellAura = NULL; @@ -4366,7 +4366,7 @@ void Spell::SendChannelStart(uint32 duration) m_caster->SetChannelObjectGuid(channelTarget); m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, m_spellInfo->Id); - m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL_X_SPELL_VISUAL, m_spellInfo->GetSpellXSpellVisualId(m_caster->GetMap()->GetDifficultyID())); + m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL_X_SPELL_VISUAL, m_SpellVisual); } void Spell::SendResurrectRequest(Player* target) @@ -5657,7 +5657,7 @@ SpellCastResult Spell::CheckCasterAuras() const Unit::AuraEffectList const& stunAuras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_STUN); for (Unit::AuraEffectList::const_iterator i = stunAuras.begin(); i != stunAuras.end(); ++i) { - if ((*i)->GetSpellInfo()->GetAllEffectsMechanicMask() && !((*i)->GetSpellInfo()->GetAllEffectsMechanicMask() & (1<<MECHANIC_STUN))) + if ((*i)->GetSpellInfo()->GetAllEffectsMechanicMask() && !((*i)->GetSpellInfo()->GetAllEffectsMechanicMask() & (1 << MECHANIC_STUN))) { foundNotStun = true; break; @@ -5673,10 +5673,12 @@ SpellCastResult Spell::CheckCasterAuras() const prevented_reason = SPELL_FAILED_CONFUSED; else if (unitflag & UNIT_FLAG_FLEEING && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED)) prevented_reason = SPELL_FAILED_FLEEING; - else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE) prevented_reason = SPELL_FAILED_SILENCED; - else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY) + else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY) prevented_reason = SPELL_FAILED_PACIFIED; + else if (m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_NO_ACTIONS) && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_NO_ACTIONS) + prevented_reason = SPELL_FAILED_NO_ACTIONS; // Attr must make flag drop spell totally immune from all effects if (prevented_reason != SPELL_CAST_OK) @@ -5722,9 +5724,9 @@ SpellCastResult Spell::CheckCasterAuras() const case SPELL_AURA_MOD_SILENCE: case SPELL_AURA_MOD_PACIFY: case SPELL_AURA_MOD_PACIFY_SILENCE: - if (m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY) + if (m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY) return SPELL_FAILED_PACIFIED; - else if (m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + else if (m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE) return SPELL_FAILED_SILENCED; break; default: break; @@ -5830,43 +5832,76 @@ SpellCastResult Spell::CheckRange(bool strict) if (!strict && m_casttime == 0) return SPELL_CAST_OK; - uint32 range_type = 0; + Unit* target = m_targets.GetUnitTarget(); + float minRange = 0.0f; + float maxRange = 0.0f; + float rangeMod = 0.0f; + if (strict && IsNextMeleeSwingSpell()) + maxRange = 100.0f; + else if (m_spellInfo->RangeEntry) + { + if (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE) + { + rangeMod = m_caster->GetCombatReach() + 4.0f / 3.0f; + if (target) + rangeMod += target->GetCombatReach(); + else + rangeMod += m_caster->GetCombatReach(); - if (m_spellInfo->RangeEntry) - { - // check needed by 68766 51693 - both spells are cast on enemies and have 0 max range - // these are triggered by other spells - possibly we should omit range check in that case? - if (m_spellInfo->RangeIndex == 1) - return SPELL_CAST_OK; + rangeMod = std::max(rangeMod, NOMINAL_MELEE_RANGE); + } + else + { + float meleeRange = 0.0f; + if (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED) + { + meleeRange = m_caster->GetCombatReach() + 4.0f / 3.0f; + if (target) + meleeRange += target->GetCombatReach(); + else + meleeRange += m_caster->GetCombatReach(); + + meleeRange = std::max(meleeRange, NOMINAL_MELEE_RANGE); + } + + minRange = m_caster->GetSpellMinRangeForTarget(target, m_spellInfo) + meleeRange; + maxRange = m_caster->GetSpellMaxRangeForTarget(target, m_spellInfo); + + if (target || m_targets.GetCorpseTarget()) + { + rangeMod = m_caster->GetCombatReach(); + if (target) + rangeMod += target->GetCombatReach(); + + if (minRange > 0.0f && !(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED)) + minRange += rangeMod; + } + } - range_type = m_spellInfo->RangeEntry->Flags; + if (target && m_caster->isMoving() && target->isMoving() && !m_caster->IsWalking() && !target->IsWalking() && + (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE || target->GetTypeId() == TYPEID_PLAYER)) + rangeMod += 5.0f / 3.0f; } - Unit* target = m_targets.GetUnitTarget(); - float max_range = m_caster->GetSpellMaxRangeForTarget(target, m_spellInfo); - float min_range = m_caster->GetSpellMinRangeForTarget(target, m_spellInfo); + if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) && m_caster->GetTypeId() == TYPEID_PLAYER) + if (Item* ranged = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK, true)) + maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, this); + + maxRange += rangeMod; + + minRange *= minRange; + maxRange *= maxRange; if (target && target != m_caster) { - if (range_type == SPELL_RANGE_MELEE) - { - // Because of lag, we can not check too strictly here. - if (!m_caster->IsWithinMeleeRange(target, max_range)) - return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; - } - else if (!m_caster->IsWithinCombatRange(target, max_range)) - return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; //0x5A; + if (m_caster->GetExactDistSq(target) > maxRange) + return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; - if (range_type == SPELL_RANGE_RANGED) - { - if (m_caster->IsWithinMeleeRange(target)) - return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_TOO_CLOSE : SPELL_FAILED_DONT_REPORT; - } - else if (min_range && m_caster->IsWithinCombatRange(target, min_range)) // skip this check if min_range = 0 - return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_TOO_CLOSE : SPELL_FAILED_DONT_REPORT; + if (minRange > 0.0f && m_caster->GetExactDistSq(target) < minRange) + return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast<float>(M_PI), target)) @@ -5875,10 +5910,10 @@ SpellCastResult Spell::CheckRange(bool strict) if (m_targets.HasDst() && !m_targets.HasTraj()) { - if (!m_caster->IsWithinDist3d(m_targets.GetDstPos(), max_range)) - return SPELL_FAILED_OUT_OF_RANGE; - if (min_range && m_caster->IsWithinDist3d(m_targets.GetDstPos(), min_range)) - return SPELL_FAILED_TOO_CLOSE; + if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange) + return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; + if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange) + return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; } return SPELL_CAST_OK; @@ -6669,7 +6704,7 @@ bool Spell::IsAutoActionResetSpell() const bool Spell::IsNeedSendToClient() const { - return m_spellInfo->GetSpellXSpellVisualId(m_caster->GetMap()->GetDifficultyID()) || m_spellInfo->IsChanneled() || + return m_SpellVisual || m_spellInfo->IsChanneled() || (m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT)) || m_spellInfo->Speed > 0.0f || (!m_triggeredByAuraSpell && !IsTriggered()); } @@ -6730,8 +6765,8 @@ bool SpellEvent::Execute(uint64 e_time, uint32 p_time) return true; // spell is deletable, finish event } // event will be re-added automatically at the end of routine) - } break; - + break; + } case SPELL_STATE_DELAYED: { // first, check, if we have just started @@ -6781,17 +6816,24 @@ bool SpellEvent::Execute(uint64 e_time, uint32 p_time) { // delaying had just started, record the moment m_Spell->SetDelayStart(e_time); + // handle effects on caster if the spell has travel time but also affects the caster in some way + if (!m_Spell->m_targets.HasDst()) + { + uint64 n_offset = m_Spell->handle_delayed(0); + ASSERT(n_offset == m_Spell->GetDelayMoment()); + } // re-plan the event for the delay moment m_Spell->GetCaster()->m_Events.AddEvent(this, e_time + m_Spell->GetDelayMoment(), false); return false; // event not complete } - } break; - + break; + } default: { // all other states // event will be re-added automatically at the end of routine) - } break; + break; + } } // spell processing not complete, plan event on the next update interval diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 3720c2addc8..6a98cd525c2 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1546,7 +1546,7 @@ void Spell::EffectPersistentAA(SpellEffIndex effIndex) if (!caster->IsInWorld()) return; DynamicObject* dynObj = new DynamicObject(false); - if (!dynObj->CreateDynamicObject(caster->GetMap()->GenerateLowGuid<HighGuid::DynamicObject>(), caster, m_spellInfo, *destTarget, radius, DYNAMIC_OBJECT_AREA_SPELL)) + if (!dynObj->CreateDynamicObject(caster->GetMap()->GenerateLowGuid<HighGuid::DynamicObject>(), caster, m_spellInfo, *destTarget, radius, DYNAMIC_OBJECT_AREA_SPELL, m_SpellVisual)) { delete dynObj; return; @@ -2387,7 +2387,7 @@ void Spell::EffectAddFarsight(SpellEffIndex /*effIndex*/) return; DynamicObject* dynObj = new DynamicObject(true); - if (!dynObj->CreateDynamicObject(m_caster->GetMap()->GenerateLowGuid<HighGuid::DynamicObject>(), m_caster, m_spellInfo, *destTarget, radius, DYNAMIC_OBJECT_FARSIGHT_FOCUS)) + if (!dynObj->CreateDynamicObject(m_caster->GetMap()->GenerateLowGuid<HighGuid::DynamicObject>(), m_caster, m_spellInfo, *destTarget, radius, DYNAMIC_OBJECT_FARSIGHT_FOCUS, m_SpellVisual)) { delete dynObj; return; @@ -2646,10 +2646,10 @@ void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex) else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN) duration = 3600; // 30 mins // other cases with this SpellVisual already selected - else if (m_spellInfo->GetSpellVisual(DIFFICULTY_NONE) == 215) + else if (m_spellInfo->GetSpellVisual() == 215) duration = 1800; // 30 mins // some fishing pole bonuses except Glow Worm which lasts full hour - else if (m_spellInfo->GetSpellVisual(DIFFICULTY_NONE) == 563 && m_spellInfo->Id != 64401) + else if (m_spellInfo->GetSpellVisual() == 563 && m_spellInfo->Id != 64401) duration = 600; // 10 mins else if (m_spellInfo->Id == 29702) duration = 300; // 5 mins @@ -3131,7 +3131,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex) // check if we can interrupt spell if ((spell->getState() == SPELL_STATE_CASTING || (spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f)) - && (curSpellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE || curSpellInfo->PreventionType == SPELL_PREVENTION_TYPE_UNK) + && (curSpellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE) && ((i == CURRENT_GENERIC_SPELL && curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT) || (i == CURRENT_CHANNELED_SPELL && curSpellInfo->ChannelInterruptFlags & CHANNEL_INTERRUPT_FLAG_INTERRUPT))) { @@ -5595,7 +5595,7 @@ void Spell::EffectCreateAreaTrigger(SpellEffIndex /*effIndex*/) uint32 triggerEntry = effectInfo->MiscValue; AreaTrigger * areaTrigger = new AreaTrigger; - if (!areaTrigger->CreateAreaTrigger(GetCaster()->GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>(), triggerEntry, GetCaster(), GetSpellInfo(), pos)) + if (!areaTrigger->CreateAreaTrigger(GetCaster()->GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>(), triggerEntry, GetCaster(), GetSpellInfo(), pos, m_SpellVisual)) delete areaTrigger; } diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index b6c7fdc17ec..657d6027594 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -261,7 +261,7 @@ void SpellHistory::HandleCooldowns(SpellInfo const* spellInfo, uint32 itemID, Sp bool SpellHistory::IsReady(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, bool ignoreCategoryCooldown /*= false*/) const { - if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + if (spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE) if (IsSchoolLocked(spellInfo->GetSchoolMask())) return false; @@ -683,7 +683,7 @@ void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTim if (spellInfo->IsCooldownStartedOnEvent()) continue; - if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE) + if (!(spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE)) continue; if ((schoolMask & spellInfo->GetSchoolMask()) && GetRemainingCooldown(spellInfo) < lockoutTime) diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 362d5e8df35..5db23525a7f 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -487,7 +487,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster /*= nullptr*/, int32 const* { GtSpellScalingEntry const* gtScaling = sSpellScalingGameTable.GetRow(level); if (_spellInfo->Scaling.Class > 0) - value = GetGameTableColumnForClass(gtScaling, _spellInfo->Scaling.Class); + value = GetSpellScalingColumnForClass(gtScaling, _spellInfo->Scaling.Class); else value = gtScaling->Item; } @@ -1029,6 +1029,9 @@ SpellInfo::SpellInfo(SpellInfoLoadHelper const& data, SpellEffectEntryMap const& ActiveIconID = _misc ? _misc->ActiveIconID : 0; _visuals = std::move(visuals); + // sort all visuals so that the ones without a condition requirement are last on the list + for (auto& visualPair : _visuals) + std::sort(visualPair.second.begin(), visualPair.second.end(), [](SpellXSpellVisualEntry const* first, SpellXSpellVisualEntry const* second) { return first->PlayerConditionID > second->PlayerConditionID; }); // SpellScalingEntry SpellScalingEntry const* _scaling = data.Scaling; @@ -1243,22 +1246,6 @@ bool SpellInfo::IsQuestTame() const return effect0 && effect1 && effect0->Effect == SPELL_EFFECT_THREAT && effect1->Effect == SPELL_EFFECT_APPLY_AURA && effect1->ApplyAuraName == SPELL_AURA_DUMMY; } -bool SpellInfo::IsProfessionOrRiding(uint32 difficulty) const -{ - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for (SpellEffectInfo const* effect : effects) - { - if ((effect && effect->Effect == SPELL_EFFECT_SKILL)) - { - uint32 skill = effect->MiscValue; - - if (IsProfessionOrRidingSkill(skill)) - return true; - } - } - return false; -} - bool SpellInfo::IsProfession(uint32 difficulty) const { SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); @@ -1296,23 +1283,6 @@ bool SpellInfo::IsPrimaryProfessionFirstRank(uint32 difficulty) const return IsPrimaryProfession(difficulty) && GetRank() == 1; } -bool SpellInfo::IsAbilityLearnedWithProfession() const -{ - SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id); - - for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx) - { - SkillLineAbilityEntry const* pAbility = _spell_idx->second; - if (!pAbility || pAbility->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE) - continue; - - if (pAbility->MinSkillLineRank > 0) - return true; - } - - return false; -} - bool SpellInfo::IsAbilityOfSkillType(uint32 skillType) const { SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id); @@ -1411,12 +1381,6 @@ bool SpellInfo::IsStackableWithRanks() const if (IsPassive()) return false; - if (IsProfessionOrRiding()) - return false; - - if (IsAbilityLearnedWithProfession()) - return false; - // All stance spells. if any better way, change it. SpellEffectInfoVector effects = GetEffectsForDifficulty(DIFFICULTY_NONE); for (SpellEffectInfo const* effect : effects) @@ -2974,32 +2938,46 @@ bool SpellInfo::IsHighRankOf(SpellInfo const* spellInfo) const return false; } -uint32 SpellInfo::GetSpellXSpellVisualId(Difficulty difficulty) const +uint32 SpellInfo::GetSpellXSpellVisualId(Unit const* caster /*= nullptr*/) const { - DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty); - while (difficultyEntry) + if (caster) { - auto itr = _visuals.find(difficulty); - if (itr != _visuals.end()) - for (SpellXSpellVisualEntry const* visual : itr->second) - if (!visual->PlayerConditionID) - return visual->ID; + Difficulty difficulty = caster->GetMap()->GetDifficultyID(); + DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty); + while (difficultyEntry) + { + auto itr = _visuals.find(difficulty); + if (itr != _visuals.end()) + { + for (SpellXSpellVisualEntry const* visual : itr->second) + { + PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(visual->PlayerConditionID); + if (!playerCondition || (caster->GetTypeId() == TYPEID_PLAYER && sConditionMgr->IsPlayerMeetingCondition(caster->ToPlayer(), playerCondition))) + return visual->ID; + } + } - difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID); + difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID); + } } auto itr = _visuals.find(DIFFICULTY_NONE); if (itr != _visuals.end()) + { for (SpellXSpellVisualEntry const* visual : itr->second) - if (!visual->PlayerConditionID) + { + PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(visual->PlayerConditionID); + if (!playerCondition || (caster && caster->GetTypeId() == TYPEID_PLAYER && sConditionMgr->IsPlayerMeetingCondition(caster->ToPlayer(), playerCondition))) return visual->ID; + } + } return 0; } -uint32 SpellInfo::GetSpellVisual(Difficulty difficulty, Player* /*forPlayer*/ /*= nullptr*/) const +uint32 SpellInfo::GetSpellVisual(Unit const* caster /*= nullptr*/) const { - if (SpellXSpellVisualEntry const* visual = sSpellXSpellVisualStore.LookupEntry(GetSpellXSpellVisualId(difficulty))) + if (SpellXSpellVisualEntry const* visual = sSpellXSpellVisualStore.LookupEntry(GetSpellXSpellVisualId(caster))) { //if (visual->SpellVisualID[1] && forPlayer->GetViolenceLevel() operator 2) // return visual->SpellVisualID[1]; diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index a5d620571a3..0888c7ebb6e 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -445,11 +445,9 @@ public: bool IsExplicitDiscovery() const; bool IsLootCrafting() const; bool IsQuestTame() const; - bool IsProfessionOrRiding(uint32 difficulty = DIFFICULTY_NONE) const; bool IsProfession(uint32 difficulty = DIFFICULTY_NONE) const; bool IsPrimaryProfession(uint32 difficulty = DIFFICULTY_NONE) const; bool IsPrimaryProfessionFirstRank(uint32 difficulty = DIFFICULTY_NONE) const; - bool IsAbilityLearnedWithProfession() const; bool IsAbilityOfSkillType(uint32 skillType) const; bool IsAffectingArea(uint32 difficulty) const; @@ -539,8 +537,8 @@ public: bool IsDifferentRankOf(SpellInfo const* spellInfo) const; bool IsHighRankOf(SpellInfo const* spellInfo) const; - uint32 GetSpellXSpellVisualId(Difficulty difficulty) const; - uint32 GetSpellVisual(Difficulty difficulty, Player* forPlayer = nullptr) const; + uint32 GetSpellXSpellVisualId(Unit const* caster = nullptr) const; + uint32 GetSpellVisual(Unit const* caster = nullptr) const; // loading helpers void _InitializeExplicitTargetMask(); diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 84cbbe90b7e..0ab8b919664 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -68,24 +68,24 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto) case SPELLFAMILY_GENERIC: { // Entrapment -- 135373 - if (spellproto->SpellIconID == 20 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 39588) + if (spellproto->SpellIconID == 20 && spellproto->GetSpellVisual() == 39588) return DIMINISHING_ROOT; // Intimidation -- 24394 - if (spellproto->SpellIconID == 166 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 2816) + if (spellproto->SpellIconID == 166 && spellproto->GetSpellVisual() == 2816) return DIMINISHING_STUN; // Pulverize (Primal Earth Elemental) -- 118345 - if (spellproto->SpellIconID == 4507 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 39877) + if (spellproto->SpellIconID == 4507 && spellproto->GetSpellVisual() == 39877) return DIMINISHING_STUN; // Static Charge (Capacitor Totem) -- 118905 - if (spellproto->SpellIconID == 54 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 24442) + if (spellproto->SpellIconID == 54 && spellproto->GetSpellVisual() == 24442) return DIMINISHING_STUN; // Remorseless Winter -- 115001 - if (spellproto->SpellIconID == 5744 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 23514) + if (spellproto->SpellIconID == 5744 && spellproto->GetSpellVisual() == 23514) return DIMINISHING_STUN; // Gorefiend's Grasp -- 108199 - if (spellproto->SpellIconID == 5743 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 28937) + if (spellproto->SpellIconID == 5743 && spellproto->GetSpellVisual() == 28937) return DIMINISHING_AOE_KNOCKBACK; break; } @@ -150,7 +150,7 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto) if (spellproto->SpellFamilyFlags[1] & 0x8000000) return DIMINISHING_INCAPACITATE; // Blood Horror -- 137143, no flags (17986) - if (spellproto->SpellIconID == 6447 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 26758) + if (spellproto->SpellIconID == 6447 && spellproto->GetSpellVisual() == 26758) return DIMINISHING_INCAPACITATE; // Fear -- 118699 @@ -194,11 +194,11 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto) if (spellproto->SpellFamilyFlags[0] & 0x2000) return DIMINISHING_STUN; // Rake -- 163505 -- no flags on the stun, 20490 - if (spellproto->SpellIconID == 494 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 38283) + if (spellproto->SpellIconID == 494 && spellproto->GetSpellVisual() == 38283) return DIMINISHING_STUN; // Incapacitating Roar -- 99, no flags on the stun, 14 - if (spellproto->SpellIconID == 960 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 38528) + if (spellproto->SpellIconID == 960 && spellproto->GetSpellVisual() == 38528) return DIMINISHING_INCAPACITATE; // Cyclone -- 33786 @@ -220,7 +220,7 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto) if (spellproto->SpellFamilyFlags[0] & 0x200) return DIMINISHING_ROOT; // Mass Entanglement -- 102359, no flags on the root, 13535 - if (spellproto->SpellIconID == 5782 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 38269) + if (spellproto->SpellIconID == 5782 && spellproto->GetSpellVisual() == 38269) return DIMINISHING_ROOT; // Faerie Fire -- 770, 20 seconds in PvP (6.0) @@ -259,14 +259,14 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto) // return DIMINISHING_AOE_KNOCKBACK; // Charge (Tenacity pet) -- 53148, no flags (5526) - if (spellproto->SpellIconID == 1559 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 39480) + if (spellproto->SpellIconID == 1559 && spellproto->GetSpellVisual() == 39480) return DIMINISHING_ROOT; // Narrow Escape -- 136634, no flags (17964) if (spellproto->SpellIconID == 3342 && spellproto->SchoolMask == 8) return DIMINISHING_ROOT; // Binding Shot -- 117526, no flags (15581) - if (spellproto->SpellIconID == 4612 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 6859) + if (spellproto->SpellIconID == 4612 && spellproto->GetSpellVisual() == 6859) return DIMINISHING_STUN; // Freezing Trap -- 3355 @@ -313,7 +313,7 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto) if (spellproto->SpellFamilyFlags[2] & 0x4000) return DIMINISHING_ROOT; // Frost Shock (with Frozen Power) -- 63685, no flags (6918) - if (spellproto->SpellIconID == 193 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 39876) + if (spellproto->SpellIconID == 193 && spellproto->GetSpellVisual() == 39876) return DIMINISHING_ROOT; break; } @@ -324,31 +324,31 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto) return DIMINISHING_SILENCE; // Chains of Ice (with Chilblains) -- 96294, no flags (13020) - if (spellproto->SpellIconID == 180 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 20135) + if (spellproto->SpellIconID == 180 && spellproto->GetSpellVisual() == 20135) return DIMINISHING_ROOT; // Asphyxiate -- 108194 if (spellproto->SpellFamilyFlags[2] & 0x100000) return DIMINISHING_STUN; // Gnaw (Ghoul) -- 91800, no flags (12511) - if (spellproto->SpellIconID == 3010 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 38760) + if (spellproto->SpellIconID == 3010 && spellproto->GetSpellVisual() == 38760) return DIMINISHING_STUN; // Monstrous Blow (Ghoul w/ Dark Transformation active) -- 91797, no flags (12510) - if (spellproto->SpellIconID == 15 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 38761) + if (spellproto->SpellIconID == 15 && spellproto->GetSpellVisual() == 38761) return DIMINISHING_STUN; break; } case SPELLFAMILY_PRIEST: { // Glyph of Mind Blast -- 87194, no flags (10092) - if (spellproto->SpellIconID == 2114 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 38927) + if (spellproto->SpellIconID == 2114 && spellproto->GetSpellVisual() == 38927) return DIMINISHING_ROOT; // Void Tendrils -- 114404, no flags (15067) - if (spellproto->SpellIconID == 5816 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 25199) + if (spellproto->SpellIconID == 5816 && spellproto->GetSpellVisual() == 25199) return DIMINISHING_ROOT; // Dominate Mind -- 605 - if (spellproto->SpellFamilyFlags[0] & 0x20000 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 39068) + if (spellproto->SpellFamilyFlags[0] & 0x20000 && spellproto->GetSpellVisual() == 39068) return DIMINISHING_INCAPACITATE; // Holy Word: Chastise -- 88625 if (spellproto->SpellFamilyFlags[2] & 0x20) @@ -369,7 +369,7 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto) case SPELLFAMILY_MONK: { // Disable -- 116706, no flags (15483) - if (spellproto->SpellIconID == 23 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 39984) + if (spellproto->SpellIconID == 23 && spellproto->GetSpellVisual() == 39984) return DIMINISHING_ROOT; // Charging Ox Wave -- 119392 @@ -383,13 +383,13 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto) return DIMINISHING_STUN; // Glyph of Breath of Fire -- 123393, no flags (16504) - if (spellproto->SpellIconID == 15 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 25408) + if (spellproto->SpellIconID == 15 && spellproto->GetSpellVisual() == 25408) return DIMINISHING_INCAPACITATE; // Paralysis -- 115078 if (spellproto->SpellFamilyFlags[2] & 0x800000) return DIMINISHING_INCAPACITATE; // Ring of Peace -- 137460, no flags (18006) - if (spellproto->SpellIconID == 7195 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 39999) + if (spellproto->SpellIconID == 7195 && spellproto->GetSpellVisual() == 39999) return DIMINISHING_INCAPACITATE; break; } @@ -443,7 +443,7 @@ int32 GetDiminishingReturnsLimitDuration(SpellInfo const* spellproto) case SPELLFAMILY_HUNTER: { // Binding Shot - 3 seconds in PvP (6.0) - if (spellproto->SpellIconID == 4612 && spellproto->GetSpellVisual(DIFFICULTY_NONE) == 6859) + if (spellproto->SpellIconID == 4612 && spellproto->GetSpellVisual() == 6859) return 3 * IN_MILLISECONDS; // Wyvern Sting - 6 seconds in PvP (6.0) if (spellproto->SpellFamilyFlags[1] & 0x1000) @@ -1260,113 +1260,71 @@ void SpellMgr::LoadSpellRanks() { uint32 oldMSTime = getMSTime(); - // 0 1 2 - QueryResult result = WorldDatabase.Query("SELECT first_spell_id, spell_id, rank from spell_ranks ORDER BY first_spell_id, rank"); - - if (!result) + std::map<uint32 /*spell*/, uint32 /*next*/> chains; + std::set<uint32> hasPrev; + for (SkillLineAbilityEntry const* skillAbility : sSkillLineAbilityStore) { - TC_LOG_INFO("server.loading", ">> Loaded 0 spell rank records. DB table `spell_ranks` is empty."); - return; - } - - uint32 count = 0; - bool finished = false; - - do - { - // spellid, rank - std::list < std::pair < int32, int32 > > rankChain; - int32 currentSpell = -1; - int32 lastSpell = -1; - - // fill one chain - while (currentSpell == lastSpell && !finished) - { - Field* fields = result->Fetch(); - - currentSpell = fields[0].GetUInt32(); - if (lastSpell == -1) - lastSpell = currentSpell; - uint32 spell_id = fields[1].GetUInt32(); - uint32 rank = fields[2].GetUInt8(); - - // don't drop the row if we're moving to the next rank - if (currentSpell == lastSpell) - { - rankChain.push_back(std::make_pair(spell_id, rank)); - if (!result->NextRow()) - finished = true; - } - else - break; - } - // check if chain is made with valid first spell - SpellInfo const* first = GetSpellInfo(lastSpell); - if (!first) - { - TC_LOG_ERROR("sql.sql", "The spell rank identifier(first_spell_id) %u listed in `spell_ranks` does not exist!", lastSpell); - continue; - } - // check if chain is long enough - if (rankChain.size() < 2) - { - TC_LOG_ERROR("sql.sql", "There is only 1 spell rank for identifier(first_spell_id) %u in `spell_ranks`, entry is not needed!", lastSpell); + if (!skillAbility->SupercedesSpell) continue; - } - int32 curRank = 0; - bool valid = true; - // check spells in chain - for (std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin(); itr!= rankChain.end(); ++itr) - { - SpellInfo const* spell = GetSpellInfo(itr->first); - if (!spell) - { - TC_LOG_ERROR("sql.sql", "The spell %u (rank %u) listed in `spell_ranks` for chain %u does not exist!", itr->first, itr->second, lastSpell); - valid = false; - break; - } - ++curRank; - if (itr->second != curRank) - { - TC_LOG_ERROR("sql.sql", "The spell %u (rank %u) listed in `spell_ranks` for chain %u does not have a proper rank value (should be %u)!", itr->first, itr->second, lastSpell, curRank); - valid = false; - break; - } - } - if (!valid) + + if (!GetSpellInfo(skillAbility->SupercedesSpell) || !GetSpellInfo(skillAbility->SpellID)) continue; - int32 prevRank = 0; - // insert the chain - std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin(); - do - { - ++count; - int32 addedSpell = itr->first; - if (mSpellInfoMap[addedSpell]->ChainEntry) - TC_LOG_ERROR("sql.sql", "The spell %u (rank: %u, first: %u) listed in `spell_ranks` already has ChainEntry from dbc.", addedSpell, itr->second, lastSpell); + chains[skillAbility->SupercedesSpell] = skillAbility->SpellID; + hasPrev.insert(skillAbility->SpellID); + } - mSpellChains[addedSpell].first = GetSpellInfo(lastSpell); - mSpellChains[addedSpell].last = GetSpellInfo(rankChain.back().first); - mSpellChains[addedSpell].rank = itr->second; - mSpellChains[addedSpell].prev = GetSpellInfo(prevRank); - mSpellInfoMap[addedSpell]->ChainEntry = &mSpellChains[addedSpell]; - prevRank = addedSpell; - ++itr; + // each key in chains that isn't present in hasPrev is a first rank + for (auto itr = chains.begin(); itr != chains.end(); ++itr) + { + if (hasPrev.count(itr->first)) + continue; - if (itr == rankChain.end()) + SpellInfo const* first = AssertSpellInfo(itr->first); + SpellInfo const* next = AssertSpellInfo(itr->second); + + mSpellChains[itr->first].first = first; + mSpellChains[itr->first].prev = nullptr; + mSpellChains[itr->first].next = next; + mSpellChains[itr->first].last = next; + mSpellChains[itr->first].rank = 1; + mSpellInfoMap[itr->first]->ChainEntry = &mSpellChains[itr->first]; + + mSpellChains[itr->second].first = first; + mSpellChains[itr->second].prev = first; + mSpellChains[itr->second].next = nullptr; + mSpellChains[itr->second].last = next; + mSpellChains[itr->second].rank = 2; + mSpellInfoMap[itr->second]->ChainEntry = &mSpellChains[itr->second]; + + uint8 rank = 3; + auto nextItr = chains.find(itr->second); + while (nextItr != chains.end()) + { + SpellInfo const* prev = AssertSpellInfo(nextItr->first); // already checked in previous iteration (or above, in case this is the first one) + SpellInfo const* last = AssertSpellInfo(nextItr->second); + + mSpellChains[nextItr->first].next = last; + + mSpellChains[nextItr->second].first = first; + mSpellChains[nextItr->second].prev = prev; + mSpellChains[nextItr->second].next = nullptr; + mSpellChains[nextItr->second].last = last; + mSpellChains[nextItr->second].rank = rank++; + mSpellInfoMap[nextItr->second]->ChainEntry = &mSpellChains[nextItr->second]; + + // fill 'last' + do { - mSpellChains[addedSpell].next = NULL; - break; - } - else - mSpellChains[addedSpell].next = GetSpellInfo(itr->first); + mSpellChains[prev->Id].last = last; + prev = mSpellChains[prev->Id].prev; + } while (prev); + + nextItr = chains.find(nextItr->second); } - while (true); } - while (!finished); - TC_LOG_INFO("server.loading", ">> Loaded %u spell rank records in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u spell rank records in %u ms", uint32(mSpellChains.size()), GetMSTimeDiffToNow(oldMSTime)); } void SpellMgr::LoadSpellRequired() @@ -1450,8 +1408,8 @@ void SpellMgr::LoadSpellLearnSkills() if (effect && effect->Effect == SPELL_EFFECT_SKILL) { SpellLearnSkillNode dbc_node; - dbc_node.skill = effect->MiscValue; - dbc_node.step = effect->CalcValue(); + dbc_node.skill = uint16(effect->MiscValue); + dbc_node.step = uint16(effect->CalcValue()); if (dbc_node.skill != SKILL_RIDING) dbc_node.value = 1; else @@ -1677,7 +1635,7 @@ void SpellMgr::LoadSpellTargetPositions() // target facing is in degrees for 6484 & 9268... (blizz sucks) if (effect->PositionFacing > 2 * M_PI) - st.target_Orientation = effect->PositionFacing * M_PI / 180; + st.target_Orientation = effect->PositionFacing * float(M_PI) / 180; else st.target_Orientation = effect->PositionFacing; @@ -2375,7 +2333,7 @@ void SpellMgr::LoadPetLevelupSpellMap() if (skillLine->SkillLine != creatureFamily->SkillLine[j]) continue; - if (skillLine->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) + if (skillLine->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) continue; SpellInfo const* spell = GetSpellInfo(skillLine->SpellID); @@ -2936,7 +2894,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes() if (!spellInfo->_IsPositiveEffect(EFFECT_2, false)) spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF2; - if (spellInfo->GetSpellVisual(DIFFICULTY_NONE) == 3879) + if (spellInfo->GetSpellVisual() == 3879) spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_BACK; if (talentSpells.count(spellInfo->Id)) @@ -3475,7 +3433,7 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_JUMP; break; case 5420: // Tree of Life (Passive) - spellInfo->Stances = UI64LIT(1) << (FORM_TREE - 1); + spellInfo->Stances = UI64LIT(1) << (FORM_TREE_OF_LIFE - 1); break; case 49376: // Feral Charge (Cat Form) spellInfo->AttributesEx3 &= ~SPELL_ATTR3_CANT_TRIGGER_PROC; @@ -3552,7 +3510,7 @@ void SpellMgr::LoadPetFamilySpellsStore() if (skillLine->SkillLine != cFamily->SkillLine[0] && skillLine->SkillLine != cFamily->SkillLine[1]) continue; - if (skillLine->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) + if (skillLine->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) continue; sPetFamilySpellsStore[i].insert(spellInfo->ID); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index dd087a63146..6f27d733eb8 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -2192,17 +2192,9 @@ public: } return true; } - /* - ComeToMe command REQUIRED for 3rd party scripting library to have access to PointMovementGenerator - Without this function 3rd party scripting library will get linking errors (unresolved external) - when attempting to use the PointMovementGenerator - */ - static bool HandleComeToMeCommand(ChatHandler* handler, char const* args) - { - char const* newFlagStr = strtok((char*)args, " "); - if (!newFlagStr) - return false; + static bool HandleComeToMeCommand(ChatHandler* handler, char const* /*args*/) + { Creature* caster = handler->getSelectedCreature(); if (!caster) { diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp index b87c836c2a4..84ee5cd97db 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp @@ -298,7 +298,7 @@ public: if (Blind_Timer <= diff) { std::list<Unit*> targets; - SelectTargetList(targets, 5, SELECT_TARGET_RANDOM, me->GetMeleeReach()*5, true); + SelectTargetList(targets, 5, SELECT_TARGET_RANDOM, me->GetCombatReach()*5, true); for (std::list<Unit*>::const_iterator i = targets.begin(); i != targets.end(); ++i) if (!me->IsWithinMeleeRange(*i)) { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 33afada15fd..3a7d8547cc9 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -1366,17 +1366,6 @@ class spell_algalon_supermassive_fail : public SpellScriptLoader } }; -class achievement_he_feeds_on_your_tears : public AchievementCriteriaScript -{ - public: - achievement_he_feeds_on_your_tears() : AchievementCriteriaScript("achievement_he_feeds_on_your_tears") { } - - bool OnCheck(Player* /*source*/, Unit* target) override - { - return !target->GetAI()->GetData(DATA_HAS_FED_ON_TEARS); - } -}; - void AddSC_boss_algalon_the_observer() { new boss_algalon_the_observer(); @@ -1393,5 +1382,4 @@ void AddSC_boss_algalon_the_observer() new spell_algalon_cosmic_smash(); new spell_algalon_cosmic_smash_damage(); new spell_algalon_supermassive_fail(); - new achievement_he_feeds_on_your_tears(); } diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 2c941a4f757..bb7ad7a84c0 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -74,7 +74,7 @@ class spell_dru_dash : public SpellScriptLoader void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) { // do not set speed if not in cat form - if (GetUnitOwner()->GetShapeshiftForm() != FORM_CAT) + if (GetUnitOwner()->GetShapeshiftForm() != FORM_CAT_FORM) amount = 0; } @@ -767,7 +767,7 @@ class spell_dru_savage_roar : public SpellScriptLoader SpellCastResult CheckCast() { Unit* caster = GetCaster(); - if (caster->GetShapeshiftForm() != FORM_CAT) + if (caster->GetShapeshiftForm() != FORM_CAT_FORM) return SPELL_FAILED_ONLY_SHAPESHIFT; return SPELL_CAST_OK; @@ -889,7 +889,7 @@ class spell_dru_stampede : public SpellScriptLoader void HandleEffectCatProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - if (GetTarget()->GetShapeshiftForm() != FORM_CAT || eventInfo.GetDamageInfo()->GetSpellInfo()->Id != SPELL_DRUID_FERAL_CHARGE_CAT) + if (GetTarget()->GetShapeshiftForm() != FORM_CAT_FORM || eventInfo.GetDamageInfo()->GetSpellInfo()->Id != SPELL_DRUID_FERAL_CHARGE_CAT) return; GetTarget()->CastSpell(GetTarget(), sSpellMgr->GetSpellWithRank(SPELL_DRUID_STAMPEDE_CAT_RANK_1, GetSpellInfo()->GetRank()), true, NULL, aurEff); @@ -899,7 +899,7 @@ class spell_dru_stampede : public SpellScriptLoader void HandleEffectBearProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - if (GetTarget()->GetShapeshiftForm() != FORM_BEAR || eventInfo.GetDamageInfo()->GetSpellInfo()->Id != SPELL_DRUID_FERAL_CHARGE_BEAR) + if (GetTarget()->GetShapeshiftForm() != FORM_BEAR_FORM || eventInfo.GetDamageInfo()->GetSpellInfo()->Id != SPELL_DRUID_FERAL_CHARGE_BEAR) return; GetTarget()->CastSpell(GetTarget(), sSpellMgr->GetSpellWithRank(SPELL_DRUID_STAMPEDE_BAER_RANK_1, GetSpellInfo()->GetRank()), true, NULL, aurEff); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index cf9ff3ef28b..f0ebfb23427 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -4228,6 +4228,164 @@ class spell_gen_clear_debuffs : public SpellScriptLoader } }; +// 169869 - Transformation Sickness +class spell_gen_decimatus_transformation_sickness : public SpellScriptLoader +{ +public: + spell_gen_decimatus_transformation_sickness() : SpellScriptLoader("spell_gen_decimatus_transformation_sickness") { } + + class spell_gen_decimatus_transformation_sickness_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_decimatus_transformation_sickness_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->SetHealth(target->CountPctFromMaxHealth(10)); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gen_decimatus_transformation_sickness_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gen_decimatus_transformation_sickness_SpellScript(); + } +}; + +// 189491 - Summon Towering Infernal. +class spell_gen_anetheron_summon_towering_infernal : public SpellScriptLoader +{ + public: + spell_gen_anetheron_summon_towering_infernal() : SpellScriptLoader("spell_gen_anetheron_summon_towering_infernal") { } + + class spell_gen_anetheron_summon_towering_infernal_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_anetheron_summon_towering_infernal_SpellScript); + + void HandleDummy(SpellEffIndex /* effIndex */) + { + GetCaster()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gen_anetheron_summon_towering_infernal_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gen_anetheron_summon_towering_infernal_SpellScript(); + } +}; + +enum KazrogalHellfireMark +{ + SPELL_MARK_OF_KAZROGAL_HELLFIRE = 189512, + SPELL_MARK_OF_KAZROGAL_DAMAGE_HELLFIRE = 189515 +}; + +class MarkTargetHellfireFilter +{ + public: + bool operator()(WorldObject* target) const + { + if (Unit* unit = target->ToUnit()) + return unit->getPowerType() != POWER_MANA; + return false; + } +}; + +class spell_gen_mark_of_kazrogal_hellfire : public SpellScriptLoader +{ + public: + spell_gen_mark_of_kazrogal_hellfire() : SpellScriptLoader("spell_gen_mark_of_kazrogal_hellfire") { } + + class spell_gen_mark_of_kazrogal_hellfire_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_mark_of_kazrogal_hellfire_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(MarkTargetHellfireFilter()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gen_mark_of_kazrogal_hellfire_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + class spell_gen_mark_of_kazrogal_hellfire_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_mark_of_kazrogal_hellfire_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_MARK_OF_KAZROGAL_DAMAGE_HELLFIRE)) + return false; + return true; + } + + void OnPeriodic(AuraEffect const* aurEff) + { + Unit* target = GetTarget(); + + if (target->GetPower(POWER_MANA) == 0) + { + target->CastSpell(target, SPELL_MARK_OF_KAZROGAL_DAMAGE_HELLFIRE, true, NULL, aurEff); + // Remove aura + SetDuration(0); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_gen_mark_of_kazrogal_hellfire_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_POWER_BURN); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gen_mark_of_kazrogal_hellfire_SpellScript(); + } + + AuraScript* GetAuraScript() const override + { + return new spell_gen_mark_of_kazrogal_hellfire_AuraScript(); + } +}; + +class spell_gen_azgalor_rain_of_fire_hellfire_citadel : public SpellScriptLoader +{ + public: + spell_gen_azgalor_rain_of_fire_hellfire_citadel() : SpellScriptLoader("spell_gen_azgalor_rain_of_fire_hellfire_citadel") { } + + class spell_gen_azgalor_rain_of_fire_hellfire_citadel_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_azgalor_rain_of_fire_hellfire_citadel_SpellScript); + + void HandleDummy(SpellEffIndex /* effIndex */) + { + GetCaster()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gen_azgalor_rain_of_fire_hellfire_citadel_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gen_azgalor_rain_of_fire_hellfire_citadel_SpellScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -4318,4 +4476,8 @@ void AddSC_generic_spell_scripts() new spell_gen_mixology_bonus(); new spell_gen_landmine_knockback_achievement(); new spell_gen_clear_debuffs(); + new spell_gen_decimatus_transformation_sickness(); + new spell_gen_anetheron_summon_towering_infernal(); + new spell_gen_mark_of_kazrogal_hellfire(); + new spell_gen_azgalor_rain_of_fire_hellfire_citadel(); } diff --git a/src/server/scripts/Spells/spell_monk.cpp b/src/server/scripts/Spells/spell_monk.cpp index 904089bc451..fd91db9216f 100644 --- a/src/server/scripts/Spells/spell_monk.cpp +++ b/src/server/scripts/Spells/spell_monk.cpp @@ -28,12 +28,15 @@ enum MonkSpells { - SPELL_MONK_CRACKLING_JADE_LIGHTNING_CHANNEL = 117952, - SPELL_MONK_CRACKLING_JADE_LIGHTNING_CHI_PROC = 123333, - SPELL_MONK_STANCE_OF_THE_SPIRITED_CRANE = 154436, - - SPELL_MONK_CRACKLING_JADE_LIGHTNING_KNOCKBACK = 117962, - SPELL_MONK_CRACKLING_JADE_LIGHTNING_KNOCKBACK_CD = 117953, + SPELL_MONK_CRACKLING_JADE_LIGHTNING_CHANNEL = 117952, + SPELL_MONK_CRACKLING_JADE_LIGHTNING_CHI_PROC = 123333, + SPELL_MONK_CRACKLING_JADE_LIGHTNING_KNOCKBACK = 117962, + SPELL_MONK_CRACKLING_JADE_LIGHTNING_KNOCKBACK_CD = 117953, + SPELL_MONK_PROVOKE_SINGLE_TARGET = 116189, + SPELL_MONK_PROVOKE_AOE = 118635, + SPELL_MONK_SOOTHING_MIST = 115175, + SPELL_MONK_STANCE_OF_THE_SPIRITED_CRANE = 154436, + SPELL_MONK_SURGING_MIST_HEAL = 116995, }; // 117952 - Crackling Jade Lightning @@ -125,8 +128,177 @@ public: } }; +// 115546 - Provoke +class spell_monk_provoke : public SpellScriptLoader +{ +public: + spell_monk_provoke() : SpellScriptLoader("spell_monk_provoke") { } + + class spell_monk_provoke_SpellScript : public SpellScript + { + PrepareSpellScript(spell_monk_provoke_SpellScript); + + static uint32 const BlackOxStatusEntry = 61146; + + bool Validate(SpellInfo const* spellInfo) override + { + if (!(spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT_MASK)) // ensure GetExplTargetUnit() will return something meaningful during CheckCast + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_MONK_PROVOKE_SINGLE_TARGET)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_MONK_PROVOKE_AOE)) + return false; + return true; + } + + SpellCastResult CheckExplicitTarget() + { + if (GetExplTargetUnit()->GetEntry() != BlackOxStatusEntry) + { + SpellInfo const* singleTarget = sSpellMgr->AssertSpellInfo(SPELL_MONK_PROVOKE_SINGLE_TARGET); + SpellCastResult singleTargetExplicitResult = singleTarget->CheckExplicitTarget(GetCaster(), GetExplTargetUnit()); + if (singleTargetExplicitResult != SPELL_CAST_OK) + return singleTargetExplicitResult; + } + else if (GetExplTargetUnit()->GetOwnerGUID() != GetCaster()->GetGUID()) + return SPELL_FAILED_BAD_TARGETS; + + return SPELL_CAST_OK; + } + + void HandleDummy(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (GetHitUnit()->GetEntry() != BlackOxStatusEntry) + GetCaster()->CastSpell(GetHitUnit(), SPELL_MONK_PROVOKE_SINGLE_TARGET, true); + else + GetCaster()->CastSpell(GetHitUnit(), SPELL_MONK_PROVOKE_AOE, true); + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_monk_provoke_SpellScript::CheckExplicitTarget); + OnEffectHitTarget += SpellEffectFn(spell_monk_provoke_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_monk_provoke_SpellScript(); + } +}; + +// 116694 - Surging Mist +class spell_monk_surging_mist : public SpellScriptLoader +{ + public: + spell_monk_surging_mist() : SpellScriptLoader("spell_monk_surging_mist") { } + + class spell_monk_surging_mist_SpellScript : public SpellScript + { + PrepareSpellScript(spell_monk_surging_mist_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_MONK_SURGING_MIST_HEAL)) + return false; + return true; + } + + void SelectTarget(WorldObject*& target) + { + Unit* caster = GetCaster(); + if (caster->GetUInt32Value(UNIT_CHANNEL_SPELL) == SPELL_MONK_SOOTHING_MIST) + if (Unit* soothingMistTarget = ObjectAccessor::GetUnit(*caster, caster->GetChannelObjectGuid())) + target = soothingMistTarget; + } + + void HandleDummy(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetCaster()->CastSpell(GetHitUnit(), SPELL_MONK_SURGING_MIST_HEAL, true); + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_monk_surging_mist_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_TARGET_ALLY); + OnEffectHitTarget += SpellEffectFn(spell_monk_surging_mist_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_monk_surging_mist_SpellScript(); + } +}; + +// 123273 - Surging Mist (Glyphed) +class spell_monk_surging_mist_glyphed : public SpellScriptLoader +{ +public: + spell_monk_surging_mist_glyphed() : SpellScriptLoader("spell_monk_surging_mist_glyphed") { } + + class spell_monk_surging_mist_glyphed_SpellScript : public SpellScript + { + PrepareSpellScript(spell_monk_surging_mist_glyphed_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_MONK_SURGING_MIST_HEAL)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_MONK_SOOTHING_MIST)) + return false; + return true; + } + + void SelectTarget(std::list<WorldObject*>& targets) + { + Unit* caster = GetCaster(); + if (caster->GetUInt32Value(UNIT_CHANNEL_SPELL) == SPELL_MONK_SOOTHING_MIST) + { + targets.clear(); + if (Unit* soothingMistTarget = ObjectAccessor::GetUnit(*caster, caster->GetChannelObjectGuid())) + targets.push_back(soothingMistTarget); + } + else + { + targets.remove_if([caster](WorldObject* target) + { + return target->GetTypeId() != TYPEID_UNIT || !target->ToUnit()->IsInRaidWith(caster); + }); + targets.sort(Trinity::HealthPctOrderPred()); + if (!targets.empty()) + targets.resize(1); + } + + if (targets.empty()) + targets.push_back(caster); + } + + void HandleDummy(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetCaster()->CastSpell(GetHitUnit(), SPELL_MONK_SURGING_MIST_HEAL, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_monk_surging_mist_glyphed_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + OnEffectHitTarget += SpellEffectFn(spell_monk_surging_mist_glyphed_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_monk_surging_mist_glyphed_SpellScript(); + } +}; + void AddSC_monk_spell_scripts() { new spell_monk_crackling_jade_lightning(); new spell_monk_crackling_jade_lightning_knockback_proc_aura(); + new spell_monk_provoke(); + new spell_monk_surging_mist(); + new spell_monk_surging_mist_glyphed(); } diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 73b5719ec18..5bf03012ec1 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -99,6 +99,12 @@ LogsDir = "" # "127.0.0.1;3306;trinity;trinity;world" - (WorldDatabaseInfo) # "127.0.0.1;3306;trinity;trinity;characters" - (CharacterDatabaseInfo) # "127.0.0.1;3306;trinity;trinity;hotfixes" - (HotfixDatabaseInfo) +# +# Don't change hostname unless you are hosting mysql on a different machine, if you need help +# with configuration allowing to connect from diferent machine than the one running server +# search for TCE00016 on forum. +# Don't open port on firewall to external connections (it belongs to mysql, not to wow server). +# The username you choose must have permisions to create/alter/rename tables. LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth" WorldDatabaseInfo = "127.0.0.1;3306;trinity;trinity;world" diff --git a/src/tools/connection_patcher/Patches/Common.hpp b/src/tools/connection_patcher/Patches/Common.hpp index 22e22beedcd..58215a42419 100644 --- a/src/tools/connection_patcher/Patches/Common.hpp +++ b/src/tools/connection_patcher/Patches/Common.hpp @@ -66,7 +66,7 @@ R"({ "SigningCertificates": [ { "RawData": "-----BEGIN CERTIFICATE-----MIIF5DCCA8ygAwIBAgIJAIgLslwk40XzMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtUcmluaXR5Q29yZTEqMCgGA1UECwwhVHJpbml0eUNvcmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MS4wLAYDVQQDDCVUcmluaXR5Q29yZSBCYXR0bGUubmV0IEF1cm9yYSBSb290IENBMB4XDTE2MDIyODEyNDkwOFoXDTM2MDIyMzEyNDkwOFowfzELMAkGA1UEBhMCVVMxFDASBgNVBAoMC1RyaW5pdHlDb3JlMSowKAYDVQQLDCFUcmluaXR5Q29yZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxLjAsBgNVBAMMJVRyaW5pdHlDb3JlIEJhdHRsZS5uZXQgQXVyb3JhIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGrYWvS0mVParJd96E4z/qjCvW6eR0buQ++VNEqVgeG14k4V41wkEzakB4nr2oGH10z9J/aqLlWnxaOl+yJ7BaomUAAOgJaCyqAJ8HaEU+7BbDO4MZXmtw1A3YcHsBkVx5wGm3tcH5IEXfVhvNZDqwAmYIcm7gKFgnds6RFJmRxF4WznWiRr2MQkSOr/kc2eQ2VUg5afTlTxZva/mXEVpShinvbhaMSgFBW+QahCwBJVQaLhEn+Wc6YNuHFmZ/i716xGb3cuYu89TF46iKQ/9Bm8yEFGg8QA28IZQ1sXgVpzJI9eowFtqAwhl65ipjGw4xH33of+WcwJQNjF7HXymRqk0WAa2jtXOEiShI3XDloblX7vKbAe9RFpfVIqT8UfKSOJGQDVzvl4wSihINshO7YgIqp97MGnWtnlWCDb2mcSj8JjnzRjG2kZZCNR/2lgfCG/1VF+QLh/3vD2+N5YkJZqBK1JTFFx+p66lVQWfdh2MXPlGjat343HZGm0YR7nRjngO2j3YtTojdJxRfLgztQv94jMtWPHE38ysUK7mS6KKqYXqyB19IOHL2QB8fjmON1hCd0wDW42ZB23ywNkASw6uJDR02xXN2wiynIIb3cz6zouXd60wC7utMTveq8+rhFFgmFDdI2o9gwWQPA/43OYIlAdKVg2NRhXb/6bzFkwIDAQABo2MwYTAdBgNVHQ4EFgQUEt6gxhfmHEc7rBOqHJEfNkzGv3MwHwYDVR0jBBgwFoAUEt6gxhfmHEc7rBOqHJEfNkzGv3MwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAFzCJkcDCPVMal+Thlip26LPkszZ4zWTsNsbUYmSe7h0kmMWt4x3mmZITfwb/eysYCnHThBVTjXj9VWBGfbECZ/xdyXC2ur+qp0Mm7xH2Wuswf7yfPC+USNO6+/tFS282FO/nM0quaKVknOC8ioCoASsBICB9lwRoYRKNBwRn3pkJplHepGahaJez4eedujO3dzxDdD32zy2/AfdeFXTxhWY8PTjMBKC2zpUQD7Kdvl+D8SfIsq73b8a9XmhdNX7qTc6MjecCD7WHAP2rrK7epjTaVJp4+PYlw7qfix/NT1fNkq2Mb2E77h2eToUG1mjs/mvG/4WfVCfMaBHOKaw6fyZULf366Jbx02r8K05P5ouvS1Z0De1mZJuUEUYhTRSs2POIdrmVrn9R83Y4l7TKNPJelq2uyEc4r+/fRrerIlT4HVlLPTC3SdW8ytYSUZXx+1NfJfQimieveIyIaTOV3SfC4EfeXtPtUpcVJvmFXqVbnXOO7bQU63bfFuuVSeU6OXWjoFRVkdHNYTGUGb5xg4hgWqlLWvWg0WPgLLabMbetrP6c5/Qhml/l07nJHeLoVxlFuwsL8HGeu0JWqnmwamp4/mmblRC9UfyrIQeDS8gsx8q/t2zdzT4bBph0nqYkZSyiIoQzlMrYdrWxeJm3sReR0G3FluL+03TGJypGfhr-----END CERTIFICATE-----" } ] -};inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature)"; +}NGISerting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature_inserting_dummy_signature)"; } }; } |
