aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/GitRevision.cpp31
-rw-r--r--src/common/Utilities/EventProcessor.cpp80
-rw-r--r--src/common/Utilities/EventProcessor.h36
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp2
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp9
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h4
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp2
-rw-r--r--src/server/game/Achievements/CriteriaHandler.cpp85
-rw-r--r--src/server/game/Achievements/CriteriaHandler.h2
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp2
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp16
-rw-r--r--src/server/game/DataStores/DB2Stores.h11
-rw-r--r--src/server/game/DataStores/DB2Structure.h19
-rw-r--r--src/server/game/DataStores/DBCEnums.h21
-rw-r--r--src/server/game/DataStores/GameTables.h49
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.cpp18
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.h3
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp8
-rw-r--r--src/server/game/Entities/DynamicObject/DynamicObject.cpp11
-rw-r--r--src/server/game/Entities/DynamicObject/DynamicObject.h3
-rw-r--r--src/server/game/Entities/Item/Item.cpp37
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp82
-rw-r--r--src/server/game/Entities/Player/Player.h4
-rw-r--r--src/server/game/Entities/Unit/StatSystem.cpp33
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp58
-rw-r--r--src/server/game/Entities/Unit/Unit.h70
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.cpp10
-rw-r--r--src/server/game/Handlers/BattlenetHandler.cpp1
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp62
-rw-r--r--src/server/game/Loot/LootMgr.cpp1
-rw-r--r--src/server/game/Loot/LootMgr.h3
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h7
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp4
-rw-r--r--src/server/game/Server/Packets/ItemPackets.cpp23
-rw-r--r--src/server/game/Server/Packets/ItemPackets.h24
-rw-r--r--src/server/game/Server/Packets/SpellPackets.cpp18
-rw-r--r--src/server/game/Server/Packets/SpellPackets.h12
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp5
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h1
-rw-r--r--src/server/game/Server/WorldSession.h2
-rw-r--r--src/server/game/Spells/Auras/SpellAuraDefines.h26
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp208
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h2
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp6
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h3
-rw-r--r--src/server/game/Spells/Spell.cpp130
-rw-r--r--src/server/game/Spells/SpellEffects.cpp12
-rw-r--r--src/server/game/Spells/SpellHistory.cpp4
-rw-r--r--src/server/game/Spells/SpellInfo.cpp82
-rw-r--r--src/server/game/Spells/SpellInfo.h6
-rw-r--r--src/server/game/Spells/SpellMgr.cpp212
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp12
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp12
-rw-r--r--src/server/scripts/Spells/spell_druid.cpp8
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp162
-rw-r--r--src/server/scripts/Spells/spell_monk.cpp184
-rw-r--r--src/server/worldserver/worldserver.conf.dist6
-rw-r--r--src/tools/connection_patcher/Patches/Common.hpp2
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)";
}
};
}