diff --git a/README.md b/README.md index bfa52386d..221e2c4a2 100644 --- a/README.md +++ b/README.md @@ -149,49 +149,48 @@ respects for all of the code used other than [OpenSSL][48]. [^2]: Clang support for Windows is experimental. Failure to compile Mangos may also relate to the experimental state of the port. -[1]: http://blizzard.com/ "Blizzard Entertainment Inc. · we love you!" +[1]: http://blizzard.com/ "Blizzard Entertainment Inc. · we love you!" [2]: http://battle.net/wow/ "World of Warcraft" -[5]: http://www.wowpedia.org/Patch_4.3.4 "WoW Cataclysm· Patch 4.3.4 release notes" +[5]: http://www.wowpedia.org/Patch_4.3.4 "WoW Cataclysm· Patch 4.3.4 release notes" [7]: http://www.cppreference.com/ "C / C++ reference" -[10]: https://getmangos.eu/ "mangos · project site" -[12]: http://github.com/mangosfour "MaNGOS Four· github organization" -[13]: http://github.com/mangosfour/server "MaNGOS Four · server repository" -[15]: http://github.com/mangosfour/database "MaNGOS four · content database repository" +[10]: https://getmangos.eu/ "mangos · project site" +[12]: http://github.com/mangosfour "MaNGOS Four· github organization" +[13]: http://github.com/mangosfour/server "MaNGOS Four · server repository" +[15]: http://github.com/mangosfour/database "MaNGOS four · content database repository" [16]: https://travis-ci.org/mangosfour/server "Travis CI . MaNGOS Four build status" -[17]: https://scan.coverity.com/ "Coverity Scan · Static Code Analysis" - -[19]: http://www.cmake.org/ "CMake · Cross Platform Make" -[20]: http://windows.microsoft.com/ "Microsoft Windows · that OS, yes." -[21]: http://www.debian.org/ "Debian · The Universal Operating System" -[22]: http://www.ubuntu.com/ "Ubuntu · The world's most popular free OS" -[23]: http://www.freebsd.org/ "FreeBSD · The Power To Serve" -[24]: http://www.netbsd.org/ "NetBSD · The NetBSD Project" -[25]: http://www.openbsd.org/ "OpenBSD · Free, functional and secure" +[17]: https://scan.coverity.com/ "Coverity Scan · Static Code Analysis" + +[19]: http://www.cmake.org/ "CMake · Cross Platform Make" +[20]: http://windows.microsoft.com/ "Microsoft Windows · that OS, yes." +[21]: http://www.debian.org/ "Debian · The Universal Operating System" +[22]: http://www.ubuntu.com/ "Ubuntu · The world's most popular free OS" +[23]: http://www.freebsd.org/ "FreeBSD · The Power To Serve" +[24]: http://www.netbsd.org/ "NetBSD · The NetBSD Project" +[25]: http://www.openbsd.org/ "OpenBSD · Free, functional and secure" [26]: http://www.dragonflybsd.org/ "DragonFlyBSD" [30]: http://www.microsoft.com/visualstudio/eng/ "Visual Studio 2012" [31]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-products "Visual Studio Express 2012 for Windows Desktop" [32]: http://www.microsoft.com/en-us/download/details.aspx?id=8279 "Windows SDK for Windows 7 and .NET Framework 4" -[33]: http://clang.llvm.org/ "clang · a C language family frontend for LLVM" -[34]: http://git-scm.com/ "Git · Distributed version control system" -[35]: http://windows.github.com/ "github · windows client" -[36]: http://www.sourcetreeapp.com/ "SourceTree · Free Mercurial and Git Client for Windows/Mac" - -[40]: http://www.mysql.com/ "MySQL · The world's most popular open source database" -[41]: http://www.mariadb.org/ "MariaDB · An enhanced, drop-in replacement for MySQL" -[43]: http://www.cs.wustl.edu/~schmidt/ACE.html "ACE · The ADAPTIVE Communication Environment" -[44]: http://github.com/memononen/recastnavigation "Recast · Navigation-mesh Toolset for Games" -[45]: http://sourceforge.net/projects/g3d/ "G3D · G3D Innovation Engine" -[46]: http://github.com/ge0rg/libmpq "libmpq · A library for reading data from MPQ archives" -[48]: http://www.openssl.org/ "OpenSSL · The Open Source toolkit for SSL/TLS" -[49]: http://www.stack.nl/~dimitri/doxygen/ "Doxygen · API documentation generator" -[50]: http://www.lua.org/ "Lua · The Programming Language" +[33]: http://clang.llvm.org/ "clang · a C language family frontend for LLVM" +[34]: http://git-scm.com/ "Git · Distributed version control system" +[35]: http://windows.github.com/ "github · windows client" +[36]: http://www.sourcetreeapp.com/ "SourceTree · Free Mercurial and Git Client for Windows/Mac" + +[40]: http://www.mysql.com/ "MySQL · The world's most popular open source database" +[41]: http://www.mariadb.org/ "MariaDB · An enhanced, drop-in replacement for MySQL" +[43]: http://www.cs.wustl.edu/~schmidt/ACE.html "ACE · The ADAPTIVE Communication Environment" +[44]: http://github.com/memononen/recastnavigation "Recast · Navigation-mesh Toolset for Games" +[45]: http://sourceforge.net/projects/g3d/ "G3D · G3D Innovation Engine" +[46]: http://github.com/ge0rg/libmpq "libmpq · A library for reading data from MPQ archives" +[48]: http://www.openssl.org/ "OpenSSL · The Open Source toolkit for SSL/TLS" +[49]: http://www.stack.nl/~dimitri/doxygen/ "Doxygen · API documentation generator" +[50]: http://www.lua.org/ "Lua · The Programming Language" [51]: http://gnuwin32.sourceforge.net/packages/zlib.htm "Zlib for Windows" [52]: http://gnuwin32.sourceforge.net/packages/bzip2.htm "Bzip2 for Windows" [53]: http://www.zlib.net/ "Zlib" [54]: http://www.bzip.org/ "Bzip2" [55]: http://slproweb.com/products/Win32OpenSSL.html "OpenSSL for Windows" [56]: http://www.lua.org/ "Lua" -[57]: https://code.google.com/p/luaforwindows/ "Lua for Windows" - +[57]: https://code.google.com/p/luaforwindows/ "Lua for Windows" \ No newline at end of file diff --git a/src/game/BattleGround/BattleGroundMgr.cpp b/src/game/BattleGround/BattleGroundMgr.cpp index c1f44a8b8..5446c95c4 100644 --- a/src/game/BattleGround/BattleGroundMgr.cpp +++ b/src/game/BattleGround/BattleGroundMgr.cpp @@ -2419,7 +2419,7 @@ void BattleGroundMgr::LoadBattleMastersEntry() Field* fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); - uint32 bgTypeId = fields[1].GetUInt32(); + uint32 bgTypeId = BattleGroundTypeId(bgTypeId); if (!sBattlemasterListStore.LookupEntry(bgTypeId)) { sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for nonexistent battleground type %u, ignored.", entry, bgTypeId); diff --git a/src/game/Object/Unit.cpp b/src/game/Object/Unit.cpp index 472e0dc79..ea7020af6 100644 --- a/src/game/Object/Unit.cpp +++ b/src/game/Object/Unit.cpp @@ -68,15 +68,15 @@ float baseMoveSpeed[MAX_MOVE_TYPE] = { - 2.5f, // MOVE_WALK - 7.0f, // MOVE_RUN - 4.5f, // MOVE_RUN_BACK - 4.722222f, // MOVE_SWIM - 2.5f, // MOVE_SWIM_BACK - 3.141594f, // MOVE_TURN_RATE - 7.0f, // MOVE_FLIGHT - 4.5f, // MOVE_FLIGHT_BACK - 3.14f // MOVE_PITCH_RATE + 2.5f, // MOVE_WALK + 7.0f, // MOVE_RUN + 4.5f, // MOVE_RUN_BACK + 4.722222f, // MOVE_SWIM + 2.5f, // MOVE_SWIM_BACK + 3.141594f, // MOVE_TURN_RATE + 7.0f, // MOVE_FLIGHT + 4.5f, // MOVE_FLIGHT_BACK + 3.14f // MOVE_PITCH_RATE }; //////////////////////////////////////////////////////////// @@ -84,415 +84,415 @@ float baseMoveSpeed[MAX_MOVE_TYPE] = void MovementInfo::Read(ByteBuffer& data, uint16 opcode) { - bool hasTransportData = false, - hasMovementFlags = false, - hasMovementFlags2 = false; - - MovementStatusElements* sequence = GetMovementStatusElementsSequence(opcode); - if(!sequence) - { - sLog.outError("Unsupported MovementInfo::Read for 0x%X (%s)!", opcode, LookupOpcodeName(opcode)); - return; - } - - for(uint32 i = 0; i < MSE_COUNT; ++i) - { - MovementStatusElements element = sequence[i]; - if (element == MSEEnd) - break; - - if (element >= MSEGuidBit0 && element <= MSEGuidBit7) - { - guid[element - MSEGuidBit0] = data.ReadBit(); - continue; - } - - //if (element >= MSEGuid2Bit0 && element <= MSEGuid2Bit7) - //{ - // guid2[element - MSEGuid2Bit0] = data.ReadBit(); - // continue; - //} - - if (element >= MSETransportGuidBit0 && element <= MSETransportGuidBit7) - { - if (hasTransportData) - t_guid[element - MSETransportGuidBit0] = data.ReadBit(); - continue; - } - - if (element >= MSEGuidByte0 && element <= MSEGuidByte7) - { - if (guid[element - MSEGuidByte0]) - guid[element - MSEGuidByte0] ^= data.ReadUInt8(); - continue; - } - - if (element >= MSETransportGuidByte0 && element <= MSETransportGuidByte7) - { - if (hasTransportData && t_guid[element - MSETransportGuidByte0]) - t_guid[element - MSETransportGuidByte0] ^= data.ReadUInt8(); - continue; - } - - switch (element) - { - case MSEFlags: - if (hasMovementFlags) - moveFlags = data.ReadBits(30); - break; - case MSEFlags2: - if (hasMovementFlags2) - moveFlags2 = data.ReadBits(13); - break; - case MSEUnknownBit: - data.ReadBit(); - break; - //case MSEUnknownBit2: - // si.unkBit2 = data.ReadBit(); - // break; - //case MSEHasUnkInt32: - // si.hasUnkInt32 = !data.ReadBit(); - // break; - case MSETimestamp: - if (si.hasTimeStamp) - data >> time; - break; - case MSEHasTimestamp: - si.hasTimeStamp = !data.ReadBit(); - break; - case MSEHasOrientation: - si.hasOrientation = !data.ReadBit(); - break; - case MSEHasMovementFlags: - hasMovementFlags = !data.ReadBit(); - break; - case MSEHasMovementFlags2: - hasMovementFlags2 = !data.ReadBit(); - break; - case MSEHasPitch: - si.hasPitch = !data.ReadBit(); - break; - case MSEHasFallData: - si.hasFallData = data.ReadBit(); - break; - case MSEHasFallDirection: - if (si.hasFallData) - si.hasFallDirection = data.ReadBit(); - break; - case MSEHasTransportData: - hasTransportData = data.ReadBit(); - break; - case MSEHasTransportTime2: - if (hasTransportData) - si.hasTransportTime2 = data.ReadBit(); - break; - case MSEHasTransportTime3: - if (hasTransportData) - si.hasTransportTime3 = data.ReadBit(); - break; - case MSEHasSpline: - si.hasSpline = data.ReadBit(); - break; - case MSEHasSplineElevation: - si.hasSplineElevation = !data.ReadBit(); - break; - case MSEPositionX: - data >> pos.x; - break; - case MSEPositionY: - data >> pos.y; - break; - case MSEPositionZ: - data >> pos.z; - break; - case MSEPositionO: - if (si.hasOrientation) - data >> pos.o; - break; - case MSEPitch: - if (si.hasPitch) - data >> s_pitch; - break;; - case MSEFallTime: - if (si.hasFallData) - data >> fallTime; - break; - case MSESplineElevation: - if (si.hasSplineElevation) - data >> splineElevation; - break; - case MSEFallHorizontalSpeed: - if (si.hasFallData && si.hasFallDirection) - data >> jump.xyspeed; - break; - case MSEFallVerticalSpeed: - if (si.hasFallData) - data >> jump.velocity; - break; - case MSEFallCosAngle: - if (si.hasFallData && si.hasFallDirection) - data >> jump.cosAngle; - break; - case MSEFallSinAngle: - if (si.hasFallData && si.hasFallDirection) - data >> jump.sinAngle; - break; - case MSETransportSeat: - if (hasTransportData) - data >> t_seat; - break; - case MSETransportPositionO: - if (hasTransportData) - data >> t_pos.o; - break; - case MSETransportPositionX: - if (hasTransportData) - data >> t_pos.x; - break; - case MSETransportPositionY: - if (hasTransportData) - data >> t_pos.y; - break; - case MSETransportPositionZ: - if (hasTransportData) - data >> t_pos.z; - break; - case MSETransportTime: - if (hasTransportData) - data >> t_time; - break; - case MSETransportTime2: - if (hasTransportData && si.hasTransportTime2) - data >> t_time2; - break; - case MSETransportTime3: - if (hasTransportData && si.hasTransportTime3) - data >> fallTime; - break; - case MSEMovementCounter: - //for (int i = 0; i < counterCount; i++) - data.read_skip(); - break; - //case MSEUnknownCount: - // unkArray.resize(data.ReadBits(24)); - // break; - //case MSEUnknownArray: - // for (std::list::iterator itr = unkArray.begin(); itr != unkArray.end(); ++itr) - // data >> *itr; - // break; - //case MSEUnkInt32: - // if (si.hasUnkInt32) - // data >> unkInt32; - // break; - default: - MANGOS_ASSERT(false && "Wrong movement status element"); - break; - } - } + bool hasTransportData = false, + hasMovementFlags = false, + hasMovementFlags2 = false; + + MovementStatusElements* sequence = GetMovementStatusElementsSequence(opcode); + if (!sequence) + { + sLog.outError("Unsupported MovementInfo::Read for 0x%X (%s)!", opcode, LookupOpcodeName(opcode)); + return; + } + + for (uint32 i = 0; i < MSE_COUNT; ++i) + { + MovementStatusElements element = sequence[i]; + if (element == MSEEnd) + break; + + if (element >= MSEGuidBit0 && element <= MSEGuidBit7) + { + guid[element - MSEGuidBit0] = data.ReadBit(); + continue; + } + + //if (element >= MSEGuid2Bit0 && element <= MSEGuid2Bit7) + //{ + // guid2[element - MSEGuid2Bit0] = data.ReadBit(); + // continue; + //} + + if (element >= MSETransportGuidBit0 && element <= MSETransportGuidBit7) + { + if (hasTransportData) + t_guid[element - MSETransportGuidBit0] = data.ReadBit(); + continue; + } + + if (element >= MSEGuidByte0 && element <= MSEGuidByte7) + { + if (guid[element - MSEGuidByte0]) + guid[element - MSEGuidByte0] ^= data.ReadUInt8(); + continue; + } + + if (element >= MSETransportGuidByte0 && element <= MSETransportGuidByte7) + { + if (hasTransportData && t_guid[element - MSETransportGuidByte0]) + t_guid[element - MSETransportGuidByte0] ^= data.ReadUInt8(); + continue; + } + + switch (element) + { + case MSEFlags: + if (hasMovementFlags) + moveFlags = data.ReadBits(30); + break; + case MSEFlags2: + if (hasMovementFlags2) + moveFlags2 = data.ReadBits(13); + break; + case MSEUnknownBit: + data.ReadBit(); + break; + //case MSEUnknownBit2: + // si.unkBit2 = data.ReadBit(); + // break; + //case MSEHasUnkInt32: + // si.hasUnkInt32 = !data.ReadBit(); + // break; + case MSETimestamp: + if (si.hasTimeStamp) + data >> time; + break; + case MSEHasTimestamp: + si.hasTimeStamp = !data.ReadBit(); + break; + case MSEHasOrientation: + si.hasOrientation = !data.ReadBit(); + break; + case MSEHasMovementFlags: + hasMovementFlags = !data.ReadBit(); + break; + case MSEHasMovementFlags2: + hasMovementFlags2 = !data.ReadBit(); + break; + case MSEHasPitch: + si.hasPitch = !data.ReadBit(); + break; + case MSEHasFallData: + si.hasFallData = data.ReadBit(); + break; + case MSEHasFallDirection: + if (si.hasFallData) + si.hasFallDirection = data.ReadBit(); + break; + case MSEHasTransportData: + hasTransportData = data.ReadBit(); + break; + case MSEHasTransportTime2: + if (hasTransportData) + si.hasTransportTime2 = data.ReadBit(); + break; + case MSEHasTransportTime3: + if (hasTransportData) + si.hasTransportTime3 = data.ReadBit(); + break; + case MSEHasSpline: + si.hasSpline = data.ReadBit(); + break; + case MSEHasSplineElevation: + si.hasSplineElevation = !data.ReadBit(); + break; + case MSEPositionX: + data >> pos.x; + break; + case MSEPositionY: + data >> pos.y; + break; + case MSEPositionZ: + data >> pos.z; + break; + case MSEPositionO: + if (si.hasOrientation) + data >> pos.o; + break; + case MSEPitch: + if (si.hasPitch) + data >> s_pitch; + break;; + case MSEFallTime: + if (si.hasFallData) + data >> fallTime; + break; + case MSESplineElevation: + if (si.hasSplineElevation) + data >> splineElevation; + break; + case MSEFallHorizontalSpeed: + if (si.hasFallData && si.hasFallDirection) + data >> jump.xyspeed; + break; + case MSEFallVerticalSpeed: + if (si.hasFallData) + data >> jump.velocity; + break; + case MSEFallCosAngle: + if (si.hasFallData && si.hasFallDirection) + data >> jump.cosAngle; + break; + case MSEFallSinAngle: + if (si.hasFallData && si.hasFallDirection) + data >> jump.sinAngle; + break; + case MSETransportSeat: + if (hasTransportData) + data >> t_seat; + break; + case MSETransportPositionO: + if (hasTransportData) + data >> t_pos.o; + break; + case MSETransportPositionX: + if (hasTransportData) + data >> t_pos.x; + break; + case MSETransportPositionY: + if (hasTransportData) + data >> t_pos.y; + break; + case MSETransportPositionZ: + if (hasTransportData) + data >> t_pos.z; + break; + case MSETransportTime: + if (hasTransportData) + data >> t_time; + break; + case MSETransportTime2: + if (hasTransportData && si.hasTransportTime2) + data >> t_time2; + break; + case MSETransportTime3: + if (hasTransportData && si.hasTransportTime3) + data >> fallTime; + break; + case MSEMovementCounter: + //for (int i = 0; i < counterCount; i++) + data.read_skip(); + break; + //case MSEUnknownCount: + // unkArray.resize(data.ReadBits(24)); + // break; + //case MSEUnknownArray: + // for (std::list::iterator itr = unkArray.begin(); itr != unkArray.end(); ++itr) + // data >> *itr; + // break; + //case MSEUnkInt32: + // if (si.hasUnkInt32) + // data >> unkInt32; + // break; + default: + MANGOS_ASSERT(false && "Wrong movement status element"); + break; + } + } } void MovementInfo::Write(ByteBuffer& data, uint16 opcode) const { - bool hasTransportData = !t_guid.IsEmpty(); - - MovementStatusElements* sequence = GetMovementStatusElementsSequence(opcode); - if (!sequence) - { - sLog.outError("Unsupported MovementInfo::Write for 0x%X (%s)!", opcode, LookupOpcodeName(opcode)); - return; - } - - for(uint32 i = 0; i < MSE_COUNT; ++i) - { - MovementStatusElements element = sequence[i]; - - if (element == MSEEnd) - break; - - if (element >= MSEGuidBit0 && element <= MSEGuidBit7) - { - data.WriteBit(guid[element - MSEGuidBit0]); - continue; - } - - if (element >= MSETransportGuidBit0 && element <= MSETransportGuidBit7) - { - if (hasTransportData) - data.WriteBit(t_guid[element - MSETransportGuidBit0]); - continue; - } - - if (element >= MSEGuidByte0 && element <= MSEGuidByte7) - { - if (guid[element - MSEGuidByte0]) - data << uint8((guid[element - MSEGuidByte0] ^ 1)); - continue; - } - - if (element >= MSETransportGuidByte0 && element <= MSETransportGuidByte7) - { - if (hasTransportData && t_guid[element - MSETransportGuidByte0]) - data << uint8((t_guid[element - MSETransportGuidByte0] ^ 1)); - continue; - } - - switch (element) - { - case MSEHasMovementFlags: - data.WriteBit(!moveFlags); - break; - case MSEHasMovementFlags2: - data.WriteBit(!moveFlags2); - break; - case MSEFlags: - if (moveFlags) - data.WriteBits(moveFlags, 30); - break; - case MSEFlags2: - if (moveFlags2) - data.WriteBits(moveFlags2, 13); - break; - case MSETimestamp: - if (si.hasTimeStamp) - data << uint32(time); - break; - case MSEHasPitch: - data.WriteBit(!si.hasPitch); - break; - case MSEHasTimestamp: - data.WriteBit(!si.hasTimeStamp); - break; - case MSEUnknownBit: - data.WriteBit(false); - break; - //case MSEUnknownBit2: - // data.WriteBit(si.unkBit2); - // break; - //case MSEHasUnkInt32: - // data.WriteBit(!si.hasUnkInt32); - // break; - case MSEHasFallData: - data.WriteBit(si.hasFallData); - break; - case MSEHasFallDirection: - if (si.hasFallData) - data.WriteBit(si.hasFallDirection); - break; - case MSEHasTransportData: - data.WriteBit(hasTransportData); - break; - case MSEHasTransportTime2: - if (hasTransportData) - data.WriteBit(si.hasTransportTime2); - break; - case MSEHasTransportTime3: - if (hasTransportData) - data.WriteBit(si.hasTransportTime3); - break; - case MSEHasSpline: - data.WriteBit(si.hasSpline); - break; - case MSEHasSplineElevation: - data.WriteBit(!si.hasSplineElevation); - break; - case MSEPositionX: - data << float(pos.x); - break; - case MSEPositionY: - data << float(pos.y); - break; - case MSEPositionZ: - data << float(pos.z); - break; - case MSEPositionO: - if (si.hasOrientation) - data << float(NormalizeOrientation(pos.o)); - break; - case MSEPitch: - if (si.hasPitch) - data << float(s_pitch); - break; - case MSEHasOrientation: - data.WriteBit(!si.hasOrientation); - break; - case MSEFallTime: - if (si.hasFallData) - data << uint32(fallTime); - break; - case MSESplineElevation: - if (si.hasSplineElevation) - data << float(splineElevation); - break; - case MSEFallHorizontalSpeed: - if (si.hasFallData && si.hasFallDirection) - data << float(jump.xyspeed); - break; - case MSEFallVerticalSpeed: - if (si.hasFallData) - data << float(jump.velocity); - break; - case MSEFallCosAngle: - if (si.hasFallData && si.hasFallDirection) - data << float(jump.cosAngle); - break; - case MSEFallSinAngle: - if (si.hasFallData && si.hasFallDirection) - data << float(jump.sinAngle); - break; - case MSETransportSeat: - if (hasTransportData) - data << int8(t_seat); - break; - case MSETransportPositionO: - if (hasTransportData) - data << float(NormalizeOrientation(t_pos.o)); - break; - case MSETransportPositionX: - if (hasTransportData) - data << float(t_pos.x); - break; - case MSETransportPositionY: - if (hasTransportData) - data << float(t_pos.y); - break; - case MSETransportPositionZ: - if (hasTransportData) - data << float(t_pos.z); - break; - case MSETransportTime: - if (hasTransportData) - data << uint32(t_time); - break; - case MSETransportTime2: - if (hasTransportData && si.hasTransportTime2) - data << uint32(t_time2); - break; - case MSETransportTime3: - if (hasTransportData && si.hasTransportTime3) - data << uint32(fallTime); - break; - case MSEMovementCounter: - data << uint32(0); - break; - /* case MSEUnknownCount: - data.WriteBits(unkArray.size(), 24); - break;*/ - case MSEUnknownArray: - for (std::list::const_iterator itr = unkArray.begin(); itr != unkArray.end(); ++itr) - data << uint32(*itr); - break; - //case MSEUnkInt32: - // if (si.hasUnkInt32) - // data << int32(unkInt32); - // break; - case MSEUintCount: - data << uint32(0); - break; - default: - MANGOS_ASSERT(false && "Wrong movement status element"); - break; - } - } + bool hasTransportData = !t_guid.IsEmpty(); + + MovementStatusElements* sequence = GetMovementStatusElementsSequence(opcode); + if (!sequence) + { + sLog.outError("Unsupported MovementInfo::Write for 0x%X (%s)!", opcode, LookupOpcodeName(opcode)); + return; + } + + for (uint32 i = 0; i < MSE_COUNT; ++i) + { + MovementStatusElements element = sequence[i]; + + if (element == MSEEnd) + break; + + if (element >= MSEGuidBit0 && element <= MSEGuidBit7) + { + data.WriteBit(guid[element - MSEGuidBit0]); + continue; + } + + if (element >= MSETransportGuidBit0 && element <= MSETransportGuidBit7) + { + if (hasTransportData) + data.WriteBit(t_guid[element - MSETransportGuidBit0]); + continue; + } + + if (element >= MSEGuidByte0 && element <= MSEGuidByte7) + { + if (guid[element - MSEGuidByte0]) + data << uint8((guid[element - MSEGuidByte0] ^ 1)); + continue; + } + + if (element >= MSETransportGuidByte0 && element <= MSETransportGuidByte7) + { + if (hasTransportData && t_guid[element - MSETransportGuidByte0]) + data << uint8((t_guid[element - MSETransportGuidByte0] ^ 1)); + continue; + } + + switch (element) + { + case MSEHasMovementFlags: + data.WriteBit(!moveFlags); + break; + case MSEHasMovementFlags2: + data.WriteBit(!moveFlags2); + break; + case MSEFlags: + if (moveFlags) + data.WriteBits(moveFlags, 30); + break; + case MSEFlags2: + if (moveFlags2) + data.WriteBits(moveFlags2, 13); + break; + case MSETimestamp: + if (si.hasTimeStamp) + data << uint32(time); + break; + case MSEHasPitch: + data.WriteBit(!si.hasPitch); + break; + case MSEHasTimestamp: + data.WriteBit(!si.hasTimeStamp); + break; + case MSEUnknownBit: + data.WriteBit(false); + break; + //case MSEUnknownBit2: + // data.WriteBit(si.unkBit2); + // break; + //case MSEHasUnkInt32: + // data.WriteBit(!si.hasUnkInt32); + // break; + case MSEHasFallData: + data.WriteBit(si.hasFallData); + break; + case MSEHasFallDirection: + if (si.hasFallData) + data.WriteBit(si.hasFallDirection); + break; + case MSEHasTransportData: + data.WriteBit(hasTransportData); + break; + case MSEHasTransportTime2: + if (hasTransportData) + data.WriteBit(si.hasTransportTime2); + break; + case MSEHasTransportTime3: + if (hasTransportData) + data.WriteBit(si.hasTransportTime3); + break; + case MSEHasSpline: + data.WriteBit(si.hasSpline); + break; + case MSEHasSplineElevation: + data.WriteBit(!si.hasSplineElevation); + break; + case MSEPositionX: + data << float(pos.x); + break; + case MSEPositionY: + data << float(pos.y); + break; + case MSEPositionZ: + data << float(pos.z); + break; + case MSEPositionO: + if (si.hasOrientation) + data << float(NormalizeOrientation(pos.o)); + break; + case MSEPitch: + if (si.hasPitch) + data << float(s_pitch); + break; + case MSEHasOrientation: + data.WriteBit(!si.hasOrientation); + break; + case MSEFallTime: + if (si.hasFallData) + data << uint32(fallTime); + break; + case MSESplineElevation: + if (si.hasSplineElevation) + data << float(splineElevation); + break; + case MSEFallHorizontalSpeed: + if (si.hasFallData && si.hasFallDirection) + data << float(jump.xyspeed); + break; + case MSEFallVerticalSpeed: + if (si.hasFallData) + data << float(jump.velocity); + break; + case MSEFallCosAngle: + if (si.hasFallData && si.hasFallDirection) + data << float(jump.cosAngle); + break; + case MSEFallSinAngle: + if (si.hasFallData && si.hasFallDirection) + data << float(jump.sinAngle); + break; + case MSETransportSeat: + if (hasTransportData) + data << int8(t_seat); + break; + case MSETransportPositionO: + if (hasTransportData) + data << float(NormalizeOrientation(t_pos.o)); + break; + case MSETransportPositionX: + if (hasTransportData) + data << float(t_pos.x); + break; + case MSETransportPositionY: + if (hasTransportData) + data << float(t_pos.y); + break; + case MSETransportPositionZ: + if (hasTransportData) + data << float(t_pos.z); + break; + case MSETransportTime: + if (hasTransportData) + data << uint32(t_time); + break; + case MSETransportTime2: + if (hasTransportData && si.hasTransportTime2) + data << uint32(t_time2); + break; + case MSETransportTime3: + if (hasTransportData && si.hasTransportTime3) + data << uint32(fallTime); + break; + case MSEMovementCounter: + data << uint32(0); + break; + /* case MSEUnknownCount: + data.WriteBits(unkArray.size(), 24); + break;*/ + case MSEUnknownArray: + for (std::list::const_iterator itr = unkArray.begin(); itr != unkArray.end(); ++itr) + data << uint32(*itr); + break; + //case MSEUnkInt32: + // if (si.hasUnkInt32) + // data << int32(unkInt32); + // break; + case MSEUintCount: + data << uint32(0); + break; + default: + MANGOS_ASSERT(false && "Wrong movement status element"); + break; + } + } } //////////////////////////////////////////////////////////// @@ -500,3356 +500,3360 @@ void MovementInfo::Write(ByteBuffer& data, uint16 opcode) const bool GlobalCooldownMgr::HasGlobalCooldown(SpellEntry const* spellInfo) const { - GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->GetStartRecoveryCategory()); - return itr != m_GlobalCooldowns.end() && itr->second.duration && WorldTimer::getMSTimeDiff(itr->second.cast_time, WorldTimer::getMSTime()) < itr->second.duration; + GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->GetStartRecoveryCategory()); + return itr != m_GlobalCooldowns.end() && itr->second.duration && WorldTimer::getMSTimeDiff(itr->second.cast_time, WorldTimer::getMSTime()) < itr->second.duration; } void GlobalCooldownMgr::AddGlobalCooldown(SpellEntry const* spellInfo, uint32 gcd) { - m_GlobalCooldowns[spellInfo->GetStartRecoveryCategory()] = GlobalCooldown(gcd, WorldTimer::getMSTime()); + m_GlobalCooldowns[spellInfo->GetStartRecoveryCategory()] = GlobalCooldown(gcd, WorldTimer::getMSTime()); } void GlobalCooldownMgr::CancelGlobalCooldown(SpellEntry const* spellInfo) { - m_GlobalCooldowns[spellInfo->GetStartRecoveryCategory()].duration = 0; + m_GlobalCooldowns[spellInfo->GetStartRecoveryCategory()].duration = 0; } //////////////////////////////////////////////////////////// // Methods of class Unit Unit::Unit() : - movespline(new Movement::MoveSpline()), - m_charmInfo(NULL), - i_motionMaster(this), - m_regenTimer(0), - m_vehicleInfo(NULL), - m_ThreatManager(this), - m_HostileRefManager(this) -{ - m_objectType |= TYPEMASK_UNIT; - m_objectTypeId = TYPEID_UNIT; - - m_updateFlag = UPDATEFLAG_LIVING; - - m_attackTimer[BASE_ATTACK] = 0; - m_attackTimer[OFF_ATTACK] = 0; - m_attackTimer[RANGED_ATTACK] = 0; - m_modAttackSpeedPct[BASE_ATTACK] = 1.0f; - m_modAttackSpeedPct[OFF_ATTACK] = 1.0f; - m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f; - - m_extraAttacks = 0; - - m_state = 0; - m_deathState = ALIVE; - - for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) - { - m_currentSpells[i] = NULL; - } - - m_castCounter = 0; - - // m_Aura = NULL; - // m_AurasCheck = 2000; - // m_removeAuraTimer = 4; - m_spellAuraHoldersUpdateIterator = m_spellAuraHolders.end(); - m_AuraFlags = 0; - - m_Visibility = VISIBILITY_ON; - m_AINotifyScheduled = false; - - m_detectInvisibilityMask = 0; - m_invisibilityMask = 0; - m_transform = 0; - m_canModifyStats = false; - - for (int i = 0; i < MAX_SPELL_IMMUNITY; ++i) - { - m_spellImmune[i].clear(); - } - for (int i = 0; i < UNIT_MOD_END; ++i) - { - m_auraModifiersGroup[i][BASE_VALUE] = 0.0f; - m_auraModifiersGroup[i][BASE_PCT] = 1.0f; - m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; - m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f; - } - - // implement 50% base damage from offhand - m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f; - - for (int i = 0; i < MAX_ATTACK; ++i) - { - m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE; - m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE; - } - for (int i = 0; i < MAX_STATS; ++i) - { - m_createStats[i] = 0.0f; - } - - m_attacking = NULL; - m_modMeleeHitChance = 0.0f; - m_modRangedHitChance = 0.0f; - m_modSpellHitChance = 0.0f; - m_baseSpellCritChance = 5; - - m_CombatTimer = 0; - - // m_victimThreat = 0.0f; - for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) - { - m_threatModifier[i] = 1.0f; - } - m_isSorted = true; - for (int i = 0; i < MAX_MOVE_TYPE; ++i) - { - m_speed_rate[i] = 1.0f; - } - - // remove aurastates allowing special moves - for (int i = 0; i < MAX_REACTIVE; ++i) - { - m_reactiveTimer[i] = 0; - } - - m_isCreatureLinkingTrigger = false; - m_isSpawningLinked = false; + movespline(new Movement::MoveSpline()), + m_charmInfo(NULL), + i_motionMaster(this), + m_regenTimer(0), + m_vehicleInfo(NULL), + m_ThreatManager(this), + m_HostileRefManager(this) +{ + m_objectType |= TYPEMASK_UNIT; + m_objectTypeId = TYPEID_UNIT; + + m_updateFlag = UPDATEFLAG_LIVING; + + m_attackTimer[BASE_ATTACK] = 0; + m_attackTimer[OFF_ATTACK] = 0; + m_attackTimer[RANGED_ATTACK] = 0; + m_modAttackSpeedPct[BASE_ATTACK] = 1.0f; + m_modAttackSpeedPct[OFF_ATTACK] = 1.0f; + m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f; + + m_extraAttacks = 0; + + m_state = 0; + m_deathState = ALIVE; + + for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) + { + m_currentSpells[i] = NULL; + } + + m_castCounter = 0; + + // m_Aura = NULL; + // m_AurasCheck = 2000; + // m_removeAuraTimer = 4; + m_spellAuraHoldersUpdateIterator = m_spellAuraHolders.end(); + m_AuraFlags = 0; + + m_Visibility = VISIBILITY_ON; + m_AINotifyScheduled = false; + + m_detectInvisibilityMask = 0; + m_invisibilityMask = 0; + m_transform = 0; + m_canModifyStats = false; + + for (int i = 0; i < MAX_SPELL_IMMUNITY; ++i) + { + m_spellImmune[i].clear(); + } + for (int i = 0; i < UNIT_MOD_END; ++i) + { + m_auraModifiersGroup[i][BASE_VALUE] = 0.0f; + m_auraModifiersGroup[i][BASE_PCT] = 1.0f; + m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; + m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f; + } + + // implement 50% base damage from offhand + m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f; + + for (int i = 0; i < MAX_ATTACK; ++i) + { + m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE; + m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE; + } + for (int i = 0; i < MAX_STATS; ++i) + { + m_createStats[i] = 0.0f; + } + + m_attacking = NULL; + m_modMeleeHitChance = 0.0f; + m_modRangedHitChance = 0.0f; + m_modSpellHitChance = 0.0f; + m_baseSpellCritChance = 5; + + m_CombatTimer = 0; + + // m_victimThreat = 0.0f; + for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) + { + m_threatModifier[i] = 1.0f; + } + m_isSorted = true; + for (int i = 0; i < MAX_MOVE_TYPE; ++i) + { + m_speed_rate[i] = 1.0f; + } + + // remove aurastates allowing special moves + for (int i = 0; i < MAX_REACTIVE; ++i) + { + m_reactiveTimer[i] = 0; + } + + m_isCreatureLinkingTrigger = false; + m_isSpawningLinked = false; } Unit::~Unit() { - // set current spells as deletable - for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) - { - if (m_currentSpells[i]) - { - m_currentSpells[i]->SetReferencedFromCurrent(false); - m_currentSpells[i] = NULL; - } - } + // set current spells as deletable + for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) + { + if (m_currentSpells[i]) + { + m_currentSpells[i]->SetReferencedFromCurrent(false); + m_currentSpells[i] = NULL; + } + } - delete m_charmInfo; - delete m_vehicleInfo; - delete movespline; + delete m_charmInfo; + delete m_vehicleInfo; + delete movespline; - // those should be already removed at "RemoveFromWorld()" call - MANGOS_ASSERT(m_gameObj.size() == 0); - MANGOS_ASSERT(m_dynObjGUIDs.size() == 0); - MANGOS_ASSERT(m_deletedAuras.size() == 0); - MANGOS_ASSERT(m_deletedHolders.size() == 0); + // those should be already removed at "RemoveFromWorld()" call + MANGOS_ASSERT(m_gameObj.size() == 0); + MANGOS_ASSERT(m_dynObjGUIDs.size() == 0); + MANGOS_ASSERT(m_deletedAuras.size() == 0); + MANGOS_ASSERT(m_deletedHolders.size() == 0); } void Unit::Update(uint32 update_diff, uint32 p_time) { - if (!IsInWorld()) - { - return; - } + if (!IsInWorld()) + { + return; + } - /*if(p_time > m_AurasCheck) - { - m_AurasCheck = 2000; - _UpdateAura(); - }else - m_AurasCheck -= p_time;*/ + /*if(p_time > m_AurasCheck) + { + m_AurasCheck = 2000; + _UpdateAura(); + }else + m_AurasCheck -= p_time;*/ #ifdef ENABLE_ELUNA - elunaEvents->Update(update_diff); + elunaEvents->Update(update_diff); #endif /* ENABLE_ELUNA */ - // WARNING! Order of execution here is important, do not change. - // Spells must be processed with event system BEFORE they go to _UpdateSpells. - // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad. - m_Events.Update(update_diff); - _UpdateSpells(update_diff); - - CleanupDeletedAuras(); - - - if (CanHaveThreatList()) - GetThreatManager().UpdateForClient(update_diff); - - // update combat timer only for players and pets - if (IsInCombat() && GetCharmerOrOwnerPlayerOrPlayerItself()) - { - // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away - // targets without stopping half way there and running off. - // These flags are reset after target dies or another command is given. - if (m_HostileRefManager.isEmpty()) - { - // m_CombatTimer set at aura start and it will be freeze until aura removing - if (m_CombatTimer <= update_diff) - { - CombatStop(); - } - else - { - m_CombatTimer -= update_diff; - } - } - } - - if (uint32 base_att = getAttackTimer(BASE_ATTACK)) - { - setAttackTimer(BASE_ATTACK, (update_diff >= base_att ? 0 : base_att - update_diff)); - } - - if (uint32 base_att = getAttackTimer(OFF_ATTACK)) - { - setAttackTimer(OFF_ATTACK, (update_diff >= base_att ? 0 : base_att - update_diff)); - } - - if (IsVehicle()) - { - // Initialize vehicle if not done - if (IsAlive() && !m_vehicleInfo->IsInitialized()) - m_vehicleInfo->Initialize(); - - // Update passenger positions if we are the first vehicle - if (!IsBoarded()) - m_vehicleInfo->Update(update_diff); - } - - // update abilities available only for fraction of time - UpdateReactives(update_diff); - - if (IsAlive()) - { - ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth() * 0.20f); - ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth() * 0.35f); - ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetHealth() > GetMaxHealth() * 0.75f); - } - - UpdateSplineMovement(p_time); - i_motionMaster.UpdateMotion(p_time); + // WARNING! Order of execution here is important, do not change. + // Spells must be processed with event system BEFORE they go to _UpdateSpells. + // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad. + m_Events.Update(update_diff); + _UpdateSpells(update_diff); + + CleanupDeletedAuras(); + + + if (CanHaveThreatList()) + GetThreatManager().UpdateForClient(update_diff); + + // update combat timer only for players and pets + if (IsInCombat() && GetCharmerOrOwnerPlayerOrPlayerItself()) + { + // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away + // targets without stopping half way there and running off. + // These flags are reset after target dies or another command is given. + if (m_HostileRefManager.isEmpty()) + { + // m_CombatTimer set at aura start and it will be freeze until aura removing + if (m_CombatTimer <= update_diff) + { + CombatStop(); + } + else + { + m_CombatTimer -= update_diff; + } + } + } + + if (uint32 base_att = getAttackTimer(BASE_ATTACK)) + { + setAttackTimer(BASE_ATTACK, (update_diff >= base_att ? 0 : base_att - update_diff)); + } + + if (uint32 base_att = getAttackTimer(OFF_ATTACK)) + { + setAttackTimer(OFF_ATTACK, (update_diff >= base_att ? 0 : base_att - update_diff)); + } + + if (IsVehicle()) + { + // Initialize vehicle if not done + if (IsAlive() && !m_vehicleInfo->IsInitialized()) + m_vehicleInfo->Initialize(); + + // Update passenger positions if we are the first vehicle + if (!IsBoarded()) + m_vehicleInfo->Update(update_diff); + } + + // update abilities available only for fraction of time + UpdateReactives(update_diff); + + if (IsAlive()) + { + ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth() * 0.20f); + ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth() * 0.35f); + ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetHealth() > GetMaxHealth() * 0.75f); + } + + UpdateSplineMovement(p_time); + i_motionMaster.UpdateMotion(p_time); } bool Unit::UpdateMeleeAttackingState() { - Unit* victim = getVictim(); - if (!victim || IsNonMeleeSpellCasted(false)) - { - return false; - } - - if (!isAttackReady(BASE_ATTACK) && !(isAttackReady(OFF_ATTACK) && haveOffhandWeapon())) - { - return false; - } - - uint8 swingError = 0; - if (!CanReachWithMeleeAttack(victim)) - { - setAttackTimer(BASE_ATTACK, 100); - setAttackTimer(OFF_ATTACK, 100); - swingError = 1; - } - // 120 degrees of radiant range - else if (!HasInArc(2 * M_PI_F / 3, victim)) - { - setAttackTimer(BASE_ATTACK, 100); - setAttackTimer(OFF_ATTACK, 100); - swingError = 2; - } - else - { - if (isAttackReady(BASE_ATTACK)) - { - // prevent base and off attack in same time, delay attack at 0.2 sec - if (haveOffhandWeapon()) - { - if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY) - { - setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY); - } - } - AttackerStateUpdate(victim, BASE_ATTACK); - resetAttackTimer(BASE_ATTACK); - } - if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) - { - // prevent base and off attack in same time, delay attack at 0.2 sec - uint32 base_att = getAttackTimer(BASE_ATTACK); - if (base_att < ATTACK_DISPLAY_DELAY) - { - setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY); - } - // do attack - AttackerStateUpdate(victim, OFF_ATTACK); - resetAttackTimer(OFF_ATTACK); - } - } - - Player* player = (GetTypeId() == TYPEID_PLAYER ? (Player*)this : NULL); - if (player && swingError != player->LastSwingErrorMsg()) - { - if (swingError == 1) - { - player->SendAttackSwingNotInRange(); - } - else if (swingError == 2) - { - player->SendAttackSwingBadFacingAttack(); - } - player->SwingErrorMsg(swingError); - } - - return swingError; + Unit* victim = getVictim(); + if (!victim || IsNonMeleeSpellCasted(false)) + { + return false; + } + + if (!isAttackReady(BASE_ATTACK) && !(isAttackReady(OFF_ATTACK) && haveOffhandWeapon())) + { + return false; + } + + uint8 swingError = 0; + if (!CanReachWithMeleeAttack(victim)) + { + setAttackTimer(BASE_ATTACK, 100); + setAttackTimer(OFF_ATTACK, 100); + swingError = 1; + } + // 120 degrees of radiant range + else if (!HasInArc(2 * M_PI_F / 3, victim)) + { + setAttackTimer(BASE_ATTACK, 100); + setAttackTimer(OFF_ATTACK, 100); + swingError = 2; + } + else + { + if (isAttackReady(BASE_ATTACK)) + { + // prevent base and off attack in same time, delay attack at 0.2 sec + if (haveOffhandWeapon()) + { + if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY) + { + setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY); + } + } + AttackerStateUpdate(victim, BASE_ATTACK); + resetAttackTimer(BASE_ATTACK); + } + if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) + { + // prevent base and off attack in same time, delay attack at 0.2 sec + uint32 base_att = getAttackTimer(BASE_ATTACK); + if (base_att < ATTACK_DISPLAY_DELAY) + { + setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY); + } + // do attack + AttackerStateUpdate(victim, OFF_ATTACK); + resetAttackTimer(OFF_ATTACK); + } + } + + Player* player = (GetTypeId() == TYPEID_PLAYER ? (Player*)this : NULL); + if (player && swingError != player->LastSwingErrorMsg()) + { + if (swingError == 1) + { + player->SendAttackSwingNotInRange(); + } + else if (swingError == 2) + { + player->SendAttackSwingBadFacingAttack(); + } + player->SwingErrorMsg(swingError); + } + + return swingError; } bool Unit::haveOffhandWeapon() const { - if (!CanUseEquippedWeapon(OFF_ATTACK)) - { - return false; - } + if (!CanUseEquippedWeapon(OFF_ATTACK)) + { + return false; + } - if (GetTypeId() == TYPEID_PLAYER) - { - return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK, true, true); - } - else - { - uint32 ItemId = GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1); - /*ItemEntry const* itemInfo = sItemStore.LookupEntry(ItemId); + if (GetTypeId() == TYPEID_PLAYER) + { + return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK, true, true); + } + else + { + uint32 ItemId = GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1); + /*ItemEntry const* itemInfo = sItemStore.LookupEntry(ItemId); - if (itemInfo && itemInfo->Class == ITEM_CLASS_WEAPON) - return true;*/ + if (itemInfo && itemInfo->Class == ITEM_CLASS_WEAPON) + return true;*/ - return false; - } + return false; + } } void Unit::SendHeartBeat() { - m_movementInfo.UpdateTime(WorldTimer::getMSTime()); - WorldPacket data(MSG_MOVE_HEARTBEAT, 64); - data << GetPackGUID(); - data << m_movementInfo; - SendMessageToSet(&data, true); + m_movementInfo.UpdateTime(WorldTimer::getMSTime()); + WorldPacket data(MSG_MOVE_HEARTBEAT, 64); + data << GetPackGUID(); + data << m_movementInfo; + SendMessageToSet(&data, true); } void Unit::resetAttackTimer(WeaponAttackType type) { - m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]); + m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]); } float Unit::GetCombatReach(Unit const* pVictim, bool forMeleeRange /*=true*/, float flat_mod /*=0.0f*/) const { - // The measured values show BASE_MELEE_OFFSET in (1.3224, 1.342) - float reach = GetFloatValue(UNIT_FIELD_COMBATREACH) + pVictim->GetFloatValue(UNIT_FIELD_COMBATREACH) + - BASE_MELEERANGE_OFFSET + flat_mod; + // The measured values show BASE_MELEE_OFFSET in (1.3224, 1.342) + float reach = GetFloatValue(UNIT_FIELD_COMBATREACH) + pVictim->GetFloatValue(UNIT_FIELD_COMBATREACH) + + BASE_MELEERANGE_OFFSET + flat_mod; - if (forMeleeRange && reach < ATTACK_DISTANCE) - { - reach = ATTACK_DISTANCE; - } + if (forMeleeRange && reach < ATTACK_DISTANCE) + { + reach = ATTACK_DISTANCE; + } - return reach; + return reach; } float Unit::GetCombatDistance(Unit const* target, bool forMeleeRange) const { - float radius = GetCombatReach(target, forMeleeRange); + float radius = GetCombatReach(target, forMeleeRange); - float dx = GetPositionX() - target->GetPositionX(); - float dy = GetPositionY() - target->GetPositionY(); - float dz = GetPositionZ() - target->GetPositionZ(); - float dist = sqrt((dx * dx) + (dy * dy) + (dz * dz)) - radius; + float dx = GetPositionX() - target->GetPositionX(); + float dy = GetPositionY() - target->GetPositionY(); + float dz = GetPositionZ() - target->GetPositionZ(); + float dist = sqrt((dx * dx) + (dy * dy) + (dz * dz)) - radius; - return (dist > 0.0f ? dist : 0.0f); + return (dist > 0.0f ? dist : 0.0f); } bool Unit::CanReachWithMeleeAttack(Unit const* pVictim, float flat_mod /*= 0.0f*/) const { - MANGOS_ASSERT(pVictim); + MANGOS_ASSERT(pVictim); - float reach = GetCombatReach(pVictim, true, flat_mod); + float reach = GetCombatReach(pVictim, true, flat_mod); - // This check is not related to bounding radius - float dx = GetPositionX() - pVictim->GetPositionX(); - float dy = GetPositionY() - pVictim->GetPositionY(); - float dz = GetPositionZ() - pVictim->GetPositionZ(); + // This check is not related to bounding radius + float dx = GetPositionX() - pVictim->GetPositionX(); + float dy = GetPositionY() - pVictim->GetPositionY(); + float dz = GetPositionZ() - pVictim->GetPositionZ(); - return dx * dx + dy * dy + dz * dz < reach * reach; + return dx * dx + dy * dy + dz * dz < reach * reach; } void Unit::RemoveSpellsCausingAura(AuraType auraType) { - for (AuraList::const_iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();) - { - RemoveAurasDueToSpell((*iter)->GetId()); - iter = m_modAuras[auraType].begin(); - } + for (AuraList::const_iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();) + { + RemoveAurasDueToSpell((*iter)->GetId()); + iter = m_modAuras[auraType].begin(); + } } void Unit::RemoveSpellsCausingAura(AuraType auraType, SpellAuraHolder* except) { - for (AuraList::const_iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();) - { - // skip `except` aura - if ((*iter)->GetHolder() == except) - { - ++iter; - continue; - } + for (AuraList::const_iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();) + { + // skip `except` aura + if ((*iter)->GetHolder() == except) + { + ++iter; + continue; + } - RemoveAurasDueToSpell((*iter)->GetId(), except); - iter = m_modAuras[auraType].begin(); - } + RemoveAurasDueToSpell((*iter)->GetId(), except); + iter = m_modAuras[auraType].begin(); + } } void Unit::RemoveSpellsCausingAura(AuraType auraType, ObjectGuid casterGuid) { - for (AuraList::const_iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();) - { - if ((*iter)->GetCasterGuid() == casterGuid) - { - RemoveSpellAuraHolder((*iter)->GetHolder()); - iter = m_modAuras[auraType].begin(); - } - else - { - ++iter; - } - } + for (AuraList::const_iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();) + { + if ((*iter)->GetCasterGuid() == casterGuid) + { + RemoveSpellAuraHolder((*iter)->GetHolder()); + iter = m_modAuras[auraType].begin(); + } + else + { + ++iter; + } + } } void Unit::DealDamageMods(Unit* pVictim, uint32& damage, uint32* absorb) { - if (!pVictim->IsAlive() || pVictim->IsTaxiFlying() || (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())) - { - if (absorb) - { - *absorb += damage; - } - damage = 0; - return; - } - - // You don't lose health from damage taken from another player while in a sanctuary - // You still see it in the combat log though - if (!IsAllowedDamageInArea(pVictim)) - { - if (absorb) - *absorb += damage; - damage = 0; - } - - uint32 originalDamage = damage; - - // Script Event damage Deal - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) - { - ((Creature*)this)->AI()->DamageDeal(pVictim, damage); - } - // Script Event damage taken - if (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->AI()) - { - ((Creature*)pVictim)->AI()->DamageTaken(this, damage); - } - - if (absorb && originalDamage > damage) - { - *absorb += (originalDamage - damage); - } + if (!pVictim->IsAlive() || pVictim->IsTaxiFlying() || (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())) + { + if (absorb) + { + *absorb += damage; + } + damage = 0; + return; + } + + // You don't lose health from damage taken from another player while in a sanctuary + // You still see it in the combat log though + if (!IsAllowedDamageInArea(pVictim)) + { + if (absorb) + *absorb += damage; + damage = 0; + } + + uint32 originalDamage = damage; + + // Script Event damage Deal + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) + { + ((Creature*)this)->AI()->DamageDeal(pVictim, damage); + } + // Script Event damage taken + if (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->AI()) + { + ((Creature*)pVictim)->AI()->DamageTaken(this, damage); + } + + if (absorb && originalDamage > damage) + { + *absorb += (originalDamage - damage); + } } uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const* spellProto, bool durabilityLoss) { - // remove affects from attacker at any non-DoT damage (including 0 damage) - if (damagetype != DOT) - { - if (damagetype != SELF_DAMAGE_ROGUE_FALL) - RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - if (pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->IsStandState() && !pVictim->hasUnitState(UNIT_STAT_STUNNED)) - pVictim->SetStandState(UNIT_STAND_STATE_STAND); - } - - if (!damage) - { - // Rage from physical damage received . - if (cleanDamage && cleanDamage->damage && (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->GetPowerType() == POWER_RAGE)) - ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false); - - return 0; - } - - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageStart"); - - uint32 health = pVictim->GetHealth(); - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "deal dmg:%d to health:%d ", damage, health); - - // Rage from Damage made (only from direct weapon damage) - if (cleanDamage && damagetype == DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (GetPowerType() == POWER_RAGE)) - { - uint32 weaponSpeedHitFactor; - - switch (cleanDamage->attackType) - { - case BASE_ATTACK: - { - if (cleanDamage->hitOutCome == MELEE_HIT_CRIT) - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 7); - else - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 3.5f); - - ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); - - break; - } - case OFF_ATTACK: - { - if (cleanDamage->hitOutCome == MELEE_HIT_CRIT) - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 3.5f); - else - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 1.75f); - - ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); - - break; - } - case RANGED_ATTACK: - break; - } - } - - // no xp,health if type 8 /critters/ - if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER) - { - // TODO: fix this part - // Critter may not die of damage taken, instead expect it to run away (no fighting back) - // If (this) is TYPEID_PLAYER, (this) will enter combat w/victim, but after some time, automatically leave combat. - // It is unclear how it should work for other cases. - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage critter, critter dies"); - - ((Creature*)pVictim)->SetLootRecipient(this); - - JustKilledCreature((Creature*)pVictim, NULL); - pVictim->SetHealth(0); - - return damage; - } - - // share damage by auras - AuraList const& vShareDamageAuras = pVictim->GetAurasByType(SPELL_AURA_SHARE_DAMAGE_PCT); - for (AuraList::const_iterator itr = vShareDamageAuras.begin(); itr != vShareDamageAuras.end(); ++itr) - { - if (!spellProto) - break; - - SpellEffectEntry const* spellEffect = spellProto->GetSpellEffect(EFFECT_INDEX_0); - - // if damage is done by another shared aura, then skip to avoid circular reference (aura 300 is only applied on effect_idx_0 - if (spellEffect && spellEffect->Effect == SPELL_EFFECT_APPLY_AURA && - spellEffect->EffectApplyAuraName == SPELL_AURA_SHARE_DAMAGE_PCT) - break; - - if (Unit* shareTarget = (*itr)->GetCaster()) - { - if (shareTarget != pVictim && ((*itr)->GetMiscValue() & damageSchoolMask)) - { - SpellEntry const* shareSpell = (*itr)->GetSpellProto(); - uint32 shareDamage = uint32(damage*(*itr)->GetModifier()->m_amount / 100.0f); - DealDamageMods(shareTarget, shareDamage, NULL); - DealDamage(shareTarget, shareDamage, NULL, damagetype, GetSpellSchoolMask(shareSpell), shareSpell, false); - } - } - } - - // duel ends when player has 1 or less hp - bool duel_hasEnded = false; - if (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health - 1)) - { - // prevent kill only if killed in duel and killed by opponent or opponent controlled creature - if (((Player*)pVictim)->duel->opponent == this || ((Player*)pVictim)->duel->opponent->GetObjectGuid() == GetOwnerGuid()) - damage = health - 1; - - duel_hasEnded = true; - } - - // Get in CombatState - if (pVictim != this && damagetype != DOT) - { - SetInCombatWith(pVictim); - pVictim->SetInCombatWith(this); - - if (Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself()) - SetContestedPvP(attackedPlayer); - } - - if (GetTypeId() == TYPEID_PLAYER && this != pVictim) - { - Player* killer = ((Player*)this); - - // in bg, count dmg if victim is also a player - if (pVictim->GetTypeId() == TYPEID_PLAYER) - { - if (BattleGround* bg = killer->GetBattleGround()) - { - // FIXME: kept by compatibility. don't know in BG if the restriction apply. - bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage); - } - } - - killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, pVictim); - killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage); - } - - if (pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED, damage); - - if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->IsPet() && !((Creature*)pVictim)->HasLootRecipient()) - { - ((Creature*)pVictim)->SetLootRecipient(this); - } - - if (health <= damage) - { - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage %s Killed %s", GetGuidStr().c_str(), pVictim->GetGuidStr().c_str()); - - /* - * Preparation: Who gets credit for killing whom, invoke SpiritOfRedemtion? - */ - // for loot will be used only if group_tap == NULL - Player* player_tap = GetCharmerOrOwnerPlayerOrPlayerItself(); - Group* group_tap = NULL; - - // in creature kill case group/player tap stored for creature - if (pVictim->GetTypeId() == TYPEID_UNIT) - { - group_tap = ((Creature*)pVictim)->GetGroupLootRecipient(); - - if (Player* recipient = ((Creature*)pVictim)->GetOriginalLootRecipient()) - { - player_tap = recipient; - } - } - // in player kill case group tap selected by player_tap (killer-player itself, or charmer, or owner, etc) - else - { - if (player_tap) - { - group_tap = player_tap->GetGroup(); - } - } - - // Spirit of Redemtion Talent - bool damageFromSpiritOfRedemtionTalent = spellProto && spellProto->Id == 27795; - // if talent known but not triggered (check priest class for speedup check) - Aura* spiritOfRedemtionTalentReady = NULL; - if (!damageFromSpiritOfRedemtionTalent && // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION - pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->getClass() == CLASS_PRIEST) - { - AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); - for (AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr) - { - if ((*itr)->GetSpellProto()->GetSpellIconID() == 1654) - { - spiritOfRedemtionTalentReady = *itr; - break; - } - } - } - - /* - * Generic Actions (ProcEvents, Combat-Log, Kill Rewards, Stop Combat) - */ - // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop) - if (player_tap && player_tap != pVictim) - { - player_tap->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0); - - WorldPacket data(SMSG_PARTYKILLLOG, (8 + 8)); // send event PARTY_KILL - data << player_tap->GetObjectGuid(); // player with killing blow - data << pVictim->GetObjectGuid(); // victim - - if (group_tap) - { - group_tap->BroadcastPacket(&data, false, group_tap->GetMemberGroup(player_tap->GetObjectGuid()), player_tap->GetObjectGuid()); - } - - player_tap->SendDirectMessage(&data); - } - else if (GetTypeId() == TYPEID_UNIT && this != pVictim) - ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0); - - // Reward player, his pets, and group/raid members - if (player_tap != pVictim) - { - if (group_tap) - { - group_tap->RewardGroupAtKill(pVictim, player_tap); - } - else if (player_tap) - { - player_tap->RewardSinglePlayerAtKill(pVictim); - } - } - - // stop combat - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageAttackStop"); - pVictim->CombatStop(); - pVictim->GetHostileRefManager().deleteReferences(); - - /* - * Actions for the killer - */ - if (spiritOfRedemtionTalentReady) - { - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage: Spirit of Redemtion ready"); - - // save value before aura remove - uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL); - if (!ressSpellId) - { - ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId(); - } - - // Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers) - pVictim->RemoveAllAurasOnDeath(); - - // restore for use at real death - pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); - - // FORM_SPIRITOFREDEMPTION and related auras - pVictim->CastSpell(pVictim, 27827, true, NULL, spiritOfRedemtionTalentReady); - } - else - { - pVictim->SetHealth(0); - } - - // Call KilledUnit for creatures - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) - { - ((Creature*)this)->AI()->KilledUnit(pVictim); - } - - if (Creature* killer = ToCreature()) - { - // Used by Eluna + // remove affects from attacker at any non-DoT damage (including 0 damage) + if (damagetype != DOT) + { + if (damagetype != SELF_DAMAGE_ROGUE_FALL) + RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + + if (pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->IsStandState() && !pVictim->hasUnitState(UNIT_STAT_STUNNED)) + pVictim->SetStandState(UNIT_STAND_STATE_STAND); + } + + if (!damage) + { + // Rage from physical damage received . + if (cleanDamage && cleanDamage->damage && (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->GetPowerType() == POWER_RAGE)) + ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false); + + return 0; + } + + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageStart"); + + uint32 health = pVictim->GetHealth(); + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "deal dmg:%d to health:%d ", damage, health); + + // Rage from Damage made (only from direct weapon damage) + if (cleanDamage && damagetype == DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (GetPowerType() == POWER_RAGE)) + { + uint32 weaponSpeedHitFactor; + + switch (cleanDamage->attackType) + { + case BASE_ATTACK: + { + if (cleanDamage->hitOutCome == MELEE_HIT_CRIT) + weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 7); + else + weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 3.5f); + + ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); + + break; + } + case OFF_ATTACK: + { + if (cleanDamage->hitOutCome == MELEE_HIT_CRIT) + weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 3.5f); + else + weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 1.75f); + + ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); + + break; + } + case RANGED_ATTACK: + break; + } + } + + // no xp,health if type 8 /critters/ + if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER) + { + // TODO: fix this part + // Critter may not die of damage taken, instead expect it to run away (no fighting back) + // If (this) is TYPEID_PLAYER, (this) will enter combat w/victim, but after some time, automatically leave combat. + // It is unclear how it should work for other cases. + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage critter, critter dies"); + + ((Creature*)pVictim)->SetLootRecipient(this); + + JustKilledCreature((Creature*)pVictim, NULL); + pVictim->SetHealth(0); + + return damage; + } + + // share damage by auras + AuraList const& vShareDamageAuras = pVictim->GetAurasByType(SPELL_AURA_SHARE_DAMAGE_PCT); + for (AuraList::const_iterator itr = vShareDamageAuras.begin(); itr != vShareDamageAuras.end(); ++itr) + { + if (!spellProto) + break; + + SpellEffectEntry const* spellEffect = spellProto->GetSpellEffect(EFFECT_INDEX_0); + + // if damage is done by another shared aura, then skip to avoid circular reference (aura 300 is only applied on effect_idx_0 + if (spellEffect && spellEffect->Effect == SPELL_EFFECT_APPLY_AURA && + spellEffect->EffectApplyAuraName == SPELL_AURA_SHARE_DAMAGE_PCT) + break; + + if (Unit* shareTarget = (*itr)->GetCaster()) + { + if (shareTarget != pVictim && ((*itr)->GetMiscValue() & damageSchoolMask)) + { + SpellEntry const* shareSpell = (*itr)->GetSpellProto(); + uint32 shareDamage = uint32(damage*(*itr)->GetModifier()->m_amount / 100.0f); + DealDamageMods(shareTarget, shareDamage, NULL); + DealDamage(shareTarget, shareDamage, NULL, damagetype, GetSpellSchoolMask(shareSpell), shareSpell, false); + } + } + } + + // duel ends when player has 1 or less hp + bool duel_hasEnded = false; + if (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health - 1)) + { + // prevent kill only if killed in duel and killed by opponent or opponent controlled creature + if (((Player*)pVictim)->duel->opponent == this || ((Player*)pVictim)->duel->opponent->GetObjectGuid() == GetOwnerGuid()) + damage = health - 1; + + duel_hasEnded = true; + } + + // Get in CombatState + if (pVictim != this && damagetype != DOT) + { + SetInCombatWith(pVictim); + pVictim->SetInCombatWith(this); + + if (Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself()) + SetContestedPvP(attackedPlayer); + } + + if (GetTypeId() == TYPEID_PLAYER && this != pVictim) + { + Player* killer = ((Player*)this); + + // in bg, count dmg if victim is also a player + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + if (BattleGround* bg = killer->GetBattleGround()) + { + // FIXME: kept by compatibility. don't know in BG if the restriction apply. + bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage); + } + } + + killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, pVictim); + killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage); + } + + if (pVictim->GetTypeId() == TYPEID_PLAYER) + ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED, damage); + + if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->IsPet() && !((Creature*)pVictim)->HasLootRecipient()) + { + ((Creature*)pVictim)->SetLootRecipient(this); + } + + if (health <= damage) + { + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage %s Killed %s", GetGuidStr().c_str(), pVictim->GetGuidStr().c_str()); + + /* + * Preparation: Who gets credit for killing whom, invoke SpiritOfRedemtion? + */ + // for loot will be used only if group_tap == NULL + Player* player_tap = GetCharmerOrOwnerPlayerOrPlayerItself(); + Group* group_tap = NULL; + + // in creature kill case group/player tap stored for creature + if (pVictim->GetTypeId() == TYPEID_UNIT) + { + group_tap = ((Creature*)pVictim)->GetGroupLootRecipient(); + + if (Player* recipient = ((Creature*)pVictim)->GetOriginalLootRecipient()) + { + player_tap = recipient; + } + } + // in player kill case group tap selected by player_tap (killer-player itself, or charmer, or owner, etc) + else + { + if (player_tap) + { + group_tap = player_tap->GetGroup(); + } + } + + // Spirit of Redemtion Talent + bool damageFromSpiritOfRedemtionTalent = spellProto && spellProto->Id == 27795; + // if talent known but not triggered (check priest class for speedup check) + Aura* spiritOfRedemtionTalentReady = NULL; + if (!damageFromSpiritOfRedemtionTalent && // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION + pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->getClass() == CLASS_PRIEST) + { + AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); + for (AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr) + { + if ((*itr)->GetSpellProto()->GetSpellIconID() == 1654) + { + spiritOfRedemtionTalentReady = *itr; + break; + } + } + } + + /* + * Generic Actions (ProcEvents, Combat-Log, Kill Rewards, Stop Combat) + */ + // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop) + if (player_tap && player_tap != pVictim) + { + player_tap->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0); + + WorldPacket data(SMSG_PARTYKILLLOG, (8 + 8)); // send event PARTY_KILL + data << player_tap->GetObjectGuid(); // player with killing blow + data << pVictim->GetObjectGuid(); // victim + + if (group_tap) + { + group_tap->BroadcastPacket(&data, false, group_tap->GetMemberGroup(player_tap->GetObjectGuid()), player_tap->GetObjectGuid()); + } + + player_tap->SendDirectMessage(&data); + } + else if (GetTypeId() == TYPEID_UNIT && this != pVictim) + ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0); + + // Reward player, his pets, and group/raid members + if (player_tap != pVictim) + { + if (group_tap) + { + group_tap->RewardGroupAtKill(pVictim, player_tap); + } + else if (player_tap) + { + player_tap->RewardSinglePlayerAtKill(pVictim); + } + } + + // stop combat + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageAttackStop"); + pVictim->CombatStop(); + pVictim->GetHostileRefManager().deleteReferences(); + + /* + * Actions for the killer + */ + if (spiritOfRedemtionTalentReady) + { + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage: Spirit of Redemtion ready"); + + // save value before aura remove + uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL); + if (!ressSpellId) + { + ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId(); + } + + // Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers) + pVictim->RemoveAllAurasOnDeath(); + + // restore for use at real death + pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); + + // FORM_SPIRITOFREDEMPTION and related auras + pVictim->CastSpell(pVictim, 27827, true, NULL, spiritOfRedemtionTalentReady); + } + else + { + pVictim->SetHealth(0); + } + + // Call KilledUnit for creatures + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) + { + ((Creature*)this)->AI()->KilledUnit(pVictim); + } + + if (Creature* killer = ToCreature()) + { + // Used by Eluna #ifdef ENABLE_ELUNA - if (Player* killed = pVictim->ToPlayer()) - sEluna->OnPlayerKilledByCreature(killer, killed); + if (Player* killed = pVictim->ToPlayer()) + sEluna->OnPlayerKilledByCreature(killer, killed); #endif /* ENABLE_ELUNA */ - } - - // Call AI OwnerKilledUnit (for any current summoned minipet/guardian/protector) - PetOwnerKilledUnit(pVictim); - - /* - * Actions for the victim - */ - if (pVictim->GetTypeId() == TYPEID_PLAYER) // Killed player - { - Player* playerVictim = (Player*)pVictim; - - // remember victim PvP death for corpse type and corpse reclaim delay - // at original death (not at SpiritOfRedemtionTalent timeout) - if (!damageFromSpiritOfRedemtionTalent) - { - playerVictim->SetPvPDeath(player_tap != NULL); - } - - // achievement stuff - playerVictim->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health); - if (player_tap) - player_tap->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, pVictim); - if (GetTypeId() == TYPEID_UNIT) - playerVictim->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry()); - else if (GetTypeId() == TYPEID_PLAYER && pVictim != this) - playerVictim->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, playerVictim->GetTeam()); - - // 10% durability loss on death - // only if not player and not controlled by player pet. And not at BG - if (durabilityLoss && !player_tap && !playerVictim->InBattleGround()) - { - DEBUG_LOG("DealDamage: Killed %s, looing 10 percents durability", pVictim->GetGuidStr().c_str()); - playerVictim->DurabilityLossAll(0.10f, false); - // durability lost message - WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); - playerVictim->GetSession()->SendPacket(&data); - } - - if (!spiritOfRedemtionTalentReady) // Before informing Battleground - { - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "SET JUST_DIED"); - pVictim->SetDeathState(JUST_DIED); - } - - // playerVictim was in duel, duel must be interrupted - // last damage from non duel opponent or non opponent controlled creature - if (duel_hasEnded) - { - playerVictim->duel->opponent->CombatStopWithPets(true); - playerVictim->CombatStopWithPets(true); - - playerVictim->DuelComplete(DUEL_INTERRUPTED); - } - - if (player_tap) // PvP kill - { - if (BattleGround* bg = playerVictim->GetBattleGround()) - { - bg->HandleKillPlayer(playerVictim, player_tap); - } - else if (pVictim != this) - { - // selfkills are not handled in outdoor pvp scripts - if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(playerVictim->GetCachedZoneId())) - { - outdoorPvP->HandlePlayerKill(player_tap, playerVictim); - } - } - - // Used by Eluna + } + + // Call AI OwnerKilledUnit (for any current summoned minipet/guardian/protector) + PetOwnerKilledUnit(pVictim); + + /* + * Actions for the victim + */ + if (pVictim->GetTypeId() == TYPEID_PLAYER) // Killed player + { + Player* playerVictim = (Player*)pVictim; + + // remember victim PvP death for corpse type and corpse reclaim delay + // at original death (not at SpiritOfRedemtionTalent timeout) + if (!damageFromSpiritOfRedemtionTalent) + { + playerVictim->SetPvPDeath(player_tap != NULL); + } + + // achievement stuff + playerVictim->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health); + if (player_tap) + player_tap->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, pVictim); + if (GetTypeId() == TYPEID_UNIT) + playerVictim->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry()); + else if (GetTypeId() == TYPEID_PLAYER && pVictim != this) + playerVictim->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, playerVictim->GetTeam()); + + // 10% durability loss on death + // only if not player and not controlled by player pet. And not at BG + if (durabilityLoss && !player_tap && !playerVictim->InBattleGround()) + { + DEBUG_LOG("DealDamage: Killed %s, looing 10 percents durability", pVictim->GetGuidStr().c_str()); + playerVictim->DurabilityLossAll(0.10f, false); + // durability lost message + WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); + playerVictim->GetSession()->SendPacket(&data); + } + + if (!spiritOfRedemtionTalentReady) // Before informing Battleground + { + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "SET JUST_DIED"); + pVictim->SetDeathState(JUST_DIED); + } + + // playerVictim was in duel, duel must be interrupted + // last damage from non duel opponent or non opponent controlled creature + if (duel_hasEnded) + { + playerVictim->duel->opponent->CombatStopWithPets(true); + playerVictim->CombatStopWithPets(true); + + playerVictim->DuelComplete(DUEL_INTERRUPTED); + } + + if (player_tap) // PvP kill + { + if (BattleGround* bg = playerVictim->GetBattleGround()) + { + bg->HandleKillPlayer(playerVictim, player_tap); + } + else if (pVictim != this) + { + // selfkills are not handled in outdoor pvp scripts + if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(playerVictim->GetCachedZoneId())) + { + outdoorPvP->HandlePlayerKill(player_tap, playerVictim); + } + } + + // Used by Eluna #ifdef ENABLE_ELUNA - sEluna->OnPVPKill(player_tap, playerVictim); + sEluna->OnPVPKill(player_tap, playerVictim); #endif /* ENABLE_ELUNA */ - } - } - else // Killed creature - { - JustKilledCreature((Creature*)pVictim, player_tap); - } - } - else // if (health <= damage) - { - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageAlive"); - - if (pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage); - - pVictim->ModifyHealth(- (int32)damage); - - if (damagetype != DOT) - { - if (!getVictim()) - { - // if not have main target then attack state with target (including AI call) - // start melee attacks only after melee hit - Attack(pVictim, (damagetype == DIRECT_DAMAGE)); - } - - // if damage pVictim call AI reaction - pVictim->AttackedBy(this); - } - - if (pVictim->GetTypeId() != TYPEID_PLAYER) - { - float threat = damage * sSpellMgr.GetSpellThreatMultiplier(spellProto); - pVictim->AddThreat(this, threat, (cleanDamage && cleanDamage->hitOutCome == MELEE_HIT_CRIT), damageSchoolMask, spellProto); - } - else // victim is a player - { - // Rage from damage received - if (this != pVictim && pVictim->GetPowerType() == POWER_RAGE) - { - uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0); - ((Player*)pVictim)->RewardRage(rage_damage, 0, false); - } - - // random durability for items (HIT TAKEN) - if (roll_chance_f(sWorld.getConfig(CONFIG_FLOAT_RATE_DURABILITY_LOSS_DAMAGE))) - { - EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END - 1)); - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(slot); - } - } - - if (GetTypeId() == TYPEID_PLAYER) - { - // random durability for items (HIT DONE) - if (roll_chance_f(sWorld.getConfig(CONFIG_FLOAT_RATE_DURABILITY_LOSS_DAMAGE))) - { - EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END - 1)); - ((Player*)this)->DurabilityPointLossForEquipSlot(slot); - } - } - - if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER) - { - if (damagetype != DOT) - { - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) - { - // skip channeled spell (processed differently below) - if (i == CURRENT_CHANNELED_SPELL) - { - continue; - } - - if (Spell* spell = pVictim->GetCurrentSpell(CurrentSpellTypes(i))) - { - if (spell->getState() == SPELL_STATE_PREPARING) - { - if(spell->m_spellInfo->GetInterruptFlags() & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) - { - pVictim->InterruptSpell(CurrentSpellTypes(i)); - } - else - { - spell->Delayed(); - } - } - } - } - } - - if (Spell* spell = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]) - { - if (spell->getState() == SPELL_STATE_CASTING) - { - uint32 channelInterruptFlags = spell->m_spellInfo->GetChannelInterruptFlags(); - if (channelInterruptFlags & CHANNEL_FLAG_DELAY) - { - if (pVictim != this) // don't shorten the duration of channeling if you damage yourself - { - spell->DelayedChannel(); - } - } - else if ((channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2))) - { - DETAIL_LOG("Spell %u canceled at damage!", spell->m_spellInfo->Id); - pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL); - } - } - else if (spell->getState() == SPELL_STATE_DELAYED) - // break channeled spell in delayed state on damage - { - DETAIL_LOG("Spell %u canceled at damage!", spell->m_spellInfo->Id); - pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL); - } - } - } - - // last damage from duel opponent - if (duel_hasEnded) - { - MANGOS_ASSERT(pVictim->GetTypeId() == TYPEID_PLAYER); - Player* he = (Player*)pVictim; - - MANGOS_ASSERT(he->duel); - - he->SetHealth(1); - - he->duel->opponent->CombatStopWithPets(true); - he->CombatStopWithPets(true); - - he->CastSpell(he, 7267, true); // beg - he->DuelComplete(DUEL_WON); - } - } - - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageEnd returned %d damage", damage); - - return damage; + } + } + else // Killed creature + { + JustKilledCreature((Creature*)pVictim, player_tap); + } + } + else // if (health <= damage) + { + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageAlive"); + + if (pVictim->GetTypeId() == TYPEID_PLAYER) + ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage); + + pVictim->ModifyHealth(-(int32)damage); + + if (damagetype != DOT) + { + if (!getVictim()) + { + // if not have main target then attack state with target (including AI call) + // start melee attacks only after melee hit + Attack(pVictim, (damagetype == DIRECT_DAMAGE)); + } + + // if damage pVictim call AI reaction + pVictim->AttackedBy(this); + } + + if (pVictim->GetTypeId() != TYPEID_PLAYER) + { + float threat = damage * sSpellMgr.GetSpellThreatMultiplier(spellProto); + pVictim->AddThreat(this, threat, (cleanDamage && cleanDamage->hitOutCome == MELEE_HIT_CRIT), damageSchoolMask, spellProto); + } + else // victim is a player + { + // Rage from damage received + if (this != pVictim && pVictim->GetPowerType() == POWER_RAGE) + { + uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0); + ((Player*)pVictim)->RewardRage(rage_damage, 0, false); + } + + // random durability for items (HIT TAKEN) + if (roll_chance_f(sWorld.getConfig(CONFIG_FLOAT_RATE_DURABILITY_LOSS_DAMAGE))) + { + EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END - 1)); + ((Player*)pVictim)->DurabilityPointLossForEquipSlot(slot); + } + } + + if (GetTypeId() == TYPEID_PLAYER) + { + // random durability for items (HIT DONE) + if (roll_chance_f(sWorld.getConfig(CONFIG_FLOAT_RATE_DURABILITY_LOSS_DAMAGE))) + { + EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END - 1)); + ((Player*)this)->DurabilityPointLossForEquipSlot(slot); + } + } + + if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER) + { + if (damagetype != DOT) + { + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) + { + // skip channeled spell (processed differently below) + if (i == CURRENT_CHANNELED_SPELL) + { + continue; + } + + if (Spell* spell = pVictim->GetCurrentSpell(CurrentSpellTypes(i))) + { + if (spell->getState() == SPELL_STATE_PREPARING) + { + if (spell->m_spellInfo->GetInterruptFlags() & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) + { + pVictim->InterruptSpell(CurrentSpellTypes(i)); + } + else + { + spell->Delayed(); + } + } + } + } + } + + if (Spell* spell = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]) + { + if (spell->getState() == SPELL_STATE_CASTING) + { + uint32 channelInterruptFlags = spell->m_spellInfo->GetChannelInterruptFlags(); + if (channelInterruptFlags & CHANNEL_FLAG_DELAY) + { + if (pVictim != this) // don't shorten the duration of channeling if you damage yourself + { + spell->DelayedChannel(); + } + } + else if ((channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2))) + { + DETAIL_LOG("Spell %u canceled at damage!", spell->m_spellInfo->Id); + pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL); + } + } + else if (spell->getState() == SPELL_STATE_DELAYED) + // break channeled spell in delayed state on damage + { + DETAIL_LOG("Spell %u canceled at damage!", spell->m_spellInfo->Id); + pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL); + } + } + } + + // last damage from duel opponent + if (duel_hasEnded) + { + MANGOS_ASSERT(pVictim->GetTypeId() == TYPEID_PLAYER); + Player* he = (Player*)pVictim; + + MANGOS_ASSERT(he->duel); + + he->SetHealth(1); + + he->duel->opponent->CombatStopWithPets(true); + he->CombatStopWithPets(true); + + he->CastSpell(he, 7267, true); // beg + he->DuelComplete(DUEL_WON); + } + } + + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageEnd returned %d damage", damage); + + return damage; } struct PetOwnerKilledUnitHelper { - explicit PetOwnerKilledUnitHelper(Unit* pVictim) : m_victim(pVictim) {} - void operator()(Unit* pTarget) const - { - if (pTarget->GetTypeId() == TYPEID_UNIT) - { - if (((Creature*)pTarget)->AI()) - { - ((Creature*)pTarget)->AI()->OwnerKilledUnit(m_victim); - } - } - } - - Unit* m_victim; + explicit PetOwnerKilledUnitHelper(Unit* pVictim) : m_victim(pVictim) {} + void operator()(Unit* pTarget) const + { + if (pTarget->GetTypeId() == TYPEID_UNIT) + { + if (((Creature*)pTarget)->AI()) + { + ((Creature*)pTarget)->AI()->OwnerKilledUnit(m_victim); + } + } + } + + Unit* m_victim; }; void Unit::JustKilledCreature(Creature* victim, Player* responsiblePlayer) { - victim->m_deathState = DEAD; // so that IsAlive, IsDead return expected results in the called hooks of JustKilledCreature - // must be used only shortly before SetDeathState(JUST_DIED) and only for Creatures or Pets - - // some critters required for quests (need normal entry instead possible heroic in any cases) - if (victim->GetCreatureType() == CREATURE_TYPE_CRITTER && GetTypeId() == TYPEID_PLAYER) - { - if (CreatureInfo const* normalInfo = ObjectMgr::GetCreatureTemplate(victim->GetEntry())) - { - ((Player*)this)->KilledMonster(normalInfo, victim->GetObjectGuid()); - } - } - - // Interrupt channeling spell when a Possessed Summoned is killed - SpellEntry const* spellInfo = sSpellStore.LookupEntry(victim->GetUInt32Value(UNIT_CREATED_BY_SPELL)); - if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR_EX_FARSIGHT) && spellInfo->HasAttribute(SPELL_ATTR_EX_CHANNELED_1)) - { - Unit* creator = GetMap()->GetUnit(victim->GetCreatorGuid()); - if (creator && creator->GetCharmGuid() == victim->GetObjectGuid()) - { - Spell* channeledSpell = creator->GetCurrentSpell(CURRENT_CHANNELED_SPELL); - if (channeledSpell && channeledSpell->m_spellInfo->Id == spellInfo->Id) - { - creator->InterruptNonMeleeSpells(false); - } - } - } - - /* ******************************* Inform various hooks ************************************ */ - // Inform victim's AI - if (victim->AI()) - { - victim->AI()->JustDied(this); - } - - // Inform Owner - Unit* pOwner = victim->GetCharmerOrOwner(); - if (victim->IsTemporarySummon()) - { - TemporarySummon* pSummon = (TemporarySummon*)victim; - if (pSummon->GetSummonerGuid().IsCreatureOrVehicle()) - if (Creature* pSummoner = victim->GetMap()->GetCreature(pSummon->GetSummonerGuid())) - if (pSummoner->AI()) - { - pSummoner->AI()->SummonedCreatureJustDied(victim); - } - } - else if (pOwner && pOwner->GetTypeId() == TYPEID_UNIT) - { - if (((Creature*)pOwner)->AI()) - { - ((Creature*)pOwner)->AI()->SummonedCreatureJustDied(victim); - } - } - - // Inform Instance Data and Linking - if (InstanceData* mapInstance = victim->GetInstanceData()) - { - mapInstance->OnCreatureDeath(victim); - } - - if (responsiblePlayer) // killedby Player, inform BG - if (BattleGround* bg = responsiblePlayer->GetBattleGround()) - bg->HandleKillUnit(victim, responsiblePlayer); - - // Used by Eluna + victim->m_deathState = DEAD; // so that IsAlive, IsDead return expected results in the called hooks of JustKilledCreature + // must be used only shortly before SetDeathState(JUST_DIED) and only for Creatures or Pets + + // some critters required for quests (need normal entry instead possible heroic in any cases) + if (victim->GetCreatureType() == CREATURE_TYPE_CRITTER && GetTypeId() == TYPEID_PLAYER) + { + if (CreatureInfo const* normalInfo = ObjectMgr::GetCreatureTemplate(victim->GetEntry())) + { + ((Player*)this)->KilledMonster(normalInfo, victim->GetObjectGuid()); + } + } + + // Interrupt channeling spell when a Possessed Summoned is killed + SpellEntry const* spellInfo = sSpellStore.LookupEntry(victim->GetUInt32Value(UNIT_CREATED_BY_SPELL)); + if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR_EX_FARSIGHT) && spellInfo->HasAttribute(SPELL_ATTR_EX_CHANNELED_1)) + { + Unit* creator = GetMap()->GetUnit(victim->GetCreatorGuid()); + if (creator && creator->GetCharmGuid() == victim->GetObjectGuid()) + { + Spell* channeledSpell = creator->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + if (channeledSpell && channeledSpell->m_spellInfo->Id == spellInfo->Id) + { + creator->InterruptNonMeleeSpells(false); + } + } + } + + /* ******************************* Inform various hooks ************************************ */ + // Inform victim's AI + if (victim->AI()) + { + victim->AI()->JustDied(this); + } + + // Inform Owner + Unit* pOwner = victim->GetCharmerOrOwner(); + if (victim->IsTemporarySummon()) + { + TemporarySummon* pSummon = (TemporarySummon*)victim; + if (pSummon->GetSummonerGuid().IsCreatureOrVehicle()) + if (Creature* pSummoner = victim->GetMap()->GetCreature(pSummon->GetSummonerGuid())) + if (pSummoner->AI()) + { + pSummoner->AI()->SummonedCreatureJustDied(victim); + } + } + else if (pOwner && pOwner->GetTypeId() == TYPEID_UNIT) + { + if (((Creature*)pOwner)->AI()) + { + ((Creature*)pOwner)->AI()->SummonedCreatureJustDied(victim); + } + } + + // Inform Instance Data and Linking + if (InstanceData* mapInstance = victim->GetInstanceData()) + { + mapInstance->OnCreatureDeath(victim); + } + + if (responsiblePlayer) // killedby Player, inform BG + if (BattleGround* bg = responsiblePlayer->GetBattleGround()) + bg->HandleKillUnit(victim, responsiblePlayer); + + // Used by Eluna #ifdef ENABLE_ELUNA - sEluna->OnCreatureKill(responsiblePlayer, victim); + sEluna->OnCreatureKill(responsiblePlayer, victim); #endif /* ENABLE_ELUNA */ - // Notify the outdoor pvp script - if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(responsiblePlayer ? responsiblePlayer->GetCachedZoneId() : GetZoneId())) - { - outdoorPvP->HandleCreatureDeath(victim); - } - - // Start creature death script - GetMap()->ScriptsStart(DBS_ON_CREATURE_DEATH, victim->GetEntry(), victim, responsiblePlayer ? responsiblePlayer : this); - - if (victim->IsLinkingEventTrigger()) - { - victim->GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_DIE, victim); - } - - // Dungeon specific stuff - if (victim->GetInstanceId()) - { - Map* m = victim->GetMap(); - Player* creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself(); - // TODO: do instance binding anyway if the charmer/owner is offline - - if (m->IsDungeon() && creditedPlayer) - { - if (m->IsRaidOrHeroicDungeon()) - { - if (victim->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_INSTANCE_BIND) - { - ((DungeonMap*)m)->PermBindAllPlayers(creditedPlayer); - } - } - else - { - DungeonPersistentState* save = ((DungeonMap*)m)->GetPersistanceState(); - // the reset time is set but not added to the scheduler - // until the players leave the instance - time_t resettime = victim->GetRespawnTimeEx() + 2 * HOUR; - if (save->GetResetTime() < resettime) - { - save->SetResetTime(resettime); - } - } - // update encounter state if needed - ((DungeonMap*)m)->GetPersistanceState()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, victim->GetEntry()); - } - } - - bool isPet = victim->IsPet(); - - /* ********************************* Set Death finally ************************************* */ - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "SET JUST_DIED"); - victim->SetDeathState(JUST_DIED); // if !spiritOfRedemtionTalentReady always true for unit - - if (isPet) - { return; } // Pets might have been unsummoned at this place, do not handle them further! - - /* ******************************** Prepare loot if can ************************************ */ - victim->DeleteThreatList(); - // only lootable if it has loot or can drop gold - victim->PrepareBodyLootState(); - // may have no loot, so update death timer if allowed, must be after SetDeathState(JUST_DIED) - victim->AllLootRemovedFromCorpse(); + // Notify the outdoor pvp script + if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(responsiblePlayer ? responsiblePlayer->GetCachedZoneId() : GetZoneId())) + { + outdoorPvP->HandleCreatureDeath(victim); + } + + // Start creature death script + GetMap()->ScriptsStart(DBS_ON_CREATURE_DEATH, victim->GetEntry(), victim, responsiblePlayer ? responsiblePlayer : this); + + if (victim->IsLinkingEventTrigger()) + { + victim->GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_DIE, victim); + } + + // Dungeon specific stuff + if (victim->GetInstanceId()) + { + Map* m = victim->GetMap(); + Player* creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself(); + // TODO: do instance binding anyway if the charmer/owner is offline + + if (m->IsDungeon() && creditedPlayer) + { + if (m->IsRaidOrHeroicDungeon()) + { + if (victim->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_INSTANCE_BIND) + { + ((DungeonMap*)m)->PermBindAllPlayers(creditedPlayer); + } + } + else + { + DungeonPersistentState* save = ((DungeonMap*)m)->GetPersistanceState(); + // the reset time is set but not added to the scheduler + // until the players leave the instance + time_t resettime = victim->GetRespawnTimeEx() + 2 * HOUR; + if (save->GetResetTime() < resettime) + { + save->SetResetTime(resettime); + } + } + // update encounter state if needed + ((DungeonMap*)m)->GetPersistanceState()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, victim->GetEntry()); + } + } + + bool isPet = victim->IsPet(); + + /* ********************************* Set Death finally ************************************* */ + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "SET JUST_DIED"); + victim->SetDeathState(JUST_DIED); // if !spiritOfRedemtionTalentReady always true for unit + + if (isPet) + { + return; + } // Pets might have been unsummoned at this place, do not handle them further! + +/* ******************************** Prepare loot if can ************************************ */ + victim->DeleteThreatList(); + // only lootable if it has loot or can drop gold + victim->PrepareBodyLootState(); + // may have no loot, so update death timer if allowed, must be after SetDeathState(JUST_DIED) + victim->AllLootRemovedFromCorpse(); } void Unit::PetOwnerKilledUnit(Unit* pVictim) { - // for minipet and guardians (including protector) - CallForAllControlledUnits(PetOwnerKilledUnitHelper(pVictim), CONTROLLED_MINIPET | CONTROLLED_GUARDIANS); + // for minipet and guardians (including protector) + CallForAllControlledUnits(PetOwnerKilledUnitHelper(pVictim), CONTROLLED_MINIPET | CONTROLLED_GUARDIANS); } void Unit::CastStop(uint32 except_spellid) { - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) - if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid) - { - InterruptSpell(CurrentSpellTypes(i), false); - } + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) + if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid) + { + InterruptSpell(CurrentSpellTypes(i), false); + } } void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item* castItem, Aura* triggeredByAura, ObjectGuid originalCaster, SpellEntry const* triggeredBy) { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo) - { - if (triggeredByAura) - { - sLog.outError("CastSpell: unknown spell id %i by caster: %s triggered by aura %u (eff %u)", spellId, GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); - } - else - { - sLog.outError("CastSpell: unknown spell id %i by caster: %s", spellId, GetGuidStr().c_str()); - } - return; - } + if (!spellInfo) + { + if (triggeredByAura) + { + sLog.outError("CastSpell: unknown spell id %i by caster: %s triggered by aura %u (eff %u)", spellId, GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); + } + else + { + sLog.outError("CastSpell: unknown spell id %i by caster: %s", spellId, GetGuidStr().c_str()); + } + return; + } - CastSpell(Victim, spellInfo, triggered, castItem, triggeredByAura, originalCaster, triggeredBy); + CastSpell(Victim, spellInfo, triggered, castItem, triggeredByAura, originalCaster, triggeredBy); } void Unit::CastSpell(Unit* Victim, SpellEntry const* spellInfo, bool triggered, Item* castItem, Aura* triggeredByAura, ObjectGuid originalCaster, SpellEntry const* triggeredBy) { - if (!spellInfo) - { - if (triggeredByAura) - { - sLog.outError("CastSpell: unknown spell by caster: %s triggered by aura %u (eff %u)", GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); - } - else - { - sLog.outError("CastSpell: unknown spell by caster: %s", GetGuidStr().c_str()); - } - return; - } - - if (castItem) - { - DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "WORLD: cast Item spellId - %i", spellInfo->Id); - } - - if (triggeredByAura) - { - if (!originalCaster) - { - originalCaster = triggeredByAura->GetCasterGuid(); - } - - triggeredBy = triggeredByAura->GetSpellProto(); - } - else - { - triggeredByAura = GetTriggeredByClientAura(spellInfo->Id); - if (triggeredByAura) - { - triggered = true; - triggeredBy = triggeredByAura->GetSpellProto(); - } - } - - Spell* spell = new Spell(this, spellInfo, triggered, originalCaster, triggeredBy); - - SpellCastTargets targets; - targets.setUnitTarget(Victim); - - if (spellInfo->GetTargets() & TARGET_FLAG_DEST_LOCATION) - { - targets.setDestination(Victim->GetPositionX(), Victim->GetPositionY(), Victim->GetPositionZ()); - } - if (spellInfo->GetTargets() & TARGET_FLAG_SOURCE_LOCATION) - if (WorldObject* caster = spell->GetCastingObject()) - targets.setSource(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); - - spell->m_CastItem = castItem; - spell->SpellStart(&targets, triggeredByAura); + if (!spellInfo) + { + if (triggeredByAura) + { + sLog.outError("CastSpell: unknown spell by caster: %s triggered by aura %u (eff %u)", GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); + } + else + { + sLog.outError("CastSpell: unknown spell by caster: %s", GetGuidStr().c_str()); + } + return; + } + + if (castItem) + { + DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "WORLD: cast Item spellId - %i", spellInfo->Id); + } + + if (triggeredByAura) + { + if (!originalCaster) + { + originalCaster = triggeredByAura->GetCasterGuid(); + } + + triggeredBy = triggeredByAura->GetSpellProto(); + } + else + { + triggeredByAura = GetTriggeredByClientAura(spellInfo->Id); + if (triggeredByAura) + { + triggered = true; + triggeredBy = triggeredByAura->GetSpellProto(); + } + } + + Spell* spell = new Spell(this, spellInfo, triggered, originalCaster, triggeredBy); + + SpellCastTargets targets; + targets.setUnitTarget(Victim); + + if (spellInfo->GetTargets() & TARGET_FLAG_DEST_LOCATION) + { + targets.setDestination(Victim->GetPositionX(), Victim->GetPositionY(), Victim->GetPositionZ()); + } + if (spellInfo->GetTargets() & TARGET_FLAG_SOURCE_LOCATION) + if (WorldObject* caster = spell->GetCastingObject()) + targets.setSource(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); + + spell->m_CastItem = castItem; + spell->SpellStart(&targets, triggeredByAura); } void Unit::CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, Aura* triggeredByAura, ObjectGuid originalCaster, SpellEntry const* triggeredBy) { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo) - { - if (triggeredByAura) - sLog.outError("CastCustomSpell: unknown spell id %i by caster: %s triggered by aura %u (eff %u)", spellId, GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); - else - { - sLog.outError("CastCustomSpell: unknown spell id %i by caster: %s", spellId, GetGuidStr().c_str()); - } - return; - } + if (!spellInfo) + { + if (triggeredByAura) + sLog.outError("CastCustomSpell: unknown spell id %i by caster: %s triggered by aura %u (eff %u)", spellId, GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); + else + { + sLog.outError("CastCustomSpell: unknown spell id %i by caster: %s", spellId, GetGuidStr().c_str()); + } + return; + } - CastCustomSpell(Victim, spellInfo, bp0, bp1, bp2, triggered, castItem, triggeredByAura, originalCaster, triggeredBy); + CastCustomSpell(Victim, spellInfo, bp0, bp1, bp2, triggered, castItem, triggeredByAura, originalCaster, triggeredBy); } void Unit::CastCustomSpell(Unit* Victim, SpellEntry const* spellInfo, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, Aura* triggeredByAura, ObjectGuid originalCaster, SpellEntry const* triggeredBy) { - if (!spellInfo) - { - if (triggeredByAura) - sLog.outError("CastCustomSpell: unknown spell by caster: %s triggered by aura %u (eff %u)", GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); - else - sLog.outError("CastCustomSpell: unknown spell by caster: %s", GetGuidStr().c_str()); - return; - } - - if (castItem) - { - DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "WORLD: cast Item spellId - %i", spellInfo->Id); - } - - if (triggeredByAura) - { - if (!originalCaster) - { - originalCaster = triggeredByAura->GetCasterGuid(); - } - - triggeredBy = triggeredByAura->GetSpellProto(); - } - - Spell* spell = new Spell(this, spellInfo, triggered, originalCaster, triggeredBy); - - if (bp0) - { - spell->m_currentBasePoints[EFFECT_INDEX_0] = *bp0; - } - - if (bp1) - { - spell->m_currentBasePoints[EFFECT_INDEX_1] = *bp1; - } - - if (bp2) - { - spell->m_currentBasePoints[EFFECT_INDEX_2] = *bp2; - } - - SpellCastTargets targets; - targets.setUnitTarget(Victim); - spell->m_CastItem = castItem; - - if (spellInfo->GetTargets() & TARGET_FLAG_DEST_LOCATION) - { - targets.setDestination(Victim->GetPositionX(), Victim->GetPositionY(), Victim->GetPositionZ()); - } - if (spellInfo->GetTargets() & TARGET_FLAG_SOURCE_LOCATION) - if (WorldObject* caster = spell->GetCastingObject()) - { - targets.setSource(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); - } - - spell->SpellStart(&targets, triggeredByAura); + if (!spellInfo) + { + if (triggeredByAura) + sLog.outError("CastCustomSpell: unknown spell by caster: %s triggered by aura %u (eff %u)", GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); + else + sLog.outError("CastCustomSpell: unknown spell by caster: %s", GetGuidStr().c_str()); + return; + } + + if (castItem) + { + DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "WORLD: cast Item spellId - %i", spellInfo->Id); + } + + if (triggeredByAura) + { + if (!originalCaster) + { + originalCaster = triggeredByAura->GetCasterGuid(); + } + + triggeredBy = triggeredByAura->GetSpellProto(); + } + + Spell* spell = new Spell(this, spellInfo, triggered, originalCaster, triggeredBy); + + if (bp0) + { + spell->m_currentBasePoints[EFFECT_INDEX_0] = *bp0; + } + + if (bp1) + { + spell->m_currentBasePoints[EFFECT_INDEX_1] = *bp1; + } + + if (bp2) + { + spell->m_currentBasePoints[EFFECT_INDEX_2] = *bp2; + } + + SpellCastTargets targets; + targets.setUnitTarget(Victim); + spell->m_CastItem = castItem; + + if (spellInfo->GetTargets() & TARGET_FLAG_DEST_LOCATION) + { + targets.setDestination(Victim->GetPositionX(), Victim->GetPositionY(), Victim->GetPositionZ()); + } + if (spellInfo->GetTargets() & TARGET_FLAG_SOURCE_LOCATION) + if (WorldObject* caster = spell->GetCastingObject()) + { + targets.setSource(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); + } + + spell->SpellStart(&targets, triggeredByAura); } // used for scripting void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem, Aura* triggeredByAura, ObjectGuid originalCaster, SpellEntry const* triggeredBy) { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo) - { - if (triggeredByAura) - sLog.outError("CastSpell(x,y,z): unknown spell id %i by caster: %s triggered by aura %u (eff %u)", spellId, GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); - else - sLog.outError("CastSpell(x,y,z): unknown spell id %i by caster: %s", spellId, GetGuidStr().c_str()); - return; - } + if (!spellInfo) + { + if (triggeredByAura) + sLog.outError("CastSpell(x,y,z): unknown spell id %i by caster: %s triggered by aura %u (eff %u)", spellId, GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); + else + sLog.outError("CastSpell(x,y,z): unknown spell id %i by caster: %s", spellId, GetGuidStr().c_str()); + return; + } - CastSpell(x, y, z, spellInfo, triggered, castItem, triggeredByAura, originalCaster, triggeredBy); + CastSpell(x, y, z, spellInfo, triggered, castItem, triggeredByAura, originalCaster, triggeredBy); } // used for scripting void Unit::CastSpell(float x, float y, float z, SpellEntry const* spellInfo, bool triggered, Item* castItem, Aura* triggeredByAura, ObjectGuid originalCaster, SpellEntry const* triggeredBy) { - if (!spellInfo) - { - if (triggeredByAura) - sLog.outError("CastSpell(x,y,z): unknown spell by caster: %s triggered by aura %u (eff %u)", GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); - else - sLog.outError("CastSpell(x,y,z): unknown spell by caster: %s", GetGuidStr().c_str()); - return; - } - - if (castItem) - { - DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "WORLD: cast Item spellId - %i", spellInfo->Id); - } - - if (triggeredByAura) - { - if (!originalCaster) - { - originalCaster = triggeredByAura->GetCasterGuid(); - } - - triggeredBy = triggeredByAura->GetSpellProto(); - } - - Spell* spell = new Spell(this, spellInfo, triggered, originalCaster, triggeredBy); - - SpellCastTargets targets; - - if (spellInfo->GetTargets() & TARGET_FLAG_DEST_LOCATION) - { - targets.setDestination(x, y, z); - } - if (spellInfo->GetTargets() & TARGET_FLAG_SOURCE_LOCATION) - { - targets.setSource(x, y, z); - } - - // Spell cast with x,y,z but without dbc target-mask, set destination - if (!(targets.m_targetMask & (TARGET_FLAG_DEST_LOCATION | TARGET_FLAG_SOURCE_LOCATION))) - { - targets.setDestination(x, y, z); - } - - spell->m_CastItem = castItem; - spell->SpellStart(&targets, triggeredByAura); + if (!spellInfo) + { + if (triggeredByAura) + sLog.outError("CastSpell(x,y,z): unknown spell by caster: %s triggered by aura %u (eff %u)", GetGuidStr().c_str(), triggeredByAura->GetId(), triggeredByAura->GetEffIndex()); + else + sLog.outError("CastSpell(x,y,z): unknown spell by caster: %s", GetGuidStr().c_str()); + return; + } + + if (castItem) + { + DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "WORLD: cast Item spellId - %i", spellInfo->Id); + } + + if (triggeredByAura) + { + if (!originalCaster) + { + originalCaster = triggeredByAura->GetCasterGuid(); + } + + triggeredBy = triggeredByAura->GetSpellProto(); + } + + Spell* spell = new Spell(this, spellInfo, triggered, originalCaster, triggeredBy); + + SpellCastTargets targets; + + if (spellInfo->GetTargets() & TARGET_FLAG_DEST_LOCATION) + { + targets.setDestination(x, y, z); + } + if (spellInfo->GetTargets() & TARGET_FLAG_SOURCE_LOCATION) + { + targets.setSource(x, y, z); + } + + // Spell cast with x,y,z but without dbc target-mask, set destination + if (!(targets.m_targetMask & (TARGET_FLAG_DEST_LOCATION | TARGET_FLAG_SOURCE_LOCATION))) + { + targets.setDestination(x, y, z); + } + + spell->m_CastItem = castItem; + spell->SpellStart(&targets, triggeredByAura); } // Obsolete func need remove, here only for comotability vs another patches uint32 Unit::SpellNonMeleeDamageLog(Unit* pVictim, uint32 spellID, uint32 damage) { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID); - SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, SpellSchoolMask(spellInfo->GetSchoolMask())); - CalculateSpellDamage(&damageInfo, damage, spellInfo); - damageInfo.target->CalculateAbsorbResistBlock(this, &damageInfo, spellInfo); - DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); - SendSpellNonMeleeDamageLog(&damageInfo); - DealSpellDamage(&damageInfo, true); - return damageInfo.damage; + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID); + SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, SpellSchoolMask(spellInfo->GetSchoolMask())); + CalculateSpellDamage(&damageInfo, damage, spellInfo); + damageInfo.target->CalculateAbsorbResistBlock(this, &damageInfo, spellInfo); + DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); + SendSpellNonMeleeDamageLog(&damageInfo); + DealSpellDamage(&damageInfo, true); + return damageInfo.damage; } void Unit::CalculateSpellDamage(SpellNonMeleeDamage* damageInfo, int32 damage, SpellEntry const* spellInfo, WeaponAttackType attackType) { - SpellSchoolMask damageSchoolMask = damageInfo->schoolMask; - Unit* pVictim = damageInfo->target; - - if (damage < 0) - { - return; - } - - if (!this || !pVictim) - { - return; - } - - // units which are not alive cannot deal damage except for dying creatures - if ((!this->IsAlive() || !pVictim->IsAlive()) && (this->GetTypeId() != TYPEID_UNIT || this->getDeathState() != DEAD)) - { - return; - } - - // Check spell crit chance - bool crit = IsSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType); - - // damage bonus (per damage class) - switch (spellInfo->GetDmgClass()) - { - // Melee and Ranged Spells - case SPELL_DAMAGE_CLASS_RANGED: - case SPELL_DAMAGE_CLASS_MELEE: - { - // Calculate damage bonus - damage = MeleeDamageBonusDone(pVictim, damage, attackType, spellInfo, SPELL_DIRECT_DAMAGE); - damage = pVictim->MeleeDamageBonusTaken(this, damage, attackType, spellInfo, SPELL_DIRECT_DAMAGE); - - // if crit add critical bonus - if (crit) - { - damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT; - damage = SpellCriticalDamageBonus(spellInfo, damage, pVictim); - // Resilience - reduce crit damage - uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damage, damageSchoolMask); - damage -= pVictim->GetCritDamageReduction(reduction_affected_damage); - } - } - break; - // Magical Attacks - case SPELL_DAMAGE_CLASS_NONE: - case SPELL_DAMAGE_CLASS_MAGIC: - { - // Calculate damage bonus - damage = SpellDamageBonusDone(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE); - damage = pVictim->SpellDamageBonusTaken(this, spellInfo, damage, SPELL_DIRECT_DAMAGE); - - // If crit add critical bonus - if (crit) - { - damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT; - damage = SpellCriticalDamageBonus(spellInfo, damage, pVictim); - // Resilience - reduce crit damage - uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damage, damageSchoolMask); - damage -= pVictim->GetCritDamageReduction(reduction_affected_damage); - } - } - break; - } - - // only from players - if (GetTypeId() == TYPEID_PLAYER) - { - uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damage, damageSchoolMask); - damage -= pVictim->GetDamageReduction(reduction_affected_damage); - } - - // damage mitigation - if (damage > 0) - { - // physical damage => armor - if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) - { - uint32 armor_affected_damage = CalcNotIgnoreDamageReduction(damage, damageSchoolMask); - damage = damage - armor_affected_damage + CalcArmorReducedDamage(pVictim, armor_affected_damage); - } - } - else - { - damage = 0; - } - damageInfo->damage = damage; + SpellSchoolMask damageSchoolMask = damageInfo->schoolMask; + Unit* pVictim = damageInfo->target; + + if (damage < 0) + { + return; + } + + if (!this || !pVictim) + { + return; + } + + // units which are not alive cannot deal damage except for dying creatures + if ((!this->IsAlive() || !pVictim->IsAlive()) && (this->GetTypeId() != TYPEID_UNIT || this->getDeathState() != DEAD)) + { + return; + } + + // Check spell crit chance + bool crit = IsSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType); + + // damage bonus (per damage class) + switch (spellInfo->GetDmgClass()) + { + // Melee and Ranged Spells + case SPELL_DAMAGE_CLASS_RANGED: + case SPELL_DAMAGE_CLASS_MELEE: + { + // Calculate damage bonus + damage = MeleeDamageBonusDone(pVictim, damage, attackType, spellInfo, SPELL_DIRECT_DAMAGE); + damage = pVictim->MeleeDamageBonusTaken(this, damage, attackType, spellInfo, SPELL_DIRECT_DAMAGE); + + // if crit add critical bonus + if (crit) + { + damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT; + damage = SpellCriticalDamageBonus(spellInfo, damage, pVictim); + // Resilience - reduce crit damage + uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damage, damageSchoolMask); + damage -= pVictim->GetCritDamageReduction(reduction_affected_damage); + } + } + break; + // Magical Attacks + case SPELL_DAMAGE_CLASS_NONE: + case SPELL_DAMAGE_CLASS_MAGIC: + { + // Calculate damage bonus + damage = SpellDamageBonusDone(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE); + damage = pVictim->SpellDamageBonusTaken(this, spellInfo, damage, SPELL_DIRECT_DAMAGE); + + // If crit add critical bonus + if (crit) + { + damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT; + damage = SpellCriticalDamageBonus(spellInfo, damage, pVictim); + // Resilience - reduce crit damage + uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damage, damageSchoolMask); + damage -= pVictim->GetCritDamageReduction(reduction_affected_damage); + } + } + break; + } + + // only from players + if (GetTypeId() == TYPEID_PLAYER) + { + uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damage, damageSchoolMask); + damage -= pVictim->GetDamageReduction(reduction_affected_damage); + } + + // damage mitigation + if (damage > 0) + { + // physical damage => armor + if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) + { + uint32 armor_affected_damage = CalcNotIgnoreDamageReduction(damage, damageSchoolMask); + damage = damage - armor_affected_damage + CalcArmorReducedDamage(pVictim, armor_affected_damage); + } + } + else + { + damage = 0; + } + damageInfo->damage = damage; } void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss) { - if (!damageInfo) - { - return; - } + if (!damageInfo) + { + return; + } - Unit* pVictim = damageInfo->target; + Unit* pVictim = damageInfo->target; - if (!this || !pVictim) - { - return; - } + if (!this || !pVictim) + { + return; + } - if (!pVictim->IsAlive() || pVictim->IsTaxiFlying() || (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())) - { - return; - } + if (!pVictim->IsAlive() || pVictim->IsTaxiFlying() || (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())) + { + return; + } - SpellEntry const* spellProto = sSpellStore.LookupEntry(damageInfo->SpellID); - if (spellProto == NULL) - { - sLog.outError("Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", damageInfo->SpellID); - return; - } + SpellEntry const* spellProto = sSpellStore.LookupEntry(damageInfo->SpellID); + if (spellProto == NULL) + { + sLog.outError("Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", damageInfo->SpellID); + return; + } - // You don't lose health from damage taken from another player while in a sanctuary - // You still see it in the combat log though - if (!IsAllowedDamageInArea(pVictim)) - { - return; - } + // You don't lose health from damage taken from another player while in a sanctuary + // You still see it in the combat log though + if (!IsAllowedDamageInArea(pVictim)) + { + return; + } - // Call default DealDamage (send critical in hit info for threat calculation) - CleanDamage cleanDamage(0, BASE_ATTACK, damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT ? MELEE_HIT_CRIT : MELEE_HIT_NORMAL); - DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, damageInfo->schoolMask, spellProto, durabilityLoss); + // Call default DealDamage (send critical in hit info for threat calculation) + CleanDamage cleanDamage(0, BASE_ATTACK, damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT ? MELEE_HIT_CRIT : MELEE_HIT_NORMAL); + DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, damageInfo->schoolMask, spellProto, durabilityLoss); } // TODO for melee need create structure as in void Unit::CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, WeaponAttackType attackType /*= BASE_ATTACK*/) { - damageInfo->attacker = this; - damageInfo->target = pVictim; - damageInfo->damageSchoolMask = GetMeleeDamageSchoolMask(); - damageInfo->attackType = attackType; - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - damageInfo->absorb = 0; - damageInfo->resist = 0; - damageInfo->blocked_amount = 0; - - damageInfo->TargetState = VICTIMSTATE_UNAFFECTED; - damageInfo->HitInfo = HITINFO_NORMALSWING; - damageInfo->procAttacker = PROC_FLAG_NONE; - damageInfo->procVictim = PROC_FLAG_NONE; - damageInfo->procEx = PROC_EX_NONE; - damageInfo->hitOutCome = MELEE_HIT_EVADE; - - if (!this || !pVictim) - { - return; - } - if (!this->IsAlive() || !pVictim->IsAlive()) - { - return; - } - - // Select HitInfo/procAttacker/procVictim flag based on attack type - switch (attackType) - { - case BASE_ATTACK: - damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT; - damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT; - damageInfo->HitInfo = HITINFO_NORMALSWING2; - break; - case OFF_ATTACK: - damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT; - damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used - damageInfo->HitInfo = HITINFO_LEFTSWING; - break; - case RANGED_ATTACK: - damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT; - damageInfo->procVictim = PROC_FLAG_TAKEN_RANGED_HIT; - damageInfo->HitInfo = HITINFO_UNK3; // test (dev note: test what? HitInfo flag possibly not confirmed.) - break; - default: - break; - } - - // Physical Immune check - if (damageInfo->target->IsImmunedToDamage(damageInfo->damageSchoolMask)) - { - damageInfo->HitInfo |= HITINFO_NORMALSWING; - damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE; - - damageInfo->procEx |= PROC_EX_IMMUNE; - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - return; - } - uint32 damage = CalculateDamage(damageInfo->attackType, false); - // Add melee damage bonus - damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType); - damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType); - - // Calculate armor reduction - uint32 armor_affected_damage = CalcNotIgnoreDamageReduction(damage, damageInfo->damageSchoolMask); - damageInfo->damage = damage - armor_affected_damage + CalcArmorReducedDamage(damageInfo->target, armor_affected_damage); - damageInfo->cleanDamage += damage - damageInfo->damage; - - damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType); - - // Disable parry or dodge for ranged attack - if (damageInfo->attackType == RANGED_ATTACK) - { - if (damageInfo->hitOutCome == MELEE_HIT_PARRY) damageInfo->hitOutCome = MELEE_HIT_NORMAL; - if (damageInfo->hitOutCome == MELEE_HIT_DODGE) damageInfo->hitOutCome = MELEE_HIT_MISS; - } - - switch (damageInfo->hitOutCome) - { - case MELEE_HIT_EVADE: - { - damageInfo->HitInfo |= HITINFO_MISS | HITINFO_SWINGNOHITSOUND; - damageInfo->TargetState = VICTIMSTATE_EVADES; - - damageInfo->procEx |= PROC_EX_EVADE; - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - return; - } - case MELEE_HIT_MISS: - { - damageInfo->HitInfo |= HITINFO_MISS; - damageInfo->TargetState = VICTIMSTATE_UNAFFECTED; - - damageInfo->procEx |= PROC_EX_MISS; - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - break; - } - case MELEE_HIT_NORMAL: - damageInfo->TargetState = VICTIMSTATE_NORMAL; - damageInfo->procEx |= PROC_EX_NORMAL_HIT; - break; - case MELEE_HIT_CRIT: - { - damageInfo->HitInfo |= HITINFO_CRITICALHIT; - damageInfo->TargetState = VICTIMSTATE_NORMAL; - - damageInfo->procEx |= PROC_EX_CRITICAL_HIT; - // Crit bonus calc - damageInfo->damage += damageInfo->damage; - - // Apply SPELL_AURA_MOD_CRIT_DAMAGE_BONUS modifier first - const int32 bonus = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, SPELL_SCHOOL_MASK_NORMAL); - damageInfo->damage += int32((damageInfo->damage) * float(bonus / 100.0f)); - - int32 mod = 0; - // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE - if (damageInfo->attackType == RANGED_ATTACK) - mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); - else - mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); - - if (mod != 0) - damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod) / 100.0f)); - - // Resilience - reduce crit damage - uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damageInfo->damage, damageInfo->damageSchoolMask); - uint32 resilienceReduction = pVictim->GetCritDamageReduction(reduction_affected_damage); - - damageInfo->damage -= resilienceReduction; - damageInfo->cleanDamage += resilienceReduction; - break; - } - case MELEE_HIT_PARRY: - damageInfo->TargetState = VICTIMSTATE_PARRY; - damageInfo->procEx |= PROC_EX_PARRY; - damageInfo->cleanDamage += damageInfo->damage; - damageInfo->damage = 0; - break; - - case MELEE_HIT_DODGE: - damageInfo->TargetState = VICTIMSTATE_DODGE; - damageInfo->procEx |= PROC_EX_DODGE; - damageInfo->cleanDamage += damageInfo->damage; - damageInfo->damage = 0; - break; - case MELEE_HIT_BLOCK: - { - damageInfo->TargetState = VICTIMSTATE_NORMAL; - damageInfo->HitInfo |= HITINFO_BLOCK; - damageInfo->procEx |= PROC_EX_BLOCK; - damageInfo->blocked_amount = damageInfo->target->GetShieldBlockDamageValue() * damageInfo->damage / 100.0f; - - // Target has a chance to double the blocked amount if it has SPELL_AURA_MOD_BLOCK_CRIT_CHANCE - if (roll_chance_i(pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_CRIT_CHANCE))) - damageInfo->blocked_amount *= 2; - - if (damageInfo->blocked_amount >= damageInfo->damage) - { - damageInfo->TargetState = VICTIMSTATE_BLOCKS; - damageInfo->blocked_amount = damageInfo->damage; - damageInfo->procEx |= PROC_EX_FULL_BLOCK; - } - else - { damageInfo->procEx |= PROC_EX_NORMAL_HIT; } // Partial blocks can still cause attacker procs - - damageInfo->damage -= damageInfo->blocked_amount; - damageInfo->cleanDamage += damageInfo->blocked_amount; - break; - } - case MELEE_HIT_GLANCING: - { - damageInfo->HitInfo |= HITINFO_GLANCING; - damageInfo->TargetState = VICTIMSTATE_NORMAL; - damageInfo->procEx |= PROC_EX_NORMAL_HIT; - float reducePercent = 1.0f; // damage factor - // calculate base values and mods - float baseLowEnd = 1.3f; - float baseHighEnd = 1.2f; - switch (getClass()) // lowering base values for casters - { - case CLASS_SHAMAN: - case CLASS_PRIEST: - case CLASS_MAGE: - case CLASS_WARLOCK: - case CLASS_DRUID: - baseLowEnd -= 0.7f; - baseHighEnd -= 0.3f; - break; - } - - float maxLowEnd = 0.6f; - switch (getClass()) // upper for melee classes - { - case CLASS_WARRIOR: - case CLASS_ROGUE: - maxLowEnd = 0.91f; // If the attacker is a melee class then instead the lower value of 0.91 - } - - // calculate values - int32 diff = damageInfo->target->GetMaxSkillValueForLevel() - GetMaxSkillValueForLevel(); - float lowEnd = baseLowEnd - (0.05f * diff); - float highEnd = baseHighEnd - (0.03f * diff); - - // apply max/min bounds - if (lowEnd < 0.01f) // the low end must not go bellow 0.01f - { - lowEnd = 0.01f; - } - else if (lowEnd > maxLowEnd) // the smaller value of this and 0.6 is kept as the low end - { - lowEnd = maxLowEnd; - } - - if (highEnd < 0.2f) // high end limits - { - highEnd = 0.2f; - } - if (highEnd > 0.99f) - { - highEnd = 0.99f; - } - - if (lowEnd > highEnd) // prevent negative range size - { - lowEnd = highEnd; - } - - reducePercent = lowEnd + rand_norm_f() * (highEnd - lowEnd); - - damageInfo->cleanDamage += damageInfo->damage - uint32(reducePercent * damageInfo->damage); - damageInfo->damage = uint32(reducePercent * damageInfo->damage); - break; - } - case MELEE_HIT_CRUSHING: - { - damageInfo->HitInfo |= HITINFO_CRUSHING; - damageInfo->TargetState = VICTIMSTATE_NORMAL; - damageInfo->procEx |= PROC_EX_NORMAL_HIT; - // 150% normal damage - damageInfo->damage += (damageInfo->damage / 2); - break; - } - default: - - break; - } - - // only from players - if (GetTypeId() == TYPEID_PLAYER) - { - uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damageInfo->damage, damageInfo->damageSchoolMask); - uint32 resilienceReduction = pVictim->GetDamageReduction(reduction_affected_damage); - damageInfo->damage -= resilienceReduction; - damageInfo->cleanDamage += resilienceReduction; - } - - // Calculate absorb resist - if (int32(damageInfo->damage) > 0) - { - damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE; - - // Calculate absorb & resists - uint32 absorb_affected_damage = CalcNotIgnoreAbsorbDamage(damageInfo->damage, damageInfo->damageSchoolMask); - damageInfo->target->CalculateDamageAbsorbAndResist(this, damageInfo->damageSchoolMask, DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, true); - damageInfo->damage -= damageInfo->absorb + damageInfo->resist; - if (damageInfo->absorb) - { - damageInfo->HitInfo |= HITINFO_ABSORB; - damageInfo->procEx |= PROC_EX_ABSORB; - } - if (damageInfo->resist) - { - damageInfo->HitInfo |= HITINFO_RESIST; - } - } - else // Umpossible get negative result but.... - { - damageInfo->damage = 0; - } + damageInfo->attacker = this; + damageInfo->target = pVictim; + damageInfo->damageSchoolMask = GetMeleeDamageSchoolMask(); + damageInfo->attackType = attackType; + damageInfo->damage = 0; + damageInfo->cleanDamage = 0; + damageInfo->absorb = 0; + damageInfo->resist = 0; + damageInfo->blocked_amount = 0; + + damageInfo->TargetState = VICTIMSTATE_UNAFFECTED; + damageInfo->HitInfo = HITINFO_NORMALSWING; + damageInfo->procAttacker = PROC_FLAG_NONE; + damageInfo->procVictim = PROC_FLAG_NONE; + damageInfo->procEx = PROC_EX_NONE; + damageInfo->hitOutCome = MELEE_HIT_EVADE; + + if (!this || !pVictim) + { + return; + } + if (!this->IsAlive() || !pVictim->IsAlive()) + { + return; + } + + // Select HitInfo/procAttacker/procVictim flag based on attack type + switch (attackType) + { + case BASE_ATTACK: + damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT; + damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT; + damageInfo->HitInfo = HITINFO_NORMALSWING2; + break; + case OFF_ATTACK: + damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT; + damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used + damageInfo->HitInfo = HITINFO_LEFTSWING; + break; + case RANGED_ATTACK: + damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT; + damageInfo->procVictim = PROC_FLAG_TAKEN_RANGED_HIT; + damageInfo->HitInfo = HITINFO_UNK3; // test (dev note: test what? HitInfo flag possibly not confirmed.) + break; + default: + break; + } + + // Physical Immune check + if (damageInfo->target->IsImmunedToDamage(damageInfo->damageSchoolMask)) + { + damageInfo->HitInfo |= HITINFO_NORMALSWING; + damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE; + + damageInfo->procEx |= PROC_EX_IMMUNE; + damageInfo->damage = 0; + damageInfo->cleanDamage = 0; + return; + } + uint32 damage = CalculateDamage(damageInfo->attackType, false); + // Add melee damage bonus + damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType); + damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType); + + // Calculate armor reduction + uint32 armor_affected_damage = CalcNotIgnoreDamageReduction(damage, damageInfo->damageSchoolMask); + damageInfo->damage = damage - armor_affected_damage + CalcArmorReducedDamage(damageInfo->target, armor_affected_damage); + damageInfo->cleanDamage += damage - damageInfo->damage; + + damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType); + + // Disable parry or dodge for ranged attack + if (damageInfo->attackType == RANGED_ATTACK) + { + if (damageInfo->hitOutCome == MELEE_HIT_PARRY) damageInfo->hitOutCome = MELEE_HIT_NORMAL; + if (damageInfo->hitOutCome == MELEE_HIT_DODGE) damageInfo->hitOutCome = MELEE_HIT_MISS; + } + + switch (damageInfo->hitOutCome) + { + case MELEE_HIT_EVADE: + { + damageInfo->HitInfo |= HITINFO_MISS | HITINFO_SWINGNOHITSOUND; + damageInfo->TargetState = VICTIMSTATE_EVADES; + + damageInfo->procEx |= PROC_EX_EVADE; + damageInfo->damage = 0; + damageInfo->cleanDamage = 0; + return; + } + case MELEE_HIT_MISS: + { + damageInfo->HitInfo |= HITINFO_MISS; + damageInfo->TargetState = VICTIMSTATE_UNAFFECTED; + + damageInfo->procEx |= PROC_EX_MISS; + damageInfo->damage = 0; + damageInfo->cleanDamage = 0; + break; + } + case MELEE_HIT_NORMAL: + damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->procEx |= PROC_EX_NORMAL_HIT; + break; + case MELEE_HIT_CRIT: + { + damageInfo->HitInfo |= HITINFO_CRITICALHIT; + damageInfo->TargetState = VICTIMSTATE_NORMAL; + + damageInfo->procEx |= PROC_EX_CRITICAL_HIT; + // Crit bonus calc + damageInfo->damage += damageInfo->damage; + + // Apply SPELL_AURA_MOD_CRIT_DAMAGE_BONUS modifier first + const int32 bonus = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, SPELL_SCHOOL_MASK_NORMAL); + damageInfo->damage += int32((damageInfo->damage) * float(bonus / 100.0f)); + + int32 mod = 0; + // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE + if (damageInfo->attackType == RANGED_ATTACK) + mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); + else + mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); + + if (mod != 0) + damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod) / 100.0f)); + + // Resilience - reduce crit damage + uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damageInfo->damage, damageInfo->damageSchoolMask); + uint32 resilienceReduction = pVictim->GetCritDamageReduction(reduction_affected_damage); + + damageInfo->damage -= resilienceReduction; + damageInfo->cleanDamage += resilienceReduction; + break; + } + case MELEE_HIT_PARRY: + damageInfo->TargetState = VICTIMSTATE_PARRY; + damageInfo->procEx |= PROC_EX_PARRY; + damageInfo->cleanDamage += damageInfo->damage; + damageInfo->damage = 0; + break; + + case MELEE_HIT_DODGE: + damageInfo->TargetState = VICTIMSTATE_DODGE; + damageInfo->procEx |= PROC_EX_DODGE; + damageInfo->cleanDamage += damageInfo->damage; + damageInfo->damage = 0; + break; + case MELEE_HIT_BLOCK: + { + damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->HitInfo |= HITINFO_BLOCK; + damageInfo->procEx |= PROC_EX_BLOCK; + damageInfo->blocked_amount = damageInfo->target->GetShieldBlockDamageValue() * damageInfo->damage / 100.0f; + + // Target has a chance to double the blocked amount if it has SPELL_AURA_MOD_BLOCK_CRIT_CHANCE + if (roll_chance_i(pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_CRIT_CHANCE))) + damageInfo->blocked_amount *= 2; + + if (damageInfo->blocked_amount >= damageInfo->damage) + { + damageInfo->TargetState = VICTIMSTATE_BLOCKS; + damageInfo->blocked_amount = damageInfo->damage; + damageInfo->procEx |= PROC_EX_FULL_BLOCK; + } + else + { + damageInfo->procEx |= PROC_EX_NORMAL_HIT; + } // Partial blocks can still cause attacker procs + + damageInfo->damage -= damageInfo->blocked_amount; + damageInfo->cleanDamage += damageInfo->blocked_amount; + break; + } + case MELEE_HIT_GLANCING: + { + damageInfo->HitInfo |= HITINFO_GLANCING; + damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->procEx |= PROC_EX_NORMAL_HIT; + float reducePercent = 1.0f; // damage factor + // calculate base values and mods + float baseLowEnd = 1.3f; + float baseHighEnd = 1.2f; + switch (getClass()) // lowering base values for casters + { + case CLASS_SHAMAN: + case CLASS_PRIEST: + case CLASS_MAGE: + case CLASS_WARLOCK: + case CLASS_DRUID: + baseLowEnd -= 0.7f; + baseHighEnd -= 0.3f; + break; + } + + float maxLowEnd = 0.6f; + switch (getClass()) // upper for melee classes + { + case CLASS_WARRIOR: + case CLASS_ROGUE: + maxLowEnd = 0.91f; // If the attacker is a melee class then instead the lower value of 0.91 + } + + // calculate values + int32 diff = damageInfo->target->GetMaxSkillValueForLevel() - GetMaxSkillValueForLevel(); + float lowEnd = baseLowEnd - (0.05f * diff); + float highEnd = baseHighEnd - (0.03f * diff); + + // apply max/min bounds + if (lowEnd < 0.01f) // the low end must not go bellow 0.01f + { + lowEnd = 0.01f; + } + else if (lowEnd > maxLowEnd) // the smaller value of this and 0.6 is kept as the low end + { + lowEnd = maxLowEnd; + } + + if (highEnd < 0.2f) // high end limits + { + highEnd = 0.2f; + } + if (highEnd > 0.99f) + { + highEnd = 0.99f; + } + + if (lowEnd > highEnd) // prevent negative range size + { + lowEnd = highEnd; + } + + reducePercent = lowEnd + rand_norm_f() * (highEnd - lowEnd); + + damageInfo->cleanDamage += damageInfo->damage - uint32(reducePercent * damageInfo->damage); + damageInfo->damage = uint32(reducePercent * damageInfo->damage); + break; + } + case MELEE_HIT_CRUSHING: + { + damageInfo->HitInfo |= HITINFO_CRUSHING; + damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->procEx |= PROC_EX_NORMAL_HIT; + // 150% normal damage + damageInfo->damage += (damageInfo->damage / 2); + break; + } + default: + + break; + } + + // only from players + if (GetTypeId() == TYPEID_PLAYER) + { + uint32 reduction_affected_damage = CalcNotIgnoreDamageReduction(damageInfo->damage, damageInfo->damageSchoolMask); + uint32 resilienceReduction = pVictim->GetDamageReduction(reduction_affected_damage); + damageInfo->damage -= resilienceReduction; + damageInfo->cleanDamage += resilienceReduction; + } + + // Calculate absorb resist + if (int32(damageInfo->damage) > 0) + { + damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE; + + // Calculate absorb & resists + uint32 absorb_affected_damage = CalcNotIgnoreAbsorbDamage(damageInfo->damage, damageInfo->damageSchoolMask); + damageInfo->target->CalculateDamageAbsorbAndResist(this, damageInfo->damageSchoolMask, DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, true); + damageInfo->damage -= damageInfo->absorb + damageInfo->resist; + if (damageInfo->absorb) + { + damageInfo->HitInfo |= HITINFO_ABSORB; + damageInfo->procEx |= PROC_EX_ABSORB; + } + if (damageInfo->resist) + { + damageInfo->HitInfo |= HITINFO_RESIST; + } + } + else // Umpossible get negative result but.... + { + damageInfo->damage = 0; + } } void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) { - if (damageInfo == 0) - { - return; - } - Unit* pVictim = damageInfo->target; - - if (!this || !pVictim) - { - return; - } - - if (!pVictim->IsAlive() || pVictim->IsTaxiFlying() || (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())) - { - return; - } - - // You don't lose health from damage taken from another player while in a sanctuary - // You still see it in the combat log though - if (!IsAllowedDamageInArea(pVictim)) - { - return; - } - - // Hmmmm dont like this emotes client must by self do all animations - if (damageInfo->HitInfo & HITINFO_CRITICALHIT) - { - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL); - } - if (damageInfo->blocked_amount && damageInfo->TargetState != VICTIMSTATE_BLOCKS) - { - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); - } - - // This seems to reduce the victims time until next attack if your attack was parried - if (damageInfo->TargetState == VICTIMSTATE_PARRY) - { - if (pVictim->GetTypeId() != TYPEID_UNIT || - !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_PARRY_HASTEN)) - { - // Get attack timers - float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); - float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); - // Reduce attack time - if (pVictim->haveOffhandWeapon() && offtime < basetime) - { - float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20f; - float percent60 = 3.0f * percent20; - if (offtime > percent20 && offtime <= percent60) - { - pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20)); - } - else if (offtime > percent60) - { - offtime -= 2.0f * percent20; - pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime)); - } - } - else - { - float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20f; - float percent60 = 3.0f * percent20; - if (basetime > percent20 && basetime <= percent60) - { - pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20)); - } - else if (basetime > percent60) - { - basetime -= 2.0f * percent20; - pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime)); - } - } - } - } - - // Call default DealDamage - CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->attackType, damageInfo->hitOutCome); - DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, damageInfo->damageSchoolMask, NULL, durabilityLoss); - - // If this is a creature and it attacks from behind it has a probability to daze it's victim - if ((damageInfo->hitOutCome == MELEE_HIT_CRIT || damageInfo->hitOutCome == MELEE_HIT_CRUSHING || damageInfo->hitOutCome == MELEE_HIT_NORMAL || damageInfo->hitOutCome == MELEE_HIT_GLANCING) && - GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGuid() && !pVictim->HasInArc(M_PI_F, this)) - { - // -probability is between 0% and 40% - // 20% base chance - float Probability = 20.0f; - - // there is a newbie protection, at level 10 just 7% base chance; assuming linear function - if (pVictim->getLevel() < 30) - { - Probability = 0.65f * pVictim->getLevel() + 0.5f; - } - - uint32 VictimDefense = pVictim->GetMaxSkillValueForLevel(this); - uint32 AttackerMeleeSkill = GetMaxSkillValueForLevel(); - - Probability *= AttackerMeleeSkill / (float)VictimDefense; - - if (Probability > 40.0f) - { - Probability = 40.0f; - } - - if (roll_chance_f(Probability)) - { - CastSpell(pVictim, 1604, true); - } - } - - // If not miss - if (!(damageInfo->HitInfo & HITINFO_MISS)) - { - // on weapon hit casts - if (GetTypeId() == TYPEID_PLAYER && pVictim->IsAlive()) - { - ((Player*)this)->CastItemCombatSpell(pVictim, damageInfo->attackType); - } - - // victim's damage shield - std::set alreadyDone; - AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD); - for (AuraList::const_iterator i = vDamageShields.begin(); i != vDamageShields.end();) - { - if (alreadyDone.find(*i) == alreadyDone.end()) - { - alreadyDone.insert(*i); - uint32 damage = (*i)->GetModifier()->m_amount; - SpellEntry const* i_spellProto = (*i)->GetSpellProto(); - // Calculate absorb resist ??? no data in opcode for this possibly unable to absorb or resist? - // uint32 absorb; - // uint32 resist; - // CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - // damage-=absorb + resist; - - pVictim->DealDamageMods(this, damage, NULL); - - uint32 targetHealth = GetHealth(); - uint32 overkill = damage > targetHealth ? damage - targetHealth : 0; - - WorldPacket data(SMSG_SPELLDAMAGESHIELD, (8 + 8 + 4 + 4 + 4 + 4)); - data << pVictim->GetObjectGuid(); - data << GetObjectGuid(); - data << uint32(i_spellProto->Id); - data << uint32(damage); // Damage - data << uint32(overkill); // Overkill - data << uint32(i_spellProto->GetSchoolMask()); - data << uint32(0); // FIXME: Resist - pVictim->SendMessageToSet(&data, true); - - pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(i_spellProto), i_spellProto, true); - - i = vDamageShields.begin(); - } - else - { - ++i; - } - } - } + if (damageInfo == 0) + { + return; + } + Unit* pVictim = damageInfo->target; + + if (!this || !pVictim) + { + return; + } + + if (!pVictim->IsAlive() || pVictim->IsTaxiFlying() || (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())) + { + return; + } + + // You don't lose health from damage taken from another player while in a sanctuary + // You still see it in the combat log though + if (!IsAllowedDamageInArea(pVictim)) + { + return; + } + + // Hmmmm dont like this emotes client must by self do all animations + if (damageInfo->HitInfo & HITINFO_CRITICALHIT) + { + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL); + } + if (damageInfo->blocked_amount && damageInfo->TargetState != VICTIMSTATE_BLOCKS) + { + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); + } + + // This seems to reduce the victims time until next attack if your attack was parried + if (damageInfo->TargetState == VICTIMSTATE_PARRY) + { + if (pVictim->GetTypeId() != TYPEID_UNIT || + !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_PARRY_HASTEN)) + { + // Get attack timers + float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); + float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); + // Reduce attack time + if (pVictim->haveOffhandWeapon() && offtime < basetime) + { + float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20f; + float percent60 = 3.0f * percent20; + if (offtime > percent20 && offtime <= percent60) + { + pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20)); + } + else if (offtime > percent60) + { + offtime -= 2.0f * percent20; + pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime)); + } + } + else + { + float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20f; + float percent60 = 3.0f * percent20; + if (basetime > percent20 && basetime <= percent60) + { + pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20)); + } + else if (basetime > percent60) + { + basetime -= 2.0f * percent20; + pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime)); + } + } + } + } + + // Call default DealDamage + CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->attackType, damageInfo->hitOutCome); + DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, damageInfo->damageSchoolMask, NULL, durabilityLoss); + + // If this is a creature and it attacks from behind it has a probability to daze it's victim + if ((damageInfo->hitOutCome == MELEE_HIT_CRIT || damageInfo->hitOutCome == MELEE_HIT_CRUSHING || damageInfo->hitOutCome == MELEE_HIT_NORMAL || damageInfo->hitOutCome == MELEE_HIT_GLANCING) && + GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGuid() && !pVictim->HasInArc(M_PI_F, this)) + { + // -probability is between 0% and 40% + // 20% base chance + float Probability = 20.0f; + + // there is a newbie protection, at level 10 just 7% base chance; assuming linear function + if (pVictim->getLevel() < 30) + { + Probability = 0.65f * pVictim->getLevel() + 0.5f; + } + + uint32 VictimDefense = pVictim->GetMaxSkillValueForLevel(this); + uint32 AttackerMeleeSkill = GetMaxSkillValueForLevel(); + + Probability *= AttackerMeleeSkill / (float)VictimDefense; + + if (Probability > 40.0f) + { + Probability = 40.0f; + } + + if (roll_chance_f(Probability)) + { + CastSpell(pVictim, 1604, true); + } + } + + // If not miss + if (!(damageInfo->HitInfo & HITINFO_MISS)) + { + // on weapon hit casts + if (GetTypeId() == TYPEID_PLAYER && pVictim->IsAlive()) + { + ((Player*)this)->CastItemCombatSpell(pVictim, damageInfo->attackType); + } + + // victim's damage shield + std::set alreadyDone; + AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD); + for (AuraList::const_iterator i = vDamageShields.begin(); i != vDamageShields.end();) + { + if (alreadyDone.find(*i) == alreadyDone.end()) + { + alreadyDone.insert(*i); + uint32 damage = (*i)->GetModifier()->m_amount; + SpellEntry const* i_spellProto = (*i)->GetSpellProto(); + // Calculate absorb resist ??? no data in opcode for this possibly unable to absorb or resist? + // uint32 absorb; + // uint32 resist; + // CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); + // damage-=absorb + resist; + + pVictim->DealDamageMods(this, damage, NULL); + + uint32 targetHealth = GetHealth(); + uint32 overkill = damage > targetHealth ? damage - targetHealth : 0; + + WorldPacket data(SMSG_SPELLDAMAGESHIELD, (8 + 8 + 4 + 4 + 4 + 4)); + data << pVictim->GetObjectGuid(); + data << GetObjectGuid(); + data << uint32(i_spellProto->Id); + data << uint32(damage); // Damage + data << uint32(overkill); // Overkill + data << uint32(i_spellProto->GetSchoolMask()); + data << uint32(0); // FIXME: Resist + pVictim->SendMessageToSet(&data, true); + + pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(i_spellProto), i_spellProto, true); + + i = vDamageShields.begin(); + } + else + { + ++i; + } + } + } } void Unit::HandleEmoteCommand(uint32 emote_id) { - DEBUG_LOG("SMSG_EMOTE %u"); - WorldPacket data(SMSG_EMOTE, 4 + 8); - data << uint32(emote_id); - data << GetObjectGuid(); - SendMessageToSet(&data, true); + DEBUG_LOG("SMSG_EMOTE %u"); + WorldPacket data(SMSG_EMOTE, 4 + 8); + data << uint32(emote_id); + data << GetObjectGuid(); + SendMessageToSet(&data, true); } void Unit::HandleEmoteState(uint32 emote_id) { - SetUInt32Value(UNIT_NPC_EMOTESTATE, emote_id); + SetUInt32Value(UNIT_NPC_EMOTESTATE, emote_id); } void Unit::HandleEmote(uint32 emote_id) { - if (!emote_id) - { - HandleEmoteState(0); - } - else if (EmotesEntry const* emoteEntry = sEmotesStore.LookupEntry(emote_id)) - { - if (emoteEntry->EmoteType) // 1,2 states, 0 command - { - HandleEmoteState(emote_id); - } - else - { - HandleEmoteCommand(emote_id); - } - } + if (!emote_id) + { + HandleEmoteState(0); + } + else if (EmotesEntry const* emoteEntry = sEmotesStore.LookupEntry(emote_id)) + { + if (emoteEntry->EmoteType) // 1,2 states, 0 command + { + HandleEmoteState(emote_id); + } + else + { + HandleEmoteCommand(emote_id); + } + } } uint32 Unit::CalcNotIgnoreAbsorbDamage(uint32 damage, SpellSchoolMask damageSchoolMask, SpellEntry const* spellInfo /*= NULL*/) { - float absorb_affected_rate = 1.0f; - Unit::AuraList const& ignoreAbsorbSchool = GetAurasByType(SPELL_AURA_MOD_IGNORE_ABSORB_SCHOOL); - for (Unit::AuraList::const_iterator i = ignoreAbsorbSchool.begin(); i != ignoreAbsorbSchool.end(); ++i) - if ((*i)->GetMiscValue() & damageSchoolMask) - absorb_affected_rate *= (100.0f - (*i)->GetModifier()->m_amount) / 100.0f; + float absorb_affected_rate = 1.0f; + Unit::AuraList const& ignoreAbsorbSchool = GetAurasByType(SPELL_AURA_MOD_IGNORE_ABSORB_SCHOOL); + for (Unit::AuraList::const_iterator i = ignoreAbsorbSchool.begin(); i != ignoreAbsorbSchool.end(); ++i) + if ((*i)->GetMiscValue() & damageSchoolMask) + absorb_affected_rate *= (100.0f - (*i)->GetModifier()->m_amount) / 100.0f; - if (spellInfo) - { - Unit::AuraList const& ignoreAbsorbForSpell = GetAurasByType(SPELL_AURA_MOD_IGNORE_ABSORB_FOR_SPELL); - for (Unit::AuraList::const_iterator citr = ignoreAbsorbForSpell.begin(); citr != ignoreAbsorbForSpell.end(); ++citr) - if ((*citr)->isAffectedOnSpell(spellInfo)) - absorb_affected_rate *= (100.0f - (*citr)->GetModifier()->m_amount) / 100.0f; - } + if (spellInfo) + { + Unit::AuraList const& ignoreAbsorbForSpell = GetAurasByType(SPELL_AURA_MOD_IGNORE_ABSORB_FOR_SPELL); + for (Unit::AuraList::const_iterator citr = ignoreAbsorbForSpell.begin(); citr != ignoreAbsorbForSpell.end(); ++citr) + if ((*citr)->isAffectedOnSpell(spellInfo)) + absorb_affected_rate *= (100.0f - (*citr)->GetModifier()->m_amount) / 100.0f; + } - return absorb_affected_rate <= 0.0f ? 0 : (absorb_affected_rate < 1.0f ? uint32(damage * absorb_affected_rate) : damage); + return absorb_affected_rate <= 0.0f ? 0 : (absorb_affected_rate < 1.0f ? uint32(damage * absorb_affected_rate) : damage); } uint32 Unit::CalcNotIgnoreDamageReduction(uint32 damage, SpellSchoolMask damageSchoolMask) { - float absorb_affected_rate = 1.0f; - Unit::AuraList const& ignoreAbsorb = GetAurasByType(SPELL_AURA_MOD_IGNORE_DAMAGE_REDUCTION_SCHOOL); - for (Unit::AuraList::const_iterator i = ignoreAbsorb.begin(); i != ignoreAbsorb.end(); ++i) - if ((*i)->GetMiscValue() & damageSchoolMask) - absorb_affected_rate *= (100.0f - (*i)->GetModifier()->m_amount) / 100.0f; + float absorb_affected_rate = 1.0f; + Unit::AuraList const& ignoreAbsorb = GetAurasByType(SPELL_AURA_MOD_IGNORE_DAMAGE_REDUCTION_SCHOOL); + for (Unit::AuraList::const_iterator i = ignoreAbsorb.begin(); i != ignoreAbsorb.end(); ++i) + if ((*i)->GetMiscValue() & damageSchoolMask) + absorb_affected_rate *= (100.0f - (*i)->GetModifier()->m_amount) / 100.0f; - return absorb_affected_rate <= 0.0f ? 0 : (absorb_affected_rate < 1.0f ? uint32(damage * absorb_affected_rate) : damage); + return absorb_affected_rate <= 0.0f ? 0 : (absorb_affected_rate < 1.0f ? uint32(damage * absorb_affected_rate) : damage); } uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage) { - uint32 newdamage = 0; - float armor = (float)pVictim->GetArmor(); + uint32 newdamage = 0; + float armor = (float)pVictim->GetArmor(); - // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura - armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); + // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura + armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); - // Apply Player CR_ARMOR_PENETRATION rating and percent talents - if (GetTypeId() == TYPEID_PLAYER) - { - float maxArmorPen = 400 + 85 * pVictim->getLevel(); - if (getLevel() > 59) - maxArmorPen += 4.5f * 85 * (pVictim->getLevel() - 59); - // Cap ignored armor to this value - maxArmorPen = std::min(((armor + maxArmorPen) / 3), armor); - // Also, armor penetration is limited to 100% since 3.1.2, before greater values did - // continue to give benefit for targets with more armor than the above cap - float armorPenPct = std::min(100.f, ((Player*)this)->GetArmorPenetrationPct()); - armor -= maxArmorPen * armorPenPct / 100.0f; - } + // Apply Player CR_ARMOR_PENETRATION rating and percent talents + if (GetTypeId() == TYPEID_PLAYER) + { + float maxArmorPen = 400 + 85 * pVictim->getLevel(); + if (getLevel() > 59) + maxArmorPen += 4.5f * 85 * (pVictim->getLevel() - 59); + // Cap ignored armor to this value + maxArmorPen = std::min(((armor + maxArmorPen) / 3), armor); + // Also, armor penetration is limited to 100% since 3.1.2, before greater values did + // continue to give benefit for targets with more armor than the above cap + float armorPenPct = std::min(100.f, ((Player*)this)->GetArmorPenetrationPct()); + armor -= maxArmorPen * armorPenPct / 100.0f; + } - if (armor < 0.0f) - { - armor = 0.0f; - } + if (armor < 0.0f) + { + armor = 0.0f; + } - float levelModifier = (float)getLevel(); - if (levelModifier > 59) - levelModifier = levelModifier + (4.5f * (levelModifier - 59)); + float levelModifier = (float)getLevel(); + if (levelModifier > 59) + levelModifier = levelModifier + (4.5f * (levelModifier - 59)); - float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40); - tmpvalue = tmpvalue / (1.0f + tmpvalue); + float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40); + tmpvalue = tmpvalue / (1.0f + tmpvalue); - if (tmpvalue < 0.0f) - { - tmpvalue = 0.0f; - } - if (tmpvalue > 0.75f) - { - tmpvalue = 0.75f; - } + if (tmpvalue < 0.0f) + { + tmpvalue = 0.0f; + } + if (tmpvalue > 0.75f) + { + tmpvalue = 0.75f; + } - newdamage = uint32(damage - (damage * tmpvalue)); + newdamage = uint32(damage - (damage * tmpvalue)); - return (newdamage > 1) ? newdamage : 1; + return (newdamage > 1) ? newdamage : 1; } void Unit::CalculateDamageAbsorbAndResist(Unit* pCaster, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32* absorb, uint32* resist, bool canReflect) { - if (!pCaster || !IsAlive() || !damage) - { - return; - } - - // Magic damage, check for resists - if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) - { - // Get base victim resistance for school - float tmpvalue2 = (float)GetResistance(GetFirstSchoolInMask(schoolMask)); - // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura - tmpvalue2 += (float)pCaster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask); - - if (pCaster->GetTypeId() == TYPEID_PLAYER) - tmpvalue2 -= (float)((Player*)pCaster)->GetSpellPenetrationItemMod(); - - tmpvalue2 *= (float)(0.15f / getLevel()); - if (tmpvalue2 < 0.0f) - { - tmpvalue2 = 0.0f; - } - if (tmpvalue2 > 0.75f) - { - tmpvalue2 = 0.75f; - } - uint32 ran = urand(0, 100); - float faq[4] = {24.0f, 6.0f, 4.0f, 6.0f}; - uint8 m = 0; - float Binom = 0.0f; - for (uint8 i = 0; i < 4; ++i) - { - Binom += 2400 * (powf(tmpvalue2, float(i)) * powf((1 - tmpvalue2), float(4 - i))) / faq[i]; - if (ran > Binom) - { - ++m; - } - else - { - break; - } - } - if (damagetype == DOT && m == 4) - { - *resist += uint32(damage - 1); - } - else - { - *resist += uint32(damage * m / 4); - } - if (*resist > damage) - { - *resist = damage; - } - } - else - { - *resist = 0; - } - - int32 RemainingDamage = damage - *resist; - - // Get unit state (need for some absorb check) - uint32 unitflag = GetUInt32Value(UNIT_FIELD_FLAGS); - // Reflect damage spells (not cast any damage spell in aura lookup) - uint32 reflectSpell = 0; - int32 reflectDamage = 0; - Aura* reflectTriggeredBy = NULL; // expected as not expired at reflect as in current cases - // Death Prevention Aura - SpellEntry const* preventDeathSpell = NULL; - int32 preventDeathAmount = 0; - - // full absorb cases (by chance) - AuraList const& vAbsorb = GetAurasByType(SPELL_AURA_SCHOOL_ABSORB); - for (AuraList::const_iterator i = vAbsorb.begin(); i != vAbsorb.end() && RemainingDamage > 0; ++i) - { - // only work with proper school mask damage - Modifier* i_mod = (*i)->GetModifier(); - if (!(i_mod->m_miscvalue & schoolMask)) - continue; - - SpellEntry const* i_spellProto = (*i)->GetSpellProto(); - SpellClassOptionsEntry const* adsClassOptions = i_spellProto->GetSpellClassOptions(); - // Fire Ward or Frost Ward - if(adsClassOptions && adsClassOptions->SpellFamilyName == SPELLFAMILY_MAGE && adsClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000000108)) - { - int chance = 0; - Unit::AuraList const& auras = GetAurasByType(SPELL_AURA_ADD_PCT_MODIFIER); - for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - SpellEntry const* itr_spellProto = (*itr)->GetSpellProto(); - // Frost Warding (chance full absorb) - if (itr_spellProto->GetSpellFamilyName() == SPELLFAMILY_MAGE && itr_spellProto->GetSpellIconID() == 501) - { - // chance stored in next dummy effect - chance = itr_spellProto->CalculateSimpleValue(EFFECT_INDEX_1); - break; - } - } - if (roll_chance_i(chance)) - { - int32 amount = RemainingDamage; - RemainingDamage = 0; - - // Frost Warding (mana regen) - CastCustomSpell(this, 57776, &amount, NULL, NULL, true, NULL, *i); - break; - } - } - } - - // Need remove expired auras after - bool existExpired = false; - - // Incanter's Absorption, for converting to spell power - int32 incanterAbsorption = 0; - - // absorb without mana cost - AuraList const& vSchoolAbsorb = GetAurasByType(SPELL_AURA_SCHOOL_ABSORB); - for (AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end() && RemainingDamage > 0; ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (!(mod->m_miscvalue & schoolMask)) - continue; - - SpellEntry const* spellProto = (*i)->GetSpellProto(); - - // Max Amount can be absorbed by this aura - int32 currentAbsorb = mod->m_amount; - - // Found empty aura (impossible but..) - if (currentAbsorb <= 0) - { - existExpired = true; - continue; - } - - // Handle custom absorb auras - // TODO: try find better way - SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); - - switch(spellProto->GetSpellFamilyName()) - { - case SPELLFAMILY_GENERIC: - { - // Astral Shift - if (spellProto->GetSpellIconID() == 3066) - { - // reduces all damage taken while stun, fear or silence - if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED)) - RemainingDamage -= RemainingDamage * currentAbsorb / 100; - continue; - } - // Nerves of Steel - if (spellProto->GetSpellIconID() == 2115) - { - // while affected by Stun and Fear - if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING)) - RemainingDamage -= RemainingDamage * currentAbsorb / 100; - continue; - } - // Spell Deflection - if (spellProto->GetSpellIconID() == 3006) - { - // You have a chance equal to your Parry chance - if (damagetype == SPELL_DIRECT_DAMAGE &&// Only for direct spell damage - roll_chance_f(GetUnitParryChance())) // Roll chance - RemainingDamage -= RemainingDamage * currentAbsorb / 100; - continue; - } - // Reflective Shield (Lady Malande boss) - if (spellProto->Id == 41475 && canReflect) - { - if (RemainingDamage < currentAbsorb) - reflectDamage = RemainingDamage / 2; - else - reflectDamage = currentAbsorb / 2; - reflectSpell = 33619; - reflectTriggeredBy = *i; - reflectTriggeredBy->SetInUse(true); // lock aura from final deletion until processing - break; - } - if (spellProto->Id == 39228 || // Argussian Compass - spellProto->Id == 60218) // Essence of Gossamer - { - // Max absorb stored in 1 dummy effect - int32 max_absorb = spellProto->CalculateSimpleValue(EFFECT_INDEX_1); - if (max_absorb < currentAbsorb) - currentAbsorb = max_absorb; - break; - } - break; - } - case SPELLFAMILY_DRUID: - { - // Primal Tenacity - if (spellProto->GetSpellIconID() == 2253) - { - // reduces all damage taken while Stunned and in Cat Form - if (GetShapeshiftForm() == FORM_CAT && (unitflag & UNIT_FLAG_STUNNED)) - RemainingDamage -= RemainingDamage * currentAbsorb / 100; - continue; - } - // Moonkin Form passive - if (spellProto->Id == 69366) - { - // reduces all damage taken while Stunned - if (unitflag & UNIT_FLAG_STUNNED) - RemainingDamage -= RemainingDamage * currentAbsorb / 100; - continue; - } - break; - } - case SPELLFAMILY_ROGUE: - { - // Cheat Death (make less prio with Guardian Spirit case) - if (spellProto->GetSpellIconID() == 2109) - { - if (!preventDeathSpell && - GetTypeId() == TYPEID_PLAYER && // Only players - !((Player*)this)->HasSpellCooldown(31231) && - // Only if no cooldown - roll_chance_i((*i)->GetModifier()->m_amount)) - // Only if roll - { - preventDeathSpell = (*i)->GetSpellProto(); - } - // always skip this spell in charge dropping, absorb amount calculation since it has chance as m_amount and doesn't need to absorb any damage - continue; - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Guardian Spirit - if (spellProto->GetSpellIconID() == 2873) - { - preventDeathSpell = (*i)->GetSpellProto(); - preventDeathAmount = (*i)->GetModifier()->m_amount; - continue; - } - // Reflective Shield - if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000001)) && canReflect) - { - if (pCaster == this) - break; - Unit* caster = (*i)->GetCaster(); - if (!caster) - break; - AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_DUMMY); - for (AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k) - { - switch ((*k)->GetModifier()->m_miscvalue) - { - case 5065: // Rank 1 - case 5064: // Rank 2 - { - if (RemainingDamage >= currentAbsorb) - reflectDamage = (*k)->GetModifier()->m_amount * currentAbsorb / 100; - else - reflectDamage = (*k)->GetModifier()->m_amount * RemainingDamage / 100; - reflectSpell = 33619; - reflectTriggeredBy = *i; - reflectTriggeredBy->SetInUse(true);// lock aura from final deletion until processing - } break; - default: break; - } - } - break; - } - break; - } - case SPELLFAMILY_SHAMAN: - { - // Astral Shift - if (spellProto->GetSpellIconID() == 3066) - { - // reduces all damage taken while stun, fear or silence - if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED)) - RemainingDamage -= RemainingDamage * currentAbsorb / 100; - continue; - } - break; - } - case SPELLFAMILY_DEATHKNIGHT: - { - // Shadow of Death - if (spellProto->GetSpellIconID() == 1958) - { - // TODO: absorb only while transform - continue; - } - // Anti-Magic Shell (on self) - if (spellProto->Id == 48707) - { - // damage absorbed by Anti-Magic Shell energizes the DK with additional runic power. - // This, if I'm not mistaken, shows that we get back ~2% of the absorbed damage as runic power. - int32 absorbed = RemainingDamage * currentAbsorb / 100; - int32 regen = absorbed * 2 / 10; - CastCustomSpell(this, 49088, ®en, NULL, NULL, true, NULL, *i); - RemainingDamage -= absorbed; - continue; - } - // Anti-Magic Shell (on single party/raid member) - if (spellProto->Id == 50462) - { - RemainingDamage -= RemainingDamage * currentAbsorb / 100; - continue; - } - // Anti-Magic Zone - if (spellProto->Id == 50461) - { - Unit* caster = (*i)->GetCaster(); - if (!caster) - continue; - int32 absorbed = RemainingDamage * currentAbsorb / 100; - int32 canabsorb = caster->GetHealth(); - if (canabsorb < absorbed) - absorbed = canabsorb; - - RemainingDamage -= absorbed; - - uint32 ab_damage = absorbed; - pCaster->DealDamageMods(caster, ab_damage, NULL); - pCaster->DealDamage(caster, ab_damage, NULL, damagetype, schoolMask, 0, false); - continue; - } - break; - } - default: - break; - } - - // currentAbsorb - damage can be absorbed by shield - // If need absorb less damage - if (RemainingDamage < currentAbsorb) - { - currentAbsorb = RemainingDamage; - } - - RemainingDamage -= currentAbsorb; - - // Fire Ward or Frost Ward or Ice Barrier (or Mana Shield) - // for Incanter's Absorption converting to spell power - if (spellProto->IsFitToFamily(SPELLFAMILY_MAGE, UI64LIT(0x0000000000000000), 0x00000008)) - incanterAbsorption += currentAbsorb; - - // Reduce shield amount - mod->m_amount -= currentAbsorb; - if ((*i)->GetHolder()->DropAuraCharge()) - { - mod->m_amount = 0; - } - // Need remove it later - if (mod->m_amount <= 0) - { - existExpired = true; - } - } - - // Remove all expired absorb auras - if (existExpired) - { - for (AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end();) - { - if ((*i)->GetModifier()->m_amount <= 0) - { - RemoveAurasDueToSpell((*i)->GetId(), NULL, AURA_REMOVE_BY_SHIELD_BREAK); - i = vSchoolAbsorb.begin(); - } - else - { - ++i; - } - } - } - - // Cast back reflect damage spell - if (canReflect && reflectSpell) - { - CastCustomSpell(pCaster, reflectSpell, &reflectDamage, NULL, NULL, true, NULL, reflectTriggeredBy); - reflectTriggeredBy->SetInUse(false); // free lock from deletion - } - - // absorb by mana cost - AuraList const& vManaShield = GetAurasByType(SPELL_AURA_MANA_SHIELD); - for (AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next) - { - next = i; ++next; - - // check damage school mask - if (((*i)->GetModifier()->m_miscvalue & schoolMask) == 0) - { - continue; - } - - int32 currentAbsorb; - if (RemainingDamage >= (*i)->GetModifier()->m_amount) - { - currentAbsorb = (*i)->GetModifier()->m_amount; - } - else - { - currentAbsorb = RemainingDamage; - } - - SpellEffectEntry const* spellEffect = (*i)->GetSpellProto()->GetSpellEffect((*i)->GetEffIndex()); - - if (float manaMultiplier = (spellEffect ? spellEffect->EffectMultipleValue : 0)) - { - if (Player* modOwner = GetSpellModOwner()) - { - modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier); - } - - int32 maxAbsorb = int32(GetPower(POWER_MANA) / manaMultiplier); - if (currentAbsorb > maxAbsorb) - { - currentAbsorb = maxAbsorb; - } - - int32 manaReduction = int32(currentAbsorb * manaMultiplier); - ApplyPowerMod(POWER_MANA, manaReduction, false); - } - - // Mana Shield (or Fire Ward or Frost Ward or Ice Barrier) - // for Incanter's Absorption converting to spell power - if ((*i)->GetSpellProto()->IsFitToFamily(SPELLFAMILY_MAGE, UI64LIT(0x0000000000000000), 0x000008)) - incanterAbsorption += currentAbsorb; - - (*i)->GetModifier()->m_amount -= currentAbsorb; - if ((*i)->GetModifier()->m_amount <= 0) - { - RemoveAurasDueToSpell((*i)->GetId()); - next = vManaShield.begin(); - } - - RemainingDamage -= currentAbsorb; - } - - // effects dependent from full absorb amount - // Incanter's Absorption, if have affective absorbing - if (incanterAbsorption) - { - Unit::AuraList const& auras = GetAurasByType(SPELL_AURA_DUMMY); - for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - SpellEntry const* itr_spellProto = (*itr)->GetSpellProto(); - - // Incanter's Absorption - if (itr_spellProto->GetSpellFamilyName() == SPELLFAMILY_GENERIC && - itr_spellProto->GetSpellIconID() == 2941) - { - int32 amount = int32(incanterAbsorption * (*itr)->GetModifier()->m_amount / 100); - - // apply normalized part of already accumulated amount in aura - if (Aura* spdAura = GetAura(44413, EFFECT_INDEX_0)) - amount += spdAura->GetModifier()->m_amount * spdAura->GetAuraDuration() / spdAura->GetAuraMaxDuration(); - - // Incanter's Absorption (triggered absorb based spell power, will replace existing if any) - CastCustomSpell(this, 44413, &amount, NULL, NULL, true); - break; - } - } - } - - // only split damage if not damaging yourself - if (pCaster != this) - { - AuraList const& vSplitDamagePct = GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT); - for (AuraList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next) - { - next = i; ++next; - - // check damage school mask - if (((*i)->GetModifier()->m_miscvalue & schoolMask) == 0) - continue; - - // Damage can be splitted only if aura has an alive caster - Unit* caster = (*i)->GetCaster(); - if (!caster || caster == this || !caster->IsInWorld() || !caster->IsAlive()) - continue; - - uint32 splitted = uint32(RemainingDamage * (*i)->GetModifier()->m_amount / 100.0f); - - RemainingDamage -= int32(splitted); - - uint32 split_absorb = 0; - pCaster->DealDamageMods(caster, splitted, &split_absorb); - - pCaster->SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false); - - CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL); - pCaster->DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); - } - } - - // Apply death prevention spells effects - if (preventDeathSpell && RemainingDamage >= (int32)GetHealth()) - { - switch(preventDeathSpell->GetSpellFamilyName()) - { - // Cheat Death - case SPELLFAMILY_ROGUE: - { - // Cheat Death - if (preventDeathSpell->GetSpellIconID() == 2109) - { - CastSpell(this, 31231, true); - ((Player*)this)->AddSpellCooldown(31231, 0, time(NULL) + 60); - // with health > 10% lost health until health==10%, in other case no losses - uint32 health10 = GetMaxHealth() / 10; - RemainingDamage = GetHealth() > health10 ? GetHealth() - health10 : 0; - } - break; - } - // Guardian Spirit - case SPELLFAMILY_PRIEST: - { - // Guardian Spirit - if (preventDeathSpell->GetSpellIconID() == 2873) - { - int32 healAmount = GetMaxHealth() * preventDeathAmount / 100; - CastCustomSpell(this, 48153, &healAmount, NULL, NULL, true); - RemoveAurasDueToSpell(preventDeathSpell->Id); - RemainingDamage = 0; - } - break; - } - } - } - - *absorb = damage - RemainingDamage - *resist; + if (!pCaster || !IsAlive() || !damage) + { + return; + } + + // Magic damage, check for resists + if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) + { + // Get base victim resistance for school + float tmpvalue2 = (float)GetResistance(GetFirstSchoolInMask(schoolMask)); + // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura + tmpvalue2 += (float)pCaster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask); + + if (pCaster->GetTypeId() == TYPEID_PLAYER) + tmpvalue2 -= (float)((Player*)pCaster)->GetSpellPenetrationItemMod(); + + tmpvalue2 *= (float)(0.15f / getLevel()); + if (tmpvalue2 < 0.0f) + { + tmpvalue2 = 0.0f; + } + if (tmpvalue2 > 0.75f) + { + tmpvalue2 = 0.75f; + } + uint32 ran = urand(0, 100); + float faq[4] = { 24.0f, 6.0f, 4.0f, 6.0f }; + uint8 m = 0; + float Binom = 0.0f; + for (uint8 i = 0; i < 4; ++i) + { + Binom += 2400 * (powf(tmpvalue2, float(i)) * powf((1 - tmpvalue2), float(4 - i))) / faq[i]; + if (ran > Binom) + { + ++m; + } + else + { + break; + } + } + if (damagetype == DOT && m == 4) + { + *resist += uint32(damage - 1); + } + else + { + *resist += uint32(damage * m / 4); + } + if (*resist > damage) + { + *resist = damage; + } + } + else + { + *resist = 0; + } + + int32 RemainingDamage = damage - *resist; + + // Get unit state (need for some absorb check) + uint32 unitflag = GetUInt32Value(UNIT_FIELD_FLAGS); + // Reflect damage spells (not cast any damage spell in aura lookup) + uint32 reflectSpell = 0; + int32 reflectDamage = 0; + Aura* reflectTriggeredBy = NULL; // expected as not expired at reflect as in current cases + // Death Prevention Aura + SpellEntry const* preventDeathSpell = NULL; + int32 preventDeathAmount = 0; + + // full absorb cases (by chance) + AuraList const& vAbsorb = GetAurasByType(SPELL_AURA_SCHOOL_ABSORB); + for (AuraList::const_iterator i = vAbsorb.begin(); i != vAbsorb.end() && RemainingDamage > 0; ++i) + { + // only work with proper school mask damage + Modifier* i_mod = (*i)->GetModifier(); + if (!(i_mod->m_miscvalue & schoolMask)) + continue; + + SpellEntry const* i_spellProto = (*i)->GetSpellProto(); + SpellClassOptionsEntry const* adsClassOptions = i_spellProto->GetSpellClassOptions(); + // Fire Ward or Frost Ward + if (adsClassOptions && adsClassOptions->SpellFamilyName == SPELLFAMILY_MAGE && adsClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000000108)) + { + int chance = 0; + Unit::AuraList const& auras = GetAurasByType(SPELL_AURA_ADD_PCT_MODIFIER); + for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + SpellEntry const* itr_spellProto = (*itr)->GetSpellProto(); + // Frost Warding (chance full absorb) + if (itr_spellProto->GetSpellFamilyName() == SPELLFAMILY_MAGE && itr_spellProto->GetSpellIconID() == 501) + { + // chance stored in next dummy effect + chance = itr_spellProto->CalculateSimpleValue(EFFECT_INDEX_1); + break; + } + } + if (roll_chance_i(chance)) + { + int32 amount = RemainingDamage; + RemainingDamage = 0; + + // Frost Warding (mana regen) + CastCustomSpell(this, 57776, &amount, NULL, NULL, true, NULL, *i); + break; + } + } + } + + // Need remove expired auras after + bool existExpired = false; + + // Incanter's Absorption, for converting to spell power + int32 incanterAbsorption = 0; + + // absorb without mana cost + AuraList const& vSchoolAbsorb = GetAurasByType(SPELL_AURA_SCHOOL_ABSORB); + for (AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end() && RemainingDamage > 0; ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (!(mod->m_miscvalue & schoolMask)) + continue; + + SpellEntry const* spellProto = (*i)->GetSpellProto(); + + // Max Amount can be absorbed by this aura + int32 currentAbsorb = mod->m_amount; + + // Found empty aura (impossible but..) + if (currentAbsorb <= 0) + { + existExpired = true; + continue; + } + + // Handle custom absorb auras + // TODO: try find better way + SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); + + switch (spellProto->GetSpellFamilyName()) + { + case SPELLFAMILY_GENERIC: + { + // Astral Shift + if (spellProto->GetSpellIconID() == 3066) + { + // reduces all damage taken while stun, fear or silence + if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED)) + RemainingDamage -= RemainingDamage * currentAbsorb / 100; + continue; + } + // Nerves of Steel + if (spellProto->GetSpellIconID() == 2115) + { + // while affected by Stun and Fear + if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING)) + RemainingDamage -= RemainingDamage * currentAbsorb / 100; + continue; + } + // Spell Deflection + if (spellProto->GetSpellIconID() == 3006) + { + // You have a chance equal to your Parry chance + if (damagetype == SPELL_DIRECT_DAMAGE &&// Only for direct spell damage + roll_chance_f(GetUnitParryChance())) // Roll chance + RemainingDamage -= RemainingDamage * currentAbsorb / 100; + continue; + } + // Reflective Shield (Lady Malande boss) + if (spellProto->Id == 41475 && canReflect) + { + if (RemainingDamage < currentAbsorb) + reflectDamage = RemainingDamage / 2; + else + reflectDamage = currentAbsorb / 2; + reflectSpell = 33619; + reflectTriggeredBy = *i; + reflectTriggeredBy->SetInUse(true); // lock aura from final deletion until processing + break; + } + if (spellProto->Id == 39228 || // Argussian Compass + spellProto->Id == 60218) // Essence of Gossamer + { + // Max absorb stored in 1 dummy effect + int32 max_absorb = spellProto->CalculateSimpleValue(EFFECT_INDEX_1); + if (max_absorb < currentAbsorb) + currentAbsorb = max_absorb; + break; + } + break; + } + case SPELLFAMILY_DRUID: + { + // Primal Tenacity + if (spellProto->GetSpellIconID() == 2253) + { + // reduces all damage taken while Stunned and in Cat Form + if (GetShapeshiftForm() == FORM_CAT && (unitflag & UNIT_FLAG_STUNNED)) + RemainingDamage -= RemainingDamage * currentAbsorb / 100; + continue; + } + // Moonkin Form passive + if (spellProto->Id == 69366) + { + // reduces all damage taken while Stunned + if (unitflag & UNIT_FLAG_STUNNED) + RemainingDamage -= RemainingDamage * currentAbsorb / 100; + continue; + } + break; + } + case SPELLFAMILY_ROGUE: + { + // Cheat Death (make less prio with Guardian Spirit case) + if (spellProto->GetSpellIconID() == 2109) + { + if (!preventDeathSpell && + GetTypeId() == TYPEID_PLAYER && // Only players + !((Player*)this)->HasSpellCooldown(31231) && + // Only if no cooldown + roll_chance_i((*i)->GetModifier()->m_amount)) + // Only if roll + { + preventDeathSpell = (*i)->GetSpellProto(); + } + // always skip this spell in charge dropping, absorb amount calculation since it has chance as m_amount and doesn't need to absorb any damage + continue; + } + break; + } + case SPELLFAMILY_PRIEST: + { + // Guardian Spirit + if (spellProto->GetSpellIconID() == 2873) + { + preventDeathSpell = (*i)->GetSpellProto(); + preventDeathAmount = (*i)->GetModifier()->m_amount; + continue; + } + // Reflective Shield + if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000001)) && canReflect) + { + if (pCaster == this) + break; + Unit* caster = (*i)->GetCaster(); + if (!caster) + break; + AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_DUMMY); + for (AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k) + { + switch ((*k)->GetModifier()->m_miscvalue) + { + case 5065: // Rank 1 + case 5064: // Rank 2 + { + if (RemainingDamage >= currentAbsorb) + reflectDamage = (*k)->GetModifier()->m_amount * currentAbsorb / 100; + else + reflectDamage = (*k)->GetModifier()->m_amount * RemainingDamage / 100; + reflectSpell = 33619; + reflectTriggeredBy = *i; + reflectTriggeredBy->SetInUse(true);// lock aura from final deletion until processing + } break; + default: break; + } + } + break; + } + break; + } + case SPELLFAMILY_SHAMAN: + { + // Astral Shift + if (spellProto->GetSpellIconID() == 3066) + { + // reduces all damage taken while stun, fear or silence + if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED)) + RemainingDamage -= RemainingDamage * currentAbsorb / 100; + continue; + } + break; + } + case SPELLFAMILY_DEATHKNIGHT: + { + // Shadow of Death + if (spellProto->GetSpellIconID() == 1958) + { + // TODO: absorb only while transform + continue; + } + // Anti-Magic Shell (on self) + if (spellProto->Id == 48707) + { + // damage absorbed by Anti-Magic Shell energizes the DK with additional runic power. + // This, if I'm not mistaken, shows that we get back ~2% of the absorbed damage as runic power. + int32 absorbed = RemainingDamage * currentAbsorb / 100; + int32 regen = absorbed * 2 / 10; + CastCustomSpell(this, 49088, ®en, NULL, NULL, true, NULL, *i); + RemainingDamage -= absorbed; + continue; + } + // Anti-Magic Shell (on single party/raid member) + if (spellProto->Id == 50462) + { + RemainingDamage -= RemainingDamage * currentAbsorb / 100; + continue; + } + // Anti-Magic Zone + if (spellProto->Id == 50461) + { + Unit* caster = (*i)->GetCaster(); + if (!caster) + continue; + int32 absorbed = RemainingDamage * currentAbsorb / 100; + int32 canabsorb = caster->GetHealth(); + if (canabsorb < absorbed) + absorbed = canabsorb; + + RemainingDamage -= absorbed; + + uint32 ab_damage = absorbed; + pCaster->DealDamageMods(caster, ab_damage, NULL); + pCaster->DealDamage(caster, ab_damage, NULL, damagetype, schoolMask, 0, false); + continue; + } + break; + } + default: + break; + } + + // currentAbsorb - damage can be absorbed by shield + // If need absorb less damage + if (RemainingDamage < currentAbsorb) + { + currentAbsorb = RemainingDamage; + } + + RemainingDamage -= currentAbsorb; + + // Fire Ward or Frost Ward or Ice Barrier (or Mana Shield) + // for Incanter's Absorption converting to spell power + if (spellProto->IsFitToFamily(SPELLFAMILY_MAGE, UI64LIT(0x0000000000000000), 0x00000008)) + incanterAbsorption += currentAbsorb; + + // Reduce shield amount + mod->m_amount -= currentAbsorb; + if ((*i)->GetHolder()->DropAuraCharge()) + { + mod->m_amount = 0; + } + // Need remove it later + if (mod->m_amount <= 0) + { + existExpired = true; + } + } + + // Remove all expired absorb auras + if (existExpired) + { + for (AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end();) + { + if ((*i)->GetModifier()->m_amount <= 0) + { + RemoveAurasDueToSpell((*i)->GetId(), NULL, AURA_REMOVE_BY_SHIELD_BREAK); + i = vSchoolAbsorb.begin(); + } + else + { + ++i; + } + } + } + + // Cast back reflect damage spell + if (canReflect && reflectSpell) + { + CastCustomSpell(pCaster, reflectSpell, &reflectDamage, NULL, NULL, true, NULL, reflectTriggeredBy); + reflectTriggeredBy->SetInUse(false); // free lock from deletion + } + + // absorb by mana cost + AuraList const& vManaShield = GetAurasByType(SPELL_AURA_MANA_SHIELD); + for (AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next) + { + next = i; ++next; + + // check damage school mask + if (((*i)->GetModifier()->m_miscvalue & schoolMask) == 0) + { + continue; + } + + int32 currentAbsorb; + if (RemainingDamage >= (*i)->GetModifier()->m_amount) + { + currentAbsorb = (*i)->GetModifier()->m_amount; + } + else + { + currentAbsorb = RemainingDamage; + } + + SpellEffectEntry const* spellEffect = (*i)->GetSpellProto()->GetSpellEffect((*i)->GetEffIndex()); + + if (float manaMultiplier = (spellEffect ? spellEffect->EffectMultipleValue : 0)) + { + if (Player* modOwner = GetSpellModOwner()) + { + modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier); + } + + int32 maxAbsorb = int32(GetPower(POWER_MANA) / manaMultiplier); + if (currentAbsorb > maxAbsorb) + { + currentAbsorb = maxAbsorb; + } + + int32 manaReduction = int32(currentAbsorb * manaMultiplier); + ApplyPowerMod(POWER_MANA, manaReduction, false); + } + + // Mana Shield (or Fire Ward or Frost Ward or Ice Barrier) + // for Incanter's Absorption converting to spell power + if ((*i)->GetSpellProto()->IsFitToFamily(SPELLFAMILY_MAGE, UI64LIT(0x0000000000000000), 0x000008)) + incanterAbsorption += currentAbsorb; + + (*i)->GetModifier()->m_amount -= currentAbsorb; + if ((*i)->GetModifier()->m_amount <= 0) + { + RemoveAurasDueToSpell((*i)->GetId()); + next = vManaShield.begin(); + } + + RemainingDamage -= currentAbsorb; + } + + // effects dependent from full absorb amount + // Incanter's Absorption, if have affective absorbing + if (incanterAbsorption) + { + Unit::AuraList const& auras = GetAurasByType(SPELL_AURA_DUMMY); + for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + SpellEntry const* itr_spellProto = (*itr)->GetSpellProto(); + + // Incanter's Absorption + if (itr_spellProto->GetSpellFamilyName() == SPELLFAMILY_GENERIC && + itr_spellProto->GetSpellIconID() == 2941) + { + int32 amount = int32(incanterAbsorption * (*itr)->GetModifier()->m_amount / 100); + + // apply normalized part of already accumulated amount in aura + if (Aura* spdAura = GetAura(44413, EFFECT_INDEX_0)) + amount += spdAura->GetModifier()->m_amount * spdAura->GetAuraDuration() / spdAura->GetAuraMaxDuration(); + + // Incanter's Absorption (triggered absorb based spell power, will replace existing if any) + CastCustomSpell(this, 44413, &amount, NULL, NULL, true); + break; + } + } + } + + // only split damage if not damaging yourself + if (pCaster != this) + { + AuraList const& vSplitDamagePct = GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT); + for (AuraList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next) + { + next = i; ++next; + + // check damage school mask + if (((*i)->GetModifier()->m_miscvalue & schoolMask) == 0) + continue; + + // Damage can be splitted only if aura has an alive caster + Unit* caster = (*i)->GetCaster(); + if (!caster || caster == this || !caster->IsInWorld() || !caster->IsAlive()) + continue; + + uint32 splitted = uint32(RemainingDamage * (*i)->GetModifier()->m_amount / 100.0f); + + RemainingDamage -= int32(splitted); + + uint32 split_absorb = 0; + pCaster->DealDamageMods(caster, splitted, &split_absorb); + + pCaster->SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false); + + CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL); + pCaster->DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); + } + } + + // Apply death prevention spells effects + if (preventDeathSpell && RemainingDamage >= (int32)GetHealth()) + { + switch (preventDeathSpell->GetSpellFamilyName()) + { + // Cheat Death + case SPELLFAMILY_ROGUE: + { + // Cheat Death + if (preventDeathSpell->GetSpellIconID() == 2109) + { + CastSpell(this, 31231, true); + ((Player*)this)->AddSpellCooldown(31231, 0, time(NULL) + 60); + // with health > 10% lost health until health==10%, in other case no losses + uint32 health10 = GetMaxHealth() / 10; + RemainingDamage = GetHealth() > health10 ? GetHealth() - health10 : 0; + } + break; + } + // Guardian Spirit + case SPELLFAMILY_PRIEST: + { + // Guardian Spirit + if (preventDeathSpell->GetSpellIconID() == 2873) + { + int32 healAmount = GetMaxHealth() * preventDeathAmount / 100; + CastCustomSpell(this, 48153, &healAmount, NULL, NULL, true); + RemoveAurasDueToSpell(preventDeathSpell->Id); + RemainingDamage = 0; + } + break; + } + } + } + + *absorb = damage - RemainingDamage - *resist; } void Unit::CalculateAbsorbResistBlock(Unit* pCaster, SpellNonMeleeDamage* damageInfo, SpellEntry const* spellProto, WeaponAttackType attType) { - bool blocked = false; - // Get blocked status - switch (spellProto->GetDmgClass()) - { - // Melee and Ranged Spells - case SPELL_DAMAGE_CLASS_RANGED: - case SPELL_DAMAGE_CLASS_MELEE: - blocked = IsSpellBlocked(pCaster, spellProto, attType); - break; - default: - break; - } - - if (blocked) - { - damageInfo->blocked = uint32(damageInfo->damage * GetShieldBlockDamageValue() / 100.0f); - if (damageInfo->damage < damageInfo->blocked) - damageInfo->blocked = damageInfo->damage; - damageInfo->damage -= damageInfo->blocked; - } - - uint32 absorb_affected_damage = pCaster->CalcNotIgnoreAbsorbDamage(damageInfo->damage, GetSpellSchoolMask(spellProto), spellProto); - CalculateDamageAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), SPELL_DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, !spellProto->HasAttribute(SPELL_ATTR_EX_CANT_REFLECTED)); - damageInfo->damage -= damageInfo->absorb + damageInfo->resist; + bool blocked = false; + // Get blocked status + switch (spellProto->GetDmgClass()) + { + // Melee and Ranged Spells + case SPELL_DAMAGE_CLASS_RANGED: + case SPELL_DAMAGE_CLASS_MELEE: + blocked = IsSpellBlocked(pCaster, spellProto, attType); + break; + default: + break; + } + + if (blocked) + { + damageInfo->blocked = uint32(damageInfo->damage * GetShieldBlockDamageValue() / 100.0f); + if (damageInfo->damage < damageInfo->blocked) + damageInfo->blocked = damageInfo->damage; + damageInfo->damage -= damageInfo->blocked; + } + + uint32 absorb_affected_damage = pCaster->CalcNotIgnoreAbsorbDamage(damageInfo->damage, GetSpellSchoolMask(spellProto), spellProto); + CalculateDamageAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), SPELL_DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, !spellProto->HasAttribute(SPELL_ATTR_EX_CANT_REFLECTED)); + damageInfo->damage -= damageInfo->absorb + damageInfo->resist; } void Unit::CalculateHealAbsorb(const uint32 heal, uint32* absorb) { - if (!IsAlive() || !heal) - { - return; - } - - int32 RemainingHeal = heal; - - // Need remove expired auras after - bool existExpired = false; - - // absorb - AuraList const& vHealAbsorb = GetAurasByType(SPELL_AURA_HEAL_ABSORB); - for (AuraList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && RemainingHeal > 0; ++i) - { - Modifier* mod = (*i)->GetModifier(); - - // Max Amount can be absorbed by this aura - int32 currentAbsorb = mod->m_amount; - - // Found empty aura (impossible but..) - if (currentAbsorb <= 0) - { - existExpired = true; - continue; - } - - // currentAbsorb - heal can be absorbed - // If need absorb less heal - if (RemainingHeal < currentAbsorb) - currentAbsorb = RemainingHeal; - - RemainingHeal -= currentAbsorb; - - // Reduce aura amount - mod->m_amount -= currentAbsorb; - if ((*i)->GetHolder()->DropAuraCharge()) - mod->m_amount = 0; - // Need remove it later - if (mod->m_amount <= 0) - existExpired = true; - } - - // Remove all expired absorb auras - if (existExpired) - { - for (AuraList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end();) - { - if ((*i)->GetModifier()->m_amount <= 0) - { - RemoveAurasDueToSpell((*i)->GetId(), NULL, AURA_REMOVE_BY_SHIELD_BREAK); - i = vHealAbsorb.begin(); - } - else - ++i; - } - } - - *absorb = heal - RemainingHeal; + if (!IsAlive() || !heal) + { + return; + } + + int32 RemainingHeal = heal; + + // Need remove expired auras after + bool existExpired = false; + + // absorb + AuraList const& vHealAbsorb = GetAurasByType(SPELL_AURA_HEAL_ABSORB); + for (AuraList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && RemainingHeal > 0; ++i) + { + Modifier* mod = (*i)->GetModifier(); + + // Max Amount can be absorbed by this aura + int32 currentAbsorb = mod->m_amount; + + // Found empty aura (impossible but..) + if (currentAbsorb <= 0) + { + existExpired = true; + continue; + } + + // currentAbsorb - heal can be absorbed + // If need absorb less heal + if (RemainingHeal < currentAbsorb) + currentAbsorb = RemainingHeal; + + RemainingHeal -= currentAbsorb; + + // Reduce aura amount + mod->m_amount -= currentAbsorb; + if ((*i)->GetHolder()->DropAuraCharge()) + mod->m_amount = 0; + // Need remove it later + if (mod->m_amount <= 0) + existExpired = true; + } + + // Remove all expired absorb auras + if (existExpired) + { + for (AuraList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end();) + { + if ((*i)->GetModifier()->m_amount <= 0) + { + RemoveAurasDueToSpell((*i)->GetId(), NULL, AURA_REMOVE_BY_SHIELD_BREAK); + i = vHealAbsorb.begin(); + } + else + ++i; + } + } + + *absorb = heal - RemainingHeal; } void Unit::AttackerStateUpdate(Unit* pVictim, WeaponAttackType attType, bool extra) { - if (hasUnitState(UNIT_STAT_CAN_NOT_REACT) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) - { - return; - } - - if (!pVictim->IsAlive()) - { - return; - } - - if (IsNonMeleeSpellCasted(false)) - { - return; - } - - if (attType == RANGED_ATTACK) - return; // ignore ranged case - - uint32 extraAttacks = m_extraAttacks; - - // melee attack spell casted at main hand attack only - if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL]) - { - m_currentSpells[CURRENT_MELEE_SPELL]->cast(); - - // not recent extra attack only at any non extra attack (melee spell case) - if (!extra && extraAttacks) - { - while (m_extraAttacks) - { - AttackerStateUpdate(pVictim, BASE_ATTACK, true); - if (m_extraAttacks > 0) - --m_extraAttacks; - } - } - return; - } - - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK); - - // attack can be redirected to another target - pVictim = SelectMagnetTarget(pVictim); - - CalcDamageInfo damageInfo; - CalculateMeleeDamage(pVictim, &damageInfo, attType); - // Send log damage message to client - DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb); - SendAttackStateUpdate(&damageInfo); - ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType); - DealMeleeDamage(&damageInfo, true); - - if (GetTypeId() == TYPEID_PLAYER) - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", - GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); - else - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", - GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); - - if (Unit* owner = GetOwner()) - if (owner->GetTypeId() == TYPEID_UNIT) - { - owner->SetInCombatWith(pVictim); - owner->AddThreat(pVictim); - pVictim->SetInCombatWith(owner); - } - - for (GuidSet::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr) - if (Unit* pet = (Unit*)GetMap()->GetPet(*itr)) - { - pet->SetInCombatWith(pVictim); - pet->AddThreat(pVictim); - pVictim->SetInCombatWith(pet); - } - - // if damage pVictim call AI reaction - pVictim->AttackedBy(this); - - // extra attack only at any non extra attack (normal case) - if (!extra && extraAttacks) - { - while (m_extraAttacks) - { - AttackerStateUpdate(pVictim, BASE_ATTACK, true); - if (m_extraAttacks > 0) - --m_extraAttacks; - } - } + if (hasUnitState(UNIT_STAT_CAN_NOT_REACT) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) + { + return; + } + + if (!pVictim->IsAlive()) + { + return; + } + + if (IsNonMeleeSpellCasted(false)) + { + return; + } + + if (attType == RANGED_ATTACK) + return; // ignore ranged case + + uint32 extraAttacks = m_extraAttacks; + + // melee attack spell casted at main hand attack only + if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL]) + { + m_currentSpells[CURRENT_MELEE_SPELL]->cast(); + + // not recent extra attack only at any non extra attack (melee spell case) + if (!extra && extraAttacks) + { + while (m_extraAttacks) + { + AttackerStateUpdate(pVictim, BASE_ATTACK, true); + if (m_extraAttacks > 0) + --m_extraAttacks; + } + } + return; + } + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK); + + // attack can be redirected to another target + pVictim = SelectMagnetTarget(pVictim); + + CalcDamageInfo damageInfo; + CalculateMeleeDamage(pVictim, &damageInfo, attType); + // Send log damage message to client + DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb); + SendAttackStateUpdate(&damageInfo); + ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType); + DealMeleeDamage(&damageInfo, true); + + if (GetTypeId() == TYPEID_PLAYER) + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", + GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); + else + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", + GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); + + if (Unit* owner = GetOwner()) + if (owner->GetTypeId() == TYPEID_UNIT) + { + owner->SetInCombatWith(pVictim); + owner->AddThreat(pVictim); + pVictim->SetInCombatWith(owner); + } + + for (GuidSet::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr) + if (Unit* pet = (Unit*)GetMap()->GetPet(*itr)) + { + pet->SetInCombatWith(pVictim); + pet->AddThreat(pVictim); + pVictim->SetInCombatWith(pet); + } + + // if damage pVictim call AI reaction + pVictim->AttackedBy(this); + + // extra attack only at any non extra attack (normal case) + if (!extra && extraAttacks) + { + while (m_extraAttacks) + { + AttackerStateUpdate(pVictim, BASE_ATTACK, true); + if (m_extraAttacks > 0) + --m_extraAttacks; + } + } } MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackType attType) const { - // This is only wrapper + // This is only wrapper - // Miss chance based on melee - float miss_chance = MeleeMissChanceCalc(pVictim, attType); + // Miss chance based on melee + float miss_chance = MeleeMissChanceCalc(pVictim, attType); - // Critical hit chance - float crit_chance = GetUnitCriticalChance(attType, pVictim); + // Critical hit chance + float crit_chance = GetUnitCriticalChance(attType, pVictim); - // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case) - float dodge_chance = pVictim->GetUnitDodgeChance(); - float block_chance = pVictim->GetUnitBlockChance(); - float parry_chance = pVictim->GetUnitParryChance(); + // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case) + float dodge_chance = pVictim->GetUnitDodgeChance(); + float block_chance = pVictim->GetUnitBlockChance(); + float parry_chance = pVictim->GetUnitParryChance(); - // Useful if want to specify crit & miss chances for melee, else it could be removed - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance, crit_chance, dodge_chance, parry_chance, block_chance); + // Useful if want to specify crit & miss chances for melee, else it could be removed + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance, crit_chance, dodge_chance, parry_chance, block_chance); - return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100), int32(miss_chance * 100), int32(dodge_chance * 100), int32(parry_chance * 100), int32(block_chance * 100)); + return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100), int32(miss_chance * 100), int32(dodge_chance * 100), int32(parry_chance * 100), int32(block_chance * 100)); } MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const { - if (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) - { - return MELEE_HIT_EVADE; - } - - int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(pVictim); - int32 victimMaxSkillValueForLevel = pVictim->GetMaxSkillValueForLevel(this); - - // bonus from skills is 0.04% - int32 skillBonus = 4 * (attackerMaxSkillValueForLevel - victimMaxSkillValueForLevel); - int32 sum = 0, tmp = 0; - int32 roll = urand(0, 10000); - - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus); - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d", - roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance); - - if (tmp > 0 && roll < (sum += tmp)) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: MISS"); - return MELEE_HIT_MISS; - } - - // always crit against a sitting target (except 0 crit chance) - if (pVictim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !pVictim->IsStandState()) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRIT (sitting victim)"); - return MELEE_HIT_CRIT; - } - - bool from_behind = !pVictim->HasInArc(M_PI_F, this); - - if (from_behind) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: attack came from behind."); - } - - // Dodge chance - - // only players can't dodge if attacker is behind - if (pVictim->GetTypeId() != TYPEID_PLAYER || !from_behind) - { - // Reduce dodge chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - dodge_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100); - else - dodge_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; - - // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE - dodge_chance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100; - - tmp = dodge_chance; - if ((tmp > 0) // check if unit _can_ dodge - && ((tmp -= skillBonus) > 0) - && roll < (sum += tmp)) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum - tmp, sum); - return MELEE_HIT_DODGE; - } - } - - // parry chances - // check if attack comes from behind, nobody can parry or block if attacker is behind if not have - if (!from_behind || pVictim->HasAuraType(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) - { - // Reduce parry chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - parry_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100); - else - parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; - - if (parry_chance > 0 && (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_PARRY))) - { - parry_chance -= skillBonus; - - // if (from_behind) -- only 100% currently and not 100% sure way value apply - // parry_chance = int32(parry_chance * (pVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT) - 1); - - if (parry_chance > 0 && // check if unit _can_ parry - (roll < (sum += parry_chance))) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum - parry_chance, sum); - return MELEE_HIT_PARRY; - } - } - } - - // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon) - if (attType != RANGED_ATTACK && - (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->IsPet()) && - pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->IsPet() && - getLevel() < pVictim->GetLevelForTarget(this)) - { - // cap possible value (with bonuses > max skill) - int32 skill = attackerMaxSkillValueForLevel; - - tmp = (10 + (victimMaxSkillValueForLevel - skill)) * 100; - tmp = tmp > 4000 ? 4000 : tmp; - if (roll < (sum += tmp)) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum - 4000, sum); - return MELEE_HIT_GLANCING; - } - } - - // block chances - // check if attack comes from behind, nobody can parry or block if attacker is behind - if (!from_behind) - { - if (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK)) - { - tmp = block_chance; - if ((tmp > 0) // check if unit _can_ block - && ((tmp -= skillBonus) > 0) - && (roll < (sum += tmp))) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum - tmp, sum); - return MELEE_HIT_BLOCK; - } - } - } - - // Critical chance - tmp = crit_chance; - - if (tmp > 0 && roll < (sum += tmp)) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum - tmp, sum); - return MELEE_HIT_CRIT; - } - - // mobs can score crushing blows if they're 4 or more levels above victim - // having defense above your maximum (from items, talents etc.) has no effect - // mob's level * 5 - player's current defense skill - add 2% chance per lacking skill point, min. is 20% - if ((getLevel() - 4) >= pVictim->getLevel() && !IsNonMeleeSpellCasted(false) /* It should have been !spellCasted but wrath doesn't have that? */ - && roll < (tmp = (((attackerMaxSkillValueForLevel - tmp) * 200) - 2000))) - { - uint32 typeId = GetTypeId(); - /* It should have been !(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH) but wrath doesn't have that? */ - if ((typeId == TYPEID_UNIT && !(GetOwnerGuid() && GetOwner()->GetTypeId() == TYPEID_PLAYER) - && !(static_cast(this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH)) - || (typeId == TYPEID_PLAYER && GetCharmerGuid() && GetCharmer()->GetTypeId() == TYPEID_UNIT)) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRUSHING %d)", tmp); - return MELEE_HIT_CRUSHING; - } - } - - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: NORMAL"); - return MELEE_HIT_NORMAL; + if (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + { + return MELEE_HIT_EVADE; + } + + int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(pVictim); + int32 victimMaxSkillValueForLevel = pVictim->GetMaxSkillValueForLevel(this); + + // bonus from skills is 0.04% + int32 skillBonus = 4 * (attackerMaxSkillValueForLevel - victimMaxSkillValueForLevel); + int32 sum = 0, tmp = 0; + int32 roll = urand(0, 10000); + + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus); + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d", + roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance); + + if (tmp > 0 && roll < (sum += tmp)) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: MISS"); + return MELEE_HIT_MISS; + } + + // always crit against a sitting target (except 0 crit chance) + if (pVictim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !pVictim->IsStandState()) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRIT (sitting victim)"); + return MELEE_HIT_CRIT; + } + + bool from_behind = !pVictim->HasInArc(M_PI_F, this); + + if (from_behind) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: attack came from behind."); + } + + // Dodge chance + + // only players can't dodge if attacker is behind + if (pVictim->GetTypeId() != TYPEID_PLAYER || !from_behind) + { + // Reduce dodge chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + dodge_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100); + else + dodge_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; + + // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE + dodge_chance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100; + + tmp = dodge_chance; + if ((tmp > 0) // check if unit _can_ dodge + && ((tmp -= skillBonus) > 0) + && roll < (sum += tmp)) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum - tmp, sum); + return MELEE_HIT_DODGE; + } + } + + // parry chances + // check if attack comes from behind, nobody can parry or block if attacker is behind if not have + if (!from_behind || pVictim->HasAuraType(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) + { + // Reduce parry chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + parry_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100); + else + parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; + + if (parry_chance > 0 && (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_PARRY))) + { + parry_chance -= skillBonus; + + // if (from_behind) -- only 100% currently and not 100% sure way value apply + // parry_chance = int32(parry_chance * (pVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT) - 1); + + if (parry_chance > 0 && // check if unit _can_ parry + (roll < (sum += parry_chance))) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum - parry_chance, sum); + return MELEE_HIT_PARRY; + } + } + } + + // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon) + if (attType != RANGED_ATTACK && + (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->IsPet()) && + pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->IsPet() && + getLevel() < pVictim->GetLevelForTarget(this)) + { + // cap possible value (with bonuses > max skill) + int32 skill = attackerMaxSkillValueForLevel; + + tmp = (10 + (victimMaxSkillValueForLevel - skill)) * 100; + tmp = tmp > 4000 ? 4000 : tmp; + if (roll < (sum += tmp)) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum - 4000, sum); + return MELEE_HIT_GLANCING; + } + } + + // block chances + // check if attack comes from behind, nobody can parry or block if attacker is behind + if (!from_behind) + { + if (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK)) + { + tmp = block_chance; + if ((tmp > 0) // check if unit _can_ block + && ((tmp -= skillBonus) > 0) + && (roll < (sum += tmp))) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum - tmp, sum); + return MELEE_HIT_BLOCK; + } + } + } + + // Critical chance + tmp = crit_chance; + + if (tmp > 0 && roll < (sum += tmp)) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum - tmp, sum); + return MELEE_HIT_CRIT; + } + + // mobs can score crushing blows if they're 4 or more levels above victim + // having defense above your maximum (from items, talents etc.) has no effect + // mob's level * 5 - player's current defense skill - add 2% chance per lacking skill point, min. is 20% + if ((getLevel() - 4) >= pVictim->getLevel() && !IsNonMeleeSpellCasted(false) /* It should have been !spellCasted but wrath doesn't have that? */ + && roll < (tmp = (((attackerMaxSkillValueForLevel - tmp) * 200) - 2000))) + { + uint32 typeId = GetTypeId(); + /* It should have been !(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH) but wrath doesn't have that? */ + if ((typeId == TYPEID_UNIT && !(GetOwnerGuid() && GetOwner()->GetTypeId() == TYPEID_PLAYER) + && !(static_cast(this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH)) + || (typeId == TYPEID_PLAYER && GetCharmerGuid() && GetCharmer()->GetTypeId() == TYPEID_UNIT)) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRUSHING %d)", tmp); + return MELEE_HIT_CRUSHING; + } + } + + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: NORMAL"); + return MELEE_HIT_NORMAL; } uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized) { - float min_damage, max_damage; - - if (normalized && GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->CalculateMinMaxDamage(attType, normalized, min_damage, max_damage); - else - { - switch (attType) - { - case RANGED_ATTACK: - min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE); - max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE); - break; - case BASE_ATTACK: - min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE); - max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE); - break; - case OFF_ATTACK: - min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE); - max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE); - break; - // Just for good manner - default: - min_damage = 0.0f; - max_damage = 0.0f; - break; - } - } - - if (min_damage > max_damage) - { - std::swap(min_damage, max_damage); - } - - if (max_damage == 0.0f) - max_damage = 5.0f; - - return urand((uint32)min_damage, (uint32)max_damage); + float min_damage, max_damage; + + if (normalized && GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->CalculateMinMaxDamage(attType, normalized, min_damage, max_damage); + else + { + switch (attType) + { + case RANGED_ATTACK: + min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE); + max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE); + break; + case BASE_ATTACK: + min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE); + max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE); + break; + case OFF_ATTACK: + min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE); + max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE); + break; + // Just for good manner + default: + min_damage = 0.0f; + max_damage = 0.0f; + break; + } + } + + if (min_damage > max_damage) + { + std::swap(min_damage, max_damage); + } + + if (max_damage == 0.0f) + max_damage = 5.0f; + + return urand((uint32)min_damage, (uint32)max_damage); } float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const { - uint32 spellLevel = spellProto->GetSpellLevel(); - if (spellLevel <= 0 || spellLevel > spellProto->GetMaxLevel()) - { - return 1.0f; - } + uint32 spellLevel = spellProto->GetSpellLevel(); + if (spellLevel <= 0 || spellLevel > spellProto->GetMaxLevel()) + { + return 1.0f; + } - float LvlPenalty = 0.0f; + float LvlPenalty = 0.0f; - if (spellLevel < 20) - LvlPenalty = 20.0f - spellLevel * 3.75f; - float LvlFactor = (float(spellLevel) + 6.0f) / float(getLevel()); - if (LvlFactor > 1.0f) - LvlFactor = 1.0f; + if (spellLevel < 20) + LvlPenalty = 20.0f - spellLevel * 3.75f; + float LvlFactor = (float(spellLevel) + 6.0f) / float(getLevel()); + if (LvlFactor > 1.0f) + LvlFactor = 1.0f; - return (100.0f - LvlPenalty) * LvlFactor / 100.0f; + return (100.0f - LvlPenalty) * LvlFactor / 100.0f; } void Unit::SendMeleeAttackStart(Unit* pVictim) { - WorldPacket data(SMSG_ATTACKSTART, 8 + 8); - data << GetObjectGuid(); - data << pVictim->GetObjectGuid(); + WorldPacket data(SMSG_ATTACKSTART, 8 + 8); + data << GetObjectGuid(); + data << pVictim->GetObjectGuid(); - SendMessageToSet(&data, true); - DEBUG_LOG("WORLD: Sent SMSG_ATTACKSTART"); + SendMessageToSet(&data, true); + DEBUG_LOG("WORLD: Sent SMSG_ATTACKSTART"); } void Unit::SendMeleeAttackStop(Unit* victim) { - if (!victim) - { - return; - } + if (!victim) + { + return; + } - WorldPacket data(SMSG_ATTACKSTOP, (4 + 16)); // we guess size - data << GetPackGUID(); - data << victim->GetPackGUID(); // can be 0x00... - data << uint32(0); // can be 0x1 - SendMessageToSet(&data, true); - DETAIL_FILTER_LOG(LOG_FILTER_COMBAT, "%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), victim->GetGUIDLow()); + WorldPacket data(SMSG_ATTACKSTOP, (4 + 16)); // we guess size + data << GetPackGUID(); + data << victim->GetPackGUID(); // can be 0x00... + data << uint32(0); // can be 0x1 + SendMessageToSet(&data, true); + DETAIL_FILTER_LOG(LOG_FILTER_COMBAT, "%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), victim->GetGUIDLow()); - /*if(victim->GetTypeId() == TYPEID_UNIT) - ((Creature*)victim)->AI().EnterEvadeMode(this);*/ + /*if(victim->GetTypeId() == TYPEID_UNIT) + ((Creature*)victim)->AI().EnterEvadeMode(this);*/ } bool Unit::IsSpellBlocked(Unit* pCaster, SpellEntry const* spellEntry, WeaponAttackType attackType) { - if (!HasInArc(M_PI_F, pCaster)) - { - return false; - } - - if (spellEntry) - { - // Some spells cannot be blocked - if (spellEntry->HasAttribute(SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)) - { - return false; - } - } - - /* - // Ignore combat result aura (parry/dodge check on prepare) - AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); - for(AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) - { - if (!(*i)->isAffectedOnSpell(spellProto)) - continue; - if ((*i)->GetModifier()->m_miscvalue == ???) - { - return false; - } - } - */ - - // Check creatures ExtraFlags for disable block - if (GetTypeId() == TYPEID_UNIT) - { - if (((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK) - { - return false; - } - } - - float blockChance = GetUnitBlockChance(); - // For each point of difference between the attacker's level and the defender's level, - // the block chance is modified by 0.5% if the target is a mob and 0.2% if the target is a player. - blockChance += (getLevel() - pCaster->GetLevelForTarget(this)) * (pCaster->GetTypeId() == TYPEID_PLAYER ? 0.2f : 0.5f); - if (blockChance < 0.0f) - blockChance = 0.0f; - - return roll_chance_f(blockChance); + if (!HasInArc(M_PI_F, pCaster)) + { + return false; + } + + if (spellEntry) + { + // Some spells cannot be blocked + if (spellEntry->HasAttribute(SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)) + { + return false; + } + } + + /* + // Ignore combat result aura (parry/dodge check on prepare) + AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); + for(AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) + { + if (!(*i)->isAffectedOnSpell(spellProto)) + continue; + if ((*i)->GetModifier()->m_miscvalue == ???) + { + return false; + } + } + */ + + // Check creatures ExtraFlags for disable block + if (GetTypeId() == TYPEID_UNIT) + { + if (((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK) + { + return false; + } + } + + float blockChance = GetUnitBlockChance(); + // For each point of difference between the attacker's level and the defender's level, + // the block chance is modified by 0.5% if the target is a mob and 0.2% if the target is a player. + blockChance += (getLevel() - pCaster->GetLevelForTarget(this)) * (pCaster->GetTypeId() == TYPEID_PLAYER ? 0.2f : 0.5f); + if (blockChance < 0.0f) + blockChance = 0.0f; + + return roll_chance_f(blockChance); } // Melee based spells can be miss, parry or dodge on this step // Crit or block - determined on damage calculation phase! (and can be both in some time) float Unit::MeleeSpellMissChance(Unit* pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const* spell) { - // Calculate hit chance (more correct for chance mod) - float hitChance = 0.0f; - - // PvP - PvE melee chances - // TODO: implement diminishing returns for defense from player's defense rating - // pure skill diff is not sufficient since 3.x anymore, but exact formulas hard to research - if (pVictim->GetTypeId() == TYPEID_PLAYER) - hitChance = 95.0f + skillDiff * 0.04f; - else if (skillDiff < -10) - hitChance = 94.0f + (skillDiff + 10) * 0.4f; - else - hitChance = 95.0f + skillDiff * 0.1f; - - // Hit chance depends from victim auras - if (attType == RANGED_ATTACK) - hitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); - else - hitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); - - // Spellmod from SPELLMOD_RESIST_MISS_CHANCE - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, hitChance); - - // Miss = 100 - hit - float missChance = 100.0f - hitChance; - - // Bonuses from attacker aura and ratings - if (attType == RANGED_ATTACK) - missChance -= m_modRangedHitChance; - else - missChance -= m_modMeleeHitChance; - - // Limit miss chance from 0 to 60% - if (missChance < 0.0f) - { - return 0.0f; - } - if (missChance > 60.0f) - { - return 60.0f; - } - return missChance; + // Calculate hit chance (more correct for chance mod) + float hitChance = 0.0f; + + // PvP - PvE melee chances + // TODO: implement diminishing returns for defense from player's defense rating + // pure skill diff is not sufficient since 3.x anymore, but exact formulas hard to research + if (pVictim->GetTypeId() == TYPEID_PLAYER) + hitChance = 95.0f + skillDiff * 0.04f; + else if (skillDiff < -10) + hitChance = 94.0f + (skillDiff + 10) * 0.4f; + else + hitChance = 95.0f + skillDiff * 0.1f; + + // Hit chance depends from victim auras + if (attType == RANGED_ATTACK) + hitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); + else + hitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); + + // Spellmod from SPELLMOD_RESIST_MISS_CHANCE + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, hitChance); + + // Miss = 100 - hit + float missChance = 100.0f - hitChance; + + // Bonuses from attacker aura and ratings + if (attType == RANGED_ATTACK) + missChance -= m_modRangedHitChance; + else + missChance -= m_modMeleeHitChance; + + // Limit miss chance from 0 to 60% + if (missChance < 0.0f) + { + return 0.0f; + } + if (missChance > 60.0f) + { + return 60.0f; + } + return missChance; } // Melee based spells hit result calculations SpellMissInfo Unit::MeleeSpellHitResult(Unit* pVictim, SpellEntry const* spell) { - WeaponAttackType attType = BASE_ATTACK; - - if (spell->GetDmgClass() == SPELL_DAMAGE_CLASS_RANGED) - attType = RANGED_ATTACK; - - // bonus from skills is 0.04% per skill Diff - int32 attackerWeaponSkill = GetMaxSkillValueForLevel(); - int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this)); - - uint32 roll = urand(0, 10000); - - uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, skillDiff, spell) * 100.0f); - // Roll miss - uint32 tmp = spell->HasAttribute(SPELL_ATTR_EX3_CANT_MISS) ? 0 : missChance; - if (roll < tmp) - { - return SPELL_MISS_MISS; - } - - // Chance resist mechanic (select max value from every mechanic spell effect) - int32 resist_mech = 0; - // Get effects mechanic and chance - for (int eff = 0; eff < MAX_EFFECT_INDEX; ++eff) - { - int32 effect_mech = GetEffectMechanic(spell, SpellEffectIndex(eff)); - if (effect_mech) - { - int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech); - if (resist_mech < temp * 100) - resist_mech = temp * 100; - } - } - // Roll chance - tmp += resist_mech; - if (roll < tmp) - { - return SPELL_MISS_RESIST; - } - - bool canDodge = true; - bool canParry = true; - - // Same spells cannot be parry/dodge - if (spell->HasAttribute(SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)) - { - return SPELL_MISS_NONE; - } - - bool from_behind = !pVictim->HasInArc(M_PI_F, this); - - // Ranged attack cannot be parry/dodge only deflect - if (attType == RANGED_ATTACK) - { - // only if in front or special ability - if (!from_behind || pVictim->HasAuraType(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) - { - int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100; - - // if (from_behind) -- only 100% currently and not 100% sure way value apply - // deflect_chance = int32(deflect_chance * (pVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT) - 1); - - tmp += deflect_chance; - if (roll < tmp) - { - return SPELL_MISS_DEFLECT; - } - } - return SPELL_MISS_NONE; - } - - // Check for attack from behind - if (from_behind) - { - // Can`t dodge from behind in PvP (but its possible in PvE) - if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) - canDodge = false; - // Can`t parry without special ability - if (!pVictim->HasAuraType(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) - canParry = false; - } - // Check creatures ExtraFlags for disable parry - if (pVictim->GetTypeId() == TYPEID_UNIT) - { - uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags; - if (flagEx & CREATURE_EXTRA_FLAG_NO_PARRY) - canParry = false; - } - // Ignore combat result aura - AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); - for (AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) - { - if (!(*i)->isAffectedOnSpell(spell)) - continue; - switch ((*i)->GetModifier()->m_miscvalue) - { - case MELEE_HIT_DODGE: canDodge = false; break; - case MELEE_HIT_BLOCK: break; // Block check in hit step - case MELEE_HIT_PARRY: canParry = false; break; - default: - DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetModifier()->m_miscvalue); - break; - } - } - - if (canDodge) - { - // Roll dodge - int32 dodgeChance = int32(pVictim->GetUnitDodgeChance() * 100.0f) - skillDiff * 4; - // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE - dodgeChance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100; - // Reduce dodge chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - dodgeChance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - else - dodgeChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; - if (dodgeChance < 0) - dodgeChance = 0; - - tmp += dodgeChance; - if (roll < tmp) - { - return SPELL_MISS_DODGE; - } - } - - if (canParry) - { - // Roll parry - int32 parryChance = int32(pVictim->GetUnitParryChance() * 100.0f) - skillDiff * 4; - // Reduce parry chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - parryChance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - else - parryChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; - if (parryChance < 0) - parryChance = 0; - - // if (from_behind) -- only 100% currently and not 100% sure way value apply - // parryChance = int32(parryChance * (pVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT) - 1)); - - tmp += parryChance; - if (roll < tmp) - { - return SPELL_MISS_PARRY; - } - } - - return SPELL_MISS_NONE; + WeaponAttackType attType = BASE_ATTACK; + + if (spell->GetDmgClass() == SPELL_DAMAGE_CLASS_RANGED) + attType = RANGED_ATTACK; + + // bonus from skills is 0.04% per skill Diff + int32 attackerWeaponSkill = GetMaxSkillValueForLevel(); + int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this)); + + uint32 roll = urand(0, 10000); + + uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, skillDiff, spell) * 100.0f); + // Roll miss + uint32 tmp = spell->HasAttribute(SPELL_ATTR_EX3_CANT_MISS) ? 0 : missChance; + if (roll < tmp) + { + return SPELL_MISS_MISS; + } + + // Chance resist mechanic (select max value from every mechanic spell effect) + int32 resist_mech = 0; + // Get effects mechanic and chance + for (int eff = 0; eff < MAX_EFFECT_INDEX; ++eff) + { + int32 effect_mech = GetEffectMechanic(spell, SpellEffectIndex(eff)); + if (effect_mech) + { + int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech); + if (resist_mech < temp * 100) + resist_mech = temp * 100; + } + } + // Roll chance + tmp += resist_mech; + if (roll < tmp) + { + return SPELL_MISS_RESIST; + } + + bool canDodge = true; + bool canParry = true; + + // Same spells cannot be parry/dodge + if (spell->HasAttribute(SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)) + { + return SPELL_MISS_NONE; + } + + bool from_behind = !pVictim->HasInArc(M_PI_F, this); + + // Ranged attack cannot be parry/dodge only deflect + if (attType == RANGED_ATTACK) + { + // only if in front or special ability + if (!from_behind || pVictim->HasAuraType(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) + { + int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100; + + // if (from_behind) -- only 100% currently and not 100% sure way value apply + // deflect_chance = int32(deflect_chance * (pVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT) - 1); + + tmp += deflect_chance; + if (roll < tmp) + { + return SPELL_MISS_DEFLECT; + } + } + return SPELL_MISS_NONE; + } + + // Check for attack from behind + if (from_behind) + { + // Can`t dodge from behind in PvP (but its possible in PvE) + if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + canDodge = false; + // Can`t parry without special ability + if (!pVictim->HasAuraType(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) + canParry = false; + } + // Check creatures ExtraFlags for disable parry + if (pVictim->GetTypeId() == TYPEID_UNIT) + { + uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags; + if (flagEx & CREATURE_EXTRA_FLAG_NO_PARRY) + canParry = false; + } + // Ignore combat result aura + AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); + for (AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) + { + if (!(*i)->isAffectedOnSpell(spell)) + continue; + switch ((*i)->GetModifier()->m_miscvalue) + { + case MELEE_HIT_DODGE: canDodge = false; break; + case MELEE_HIT_BLOCK: break; // Block check in hit step + case MELEE_HIT_PARRY: canParry = false; break; + default: + DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetModifier()->m_miscvalue); + break; + } + } + + if (canDodge) + { + // Roll dodge + int32 dodgeChance = int32(pVictim->GetUnitDodgeChance() * 100.0f) - skillDiff * 4; + // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE + dodgeChance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100; + // Reduce dodge chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + dodgeChance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); + else + dodgeChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; + if (dodgeChance < 0) + dodgeChance = 0; + + tmp += dodgeChance; + if (roll < tmp) + { + return SPELL_MISS_DODGE; + } + } + + if (canParry) + { + // Roll parry + int32 parryChance = int32(pVictim->GetUnitParryChance() * 100.0f) - skillDiff * 4; + // Reduce parry chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + parryChance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); + else + parryChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; + if (parryChance < 0) + parryChance = 0; + + // if (from_behind) -- only 100% currently and not 100% sure way value apply + // parryChance = int32(parryChance * (pVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT) - 1)); + + tmp += parryChance; + if (roll < tmp) + { + return SPELL_MISS_PARRY; + } + } + + return SPELL_MISS_NONE; } // TODO need use unit spell resistances in calculations SpellMissInfo Unit::MagicSpellHitResult(Unit* pVictim, SpellEntry const* spell) { - // Can`t miss on dead target (on skinning for example) - if (!pVictim->IsAlive()) - { - return SPELL_MISS_NONE; - } - - SpellSchoolMask schoolMask = GetSpellSchoolMask(spell); - // PvP - PvE spell misschances per leveldif > 2 - int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11; - int32 leveldif = int32(pVictim->GetLevelForTarget(this)) - int32(GetLevelForTarget(pVictim)); - - // Base hit chance from attacker and victim levels - int32 modHitChance; - if (leveldif < 3) - modHitChance = 96 - leveldif; - else - modHitChance = 94 - (leveldif - 2) * lchance; - - // Spellmod from SPELLMOD_RESIST_MISS_CHANCE - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance); - // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras - modHitChance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask); - // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST - if (IsDispelSpell(spell)) - modHitChance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST); - // Chance resist mechanic (select max value from every mechanic spell effect) - int32 resist_mech = 0; - // Get effects mechanic and chance - for (int eff = 0; eff < MAX_EFFECT_INDEX; ++eff) - { - int32 effect_mech = GetEffectMechanic(spell, SpellEffectIndex(eff)); - if (effect_mech) - { - int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech); - if (resist_mech < temp) - resist_mech = temp; - } - } - // Apply mod - modHitChance -= resist_mech; - - int32 HitChance = modHitChance * 100; - // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings - HitChance += int32(m_modSpellHitChance * 100.0f); - - - if (HitChance < 100) HitChance = 100; - if (HitChance > 10000) HitChance = 10000; - - int32 tmp = spell->HasAttribute(SPELL_ATTR_EX3_CANT_MISS) ? 0 : (10000 - HitChance); - - int32 rand = irand(0, 10000); - - if (rand < tmp) - { - return SPELL_MISS_MISS; - } - - bool from_behind = !pVictim->HasInArc(M_PI_F, this); - - // cast by caster in front of victim or behind with special ability - if (!from_behind || pVictim->HasAuraType(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) - { - int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100; - - // if (from_behind) -- only 100% currently and not 100% sure way value apply - // deflect_chance = int32(deflect_chance * (pVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) - 1); - - tmp += deflect_chance; - if (rand < tmp) - { - return SPELL_MISS_DEFLECT; - } - } - - return SPELL_MISS_NONE; + // Can`t miss on dead target (on skinning for example) + if (!pVictim->IsAlive()) + { + return SPELL_MISS_NONE; + } + + SpellSchoolMask schoolMask = GetSpellSchoolMask(spell); + // PvP - PvE spell misschances per leveldif > 2 + int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11; + int32 leveldif = int32(pVictim->GetLevelForTarget(this)) - int32(GetLevelForTarget(pVictim)); + + // Base hit chance from attacker and victim levels + int32 modHitChance; + if (leveldif < 3) + modHitChance = 96 - leveldif; + else + modHitChance = 94 - (leveldif - 2) * lchance; + + // Spellmod from SPELLMOD_RESIST_MISS_CHANCE + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance); + // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras + modHitChance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask); + // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST + if (IsDispelSpell(spell)) + modHitChance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST); + // Chance resist mechanic (select max value from every mechanic spell effect) + int32 resist_mech = 0; + // Get effects mechanic and chance + for (int eff = 0; eff < MAX_EFFECT_INDEX; ++eff) + { + int32 effect_mech = GetEffectMechanic(spell, SpellEffectIndex(eff)); + if (effect_mech) + { + int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech); + if (resist_mech < temp) + resist_mech = temp; + } + } + // Apply mod + modHitChance -= resist_mech; + + int32 HitChance = modHitChance * 100; + // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings + HitChance += int32(m_modSpellHitChance * 100.0f); + + + if (HitChance < 100) HitChance = 100; + if (HitChance > 10000) HitChance = 10000; + + int32 tmp = spell->HasAttribute(SPELL_ATTR_EX3_CANT_MISS) ? 0 : (10000 - HitChance); + + int32 rand = irand(0, 10000); + + if (rand < tmp) + { + return SPELL_MISS_MISS; + } + + bool from_behind = !pVictim->HasInArc(M_PI_F, this); + + // cast by caster in front of victim or behind with special ability + if (!from_behind || pVictim->HasAuraType(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) + { + int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100; + + // if (from_behind) -- only 100% currently and not 100% sure way value apply + // deflect_chance = int32(deflect_chance * (pVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT)) - 1); + + tmp += deflect_chance; + if (rand < tmp) + { + return SPELL_MISS_DEFLECT; + } + } + + return SPELL_MISS_NONE; } // Calculate spell hit result can be: @@ -3862,3408 +3866,3408 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* pVictim, SpellEntry const* spell) // Resist SpellMissInfo Unit::SpellHitResult(Unit* pVictim, SpellEntry const* spell, bool CanReflect) { - // Return evade for units in evade mode - if (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) - { - return SPELL_MISS_EVADE; - } - - // Check for immune - if (pVictim->IsImmuneToSpell(spell, this == pVictim) && !spell->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)) - { - return SPELL_MISS_IMMUNE; - } - - // All positive spells can`t miss - // TODO: client not show miss log for this spells - so need find info for this in dbc and use it! - if (IsPositiveSpell(spell->Id)) - { - return SPELL_MISS_NONE; - } - - // Check for immune - if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell)) && !spell->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)) - { - return SPELL_MISS_IMMUNE; - } - - // Try victim reflect spell - if (CanReflect) - { - int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS); - Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL); - for (Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i) - if ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell)) - reflectchance += (*i)->GetModifier()->m_amount; - if (reflectchance > 0 && roll_chance_i(reflectchance)) - { - // Start triggers for remove charges if need (trigger only for victim, and mark as active spell) - ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 1, BASE_ATTACK, spell); - return SPELL_MISS_REFLECT; - } - } - - switch (spell->GetDmgClass()) - { - case SPELL_DAMAGE_CLASS_NONE: - return SPELL_MISS_NONE; - case SPELL_DAMAGE_CLASS_MAGIC: - return MagicSpellHitResult(pVictim, spell); - case SPELL_DAMAGE_CLASS_MELEE: - case SPELL_DAMAGE_CLASS_RANGED: - return MeleeSpellHitResult(pVictim, spell); - } - return SPELL_MISS_NONE; + // Return evade for units in evade mode + if (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + { + return SPELL_MISS_EVADE; + } + + // Check for immune + if (pVictim->IsImmuneToSpell(spell, this == pVictim) && !spell->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)) + { + return SPELL_MISS_IMMUNE; + } + + // All positive spells can`t miss + // TODO: client not show miss log for this spells - so need find info for this in dbc and use it! + if (IsPositiveSpell(spell->Id)) + { + return SPELL_MISS_NONE; + } + + // Check for immune + if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell)) && !spell->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)) + { + return SPELL_MISS_IMMUNE; + } + + // Try victim reflect spell + if (CanReflect) + { + int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS); + Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL); + for (Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i) + if ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell)) + reflectchance += (*i)->GetModifier()->m_amount; + if (reflectchance > 0 && roll_chance_i(reflectchance)) + { + // Start triggers for remove charges if need (trigger only for victim, and mark as active spell) + ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 1, BASE_ATTACK, spell); + return SPELL_MISS_REFLECT; + } + } + + switch (spell->GetDmgClass()) + { + case SPELL_DAMAGE_CLASS_NONE: + return SPELL_MISS_NONE; + case SPELL_DAMAGE_CLASS_MAGIC: + return MagicSpellHitResult(pVictim, spell); + case SPELL_DAMAGE_CLASS_MELEE: + case SPELL_DAMAGE_CLASS_RANGED: + return MeleeSpellHitResult(pVictim, spell); + } + return SPELL_MISS_NONE; } float Unit::MeleeMissChanceCalc(const Unit* pVictim, WeaponAttackType attType) const { - if (!pVictim) - { - return 0.0f; - } - - // Base misschance 5% - float missChance = 5.0f; - - // DualWield - white damage has additional 19% miss penalty - if (haveOffhandWeapon() && attType != RANGED_ATTACK) - { - bool isNormal = false; - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) - { - if (m_currentSpells[i] && (GetSpellSchoolMask(m_currentSpells[i]->m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL)) - { - isNormal = true; - break; - } - } - if (!isNormal && !m_currentSpells[CURRENT_MELEE_SPELL]) - missChance += 19.0f; - } - - int32 skillDiff = int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetMaxSkillValueForLevel(this)); - - // PvP - PvE melee chances - // TODO: implement diminishing returns for defense from player's defense rating - // pure skill diff is not sufficient since 3.x anymore, but exact formulas hard to research - if (pVictim->GetTypeId() == TYPEID_PLAYER) - missChance -= skillDiff * 0.04f; - else if (skillDiff < -10) - missChance -= (skillDiff + 10) * 0.4f - 1.0f; - else - missChance -= skillDiff * 0.1f; - - // Hit chance bonus from attacker based on ratings and auras - if (attType == RANGED_ATTACK) - missChance -= m_modRangedHitChance; - else - missChance -= m_modMeleeHitChance; - - // Modify miss chance by victim auras - if (attType == RANGED_ATTACK) - missChance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); - else - missChance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); - - // Limit miss chance from 0 to 60% - if (missChance < 0.0f) - { - return 0.0f; - } - if (missChance > 60.0f) - { - return 60.0f; - } - - return missChance; + if (!pVictim) + { + return 0.0f; + } + + // Base misschance 5% + float missChance = 5.0f; + + // DualWield - white damage has additional 19% miss penalty + if (haveOffhandWeapon() && attType != RANGED_ATTACK) + { + bool isNormal = false; + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) + { + if (m_currentSpells[i] && (GetSpellSchoolMask(m_currentSpells[i]->m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL)) + { + isNormal = true; + break; + } + } + if (!isNormal && !m_currentSpells[CURRENT_MELEE_SPELL]) + missChance += 19.0f; + } + + int32 skillDiff = int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetMaxSkillValueForLevel(this)); + + // PvP - PvE melee chances + // TODO: implement diminishing returns for defense from player's defense rating + // pure skill diff is not sufficient since 3.x anymore, but exact formulas hard to research + if (pVictim->GetTypeId() == TYPEID_PLAYER) + missChance -= skillDiff * 0.04f; + else if (skillDiff < -10) + missChance -= (skillDiff + 10) * 0.4f - 1.0f; + else + missChance -= skillDiff * 0.1f; + + // Hit chance bonus from attacker based on ratings and auras + if (attType == RANGED_ATTACK) + missChance -= m_modRangedHitChance; + else + missChance -= m_modMeleeHitChance; + + // Modify miss chance by victim auras + if (attType == RANGED_ATTACK) + missChance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); + else + missChance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); + + // Limit miss chance from 0 to 60% + if (missChance < 0.0f) + { + return 0.0f; + } + if (missChance > 60.0f) + { + return 60.0f; + } + + return missChance; } float Unit::GetUnitDodgeChance() const { - if (hasUnitState(UNIT_STAT_STUNNED)) - { - return 0.0f; - } - if (GetTypeId() == TYPEID_PLAYER) - { - return GetFloatValue(PLAYER_DODGE_PERCENTAGE); - } - else - { - if (((Creature const*)this)->IsTotem()) - { - return 0.0f; - } - else - { - float dodge = 5.0f; - dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); - return dodge > 0.0f ? dodge : 0.0f; - } - } + if (hasUnitState(UNIT_STAT_STUNNED)) + { + return 0.0f; + } + if (GetTypeId() == TYPEID_PLAYER) + { + return GetFloatValue(PLAYER_DODGE_PERCENTAGE); + } + else + { + if (((Creature const*)this)->IsTotem()) + { + return 0.0f; + } + else + { + float dodge = 5.0f; + dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); + return dodge > 0.0f ? dodge : 0.0f; + } + } } float Unit::GetUnitParryChance() const { - if (IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED)) - { - return 0.0f; - } - - float chance = 0.0f; - - if (GetTypeId() == TYPEID_PLAYER) - { - Player const* player = (Player const*)this; - if (player->CanParry()) - { - Item* tmpitem = player->GetWeaponForAttack(BASE_ATTACK, true, true); - if (!tmpitem) - tmpitem = player->GetWeaponForAttack(OFF_ATTACK, true, true); - - if (tmpitem) - chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE); - } - } - else if (GetTypeId() == TYPEID_UNIT) - { - if (GetCreatureType() == CREATURE_TYPE_HUMANOID) - { - chance = 5.0f; - chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); - } - } - - return chance > 0.0f ? chance : 0.0f; + if (IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED)) + { + return 0.0f; + } + + float chance = 0.0f; + + if (GetTypeId() == TYPEID_PLAYER) + { + Player const* player = (Player const*)this; + if (player->CanParry()) + { + Item* tmpitem = player->GetWeaponForAttack(BASE_ATTACK, true, true); + if (!tmpitem) + tmpitem = player->GetWeaponForAttack(OFF_ATTACK, true, true); + + if (tmpitem) + chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE); + } + } + else if (GetTypeId() == TYPEID_UNIT) + { + if (GetCreatureType() == CREATURE_TYPE_HUMANOID) + { + chance = 5.0f; + chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); + } + } + + return chance > 0.0f ? chance : 0.0f; } float Unit::GetUnitBlockChance() const { - if (IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED)) - { - return 0.0f; - } - - if (GetTypeId() == TYPEID_PLAYER) - { - Player const* player = (Player const*)this; - if (player->CanBlock() && player->CanUseEquippedWeapon(OFF_ATTACK)) - { - Item* tmpitem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - if (tmpitem && !tmpitem->IsBroken()) - { - return GetFloatValue(PLAYER_BLOCK_PERCENTAGE); - } - } - // is player but has no block ability or no not broken shield equipped - return 0.0f; - } - else - { - if (((Creature const*)this)->IsTotem()) - { - return 0.0f; - } - else - { - float block = 5.0f; - block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_CHANCE_PERCENT); - return block > 0.0f ? block : 0.0f; - } - } + if (IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED)) + { + return 0.0f; + } + + if (GetTypeId() == TYPEID_PLAYER) + { + Player const* player = (Player const*)this; + if (player->CanBlock() && player->CanUseEquippedWeapon(OFF_ATTACK)) + { + Item* tmpitem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + if (tmpitem && !tmpitem->IsBroken()) + { + return GetFloatValue(PLAYER_BLOCK_PERCENTAGE); + } + } + // is player but has no block ability or no not broken shield equipped + return 0.0f; + } + else + { + if (((Creature const*)this)->IsTotem()) + { + return 0.0f; + } + else + { + float block = 5.0f; + block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_CHANCE_PERCENT); + return block > 0.0f ? block : 0.0f; + } + } } float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit* pVictim) const { - float crit; - - if (GetTypeId() == TYPEID_PLAYER) - { - switch (attackType) - { - case BASE_ATTACK: - crit = GetFloatValue(PLAYER_CRIT_PERCENTAGE); - break; - case OFF_ATTACK: - crit = GetFloatValue(PLAYER_OFFHAND_CRIT_PERCENTAGE); - break; - case RANGED_ATTACK: - crit = GetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE); - break; - // Just for good manner - default: - crit = 0.0f; - break; - } - } - else - { - crit = 5.0f; - crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT); - } - - // flat aura mods - if (attackType == RANGED_ATTACK) - crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE); - else - crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE); - - crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); - - if (crit < 0.0f) - crit = 0.0f; - return crit; + float crit; + + if (GetTypeId() == TYPEID_PLAYER) + { + switch (attackType) + { + case BASE_ATTACK: + crit = GetFloatValue(PLAYER_CRIT_PERCENTAGE); + break; + case OFF_ATTACK: + crit = GetFloatValue(PLAYER_OFFHAND_CRIT_PERCENTAGE); + break; + case RANGED_ATTACK: + crit = GetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE); + break; + // Just for good manner + default: + crit = 0.0f; + break; + } + } + else + { + crit = 5.0f; + crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT); + } + + // flat aura mods + if (attackType == RANGED_ATTACK) + crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE); + else + crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE); + + crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); + + if (crit < 0.0f) + crit = 0.0f; + return crit; } void Unit::_UpdateSpells(uint32 time) { - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) - _UpdateAutoRepeatSpell(); - - // remove finished spells from current pointers - for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) - { - if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED) - { - m_currentSpells[i]->SetReferencedFromCurrent(false); - m_currentSpells[i] = NULL; // remove pointer - } - } - - // update auras - // m_AurasUpdateIterator can be updated in inderect called code at aura remove to skip next planned to update but removed auras - for (m_spellAuraHoldersUpdateIterator = m_spellAuraHolders.begin(); m_spellAuraHoldersUpdateIterator != m_spellAuraHolders.end();) - { - SpellAuraHolder* i_holder = m_spellAuraHoldersUpdateIterator->second; - ++m_spellAuraHoldersUpdateIterator; // need shift to next for allow update if need into aura update - i_holder->UpdateHolder(time); - } - - // remove expired auras - for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) - { - SpellAuraHolder* holder = iter->second; - - if (!(holder->IsPermanent() || holder->IsPassive()) && holder->GetAuraDuration() == 0) - { - RemoveSpellAuraHolder(holder, AURA_REMOVE_BY_EXPIRE); - iter = m_spellAuraHolders.begin(); - } - else - ++iter; - } - - if (!m_gameObj.empty()) - { - GameObjectList::iterator ite1, dnext1; - for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1) - { - dnext1 = ite1; - //(*i)->Update( difftime ); - if (!(*ite1)->isSpawned()) - { - (*ite1)->SetOwnerGuid(ObjectGuid()); - (*ite1)->SetRespawnTime(0); - (*ite1)->Delete(); - dnext1 = m_gameObj.erase(ite1); - } - else - ++dnext1; - } - } + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) + _UpdateAutoRepeatSpell(); + + // remove finished spells from current pointers + for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) + { + if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED) + { + m_currentSpells[i]->SetReferencedFromCurrent(false); + m_currentSpells[i] = NULL; // remove pointer + } + } + + // update auras + // m_AurasUpdateIterator can be updated in inderect called code at aura remove to skip next planned to update but removed auras + for (m_spellAuraHoldersUpdateIterator = m_spellAuraHolders.begin(); m_spellAuraHoldersUpdateIterator != m_spellAuraHolders.end();) + { + SpellAuraHolder* i_holder = m_spellAuraHoldersUpdateIterator->second; + ++m_spellAuraHoldersUpdateIterator; // need shift to next for allow update if need into aura update + i_holder->UpdateHolder(time); + } + + // remove expired auras + for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) + { + SpellAuraHolder* holder = iter->second; + + if (!(holder->IsPermanent() || holder->IsPassive()) && holder->GetAuraDuration() == 0) + { + RemoveSpellAuraHolder(holder, AURA_REMOVE_BY_EXPIRE); + iter = m_spellAuraHolders.begin(); + } + else + ++iter; + } + + if (!m_gameObj.empty()) + { + GameObjectList::iterator ite1, dnext1; + for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1) + { + dnext1 = ite1; + //(*i)->Update( difftime ); + if (!(*ite1)->isSpawned()) + { + (*ite1)->SetOwnerGuid(ObjectGuid()); + (*ite1)->SetRespawnTime(0); + (*ite1)->Delete(); + dnext1 = m_gameObj.erase(ite1); + } + else + ++dnext1; + } + } } void Unit::_UpdateAutoRepeatSpell() { - bool isAutoShot = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == SPELL_ID_AUTOSHOT; - - // check movement - if (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving() && - !HasAffectedAura(SPELL_AURA_ALLOW_CAST_WHILE_MOVING, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo)) - { - // cancel wand shoot - if (!isAutoShot) - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - // auto shot just waits - return; - } - - // check spell casts - if (IsNonMeleeSpellCasted(false, false, true)) - { - // cancel wand shoot - if (!isAutoShot) - { - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - return; - } - // auto shot is delayed by everythihng, except ranged(!) CURRENT_GENERIC_SPELL's -> recheck that - else if (!(m_currentSpells[CURRENT_GENERIC_SPELL] && m_currentSpells[CURRENT_GENERIC_SPELL]->IsRangedSpell())) - { - return; - } - } - - // castroutine - if (isAttackReady(RANGED_ATTACK)) - { - // Check if able to cast - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK) - { - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - return; - } - - // we want to shoot - Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true); - spell->SpellStart(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets)); - - // all went good, reset attack - resetAttackTimer(RANGED_ATTACK); - } + bool isAutoShot = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == SPELL_ID_AUTOSHOT; + + // check movement + if (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving() && + !HasAffectedAura(SPELL_AURA_ALLOW_CAST_WHILE_MOVING, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo)) + { + // cancel wand shoot + if (!isAutoShot) + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + // auto shot just waits + return; + } + + // check spell casts + if (IsNonMeleeSpellCasted(false, false, true)) + { + // cancel wand shoot + if (!isAutoShot) + { + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + return; + } + // auto shot is delayed by everythihng, except ranged(!) CURRENT_GENERIC_SPELL's -> recheck that + else if (!(m_currentSpells[CURRENT_GENERIC_SPELL] && m_currentSpells[CURRENT_GENERIC_SPELL]->IsRangedSpell())) + { + return; + } + } + + // castroutine + if (isAttackReady(RANGED_ATTACK)) + { + // Check if able to cast + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK) + { + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + return; + } + + // we want to shoot + Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true); + spell->SpellStart(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets)); + + // all went good, reset attack + resetAttackTimer(RANGED_ATTACK); + } } void Unit::SetCurrentCastedSpell(Spell* pSpell) { - MANGOS_ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells - - CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer(); - - if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self - - // break same type spell if it is not delayed - InterruptSpell(CSpellType, false); - - // special breakage effects: - switch (CSpellType) - { - case CURRENT_GENERIC_SPELL: - { - // generic spells always break channeled not delayed spells - InterruptSpell(CURRENT_CHANNELED_SPELL, false); - - // autorepeat breaking - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) - { - // break autorepeat if not Auto Shot - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT) - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - } - } break; - - case CURRENT_CHANNELED_SPELL: - { - // channel spells always break generic non-delayed and any channeled spells - InterruptSpell(CURRENT_GENERIC_SPELL, false); - InterruptSpell(CURRENT_CHANNELED_SPELL); - - // it also does break autorepeat if not Auto Shot - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT) - InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - } break; - - case CURRENT_AUTOREPEAT_SPELL: - { - // only Auto Shoot does not break anything - if (pSpell->m_spellInfo->Id != SPELL_ID_AUTOSHOT) - { - // generic autorepeats break generic non-delayed and channeled non-delayed spells - InterruptSpell(CURRENT_GENERIC_SPELL, false); - InterruptSpell(CURRENT_CHANNELED_SPELL, false); - // special action: first cast delay - if (getAttackTimer(RANGED_ATTACK) < 500) - setAttackTimer(RANGED_ATTACK, 500); - } - } break; - - default: - { - // other spell types don't break anything now - } break; - } - - // current spell (if it is still here) may be safely deleted now - if (m_currentSpells[CSpellType]) - m_currentSpells[CSpellType]->SetReferencedFromCurrent(false); - - // set new current spell - m_currentSpells[CSpellType] = pSpell; - pSpell->SetReferencedFromCurrent(true); - - pSpell->SetSelfContainer(&(m_currentSpells[pSpell->GetCurrentContainer()])); // this works, but is not safe - - - // original and faulty code - delete once the above has been proven to work - // pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]); // m_selfContainer is not accessible, due to being a protected member + MANGOS_ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells + + CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer(); + + if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self + + // break same type spell if it is not delayed + InterruptSpell(CSpellType, false); + + // special breakage effects: + switch (CSpellType) + { + case CURRENT_GENERIC_SPELL: + { + // generic spells always break channeled not delayed spells + InterruptSpell(CURRENT_CHANNELED_SPELL, false); + + // autorepeat breaking + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) + { + // break autorepeat if not Auto Shot + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT) + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + } + } break; + + case CURRENT_CHANNELED_SPELL: + { + // channel spells always break generic non-delayed and any channeled spells + InterruptSpell(CURRENT_GENERIC_SPELL, false); + InterruptSpell(CURRENT_CHANNELED_SPELL); + + // it also does break autorepeat if not Auto Shot + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && + m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT) + InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + } break; + + case CURRENT_AUTOREPEAT_SPELL: + { + // only Auto Shoot does not break anything + if (pSpell->m_spellInfo->Id != SPELL_ID_AUTOSHOT) + { + // generic autorepeats break generic non-delayed and channeled non-delayed spells + InterruptSpell(CURRENT_GENERIC_SPELL, false); + InterruptSpell(CURRENT_CHANNELED_SPELL, false); + // special action: first cast delay + if (getAttackTimer(RANGED_ATTACK) < 500) + setAttackTimer(RANGED_ATTACK, 500); + } + } break; + + default: + { + // other spell types don't break anything now + } break; + } + + // current spell (if it is still here) may be safely deleted now + if (m_currentSpells[CSpellType]) + m_currentSpells[CSpellType]->SetReferencedFromCurrent(false); + + // set new current spell + m_currentSpells[CSpellType] = pSpell; + pSpell->SetReferencedFromCurrent(true); + + pSpell->SetSelfContainer(&(m_currentSpells[pSpell->GetCurrentContainer()])); // this works, but is not safe - + + // original and faulty code - delete once the above has been proven to work + // pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]); // m_selfContainer is not accessible, due to being a protected member } void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool sendAutoRepeatCancelToClient) { - MANGOS_ASSERT(spellType < CURRENT_MAX_SPELL); + MANGOS_ASSERT(spellType < CURRENT_MAX_SPELL); - if (m_currentSpells[spellType] && (withDelayed || m_currentSpells[spellType]->getState() != SPELL_STATE_DELAYED)) - { - // send autorepeat cancel message for autorepeat spells - if (spellType == CURRENT_AUTOREPEAT_SPELL && sendAutoRepeatCancelToClient) - { - if (GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->SendAutoRepeatCancel(this); - } + if (m_currentSpells[spellType] && (withDelayed || m_currentSpells[spellType]->getState() != SPELL_STATE_DELAYED)) + { + // send autorepeat cancel message for autorepeat spells + if (spellType == CURRENT_AUTOREPEAT_SPELL && sendAutoRepeatCancelToClient) + { + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SendAutoRepeatCancel(this); + } - if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED) - m_currentSpells[spellType]->cancel(); + if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED) + m_currentSpells[spellType]->cancel(); - // cancel can interrupt spell already (caster cancel ->target aura remove -> caster iterrupt) - if (m_currentSpells[spellType]) - { - m_currentSpells[spellType]->SetReferencedFromCurrent(false); - m_currentSpells[spellType] = NULL; - } - } + // cancel can interrupt spell already (caster cancel ->target aura remove -> caster iterrupt) + if (m_currentSpells[spellType]) + { + m_currentSpells[spellType]->SetReferencedFromCurrent(false); + m_currentSpells[spellType] = NULL; + } + } } void Unit::FinishSpell(CurrentSpellTypes spellType, bool ok /*= true*/) { - Spell* spell = m_currentSpells[spellType]; - if (!spell) - { - return; - } + Spell* spell = m_currentSpells[spellType]; + if (!spell) + { + return; + } - if (spellType == CURRENT_CHANNELED_SPELL) - spell->SendChannelUpdate(0); + if (spellType == CURRENT_CHANNELED_SPELL) + spell->SendChannelUpdate(0); - spell->finish(ok); + spell->finish(ok); } bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat) const { - // We don't do loop here to explicitly show that melee spell is excluded. - // Maybe later some special spells will be excluded too. + // We don't do loop here to explicitly show that melee spell is excluded. + // Maybe later some special spells will be excluded too. - // generic spells are casted when they are not finished and not delayed - if (m_currentSpells[CURRENT_GENERIC_SPELL] && - (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) && - (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED)) - return true; + // generic spells are casted when they are not finished and not delayed + if (m_currentSpells[CURRENT_GENERIC_SPELL] && + (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) && + (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED)) + return true; - // channeled spells may be delayed, but they are still considered casted - else if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] && - (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED)) - return true; + // channeled spells may be delayed, but they are still considered casted + else if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] && + (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED)) + return true; - // autorepeat spells may be finished or delayed, but they are still considered casted - else if (!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) - { - return true; - } + // autorepeat spells may be finished or delayed, but they are still considered casted + else if (!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) + { + return true; + } - return false; + return false; } void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id) { - // generic spells are interrupted if they are not finished or delayed - if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id)) - InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed); + // generic spells are interrupted if they are not finished or delayed + if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id)) + InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed); - // autorepeat spells are interrupted if they are not finished or delayed - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id)) - InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed); + // autorepeat spells are interrupted if they are not finished or delayed + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id)) + InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed); - // channeled spells are interrupted if they are not finished, even if they are delayed - if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id)) - InterruptSpell(CURRENT_CHANNELED_SPELL, true); + // channeled spells are interrupted if they are not finished, even if they are delayed + if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id)) + InterruptSpell(CURRENT_CHANNELED_SPELL, true); } Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const { - for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) - if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spell_id) - { - return m_currentSpells[i]; - } - return NULL; + for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) + if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spell_id) + { + return m_currentSpells[i]; + } + return NULL; } void Unit::SetInFront(Unit const* target) { - SetOrientation(GetAngle(target)); + SetOrientation(GetAngle(target)); } void Unit::SetFacingTo(float ori) { - Movement::MoveSplineInit init(*this); - init.SetFacing(ori); - init.Launch(); + Movement::MoveSplineInit init(*this); + init.SetFacing(ori); + init.Launch(); } void Unit::SetFacingToObject(WorldObject* pObject) { - // never face when already moving - if (!IsStopped()) - { - return; - } + // never face when already moving + if (!IsStopped()) + { + return; + } - // TODO: figure out under what conditions creature will move towards object instead of facing it where it currently is. - SetFacingTo(GetAngle(pObject)); + // TODO: figure out under what conditions creature will move towards object instead of facing it where it currently is. + SetFacingTo(GetAngle(pObject)); } bool Unit::isInAccessablePlaceFor(Creature const* c) const { - if (IsInWater()) - { - return c->CanSwim(); - } - else - { - return c->CanWalk() || c->CanFly(); - } + if (IsInWater()) + { + return c->CanSwim(); + } + else + { + return c->CanWalk() || c->CanFly(); + } } bool Unit::IsInWater() const { - return GetTerrain()->IsInWater(GetPositionX(), GetPositionY(), GetPositionZ()); + return GetTerrain()->IsInWater(GetPositionX(), GetPositionY(), GetPositionZ()); } bool Unit::IsUnderWater() const { - return GetTerrain()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ()); + return GetTerrain()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ()); } void Unit::DeMorph() { - SetDisplayId(GetNativeDisplayId()); + SetDisplayId(GetNativeDisplayId()); } int32 Unit::GetTotalAuraModifier(AuraType auratype) const { - int32 modifier = 0; + int32 modifier = 0; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - modifier += (*i)->GetModifier()->m_amount; - } + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + modifier += (*i)->GetModifier()->m_amount; + } - return modifier; + return modifier; } float Unit::GetTotalAuraMultiplier(AuraType auratype) const { - float multiplier = 1.0f; + float multiplier = 1.0f; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - multiplier *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; - } + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + multiplier *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; + } - return multiplier; + return multiplier; } int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) const { - int32 modifier = 0; + int32 modifier = 0; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - if ((*i)->GetModifier()->m_amount > modifier) - modifier = (*i)->GetModifier()->m_amount; + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + if ((*i)->GetModifier()->m_amount > modifier) + modifier = (*i)->GetModifier()->m_amount; - return modifier; + return modifier; } int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const { - int32 modifier = 0; + int32 modifier = 0; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - if ((*i)->GetModifier()->m_amount < modifier) - modifier = (*i)->GetModifier()->m_amount; + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + if ((*i)->GetModifier()->m_amount < modifier) + modifier = (*i)->GetModifier()->m_amount; - return modifier; + return modifier; } int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const { - if (!misc_mask) - { - return 0; - } + if (!misc_mask) + { + return 0; + } - int32 modifier = 0; + int32 modifier = 0; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue & misc_mask) - modifier += mod->m_amount; - } - return modifier; + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue & misc_mask) + modifier += mod->m_amount; + } + return modifier; } float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const { - if (!misc_mask) - { - return 1.0f; - } + if (!misc_mask) + { + return 1.0f; + } - float multiplier = 1.0f; + float multiplier = 1.0f; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue & misc_mask) - multiplier *= (100.0f + mod->m_amount) / 100.0f; - } - return multiplier; + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue & misc_mask) + multiplier *= (100.0f + mod->m_amount) / 100.0f; + } + return multiplier; } int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const { - if (!misc_mask) - { - return 0; - } + if (!misc_mask) + { + return 0; + } - int32 modifier = 0; + int32 modifier = 0; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue & misc_mask && mod->m_amount > modifier) - modifier = mod->m_amount; - } + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue & misc_mask && mod->m_amount > modifier) + modifier = mod->m_amount; + } - return modifier; + return modifier; } int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const { - if (!misc_mask) - { - return 0; - } + if (!misc_mask) + { + return 0; + } - int32 modifier = 0; + int32 modifier = 0; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue & misc_mask && mod->m_amount < modifier) - modifier = mod->m_amount; - } + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue & misc_mask && mod->m_amount < modifier) + modifier = mod->m_amount; + } - return modifier; + return modifier; } int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const { - int32 modifier = 0; + int32 modifier = 0; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue == misc_value) - modifier += mod->m_amount; - } - return modifier; + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue == misc_value) + modifier += mod->m_amount; + } + return modifier; } float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const { - float multiplier = 1.0f; + float multiplier = 1.0f; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue == misc_value) - multiplier *= (100.0f + mod->m_amount) / 100.0f; - } - return multiplier; + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue == misc_value) + multiplier *= (100.0f + mod->m_amount) / 100.0f; + } + return multiplier; } int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const { - int32 modifier = 0; + int32 modifier = 0; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue == misc_value && mod->m_amount > modifier) - modifier = mod->m_amount; - } + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue == misc_value && mod->m_amount > modifier) + modifier = mod->m_amount; + } - return modifier; + return modifier; } int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const { - int32 modifier = 0; + int32 modifier = 0; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mod->m_miscvalue == misc_value && mod->m_amount < modifier) - modifier = mod->m_amount; - } + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mod->m_miscvalue == misc_value && mod->m_amount < modifier) + modifier = mod->m_amount; + } - return modifier; + return modifier; } float Unit::GetTotalAuraMultiplierByMiscValueForMask(AuraType auratype, uint32 mask) const { - if (!mask) - { - return 1.0f; - } + if (!mask) + { + return 1.0f; + } - float multiplier = 1.0f; + float multiplier = 1.0f; - AuraList const& mTotalAuraList = GetAurasByType(auratype); - for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - { - Modifier* mod = (*i)->GetModifier(); - if (mask & (1 << (mod->m_miscvalue - 1))) - multiplier *= (100.0f + mod->m_amount) / 100.0f; - } - return multiplier; + AuraList const& mTotalAuraList = GetAurasByType(auratype); + for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + { + Modifier* mod = (*i)->GetModifier(); + if (mask & (1 << (mod->m_miscvalue - 1))) + multiplier *= (100.0f + mod->m_amount) / 100.0f; + } + return multiplier; } bool Unit::AddSpellAuraHolder(SpellAuraHolder* holder) { - SpellEntry const* aurSpellInfo = holder->GetSpellProto(); - - // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load) - if (!IsAlive() && !IsDeathPersistentSpell(aurSpellInfo) && - !IsDeathOnlySpell(aurSpellInfo) && - (GetTypeId() != TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading())) - { - delete holder; - return false; - } - - if (holder->GetTarget() != this) - { - sLog.outError("Holder (spell %u) add to spell aura holder list of %s (lowguid: %u) but spell aura holder target is %s (lowguid: %u)", - holder->GetId(), (GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), - (holder->GetTarget()->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), holder->GetTarget()->GetGUIDLow()); - delete holder; - return false; - } - - // passive and persistent auras can stack with themselves any number of times - if ((!holder->IsPassive() && !holder->IsPersistent()) || holder->IsAreaAura()) - { - SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(aurSpellInfo->Id); - - // take out same spell - for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second; ++iter) - { - SpellAuraHolder* foundHolder = iter->second; - if (foundHolder->GetCasterGuid() == holder->GetCasterGuid()) - { - // Aura can stack on self -> Stack it; - if (aurSpellInfo->GetStackAmount()) - { - // can be created with >1 stack by some spell mods - foundHolder->ModStackAmount(holder->GetStackAmount()); - delete holder; - return false; - } - - // Check for coexisting Weapon-proced Auras - if (holder->IsWeaponBuffCoexistableWith(foundHolder)) - continue; - - // Carry over removed Aura's remaining damage if Aura still has ticks remaining - if (foundHolder->GetSpellProto()->HasAttribute(SPELL_ATTR_EX4_STACK_DOT_MODIFIER)) - { - for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) - { - if (Aura* aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i))) - { - // m_auraname can be modified to SPELL_AURA_NONE for area auras, use original - SpellEffectEntry const* spellEffect = aurSpellInfo->GetSpellEffect(SpellEffectIndex(i)); - AuraType aurNameReal = AuraType(spellEffect ? spellEffect->EffectApplyAuraName : 0); - - if (aurNameReal == SPELL_AURA_PERIODIC_DAMAGE && aur->GetAuraDuration() > 0) - { - if (Aura* existing = foundHolder->GetAuraByEffectIndex(SpellEffectIndex(i))) - { - int32 remainingTicks = existing->GetAuraMaxTicks() - existing->GetAuraTicks(); - int32 remainingDamage = existing->GetModifier()->m_amount * remainingTicks; - - aur->GetModifier()->m_amount += int32(remainingDamage / aur->GetAuraMaxTicks()); - } - else - DEBUG_LOG("Holder (spell %u) on target (lowguid: %u) doesn't have aura on effect index %u. skipping.", aurSpellInfo->Id, holder->GetTarget()->GetGUIDLow(), i); - } - } - } - } - - // can be only single - RemoveSpellAuraHolder(foundHolder, AURA_REMOVE_BY_STACK); - break; - } - - bool stop = false; - - for (int32 i = 0; i < MAX_EFFECT_INDEX && !stop; ++i) - { - // no need to check non stacking auras that weren't/won't be applied on this target - if (!foundHolder->m_auras[i] || !holder->m_auras[i]) - continue; - - // m_auraname can be modified to SPELL_AURA_NONE for area auras, use original - SpellEffectEntry const* spellEffect = aurSpellInfo->GetSpellEffect(SpellEffectIndex(i)); - AuraType aurNameReal = AuraType(spellEffect ? spellEffect->EffectApplyAuraName : SPELL_AURA_NONE); - - switch (aurNameReal) - { - // DoT/HoT/etc - case SPELL_AURA_DUMMY: // allow stack - case SPELL_AURA_PERIODIC_DAMAGE: - case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: - case SPELL_AURA_PERIODIC_LEECH: - case SPELL_AURA_PERIODIC_HEAL: - case SPELL_AURA_OBS_MOD_HEALTH: - case SPELL_AURA_PERIODIC_MANA_LEECH: - case SPELL_AURA_OBS_MOD_MANA: - case SPELL_AURA_POWER_BURN_MANA: - case SPELL_AURA_CONTROL_VEHICLE: - case SPELL_AURA_TRIGGER_LINKED_AURA: - case SPELL_AURA_PERIODIC_DUMMY: - break; - case SPELL_AURA_PERIODIC_ENERGIZE: // all or self or clear non-stackable - default: // not allow - // can be only single (this check done at _each_ aura add - RemoveSpellAuraHolder(foundHolder, AURA_REMOVE_BY_STACK); - stop = true; - break; - } - } - - if (stop) - break; - } - } - - // normal spell or passive auras not stackable with other ranks - if (!IsPassiveSpell(aurSpellInfo) || !IsPassiveSpellStackableWithRanks(aurSpellInfo)) - { - // Hack exceptions for Vehicle/Linked auras - if (!IsSpellHaveAura(aurSpellInfo, SPELL_AURA_CONTROL_VEHICLE) && !IsSpellHaveAura(aurSpellInfo, SPELL_AURA_TRIGGER_LINKED_AURA) && - !RemoveNoStackAurasDueToAuraHolder(holder)) - { - delete holder; - return false; // couldn't remove conflicting aura with higher rank - } - } - - // update tracked aura targets list (before aura add to aura list, to prevent unexpected remove recently added aura) - if (TrackedAuraType trackedType = holder->GetTrackedAuraType()) - { - if (Unit* caster = holder->GetCaster()) // caster not in world - { - // Only compare TrackedAuras of same tracking type - TrackedAuraTargetMap& scTargets = caster->GetTrackedAuraTargets(trackedType); - for (TrackedAuraTargetMap::iterator itr = scTargets.begin(); itr != scTargets.end();) - { - SpellEntry const* itr_spellEntry = itr->first; - ObjectGuid itr_targetGuid = itr->second; // Target on whom the tracked aura is - - if (itr_targetGuid == GetObjectGuid()) // Note: I don't understand this check (based on old aura concepts, kept when adding holders) - { - ++itr; - continue; - } - - bool removed = false; - switch (trackedType) - { - case TRACK_AURA_TYPE_SINGLE_TARGET: - if (IsSingleTargetSpells(itr_spellEntry, aurSpellInfo)) - { - removed = true; - // remove from target if target found - if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid)) - itr_target->RemoveAurasDueToSpell(itr_spellEntry->Id); // TODO AURA_REMOVE_BY_TRACKING (might require additional work elsewhere) - else // Normally the tracking will be removed by the AuraRemoval - scTargets.erase(itr); - } - break; - case TRACK_AURA_TYPE_CONTROL_VEHICLE: - { - // find minimal effect-index that applies an aura - uint8 i = EFFECT_INDEX_0; - for (; i < MAX_EFFECT_INDEX; ++i) - if (IsAuraApplyEffect(aurSpellInfo, SpellEffectIndex(i))) - break; - - // Remove auras when first holder is applied - if ((1 << i) & holder->GetAuraFlags()) - { - removed = true; // each caster can only control one vehicle - - // remove from target if target found - if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid)) - itr_target->RemoveAurasByCasterSpell(itr_spellEntry->Id, caster->GetObjectGuid(), AURA_REMOVE_BY_TRACKING); - else // Normally the tracking will be removed by the AuraRemoval - scTargets.erase(itr); - } - break; - } - case TRACK_AURA_TYPE_NOT_TRACKED: // These two can never happen - case MAX_TRACKED_AURA_TYPES: - MANGOS_ASSERT(false); - break; - } - - if (removed) - { - itr = scTargets.begin(); // list can be chnaged at remove aura - continue; - } - - ++itr; - } - - switch (trackedType) - { - case TRACK_AURA_TYPE_CONTROL_VEHICLE: // Only track the controlled vehicle, no secondary effects - if (!IsSpellHaveAura(aurSpellInfo, SPELL_AURA_CONTROL_VEHICLE, holder->GetAuraFlags())) - break; - // no break here, track other controlled - case TRACK_AURA_TYPE_SINGLE_TARGET: // Register spell holder single target - scTargets[aurSpellInfo] = GetObjectGuid(); - break; - } - } - } - - // add aura, register in lists and arrays - holder->_AddSpellAuraHolder(); - m_spellAuraHolders.insert(SpellAuraHolderMap::value_type(holder->GetId(), holder)); - - for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) - if (Aura* aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i))) - AddAuraToModList(aur); - - holder->ApplyAuraModifiers(true, true); // This is the place where auras are actually applied onto the target - DEBUG_LOG("Holder of spell %u now is in use", holder->GetId()); - - // if aura deleted before boosts apply ignore - // this can be possible it it removed indirectly by triggered spell effect at ApplyModifier - if (holder->IsDeleted()) - { - return false; - } - - holder->HandleSpellSpecificBoosts(true); - - return true; + SpellEntry const* aurSpellInfo = holder->GetSpellProto(); + + // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load) + if (!IsAlive() && !IsDeathPersistentSpell(aurSpellInfo) && + !IsDeathOnlySpell(aurSpellInfo) && + (GetTypeId() != TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading())) + { + delete holder; + return false; + } + + if (holder->GetTarget() != this) + { + sLog.outError("Holder (spell %u) add to spell aura holder list of %s (lowguid: %u) but spell aura holder target is %s (lowguid: %u)", + holder->GetId(), (GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), + (holder->GetTarget()->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), holder->GetTarget()->GetGUIDLow()); + delete holder; + return false; + } + + // passive and persistent auras can stack with themselves any number of times + if ((!holder->IsPassive() && !holder->IsPersistent()) || holder->IsAreaAura()) + { + SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(aurSpellInfo->Id); + + // take out same spell + for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second; ++iter) + { + SpellAuraHolder* foundHolder = iter->second; + if (foundHolder->GetCasterGuid() == holder->GetCasterGuid()) + { + // Aura can stack on self -> Stack it; + if (aurSpellInfo->GetStackAmount()) + { + // can be created with >1 stack by some spell mods + foundHolder->ModStackAmount(holder->GetStackAmount()); + delete holder; + return false; + } + + // Check for coexisting Weapon-proced Auras + if (holder->IsWeaponBuffCoexistableWith(foundHolder)) + continue; + + // Carry over removed Aura's remaining damage if Aura still has ticks remaining + if (foundHolder->GetSpellProto()->HasAttribute(SPELL_ATTR_EX4_STACK_DOT_MODIFIER)) + { + for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) + { + if (Aura* aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i))) + { + // m_auraname can be modified to SPELL_AURA_NONE for area auras, use original + SpellEffectEntry const* spellEffect = aurSpellInfo->GetSpellEffect(SpellEffectIndex(i)); + AuraType aurNameReal = AuraType(spellEffect ? spellEffect->EffectApplyAuraName : 0); + + if (aurNameReal == SPELL_AURA_PERIODIC_DAMAGE && aur->GetAuraDuration() > 0) + { + if (Aura* existing = foundHolder->GetAuraByEffectIndex(SpellEffectIndex(i))) + { + int32 remainingTicks = existing->GetAuraMaxTicks() - existing->GetAuraTicks(); + int32 remainingDamage = existing->GetModifier()->m_amount * remainingTicks; + + aur->GetModifier()->m_amount += int32(remainingDamage / aur->GetAuraMaxTicks()); + } + else + DEBUG_LOG("Holder (spell %u) on target (lowguid: %u) doesn't have aura on effect index %u. skipping.", aurSpellInfo->Id, holder->GetTarget()->GetGUIDLow(), i); + } + } + } + } + + // can be only single + RemoveSpellAuraHolder(foundHolder, AURA_REMOVE_BY_STACK); + break; + } + + bool stop = false; + + for (int32 i = 0; i < MAX_EFFECT_INDEX && !stop; ++i) + { + // no need to check non stacking auras that weren't/won't be applied on this target + if (!foundHolder->m_auras[i] || !holder->m_auras[i]) + continue; + + // m_auraname can be modified to SPELL_AURA_NONE for area auras, use original + SpellEffectEntry const* spellEffect = aurSpellInfo->GetSpellEffect(SpellEffectIndex(i)); + AuraType aurNameReal = AuraType(spellEffect ? spellEffect->EffectApplyAuraName : SPELL_AURA_NONE); + + switch (aurNameReal) + { + // DoT/HoT/etc + case SPELL_AURA_DUMMY: // allow stack + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: + case SPELL_AURA_PERIODIC_LEECH: + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_OBS_MOD_HEALTH: + case SPELL_AURA_PERIODIC_MANA_LEECH: + case SPELL_AURA_OBS_MOD_MANA: + case SPELL_AURA_POWER_BURN_MANA: + case SPELL_AURA_CONTROL_VEHICLE: + case SPELL_AURA_TRIGGER_LINKED_AURA: + case SPELL_AURA_PERIODIC_DUMMY: + break; + case SPELL_AURA_PERIODIC_ENERGIZE: // all or self or clear non-stackable + default: // not allow + // can be only single (this check done at _each_ aura add + RemoveSpellAuraHolder(foundHolder, AURA_REMOVE_BY_STACK); + stop = true; + break; + } + } + + if (stop) + break; + } + } + + // normal spell or passive auras not stackable with other ranks + if (!IsPassiveSpell(aurSpellInfo) || !IsPassiveSpellStackableWithRanks(aurSpellInfo)) + { + // Hack exceptions for Vehicle/Linked auras + if (!IsSpellHaveAura(aurSpellInfo, SPELL_AURA_CONTROL_VEHICLE) && !IsSpellHaveAura(aurSpellInfo, SPELL_AURA_TRIGGER_LINKED_AURA) && + !RemoveNoStackAurasDueToAuraHolder(holder)) + { + delete holder; + return false; // couldn't remove conflicting aura with higher rank + } + } + + // update tracked aura targets list (before aura add to aura list, to prevent unexpected remove recently added aura) + if (TrackedAuraType trackedType = holder->GetTrackedAuraType()) + { + if (Unit* caster = holder->GetCaster()) // caster not in world + { + // Only compare TrackedAuras of same tracking type + TrackedAuraTargetMap& scTargets = caster->GetTrackedAuraTargets(trackedType); + for (TrackedAuraTargetMap::iterator itr = scTargets.begin(); itr != scTargets.end();) + { + SpellEntry const* itr_spellEntry = itr->first; + ObjectGuid itr_targetGuid = itr->second; // Target on whom the tracked aura is + + if (itr_targetGuid == GetObjectGuid()) // Note: I don't understand this check (based on old aura concepts, kept when adding holders) + { + ++itr; + continue; + } + + bool removed = false; + switch (trackedType) + { + case TRACK_AURA_TYPE_SINGLE_TARGET: + if (IsSingleTargetSpells(itr_spellEntry, aurSpellInfo)) + { + removed = true; + // remove from target if target found + if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid)) + itr_target->RemoveAurasDueToSpell(itr_spellEntry->Id); // TODO AURA_REMOVE_BY_TRACKING (might require additional work elsewhere) + else // Normally the tracking will be removed by the AuraRemoval + scTargets.erase(itr); + } + break; + case TRACK_AURA_TYPE_CONTROL_VEHICLE: + { + // find minimal effect-index that applies an aura + uint8 i = EFFECT_INDEX_0; + for (; i < MAX_EFFECT_INDEX; ++i) + if (IsAuraApplyEffect(aurSpellInfo, SpellEffectIndex(i))) + break; + + // Remove auras when first holder is applied + if ((1 << i) & holder->GetAuraFlags()) + { + removed = true; // each caster can only control one vehicle + + // remove from target if target found + if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid)) + itr_target->RemoveAurasByCasterSpell(itr_spellEntry->Id, caster->GetObjectGuid(), AURA_REMOVE_BY_TRACKING); + else // Normally the tracking will be removed by the AuraRemoval + scTargets.erase(itr); + } + break; + } + case TRACK_AURA_TYPE_NOT_TRACKED: // These two can never happen + case MAX_TRACKED_AURA_TYPES: + MANGOS_ASSERT(false); + break; + } + + if (removed) + { + itr = scTargets.begin(); // list can be chnaged at remove aura + continue; + } + + ++itr; + } + + switch (trackedType) + { + case TRACK_AURA_TYPE_CONTROL_VEHICLE: // Only track the controlled vehicle, no secondary effects + if (!IsSpellHaveAura(aurSpellInfo, SPELL_AURA_CONTROL_VEHICLE, holder->GetAuraFlags())) + break; + // no break here, track other controlled + case TRACK_AURA_TYPE_SINGLE_TARGET: // Register spell holder single target + scTargets[aurSpellInfo] = GetObjectGuid(); + break; + } + } + } + + // add aura, register in lists and arrays + holder->_AddSpellAuraHolder(); + m_spellAuraHolders.insert(SpellAuraHolderMap::value_type(holder->GetId(), holder)); + + for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) + if (Aura* aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i))) + AddAuraToModList(aur); + + holder->ApplyAuraModifiers(true, true); // This is the place where auras are actually applied onto the target + DEBUG_LOG("Holder of spell %u now is in use", holder->GetId()); + + // if aura deleted before boosts apply ignore + // this can be possible it it removed indirectly by triggered spell effect at ApplyModifier + if (holder->IsDeleted()) + { + return false; + } + + holder->HandleSpellSpecificBoosts(true); + + return true; } void Unit::AddAuraToModList(Aura* aura) { - if (aura->GetModifier()->m_auraname < TOTAL_AURAS) - m_modAuras[aura->GetModifier()->m_auraname].push_back(aura); + if (aura->GetModifier()->m_auraname < TOTAL_AURAS) + m_modAuras[aura->GetModifier()->m_auraname].push_back(aura); } void Unit::RemoveRankAurasDueToSpell(uint32 spellId) { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo) - { - return; - } - SpellAuraHolderMap::const_iterator i, next; - for (i = m_spellAuraHolders.begin(); i != m_spellAuraHolders.end(); i = next) - { - next = i; - ++next; - uint32 i_spellId = (*i).second->GetId(); - if ((*i).second && i_spellId && i_spellId != spellId) - { - if (sSpellMgr.IsRankSpellDueToSpell(spellInfo, i_spellId)) - { - RemoveAurasDueToSpell(i_spellId); - - if (m_spellAuraHolders.empty()) - break; - else - next = m_spellAuraHolders.begin(); - } - } - } + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo) + { + return; + } + SpellAuraHolderMap::const_iterator i, next; + for (i = m_spellAuraHolders.begin(); i != m_spellAuraHolders.end(); i = next) + { + next = i; + ++next; + uint32 i_spellId = (*i).second->GetId(); + if ((*i).second && i_spellId && i_spellId != spellId) + { + if (sSpellMgr.IsRankSpellDueToSpell(spellInfo, i_spellId)) + { + RemoveAurasDueToSpell(i_spellId); + + if (m_spellAuraHolders.empty()) + break; + else + next = m_spellAuraHolders.begin(); + } + } + } } bool Unit::RemoveNoStackAurasDueToAuraHolder(SpellAuraHolder* holder) { - if (!holder) - { - return false; - } - - SpellEntry const* spellProto = holder->GetSpellProto(); - if (!spellProto) - { - return false; - } - - uint32 spellId = holder->GetId(); - - // passive spell special case (only non stackable with ranks) - if (IsPassiveSpell(spellProto) && IsPassiveSpellStackableWithRanks(spellProto)) - { - return true; - } - - SpellSpecific spellId_spec = GetSpellSpecific(spellId); - - SpellAuraHolderMap::iterator i, next; - for (i = m_spellAuraHolders.begin(); i != m_spellAuraHolders.end(); i = next) - { - next = i; - ++next; - if (!(*i).second) continue; - - SpellEntry const* i_spellProto = (*i).second->GetSpellProto(); - - if (!i_spellProto) - continue; - - uint32 i_spellId = i_spellProto->Id; - - // early checks that spellId is passive non stackable spell - if (IsPassiveSpell(i_spellProto)) - { - // passive non-stackable spells not stackable only for same caster - if (holder->GetCasterGuid() != i->second->GetCasterGuid()) - continue; - - // passive non-stackable spells not stackable only with another rank of same spell - if (!sSpellMgr.IsRankSpellDueToSpell(spellProto, i_spellId)) - continue; - } - - // prevent triggering aura of removing aura that triggered it - if (((*i).second->GetTriggeredBy() && (*i).second->GetTriggeredBy()->Id == spellId) - || (holder->GetTriggeredBy() && holder->GetTriggeredBy()->Id == i_spellId)) - continue; - - SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId); - - // single allowed spell specific from same caster or from any caster at target - bool is_spellSpecPerTargetPerCaster = IsSingleFromSpellSpecificPerTargetPerCaster(spellId_spec, i_spellId_spec); - bool is_spellSpecPerTarget = IsSingleFromSpellSpecificPerTarget(spellId_spec, i_spellId_spec); - if (is_spellSpecPerTarget || (is_spellSpecPerTargetPerCaster && holder->GetCasterGuid() == (*i).second->GetCasterGuid())) - { - // cannot remove higher rank - if (sSpellMgr.IsRankSpellDueToSpell(spellProto, i_spellId)) - if (CompareAuraRanks(spellId, i_spellId) < 0) - { - return false; - } - - // Its a parent aura (create this aura in ApplyModifier) - if ((*i).second->IsInUse()) - { - sLog.outError("SpellAuraHolder (Spell %u) is in process but attempt removed at SpellAuraHolder (Spell %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAuraHolder", i->second->GetId(), holder->GetId()); - continue; - } - RemoveAurasDueToSpell(i_spellId); - - if (m_spellAuraHolders.empty()) - break; - else - next = m_spellAuraHolders.begin(); - - continue; - } - - // spell with spell specific that allow single ranks for spell from diff caster - // same caster case processed or early or later - bool is_spellPerTarget = IsSingleFromSpellSpecificSpellRanksPerTarget(spellId_spec, i_spellId_spec); - if (is_spellPerTarget && holder->GetCasterGuid() != (*i).second->GetCasterGuid() && sSpellMgr.IsRankSpellDueToSpell(spellProto, i_spellId)) - { - // cannot remove higher rank - if (CompareAuraRanks(spellId, i_spellId) < 0) - { - return false; - } - - // Its a parent aura (create this aura in ApplyModifier) - if ((*i).second->IsInUse()) - { - sLog.outError("SpellAuraHolder (Spell %u) is in process but attempt removed at SpellAuraHolder (Spell %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAuraHolder", i->second->GetId(), holder->GetId()); - continue; - } - RemoveAurasDueToSpell(i_spellId); - - if (m_spellAuraHolders.empty()) - break; - else - next = m_spellAuraHolders.begin(); - - continue; - } - - // non single (per caster) per target spell specific (possible single spell per target at caster) - if (!is_spellSpecPerTargetPerCaster && !is_spellSpecPerTarget) - { - SpellEntry const* triggeredBy = holder->GetTriggeredBy(); - if (triggeredBy && sSpellMgr.IsSpellCanAffectSpell(triggeredBy, i_spellProto)) // check if this spell can be triggered by any talent aura - continue; - - if (sSpellMgr.IsNoStackSpellDueToSpell(spellProto->Id, i_spellProto->Id)) - { - // Its a parent aura (create this aura in ApplyModifier) - if ((*i).second->IsInUse()) - { - sLog.outError("SpellAuraHolder (Spell %u) is in process but attempt removed at SpellAuraHolder (Spell %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAuraHolder", i->second->GetId(), holder->GetId()); - continue; - } - RemoveAurasDueToSpell(i_spellId); - - if (m_spellAuraHolders.empty()) - break; - else - next = m_spellAuraHolders.begin(); - } - continue; - } - - // Potions stack aura by aura (elixirs/flask already checked) - if( spellProto->GetSpellFamilyName() == SPELLFAMILY_POTION && i_spellProto->GetSpellFamilyName() == SPELLFAMILY_POTION ) - { - if (IsNoStackAuraDueToAura(spellId, i_spellId)) - { - if (CompareAuraRanks(spellId, i_spellId) < 0) - return false; // cannot remove higher rank - - // Its a parent aura (create this aura in ApplyModifier) - if ((*i).second->IsInUse()) - { - sLog.outError("SpellAuraHolder (Spell %u) is in process but attempt removed at SpellAuraHolder (Spell %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAuraHolder", i->second->GetId(), holder->GetId()); - continue; - } - RemoveAurasDueToSpell(i_spellId); - - if (m_spellAuraHolders.empty()) - break; - else - next = m_spellAuraHolders.begin(); - } - } - } - return true; + if (!holder) + { + return false; + } + + SpellEntry const* spellProto = holder->GetSpellProto(); + if (!spellProto) + { + return false; + } + + uint32 spellId = holder->GetId(); + + // passive spell special case (only non stackable with ranks) + if (IsPassiveSpell(spellProto) && IsPassiveSpellStackableWithRanks(spellProto)) + { + return true; + } + + SpellSpecific spellId_spec = GetSpellSpecific(spellId); + + SpellAuraHolderMap::iterator i, next; + for (i = m_spellAuraHolders.begin(); i != m_spellAuraHolders.end(); i = next) + { + next = i; + ++next; + if (!(*i).second) continue; + + SpellEntry const* i_spellProto = (*i).second->GetSpellProto(); + + if (!i_spellProto) + continue; + + uint32 i_spellId = i_spellProto->Id; + + // early checks that spellId is passive non stackable spell + if (IsPassiveSpell(i_spellProto)) + { + // passive non-stackable spells not stackable only for same caster + if (holder->GetCasterGuid() != i->second->GetCasterGuid()) + continue; + + // passive non-stackable spells not stackable only with another rank of same spell + if (!sSpellMgr.IsRankSpellDueToSpell(spellProto, i_spellId)) + continue; + } + + // prevent triggering aura of removing aura that triggered it + if (((*i).second->GetTriggeredBy() && (*i).second->GetTriggeredBy()->Id == spellId) + || (holder->GetTriggeredBy() && holder->GetTriggeredBy()->Id == i_spellId)) + continue; + + SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId); + + // single allowed spell specific from same caster or from any caster at target + bool is_spellSpecPerTargetPerCaster = IsSingleFromSpellSpecificPerTargetPerCaster(spellId_spec, i_spellId_spec); + bool is_spellSpecPerTarget = IsSingleFromSpellSpecificPerTarget(spellId_spec, i_spellId_spec); + if (is_spellSpecPerTarget || (is_spellSpecPerTargetPerCaster && holder->GetCasterGuid() == (*i).second->GetCasterGuid())) + { + // cannot remove higher rank + if (sSpellMgr.IsRankSpellDueToSpell(spellProto, i_spellId)) + if (CompareAuraRanks(spellId, i_spellId) < 0) + { + return false; + } + + // Its a parent aura (create this aura in ApplyModifier) + if ((*i).second->IsInUse()) + { + sLog.outError("SpellAuraHolder (Spell %u) is in process but attempt removed at SpellAuraHolder (Spell %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAuraHolder", i->second->GetId(), holder->GetId()); + continue; + } + RemoveAurasDueToSpell(i_spellId); + + if (m_spellAuraHolders.empty()) + break; + else + next = m_spellAuraHolders.begin(); + + continue; + } + + // spell with spell specific that allow single ranks for spell from diff caster + // same caster case processed or early or later + bool is_spellPerTarget = IsSingleFromSpellSpecificSpellRanksPerTarget(spellId_spec, i_spellId_spec); + if (is_spellPerTarget && holder->GetCasterGuid() != (*i).second->GetCasterGuid() && sSpellMgr.IsRankSpellDueToSpell(spellProto, i_spellId)) + { + // cannot remove higher rank + if (CompareAuraRanks(spellId, i_spellId) < 0) + { + return false; + } + + // Its a parent aura (create this aura in ApplyModifier) + if ((*i).second->IsInUse()) + { + sLog.outError("SpellAuraHolder (Spell %u) is in process but attempt removed at SpellAuraHolder (Spell %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAuraHolder", i->second->GetId(), holder->GetId()); + continue; + } + RemoveAurasDueToSpell(i_spellId); + + if (m_spellAuraHolders.empty()) + break; + else + next = m_spellAuraHolders.begin(); + + continue; + } + + // non single (per caster) per target spell specific (possible single spell per target at caster) + if (!is_spellSpecPerTargetPerCaster && !is_spellSpecPerTarget) + { + SpellEntry const* triggeredBy = holder->GetTriggeredBy(); + if (triggeredBy && sSpellMgr.IsSpellCanAffectSpell(triggeredBy, i_spellProto)) // check if this spell can be triggered by any talent aura + continue; + + if (sSpellMgr.IsNoStackSpellDueToSpell(spellProto->Id, i_spellProto->Id)) + { + // Its a parent aura (create this aura in ApplyModifier) + if ((*i).second->IsInUse()) + { + sLog.outError("SpellAuraHolder (Spell %u) is in process but attempt removed at SpellAuraHolder (Spell %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAuraHolder", i->second->GetId(), holder->GetId()); + continue; + } + RemoveAurasDueToSpell(i_spellId); + + if (m_spellAuraHolders.empty()) + break; + else + next = m_spellAuraHolders.begin(); + } + continue; + } + + // Potions stack aura by aura (elixirs/flask already checked) + if (spellProto->GetSpellFamilyName() == SPELLFAMILY_POTION && i_spellProto->GetSpellFamilyName() == SPELLFAMILY_POTION) + { + if (IsNoStackAuraDueToAura(spellId, i_spellId)) + { + if (CompareAuraRanks(spellId, i_spellId) < 0) + return false; // cannot remove higher rank + + // Its a parent aura (create this aura in ApplyModifier) + if ((*i).second->IsInUse()) + { + sLog.outError("SpellAuraHolder (Spell %u) is in process but attempt removed at SpellAuraHolder (Spell %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAuraHolder", i->second->GetId(), holder->GetId()); + continue; + } + RemoveAurasDueToSpell(i_spellId); + + if (m_spellAuraHolders.empty()) + break; + else + next = m_spellAuraHolders.begin(); + } + } + } + return true; } void Unit::RemoveAura(uint32 spellId, SpellEffectIndex effindex, Aura* except) { - SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); - for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second;) - { - Aura* aur = iter->second->m_auras[effindex]; - if (aur && aur != except) - { - RemoveSingleAuraFromSpellAuraHolder(iter->second, effindex); - // may remove holder - spair = GetSpellAuraHolderBounds(spellId); - iter = spair.first; - } - else - ++iter; - } + SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); + for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second;) + { + Aura* aur = iter->second->m_auras[effindex]; + if (aur && aur != except) + { + RemoveSingleAuraFromSpellAuraHolder(iter->second, effindex); + // may remove holder + spair = GetSpellAuraHolderBounds(spellId); + iter = spair.first; + } + else + ++iter; + } } void Unit::RemoveAurasByCasterSpell(uint32 spellId, ObjectGuid casterGuid, AuraRemoveMode mode /*=AURA_REMOVE_BY_DEFAULT*/) { - SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); - for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second;) - { - if (iter->second->GetCasterGuid() == casterGuid) - { - RemoveSpellAuraHolder(iter->second); - spair = GetSpellAuraHolderBounds(spellId); - iter = spair.first; - } - else - ++iter; - } + SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); + for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second;) + { + if (iter->second->GetCasterGuid() == casterGuid) + { + RemoveSpellAuraHolder(iter->second); + spair = GetSpellAuraHolderBounds(spellId); + iter = spair.first; + } + else + ++iter; + } } void Unit::RemoveSingleAuraFromSpellAuraHolder(uint32 spellId, SpellEffectIndex effindex, ObjectGuid casterGuid, AuraRemoveMode mode) { - SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); - for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second;) - { - Aura* aur = iter->second->m_auras[effindex]; - if (aur && aur->GetCasterGuid() == casterGuid) - { - RemoveSingleAuraFromSpellAuraHolder(iter->second, effindex, mode); - spair = GetSpellAuraHolderBounds(spellId); - iter = spair.first; - } - else - ++iter; - } + SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); + for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second;) + { + Aura* aur = iter->second->m_auras[effindex]; + if (aur && aur->GetCasterGuid() == casterGuid) + { + RemoveSingleAuraFromSpellAuraHolder(iter->second, effindex, mode); + spair = GetSpellAuraHolderBounds(spellId); + iter = spair.first; + } + else + ++iter; + } } void Unit::RemoveAuraHolderDueToSpellByDispel(uint32 spellId, uint32 stackAmount, ObjectGuid casterGuid, Unit* dispeller) { - SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId); - SpellClassOptionsEntry const* classOptions = spellEntry->GetSpellClassOptions(); - - // Custom dispel case - // Unstable Affliction - if(classOptions && classOptions->SpellFamilyName == SPELLFAMILY_WARLOCK && (classOptions->SpellFamilyFlags & UI64LIT(0x010000000000))) - { - if (Aura* dotAura = GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, UI64LIT(0x010000000000), 0x00000000, casterGuid)) - { - // use clean value for initial damage - int32 damage = dotAura->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_0); - damage *= 9; - - // Remove spell auras from stack - RemoveAuraHolderFromStack(spellId, stackAmount, casterGuid, AURA_REMOVE_BY_DISPEL); - - // backfire damage and silence - dispeller->CastCustomSpell(dispeller, 31117, &damage, NULL, NULL, true, NULL, NULL, casterGuid); - return; - } - } - // Lifebloom - else if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_DRUID && (classOptions->SpellFamilyFlags & UI64LIT(0x0000001000000000))) - { - if (Aura* dotAura = GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_DRUID, UI64LIT(0x0000001000000000), 0x00000000, casterGuid)) - { - int32 amount = (dotAura->GetModifier()->m_amount / dotAura->GetStackAmount()) * stackAmount; - CastCustomSpell(this, 33778, &amount, NULL, NULL, true, NULL, dotAura, casterGuid); - - if (Unit* caster = dotAura->GetCaster()) - { - int32 returnmana = (spellEntry->GetManaCostPercentage() * caster->GetCreateMana() / 100) * stackAmount / 2; - caster->CastCustomSpell(caster, 64372, &returnmana, NULL, NULL, true, NULL, dotAura, casterGuid); - } - } - } - // Flame Shock - else if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_SHAMAN && (classOptions->SpellFamilyFlags & UI64LIT(0x10000000))) - { - Unit* caster = NULL; - uint32 triggeredSpell = 0; - - if (Aura* dotAura = GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, UI64LIT(0x10000000), 0x00000000, casterGuid)) - caster = dotAura->GetCaster(); - - if (caster && !caster->IsDead()) - { - Unit::AuraList const& auras = caster->GetAurasByType(SPELL_AURA_DUMMY); - for (Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); ++i) - { - switch ((*i)->GetId()) - { - case 51480: triggeredSpell = 64694; break; // Lava Flows, Rank 1 - case 51481: triggeredSpell = 65263; break; // Lava Flows, Rank 2 - case 51482: triggeredSpell = 65264; break; // Lava Flows, Rank 3 - default: continue; - } - break; - } - } - - // Remove spell auras from stack - RemoveAuraHolderFromStack(spellId, stackAmount, casterGuid, AURA_REMOVE_BY_DISPEL); - - // Haste - if (triggeredSpell) - caster->CastSpell(caster, triggeredSpell, true); - return; - } - // Vampiric touch (first dummy aura) - else if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_PRIEST && classOptions->SpellFamilyFlags & UI64LIT(0x0000040000000000)) - { - if (Aura* dot = GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, UI64LIT(0x0000040000000000), 0x00000000, casterGuid)) - { - if (dot->GetCaster()) - { - // use clean value for initial damage - int32 bp0 = dot->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_1); - bp0 *= 8; - - // Remove spell auras from stack - RemoveAuraHolderFromStack(spellId, stackAmount, casterGuid, AURA_REMOVE_BY_DISPEL); - - CastCustomSpell(this, 64085, &bp0, NULL, NULL, true, NULL, NULL, casterGuid); - return; - } - } - } - - RemoveAuraHolderFromStack(spellId, stackAmount, casterGuid, AURA_REMOVE_BY_DISPEL); + SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId); + SpellClassOptionsEntry const* classOptions = spellEntry->GetSpellClassOptions(); + + // Custom dispel case + // Unstable Affliction + if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_WARLOCK && (classOptions->SpellFamilyFlags & UI64LIT(0x010000000000))) + { + if (Aura* dotAura = GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, UI64LIT(0x010000000000), 0x00000000, casterGuid)) + { + // use clean value for initial damage + int32 damage = dotAura->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_0); + damage *= 9; + + // Remove spell auras from stack + RemoveAuraHolderFromStack(spellId, stackAmount, casterGuid, AURA_REMOVE_BY_DISPEL); + + // backfire damage and silence + dispeller->CastCustomSpell(dispeller, 31117, &damage, NULL, NULL, true, NULL, NULL, casterGuid); + return; + } + } + // Lifebloom + else if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_DRUID && (classOptions->SpellFamilyFlags & UI64LIT(0x0000001000000000))) + { + if (Aura* dotAura = GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_DRUID, UI64LIT(0x0000001000000000), 0x00000000, casterGuid)) + { + int32 amount = (dotAura->GetModifier()->m_amount / dotAura->GetStackAmount()) * stackAmount; + CastCustomSpell(this, 33778, &amount, NULL, NULL, true, NULL, dotAura, casterGuid); + + if (Unit* caster = dotAura->GetCaster()) + { + int32 returnmana = (spellEntry->GetManaCostPercentage() * caster->GetCreateMana() / 100) * stackAmount / 2; + caster->CastCustomSpell(caster, 64372, &returnmana, NULL, NULL, true, NULL, dotAura, casterGuid); + } + } + } + // Flame Shock + else if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_SHAMAN && (classOptions->SpellFamilyFlags & UI64LIT(0x10000000))) + { + Unit* caster = NULL; + uint32 triggeredSpell = 0; + + if (Aura* dotAura = GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, UI64LIT(0x10000000), 0x00000000, casterGuid)) + caster = dotAura->GetCaster(); + + if (caster && !caster->IsDead()) + { + Unit::AuraList const& auras = caster->GetAurasByType(SPELL_AURA_DUMMY); + for (Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); ++i) + { + switch ((*i)->GetId()) + { + case 51480: triggeredSpell = 64694; break; // Lava Flows, Rank 1 + case 51481: triggeredSpell = 65263; break; // Lava Flows, Rank 2 + case 51482: triggeredSpell = 65264; break; // Lava Flows, Rank 3 + default: continue; + } + break; + } + } + + // Remove spell auras from stack + RemoveAuraHolderFromStack(spellId, stackAmount, casterGuid, AURA_REMOVE_BY_DISPEL); + + // Haste + if (triggeredSpell) + caster->CastSpell(caster, triggeredSpell, true); + return; + } + // Vampiric touch (first dummy aura) + else if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_PRIEST && classOptions->SpellFamilyFlags & UI64LIT(0x0000040000000000)) + { + if (Aura* dot = GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, UI64LIT(0x0000040000000000), 0x00000000, casterGuid)) + { + if (dot->GetCaster()) + { + // use clean value for initial damage + int32 bp0 = dot->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_1); + bp0 *= 8; + + // Remove spell auras from stack + RemoveAuraHolderFromStack(spellId, stackAmount, casterGuid, AURA_REMOVE_BY_DISPEL); + + CastCustomSpell(this, 64085, &bp0, NULL, NULL, true, NULL, NULL, casterGuid); + return; + } + } + } + + RemoveAuraHolderFromStack(spellId, stackAmount, casterGuid, AURA_REMOVE_BY_DISPEL); } void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGuid, Unit* stealer) { - SpellAuraHolder* holder = GetSpellAuraHolder(spellId, casterGuid); - SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId); - SpellAuraHolder* new_holder = CreateSpellAuraHolder(spellProto, stealer, this); + SpellAuraHolder* holder = GetSpellAuraHolder(spellId, casterGuid); + SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId); + SpellAuraHolder* new_holder = CreateSpellAuraHolder(spellProto, stealer, this); - // set its duration and maximum duration - // max duration 2 minutes (in msecs) - int32 dur = holder->GetAuraDuration(); - int32 max_dur = 2 * MINUTE * IN_MILLISECONDS; - int32 new_max_dur = max_dur > dur ? dur : max_dur; - new_holder->SetAuraMaxDuration(new_max_dur); - new_holder->SetAuraDuration(new_max_dur); + // set its duration and maximum duration + // max duration 2 minutes (in msecs) + int32 dur = holder->GetAuraDuration(); + int32 max_dur = 2 * MINUTE * IN_MILLISECONDS; + int32 new_max_dur = max_dur > dur ? dur : max_dur; + new_holder->SetAuraMaxDuration(new_max_dur); + new_holder->SetAuraDuration(new_max_dur); - for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) - { - Aura* aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i)); + for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) + { + Aura* aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i)); - if (!aur) - continue; + if (!aur) + continue; - int32 basePoints = aur->GetBasePoints(); - // construct the new aura for the attacker - will never return NULL, it's just a wrapper for - // some different constructors - Aura* new_aur = CreateAura(spellProto, aur->GetEffIndex(), &basePoints, new_holder, stealer, this); + int32 basePoints = aur->GetBasePoints(); + // construct the new aura for the attacker - will never return NULL, it's just a wrapper for + // some different constructors + Aura* new_aur = CreateAura(spellProto, aur->GetEffIndex(), &basePoints, new_holder, stealer, this); - // set periodic to do at least one tick (for case when original aura has been at last tick preparing) - int32 periodic = aur->GetModifier()->periodictime; - new_aur->GetModifier()->periodictime = periodic < new_max_dur ? periodic : new_max_dur; + // set periodic to do at least one tick (for case when original aura has been at last tick preparing) + int32 periodic = aur->GetModifier()->periodictime; + new_aur->GetModifier()->periodictime = periodic < new_max_dur ? periodic : new_max_dur; - // add the new aura to stealer - new_holder->AddAura(new_aur, new_aur->GetEffIndex()); - } + // add the new aura to stealer + new_holder->AddAura(new_aur, new_aur->GetEffIndex()); + } - if (holder->ModStackAmount(-1)) - // Remove aura as dispel - RemoveSpellAuraHolder(holder, AURA_REMOVE_BY_DISPEL); + if (holder->ModStackAmount(-1)) + // Remove aura as dispel + RemoveSpellAuraHolder(holder, AURA_REMOVE_BY_DISPEL); - // strange but intended behaviour: Stolen single target auras won't be treated as single targeted - new_holder->SetTrackedAuraType(TRACK_AURA_TYPE_NOT_TRACKED); + // strange but intended behaviour: Stolen single target auras won't be treated as single targeted + new_holder->SetTrackedAuraType(TRACK_AURA_TYPE_NOT_TRACKED); - stealer->AddSpellAuraHolder(new_holder); + stealer->AddSpellAuraHolder(new_holder); } void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId) { - SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); - for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second;) - { - RemoveSpellAuraHolder(iter->second, AURA_REMOVE_BY_CANCEL); - spair = GetSpellAuraHolderBounds(spellId); - iter = spair.first; - } + SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); + for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second;) + { + RemoveSpellAuraHolder(iter->second, AURA_REMOVE_BY_CANCEL); + spair = GetSpellAuraHolderBounds(spellId); + iter = spair.first; + } } void Unit::RemoveAurasWithDispelType(DispelType type, ObjectGuid casterGuid) { - // Create dispel mask by dispel type - uint32 dispelMask = GetDispellMask(type); - // Dispel all existing auras vs current dispel type - SpellAuraHolderMap& auras = GetSpellAuraHolderMap(); - for (SpellAuraHolderMap::iterator itr = auras.begin(); itr != auras.end();) - { - SpellEntry const* spell = itr->second->GetSpellProto(); - if (((1<GetDispel()) & dispelMask) && (!casterGuid || casterGuid == itr->second->GetCasterGuid())) - { - // Dispel aura - RemoveAurasDueToSpell(spell->Id); - itr = auras.begin(); - } - else - ++itr; - } + // Create dispel mask by dispel type + uint32 dispelMask = GetDispellMask(type); + // Dispel all existing auras vs current dispel type + SpellAuraHolderMap& auras = GetSpellAuraHolderMap(); + for (SpellAuraHolderMap::iterator itr = auras.begin(); itr != auras.end();) + { + SpellEntry const* spell = itr->second->GetSpellProto(); + if (((1 << spell->GetDispel()) & dispelMask) && (!casterGuid || casterGuid == itr->second->GetCasterGuid())) + { + // Dispel aura + RemoveAurasDueToSpell(spell->Id); + itr = auras.begin(); + } + else + ++itr; + } } void Unit::RemoveAuraHolderFromStack(uint32 spellId, uint32 stackAmount, ObjectGuid casterGuid, AuraRemoveMode mode) { - SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); - for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second; ++iter) - { - if (!casterGuid || iter->second->GetCasterGuid() == casterGuid) - { - if (iter->second->ModStackAmount(-int32(stackAmount))) - { - RemoveSpellAuraHolder(iter->second, mode); - break; - } - } - } + SpellAuraHolderBounds spair = GetSpellAuraHolderBounds(spellId); + for (SpellAuraHolderMap::iterator iter = spair.first; iter != spair.second; ++iter) + { + if (!casterGuid || iter->second->GetCasterGuid() == casterGuid) + { + if (iter->second->ModStackAmount(-int32(stackAmount))) + { + RemoveSpellAuraHolder(iter->second, mode); + break; + } + } + } } void Unit::RemoveAurasDueToSpell(uint32 spellId, SpellAuraHolder* except, AuraRemoveMode mode) { - // FIXME - //SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId); - //if (spellEntry && spellEntry->SpellDifficultyId && IsInWorld() && GetMap()->IsDungeon()) - // if (SpellEntry const* spellDiffEntry = GetSpellEntryByDifficulty(spellEntry->SpellDifficultyId, GetMap()->GetDifficulty(), GetMap()->IsRaid())) - // spellId = spellDiffEntry->Id; - - SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId); - for (SpellAuraHolderMap::iterator iter = bounds.first; iter != bounds.second;) - { - if (iter->second != except) - { - RemoveSpellAuraHolder(iter->second, mode); - bounds = GetSpellAuraHolderBounds(spellId); - iter = bounds.first; - } - else - ++iter; - } + // FIXME + //SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId); + //if (spellEntry && spellEntry->SpellDifficultyId && IsInWorld() && GetMap()->IsDungeon()) + // if (SpellEntry const* spellDiffEntry = GetSpellEntryByDifficulty(spellEntry->SpellDifficultyId, GetMap()->GetDifficulty(), GetMap()->IsRaid())) + // spellId = spellDiffEntry->Id; + + SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId); + for (SpellAuraHolderMap::iterator iter = bounds.first; iter != bounds.second;) + { + if (iter->second != except) + { + RemoveSpellAuraHolder(iter->second, mode); + bounds = GetSpellAuraHolderBounds(spellId); + iter = bounds.first; + } + else + ++iter; + } } void Unit::RemoveAurasDueToItemSpell(Item* castItem, uint32 spellId) { - SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId); - for (SpellAuraHolderMap::iterator iter = bounds.first; iter != bounds.second;) - { - if (iter->second->GetCastItemGuid() == castItem->GetObjectGuid()) - { - RemoveSpellAuraHolder(iter->second); - bounds = GetSpellAuraHolderBounds(spellId); - iter = bounds.first; - } - else - ++iter; - } + SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId); + for (SpellAuraHolderMap::iterator iter = bounds.first; iter != bounds.second;) + { + if (iter->second->GetCastItemGuid() == castItem->GetObjectGuid()) + { + RemoveSpellAuraHolder(iter->second); + bounds = GetSpellAuraHolderBounds(spellId); + iter = bounds.first; + } + else + ++iter; + } } void Unit::RemoveAurasWithInterruptFlags(uint32 flags) { - for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) - { - if (iter->second->GetSpellProto()->GetAuraInterruptFlags() & flags) - { - RemoveSpellAuraHolder(iter->second); - iter = m_spellAuraHolders.begin(); - } - else - ++iter; - } + for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) + { + if (iter->second->GetSpellProto()->GetAuraInterruptFlags() & flags) + { + RemoveSpellAuraHolder(iter->second); + iter = m_spellAuraHolders.begin(); + } + else + ++iter; + } } void Unit::RemoveAurasWithAttribute(uint32 flags) { - for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) - { - if (iter->second->GetSpellProto()->HasAttribute((SpellAttributes)flags)) - { - RemoveSpellAuraHolder(iter->second); - iter = m_spellAuraHolders.begin(); - } - else - ++iter; - } + for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) + { + if (iter->second->GetSpellProto()->HasAttribute((SpellAttributes)flags)) + { + RemoveSpellAuraHolder(iter->second); + iter = m_spellAuraHolders.begin(); + } + else + ++iter; + } } void Unit::RemoveAurasOnCast(SpellEntry const* castedSpellEntry) { - for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) - { - SpellAuraHolder* holder = iter->second; - SpellEntry const* spellEntry = holder->GetSpellProto(); - bool removeThisHolder = false; - - if (spellEntry->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_UNK2) - { - if (castedSpellEntry->HasAttribute(SPELL_ATTR_EX_NOT_BREAK_STEALTH)) - { - bool foundStealth = false; - for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) - { - if (Aura* aura = holder->m_auras[i]) - { - if (aura->GetModifier()->m_auraname == SPELL_AURA_MOD_STEALTH) - { - foundStealth = true; - break; - } - } - } - removeThisHolder = !foundStealth; - } - else - removeThisHolder = true; - } - - if (removeThisHolder) - { - RemoveSpellAuraHolder(iter->second); - iter = m_spellAuraHolders.begin(); - } - else - ++iter; - } + for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) + { + SpellAuraHolder* holder = iter->second; + SpellEntry const* spellEntry = holder->GetSpellProto(); + bool removeThisHolder = false; + + if (spellEntry->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_UNK2) + { + if (castedSpellEntry->HasAttribute(SPELL_ATTR_EX_NOT_BREAK_STEALTH)) + { + bool foundStealth = false; + for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) + { + if (Aura* aura = holder->m_auras[i]) + { + if (aura->GetModifier()->m_auraname == SPELL_AURA_MOD_STEALTH) + { + foundStealth = true; + break; + } + } + } + removeThisHolder = !foundStealth; + } + else + removeThisHolder = true; + } + + if (removeThisHolder) + { + RemoveSpellAuraHolder(iter->second); + iter = m_spellAuraHolders.begin(); + } + else + ++iter; + } } void Unit::RemoveNotOwnTrackedTargetAuras(uint32 newPhase) { - // tracked aura targets from other casters are removed if the phase does no more fit - for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) - { - TrackedAuraType trackedType = iter->second->GetTrackedAuraType(); - if (!trackedType) - { - ++iter; - continue; - } - - if (trackedType == TRACK_AURA_TYPE_CONTROL_VEHICLE || iter->second->GetCasterGuid() != GetObjectGuid()) - { - if (!newPhase) - { - RemoveSpellAuraHolder(iter->second); - iter = m_spellAuraHolders.begin(); - continue; - } - else - { - Unit* caster = iter->second->GetCaster(); - if (!caster || !caster->InSamePhase(newPhase)) - { - RemoveSpellAuraHolder(iter->second); - iter = m_spellAuraHolders.begin(); - continue; - } - } - } - - ++iter; - } - - // tracked aura targets at other targets - for (uint8 type = TRACK_AURA_TYPE_SINGLE_TARGET; type < MAX_TRACKED_AURA_TYPES; ++type) - { - TrackedAuraTargetMap& scTargets = GetTrackedAuraTargets(TrackedAuraType(type)); - for (TrackedAuraTargetMap::iterator itr = scTargets.begin(); itr != scTargets.end();) - { - SpellEntry const* itr_spellEntry = itr->first; - ObjectGuid itr_targetGuid = itr->second; - - if (itr_targetGuid != GetObjectGuid()) - { - if (!newPhase) - { - scTargets.erase(itr); // remove for caster in any case - - // remove from target if target found - if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid)) - itr_target->RemoveAurasByCasterSpell(itr_spellEntry->Id, GetObjectGuid()); - - itr = scTargets.begin(); // list can be changed at remove aura - continue; - } - else - { - Unit* itr_target = GetMap()->GetUnit(itr_targetGuid); - if (!itr_target || !itr_target->InSamePhase(newPhase)) - { - scTargets.erase(itr); // remove for caster in any case - - // remove from target if target found - if (itr_target) - itr_target->RemoveAurasByCasterSpell(itr_spellEntry->Id, GetObjectGuid()); - - itr = scTargets.begin(); // list can be changed at remove aura - continue; - } - } - } - - ++itr; - } - } + // tracked aura targets from other casters are removed if the phase does no more fit + for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) + { + TrackedAuraType trackedType = iter->second->GetTrackedAuraType(); + if (!trackedType) + { + ++iter; + continue; + } + + if (trackedType == TRACK_AURA_TYPE_CONTROL_VEHICLE || iter->second->GetCasterGuid() != GetObjectGuid()) + { + if (!newPhase) + { + RemoveSpellAuraHolder(iter->second); + iter = m_spellAuraHolders.begin(); + continue; + } + else + { + Unit* caster = iter->second->GetCaster(); + if (!caster || !caster->InSamePhase(newPhase)) + { + RemoveSpellAuraHolder(iter->second); + iter = m_spellAuraHolders.begin(); + continue; + } + } + } + + ++iter; + } + + // tracked aura targets at other targets + for (uint8 type = TRACK_AURA_TYPE_SINGLE_TARGET; type < MAX_TRACKED_AURA_TYPES; ++type) + { + TrackedAuraTargetMap& scTargets = GetTrackedAuraTargets(TrackedAuraType(type)); + for (TrackedAuraTargetMap::iterator itr = scTargets.begin(); itr != scTargets.end();) + { + SpellEntry const* itr_spellEntry = itr->first; + ObjectGuid itr_targetGuid = itr->second; + + if (itr_targetGuid != GetObjectGuid()) + { + if (!newPhase) + { + scTargets.erase(itr); // remove for caster in any case + + // remove from target if target found + if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid)) + itr_target->RemoveAurasByCasterSpell(itr_spellEntry->Id, GetObjectGuid()); + + itr = scTargets.begin(); // list can be changed at remove aura + continue; + } + else + { + Unit* itr_target = GetMap()->GetUnit(itr_targetGuid); + if (!itr_target || !itr_target->InSamePhase(newPhase)) + { + scTargets.erase(itr); // remove for caster in any case + + // remove from target if target found + if (itr_target) + itr_target->RemoveAurasByCasterSpell(itr_spellEntry->Id, GetObjectGuid()); + + itr = scTargets.begin(); // list can be changed at remove aura + continue; + } + } + } + + ++itr; + } + } } void Unit::RemoveSpellAuraHolder(SpellAuraHolder* holder, AuraRemoveMode mode) { - // Statue unsummoned at holder remove - SpellEntry const* AurSpellInfo = holder->GetSpellProto(); - Totem* statue = NULL; - Unit* caster = holder->GetCaster(); - if (IsChanneledSpell(AurSpellInfo) && caster) - if (caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->IsTotem() && ((Totem*)caster)->GetTotemType() == TOTEM_STATUE) - statue = ((Totem*)caster); - - if (m_spellAuraHoldersUpdateIterator != m_spellAuraHolders.end() && m_spellAuraHoldersUpdateIterator->second == holder) - ++m_spellAuraHoldersUpdateIterator; - - SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(holder->GetId()); - for (SpellAuraHolderMap::iterator itr = bounds.first; itr != bounds.second; ++itr) - { - if (itr->second == holder) - { - m_spellAuraHolders.erase(itr); - break; - } - } - - holder->SetRemoveMode(mode); - holder->UnregisterAndCleanupTrackedAuras(); - - for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) - { - if (Aura* aura = holder->m_auras[i]) - RemoveAura(aura, mode); - } - - holder->_RemoveSpellAuraHolder(); - - if (mode != AURA_REMOVE_BY_DELETE) - holder->HandleSpellSpecificBoosts(false); - - if (statue) - statue->UnSummon(); - - // If holder in use (removed from code that plan access to it data after return) - // store it in holder list with delayed deletion - if (holder->IsInUse()) - { - holder->SetDeleted(); - m_deletedHolders.push_back(holder); - } - else - delete holder; - - if (mode != AURA_REMOVE_BY_EXPIRE && IsChanneledSpell(AurSpellInfo) && !IsAreaOfEffectSpell(AurSpellInfo) && - caster && caster->GetObjectGuid() != GetObjectGuid()) - { - caster->InterruptSpell(CURRENT_CHANNELED_SPELL); - } + // Statue unsummoned at holder remove + SpellEntry const* AurSpellInfo = holder->GetSpellProto(); + Totem* statue = NULL; + Unit* caster = holder->GetCaster(); + if (IsChanneledSpell(AurSpellInfo) && caster) + if (caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->IsTotem() && ((Totem*)caster)->GetTotemType() == TOTEM_STATUE) + statue = ((Totem*)caster); + + if (m_spellAuraHoldersUpdateIterator != m_spellAuraHolders.end() && m_spellAuraHoldersUpdateIterator->second == holder) + ++m_spellAuraHoldersUpdateIterator; + + SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(holder->GetId()); + for (SpellAuraHolderMap::iterator itr = bounds.first; itr != bounds.second; ++itr) + { + if (itr->second == holder) + { + m_spellAuraHolders.erase(itr); + break; + } + } + + holder->SetRemoveMode(mode); + holder->UnregisterAndCleanupTrackedAuras(); + + for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) + { + if (Aura* aura = holder->m_auras[i]) + RemoveAura(aura, mode); + } + + holder->_RemoveSpellAuraHolder(); + + if (mode != AURA_REMOVE_BY_DELETE) + holder->HandleSpellSpecificBoosts(false); + + if (statue) + statue->UnSummon(); + + // If holder in use (removed from code that plan access to it data after return) + // store it in holder list with delayed deletion + if (holder->IsInUse()) + { + holder->SetDeleted(); + m_deletedHolders.push_back(holder); + } + else + delete holder; + + if (mode != AURA_REMOVE_BY_EXPIRE && IsChanneledSpell(AurSpellInfo) && !IsAreaOfEffectSpell(AurSpellInfo) && + caster && caster->GetObjectGuid() != GetObjectGuid()) + { + caster->InterruptSpell(CURRENT_CHANNELED_SPELL); + } } void Unit::RemoveSingleAuraFromSpellAuraHolder(SpellAuraHolder* holder, SpellEffectIndex index, AuraRemoveMode mode) { - Aura* aura = holder->GetAuraByEffectIndex(index); - if (!aura) - { - return; - } + Aura* aura = holder->GetAuraByEffectIndex(index); + if (!aura) + { + return; + } - if (aura->IsLastAuraOnHolder()) - RemoveSpellAuraHolder(holder, mode); - else - RemoveAura(aura, mode); + if (aura->IsLastAuraOnHolder()) + RemoveSpellAuraHolder(holder, mode); + else + RemoveAura(aura, mode); } void Unit::RemoveAura(Aura* Aur, AuraRemoveMode mode) { - // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order) - if (Aur->GetModifier()->m_auraname < TOTAL_AURAS) - { - m_modAuras[Aur->GetModifier()->m_auraname].remove(Aur); - } - - // Set remove mode - Aur->SetRemoveMode(mode); - - // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura - // remove aura from list before to prevent deleting it before - /// m_Auras.erase(i); - - DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Aura %u now is remove mode %d", Aur->GetModifier()->m_auraname, mode); - - // aura _MUST_ be remove from holder before unapply. - // un-apply code expected that aura not find by diff searches - // in another case it can be double removed for example, if target die/etc in un-apply process. - Aur->GetHolder()->RemoveAura(Aur->GetEffIndex()); - - // some auras also need to apply modifier (on caster) on remove - if (mode == AURA_REMOVE_BY_DELETE) - { - switch (Aur->GetModifier()->m_auraname) - { - // need properly undo any auras with player-caster mover set (or will crash at next caster move packet) - case SPELL_AURA_MOD_POSSESS: - case SPELL_AURA_MOD_POSSESS_PET: - case SPELL_AURA_CONTROL_VEHICLE: - Aur->ApplyModifier(false, true); - break; - default: break; - } - } - else - Aur->ApplyModifier(false, true); - - // If aura in use (removed from code that plan access to it data after return) - // store it in aura list with delayed deletion - if (Aur->IsInUse()) - m_deletedAuras.push_back(Aur); - else - delete Aur; + // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order) + if (Aur->GetModifier()->m_auraname < TOTAL_AURAS) + { + m_modAuras[Aur->GetModifier()->m_auraname].remove(Aur); + } + + // Set remove mode + Aur->SetRemoveMode(mode); + + // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura + // remove aura from list before to prevent deleting it before + /// m_Auras.erase(i); + + DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Aura %u now is remove mode %d", Aur->GetModifier()->m_auraname, mode); + + // aura _MUST_ be remove from holder before unapply. + // un-apply code expected that aura not find by diff searches + // in another case it can be double removed for example, if target die/etc in un-apply process. + Aur->GetHolder()->RemoveAura(Aur->GetEffIndex()); + + // some auras also need to apply modifier (on caster) on remove + if (mode == AURA_REMOVE_BY_DELETE) + { + switch (Aur->GetModifier()->m_auraname) + { + // need properly undo any auras with player-caster mover set (or will crash at next caster move packet) + case SPELL_AURA_MOD_POSSESS: + case SPELL_AURA_MOD_POSSESS_PET: + case SPELL_AURA_CONTROL_VEHICLE: + Aur->ApplyModifier(false, true); + break; + default: break; + } + } + else + Aur->ApplyModifier(false, true); + + // If aura in use (removed from code that plan access to it data after return) + // store it in aura list with delayed deletion + if (Aur->IsInUse()) + m_deletedAuras.push_back(Aur); + else + delete Aur; } void Unit::RemoveAllAuras(AuraRemoveMode mode /*= AURA_REMOVE_BY_DEFAULT*/) { - while (!m_spellAuraHolders.empty()) - { - SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); - RemoveSpellAuraHolder(iter->second, mode); - } + while (!m_spellAuraHolders.empty()) + { + SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); + RemoveSpellAuraHolder(iter->second, mode); + } } void Unit::RemoveArenaAuras(bool onleave) { - // in join, remove positive buffs, on end, remove negative - // used to remove positive visible auras in arenas - for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) - { - if (!iter->second->GetSpellProto()->HasAttribute(SPELL_ATTR_EX4_UNK21) && - // don't remove stances, shadowform, pally/hunter auras - !iter->second->IsPassive() && // don't remove passive auras - (!iter->second->GetSpellProto()->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) || - !iter->second->GetSpellProto()->HasAttribute(SPELL_ATTR_UNK8)) && - // not unaffected by invulnerability auras or not having that unknown flag (that seemed the most probable) - (iter->second->IsPositive() != onleave)) // remove positive buffs on enter, negative buffs on leave - { - RemoveSpellAuraHolder(iter->second); - iter = m_spellAuraHolders.begin(); - } - else - ++iter; - } + // in join, remove positive buffs, on end, remove negative + // used to remove positive visible auras in arenas + for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) + { + if (!iter->second->GetSpellProto()->HasAttribute(SPELL_ATTR_EX4_UNK21) && + // don't remove stances, shadowform, pally/hunter auras + !iter->second->IsPassive() && // don't remove passive auras + (!iter->second->GetSpellProto()->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) || + !iter->second->GetSpellProto()->HasAttribute(SPELL_ATTR_UNK8)) && + // not unaffected by invulnerability auras or not having that unknown flag (that seemed the most probable) + (iter->second->IsPositive() != onleave)) // remove positive buffs on enter, negative buffs on leave + { + RemoveSpellAuraHolder(iter->second); + iter = m_spellAuraHolders.begin(); + } + else + ++iter; + } } void Unit::RemoveAllAurasOnDeath() { - // used just after dieing to remove all visible auras - // and disable the mods for the passive ones - for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) - { - if (!iter->second->IsPassive() && !iter->second->IsDeathPersistent()) - { - RemoveSpellAuraHolder(iter->second, AURA_REMOVE_BY_DEATH); - iter = m_spellAuraHolders.begin(); - } - else - ++iter; - } + // used just after dieing to remove all visible auras + // and disable the mods for the passive ones + for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) + { + if (!iter->second->IsPassive() && !iter->second->IsDeathPersistent()) + { + RemoveSpellAuraHolder(iter->second, AURA_REMOVE_BY_DEATH); + iter = m_spellAuraHolders.begin(); + } + else + ++iter; + } } void Unit::RemoveAllAurasOnEvade() { - // used when evading to remove all auras except some special auras - // Vehicle control auras / Fly should not be removed on evade - neither should linked auras - for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) - { - SpellEntry const* proto = iter->second->GetSpellProto(); - if (!IsSpellHaveAura(proto, SPELL_AURA_CONTROL_VEHICLE) && !IsSpellHaveAura(proto, SPELL_AURA_FLY)) - { - RemoveSpellAuraHolder(iter->second, AURA_REMOVE_BY_DEFAULT); - iter = m_spellAuraHolders.begin(); - } - else - ++iter; - } + // used when evading to remove all auras except some special auras + // Vehicle control auras / Fly should not be removed on evade - neither should linked auras + for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) + { + SpellEntry const* proto = iter->second->GetSpellProto(); + if (!IsSpellHaveAura(proto, SPELL_AURA_CONTROL_VEHICLE) && !IsSpellHaveAura(proto, SPELL_AURA_FLY)) + { + RemoveSpellAuraHolder(iter->second, AURA_REMOVE_BY_DEFAULT); + iter = m_spellAuraHolders.begin(); + } + else + ++iter; + } } void Unit::DelaySpellAuraHolder(uint32 spellId, int32 delaytime, ObjectGuid casterGuid) { - SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId); - for (SpellAuraHolderMap::iterator iter = bounds.first; iter != bounds.second; ++iter) - { - SpellAuraHolder* holder = iter->second; + SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId); + for (SpellAuraHolderMap::iterator iter = bounds.first; iter != bounds.second; ++iter) + { + SpellAuraHolder* holder = iter->second; - if (casterGuid != holder->GetCasterGuid()) - continue; + if (casterGuid != holder->GetCasterGuid()) + continue; - if (holder->GetAuraDuration() < delaytime) - holder->SetAuraDuration(0); - else - holder->SetAuraDuration(holder->GetAuraDuration() - delaytime); + if (holder->GetAuraDuration() < delaytime) + holder->SetAuraDuration(0); + else + holder->SetAuraDuration(holder->GetAuraDuration() - delaytime); - holder->SendAuraUpdate(false); + holder->SendAuraUpdate(false); - DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u partially interrupted on %s, new duration: %u ms", spellId, GetGuidStr().c_str(), holder->GetAuraDuration()); - } + DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u partially interrupted on %s, new duration: %u ms", spellId, GetGuidStr().c_str(), holder->GetAuraDuration()); + } } void Unit::_RemoveAllAuraMods() { - for (SpellAuraHolderMap::const_iterator i = m_spellAuraHolders.begin(); i != m_spellAuraHolders.end(); ++i) - { - (*i).second->ApplyAuraModifiers(false); - } + for (SpellAuraHolderMap::const_iterator i = m_spellAuraHolders.begin(); i != m_spellAuraHolders.end(); ++i) + { + (*i).second->ApplyAuraModifiers(false); + } } void Unit::_ApplyAllAuraMods() { - for (SpellAuraHolderMap::const_iterator i = m_spellAuraHolders.begin(); i != m_spellAuraHolders.end(); ++i) - { - (*i).second->ApplyAuraModifiers(true); - } + for (SpellAuraHolderMap::const_iterator i = m_spellAuraHolders.begin(); i != m_spellAuraHolders.end(); ++i) + { + (*i).second->ApplyAuraModifiers(true); + } } bool Unit::HasAuraType(AuraType auraType) const { - return !GetAurasByType(auraType).empty(); + return !GetAurasByType(auraType).empty(); } bool Unit::HasAffectedAura(AuraType auraType, SpellEntry const* spellProto) const { - Unit::AuraList const& auras = GetAurasByType(auraType); + Unit::AuraList const& auras = GetAurasByType(auraType); - for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - if ((*itr)->isAffectedOnSpell(spellProto)) - { - return true; - } - } + for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + if ((*itr)->isAffectedOnSpell(spellProto)) + { + return true; + } + } - return false; + return false; } Aura* Unit::GetAura(uint32 spellId, SpellEffectIndex effindex) { - SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId); - if (bounds.first != bounds.second) - { - return bounds.first->second->GetAuraByEffectIndex(effindex); - } - return NULL; + SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId); + if (bounds.first != bounds.second) + { + return bounds.first->second->GetAuraByEffectIndex(effindex); + } + return NULL; } Aura* Unit::GetAura(AuraType type, SpellFamily family, uint64 familyFlag, uint32 familyFlag2, ObjectGuid casterGuid) { - AuraList const& auras = GetAurasByType(type); - for (AuraList::const_iterator i = auras.begin(); i != auras.end(); ++i) - if ((*i)->GetSpellProto()->IsFitToFamily(family, familyFlag, familyFlag2) && - (!casterGuid || (*i)->GetCasterGuid() == casterGuid)) - return *i; + AuraList const& auras = GetAurasByType(type); + for (AuraList::const_iterator i = auras.begin(); i != auras.end(); ++i) + if ((*i)->GetSpellProto()->IsFitToFamily(family, familyFlag, familyFlag2) && + (!casterGuid || (*i)->GetCasterGuid() == casterGuid)) + return *i; - return NULL; + return NULL; } Aura* Unit::GetTriggeredByClientAura(uint32 spellId) const { - MANGOS_ASSERT(spellId); + MANGOS_ASSERT(spellId); - AuraList const& auras = GetAurasByType(SPELL_AURA_PERIODIC_TRIGGER_BY_CLIENT); - for (AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - SpellAuraHolder const* holder = (*itr)->GetHolder(); - if (!holder || holder->IsDeleted()) - continue; + AuraList const& auras = GetAurasByType(SPELL_AURA_PERIODIC_TRIGGER_BY_CLIENT); + for (AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + SpellAuraHolder const* holder = (*itr)->GetHolder(); + if (!holder || holder->IsDeleted()) + continue; - SpellEffectEntry const* spellEffect = holder->GetSpellProto()->GetSpellEffect(SpellEffectIndex((*itr)->GetEffIndex())); - if(!spellEffect) - continue; + SpellEffectEntry const* spellEffect = holder->GetSpellProto()->GetSpellEffect(SpellEffectIndex((*itr)->GetEffIndex())); + if (!spellEffect) + continue; - // NOTE for further development: If there are more spells of this aura type, it might be required to check that this is the effect that applies SPELL_AURA_PERIODIC_TRIGGER_BY_CLIENT - if (holder->GetCasterGuid() == GetObjectGuid() && spellEffect->EffectTriggerSpell == spellId) - { - return *itr; - } - } + // NOTE for further development: If there are more spells of this aura type, it might be required to check that this is the effect that applies SPELL_AURA_PERIODIC_TRIGGER_BY_CLIENT + if (holder->GetCasterGuid() == GetObjectGuid() && spellEffect->EffectTriggerSpell == spellId) + { + return *itr; + } + } - return NULL; + return NULL; } bool Unit::HasAura(uint32 spellId, SpellEffectIndex effIndex) const { - SpellAuraHolderConstBounds spair = GetSpellAuraHolderBounds(spellId); - for (SpellAuraHolderMap::const_iterator i_holder = spair.first; i_holder != spair.second; ++i_holder) - if (i_holder->second->GetAuraByEffectIndex(effIndex)) - { - return true; - } + SpellAuraHolderConstBounds spair = GetSpellAuraHolderBounds(spellId); + for (SpellAuraHolderMap::const_iterator i_holder = spair.first; i_holder != spair.second; ++i_holder) + if (i_holder->second->GetAuraByEffectIndex(effIndex)) + { + return true; + } - return false; + return false; } bool Unit::HasAuraOfDifficulty(uint32 spellId) const { - // FIXME - //SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId); - //if (spellEntry && spellEntry->SpellDifficultyId && IsInWorld() && GetMap()->IsDungeon()) - // if (SpellEntry const* spellDiffEntry = GetSpellEntryByDifficulty(spellEntry->SpellDifficultyId, GetMap()->GetDifficulty(), GetMap()->IsRaid())) - // spellId = spellDiffEntry->Id; + // FIXME + //SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId); + //if (spellEntry && spellEntry->SpellDifficultyId && IsInWorld() && GetMap()->IsDungeon()) + // if (SpellEntry const* spellDiffEntry = GetSpellEntryByDifficulty(spellEntry->SpellDifficultyId, GetMap()->GetDifficulty(), GetMap()->IsRaid())) + // spellId = spellDiffEntry->Id; - return m_spellAuraHolders.find(spellId) != m_spellAuraHolders.end(); + return m_spellAuraHolders.find(spellId) != m_spellAuraHolders.end(); } void Unit::AddDynObject(DynamicObject* dynObj) { - m_dynObjGUIDs.push_back(dynObj->GetObjectGuid()); + m_dynObjGUIDs.push_back(dynObj->GetObjectGuid()); } void Unit::RemoveDynObject(uint32 spellid) { - if (m_dynObjGUIDs.empty()) - { - return; - } - for (GuidList::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) - { - DynamicObject* dynObj = GetMap()->GetDynamicObject(*i); - if (!dynObj) - { - i = m_dynObjGUIDs.erase(i); - } - else if (spellid == 0 || dynObj->GetSpellId() == spellid) - { - dynObj->Delete(); - i = m_dynObjGUIDs.erase(i); - } - else - ++i; - } + if (m_dynObjGUIDs.empty()) + { + return; + } + for (GuidList::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) + { + DynamicObject* dynObj = GetMap()->GetDynamicObject(*i); + if (!dynObj) + { + i = m_dynObjGUIDs.erase(i); + } + else if (spellid == 0 || dynObj->GetSpellId() == spellid) + { + dynObj->Delete(); + i = m_dynObjGUIDs.erase(i); + } + else + ++i; + } } void Unit::RemoveAllDynObjects() { - while (!m_dynObjGUIDs.empty()) - { - if (DynamicObject* dynObj = GetMap()->GetDynamicObject(*m_dynObjGUIDs.begin())) - dynObj->Delete(); - m_dynObjGUIDs.erase(m_dynObjGUIDs.begin()); - } + while (!m_dynObjGUIDs.empty()) + { + if (DynamicObject* dynObj = GetMap()->GetDynamicObject(*m_dynObjGUIDs.begin())) + dynObj->Delete(); + m_dynObjGUIDs.erase(m_dynObjGUIDs.begin()); + } } DynamicObject* Unit::GetDynObject(uint32 spellId, SpellEffectIndex effIndex) { - for (GuidList::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) - { - DynamicObject* dynObj = GetMap()->GetDynamicObject(*i); - if (!dynObj) - { - i = m_dynObjGUIDs.erase(i); - continue; - } + for (GuidList::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) + { + DynamicObject* dynObj = GetMap()->GetDynamicObject(*i); + if (!dynObj) + { + i = m_dynObjGUIDs.erase(i); + continue; + } - if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex) - { - return dynObj; - } - ++i; - } - return NULL; + if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex) + { + return dynObj; + } + ++i; + } + return NULL; } DynamicObject* Unit::GetDynObject(uint32 spellId) { - for (GuidList::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) - { - DynamicObject* dynObj = GetMap()->GetDynamicObject(*i); - if (!dynObj) - { - i = m_dynObjGUIDs.erase(i); - continue; - } + for (GuidList::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();) + { + DynamicObject* dynObj = GetMap()->GetDynamicObject(*i); + if (!dynObj) + { + i = m_dynObjGUIDs.erase(i); + continue; + } - if (dynObj->GetSpellId() == spellId) - { - return dynObj; - } - ++i; - } - return NULL; + if (dynObj->GetSpellId() == spellId) + { + return dynObj; + } + ++i; + } + return NULL; } GameObject* Unit::GetGameObject(uint32 spellId) const { - for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i) - if ((*i)->GetSpellId() == spellId) - { - return *i; - } + for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i) + if ((*i)->GetSpellId() == spellId) + { + return *i; + } - WildGameObjectMap::const_iterator find = m_wildGameObjs.find(spellId); - if (find != m_wildGameObjs.end()) - return GetMap()->GetGameObject(find->second); // Can be NULL + WildGameObjectMap::const_iterator find = m_wildGameObjs.find(spellId); + if (find != m_wildGameObjs.end()) + return GetMap()->GetGameObject(find->second); // Can be NULL - return NULL; + return NULL; } void Unit::AddGameObject(GameObject* gameObj) { - MANGOS_ASSERT(gameObj && !gameObj->GetOwnerGuid()); - m_gameObj.push_back(gameObj); - gameObj->SetOwnerGuid(GetObjectGuid()); + MANGOS_ASSERT(gameObj && !gameObj->GetOwnerGuid()); + m_gameObj.push_back(gameObj); + gameObj->SetOwnerGuid(GetObjectGuid()); - if (GetTypeId() == TYPEID_PLAYER && gameObj->GetSpellId()) - { - SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId()); - // Need disable spell use for owner - if (createBySpell && createBySpell->HasAttribute(SPELL_ATTR_DISABLED_WHILE_ACTIVE)) - // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) - ((Player*)this)->AddSpellAndCategoryCooldowns(createBySpell, 0, NULL, true); - } + if (GetTypeId() == TYPEID_PLAYER && gameObj->GetSpellId()) + { + SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId()); + // Need disable spell use for owner + if (createBySpell && createBySpell->HasAttribute(SPELL_ATTR_DISABLED_WHILE_ACTIVE)) + // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) + ((Player*)this)->AddSpellAndCategoryCooldowns(createBySpell, 0, NULL, true); + } } void Unit::AddWildGameObject(GameObject* gameObj) { - MANGOS_ASSERT(gameObj && gameObj->GetOwnerGuid().IsEmpty()); - m_wildGameObjs[gameObj->GetSpellId()] = gameObj->GetObjectGuid(); + MANGOS_ASSERT(gameObj && gameObj->GetOwnerGuid().IsEmpty()); + m_wildGameObjs[gameObj->GetSpellId()] = gameObj->GetObjectGuid(); - // As of 335 there are no wild-summon spells with SPELL_ATTR_DISABLED_WHILE_ACTIVE + // As of 335 there are no wild-summon spells with SPELL_ATTR_DISABLED_WHILE_ACTIVE - // Remove outdated wild summoned GOs - for (WildGameObjectMap::iterator itr = m_wildGameObjs.begin(); itr != m_wildGameObjs.end();) - { - GameObject* pGo = GetMap()->GetGameObject(itr->second); - if (pGo) - ++itr; - else - m_wildGameObjs.erase(itr++); - } + // Remove outdated wild summoned GOs + for (WildGameObjectMap::iterator itr = m_wildGameObjs.begin(); itr != m_wildGameObjs.end();) + { + GameObject* pGo = GetMap()->GetGameObject(itr->second); + if (pGo) + ++itr; + else + m_wildGameObjs.erase(itr++); + } } void Unit::RemoveGameObject(GameObject* gameObj, bool del) { - MANGOS_ASSERT(gameObj && gameObj->GetOwnerGuid() == GetObjectGuid()); + MANGOS_ASSERT(gameObj && gameObj->GetOwnerGuid() == GetObjectGuid()); - gameObj->SetOwnerGuid(ObjectGuid()); + gameObj->SetOwnerGuid(ObjectGuid()); - // GO created by some spell - if (uint32 spellid = gameObj->GetSpellId()) - { - RemoveAurasDueToSpell(spellid); + // GO created by some spell + if (uint32 spellid = gameObj->GetSpellId()) + { + RemoveAurasDueToSpell(spellid); - if (GetTypeId() == TYPEID_PLAYER) - { - SpellEntry const* createBySpell = sSpellStore.LookupEntry(spellid); - // Need activate spell use for owner - if (createBySpell && createBySpell->HasAttribute(SPELL_ATTR_DISABLED_WHILE_ACTIVE)) - // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) - ((Player*)this)->SendCooldownEvent(createBySpell); - } - } + if (GetTypeId() == TYPEID_PLAYER) + { + SpellEntry const* createBySpell = sSpellStore.LookupEntry(spellid); + // Need activate spell use for owner + if (createBySpell && createBySpell->HasAttribute(SPELL_ATTR_DISABLED_WHILE_ACTIVE)) + // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) + ((Player*)this)->SendCooldownEvent(createBySpell); + } + } - m_gameObj.remove(gameObj); + m_gameObj.remove(gameObj); - if (del) - { - gameObj->SetRespawnTime(0); - gameObj->Delete(); - } + if (del) + { + gameObj->SetRespawnTime(0); + gameObj->Delete(); + } } void Unit::RemoveGameObject(uint32 spellid, bool del) { - if (m_gameObj.empty()) - { - return; - } - - GameObjectList::iterator i, next; - for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next) - { - next = i; - if (spellid == 0 || (*i)->GetSpellId() == spellid) - { - (*i)->SetOwnerGuid(ObjectGuid()); - if (del) - { - (*i)->SetRespawnTime(0); - (*i)->Delete(); - } - - next = m_gameObj.erase(i); - } - else - ++next; - } + if (m_gameObj.empty()) + { + return; + } + + GameObjectList::iterator i, next; + for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next) + { + next = i; + if (spellid == 0 || (*i)->GetSpellId() == spellid) + { + (*i)->SetOwnerGuid(ObjectGuid()); + if (del) + { + (*i)->SetRespawnTime(0); + (*i)->Delete(); + } + + next = m_gameObj.erase(i); + } + else + ++next; + } } void Unit::RemoveAllGameObjects() { - // remove references to unit - for (GameObjectList::iterator i = m_gameObj.begin(); i != m_gameObj.end();) - { - (*i)->SetOwnerGuid(ObjectGuid()); - (*i)->SetRespawnTime(0); - (*i)->Delete(); - i = m_gameObj.erase(i); - } + // remove references to unit + for (GameObjectList::iterator i = m_gameObj.begin(); i != m_gameObj.end();) + { + (*i)->SetOwnerGuid(ObjectGuid()); + (*i)->SetRespawnTime(0); + (*i)->Delete(); + i = m_gameObj.erase(i); + } - // wild summoned GOs - only remove references, do not remove GOs - m_wildGameObjs.clear(); + // wild summoned GOs - only remove references, do not remove GOs + m_wildGameObjs.clear(); } void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage* log) { - uint32 targetHealth = log->target->GetHealth(); - uint32 overkill = log->damage > targetHealth ? log->damage - targetHealth : 0; - - WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16 + 4 + 4 + 4 + 1 + 4 + 4 + 1 + 1 + 4 + 4 + 1)); // we guess size - data << log->target->GetPackGUID(); - data << log->attacker->GetPackGUID(); - data << uint32(log->SpellID); - data << uint32(log->damage); // damage amount - data << uint32(overkill); // overkill - data << uint8(log->schoolMask); // damage school - data << uint32(log->absorb); // AbsorbedDamage - data << uint32(log->resist); // resist - data << uint8(log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name - data << uint8(log->unused); // unused - data << uint32(log->blocked); // blocked - data << uint32(log->HitInfo); - data << uint8(0); // flag to use extend data - SendMessageToSet(&data, true); + uint32 targetHealth = log->target->GetHealth(); + uint32 overkill = log->damage > targetHealth ? log->damage - targetHealth : 0; + + WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16 + 4 + 4 + 4 + 1 + 4 + 4 + 1 + 1 + 4 + 4 + 1)); // we guess size + data << log->target->GetPackGUID(); + data << log->attacker->GetPackGUID(); + data << uint32(log->SpellID); + data << uint32(log->damage); // damage amount + data << uint32(overkill); // overkill + data << uint8(log->schoolMask); // damage school + data << uint32(log->absorb); // AbsorbedDamage + data << uint32(log->resist); // resist + data << uint8(log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name + data << uint8(log->unused); // unused + data << uint32(log->blocked); // blocked + data << uint32(log->HitInfo); + data << uint8(0); // flag to use extend data + SendMessageToSet(&data, true); } void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit) { - SpellNonMeleeDamage log(this, target, SpellID, damageSchoolMask); - log.damage = Damage - AbsorbedDamage - Resist - Blocked; - log.absorb = AbsorbedDamage; - log.resist = Resist; - log.physicalLog = PhysicalDamage; - log.blocked = Blocked; - log.HitInfo = SPELL_HIT_TYPE_UNK1 | SPELL_HIT_TYPE_UNK3 | SPELL_HIT_TYPE_UNK6; - if (CriticalHit) - log.HitInfo |= SPELL_HIT_TYPE_CRIT; - SendSpellNonMeleeDamageLog(&log); + SpellNonMeleeDamage log(this, target, SpellID, damageSchoolMask); + log.damage = Damage - AbsorbedDamage - Resist - Blocked; + log.absorb = AbsorbedDamage; + log.resist = Resist; + log.physicalLog = PhysicalDamage; + log.blocked = Blocked; + log.HitInfo = SPELL_HIT_TYPE_UNK1 | SPELL_HIT_TYPE_UNK3 | SPELL_HIT_TYPE_UNK6; + if (CriticalHit) + log.HitInfo |= SPELL_HIT_TYPE_CRIT; + SendSpellNonMeleeDamageLog(&log); } void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo) { - Aura* aura = pInfo->aura; - Modifier* mod = aura->GetModifier(); - - WorldPacket data(SMSG_PERIODICAURALOG, 30); - data << aura->GetTarget()->GetPackGUID(); - data << aura->GetCasterGuid().WriteAsPacked(); - data << uint32(aura->GetId()); // spellId - data << uint32(1); // count - data << uint32(mod->m_auraname); // auraId - switch (mod->m_auraname) - { - case SPELL_AURA_PERIODIC_DAMAGE: - case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: - data << uint32(pInfo->damage); // damage - data << uint32(pInfo->overDamage); // overkill? - data << uint32(GetSpellSchoolMask(aura->GetSpellProto())); - data << uint32(pInfo->absorb); // absorb - data << uint32(pInfo->resist); // resist - data << uint8(pInfo->critical ? 1 : 0); // new 3.1.2 critical flag - break; - case SPELL_AURA_PERIODIC_HEAL: - case SPELL_AURA_OBS_MOD_HEALTH: - data << uint32(pInfo->damage); // damage - data << uint32(pInfo->overDamage); // overheal? - data << uint32(pInfo->absorb); // absorb - data << uint8(pInfo->critical ? 1 : 0); // new 3.1.2 critical flag - break; - case SPELL_AURA_OBS_MOD_MANA: - case SPELL_AURA_PERIODIC_ENERGIZE: - data << uint32(mod->m_miscvalue); // power type - data << uint32(pInfo->damage); // damage - break; - case SPELL_AURA_PERIODIC_MANA_LEECH: - data << uint32(mod->m_miscvalue); // power type - data << uint32(pInfo->damage); // amount - data << float(pInfo->multiplier); // gain multiplier - break; - default: - sLog.outError("Unit::SendPeriodicAuraLog: unknown aura %u", uint32(mod->m_auraname)); - return; - } - - aura->GetTarget()->SendMessageToSet(&data, true); + Aura* aura = pInfo->aura; + Modifier* mod = aura->GetModifier(); + + WorldPacket data(SMSG_PERIODICAURALOG, 30); + data << aura->GetTarget()->GetPackGUID(); + data << aura->GetCasterGuid().WriteAsPacked(); + data << uint32(aura->GetId()); // spellId + data << uint32(1); // count + data << uint32(mod->m_auraname); // auraId + switch (mod->m_auraname) + { + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: + data << uint32(pInfo->damage); // damage + data << uint32(pInfo->overDamage); // overkill? + data << uint32(GetSpellSchoolMask(aura->GetSpellProto())); + data << uint32(pInfo->absorb); // absorb + data << uint32(pInfo->resist); // resist + data << uint8(pInfo->critical ? 1 : 0); // new 3.1.2 critical flag + break; + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_OBS_MOD_HEALTH: + data << uint32(pInfo->damage); // damage + data << uint32(pInfo->overDamage); // overheal? + data << uint32(pInfo->absorb); // absorb + data << uint8(pInfo->critical ? 1 : 0); // new 3.1.2 critical flag + break; + case SPELL_AURA_OBS_MOD_MANA: + case SPELL_AURA_PERIODIC_ENERGIZE: + data << uint32(mod->m_miscvalue); // power type + data << uint32(pInfo->damage); // damage + break; + case SPELL_AURA_PERIODIC_MANA_LEECH: + data << uint32(mod->m_miscvalue); // power type + data << uint32(pInfo->damage); // amount + data << float(pInfo->multiplier); // gain multiplier + break; + default: + sLog.outError("Unit::SendPeriodicAuraLog: unknown aura %u", uint32(mod->m_auraname)); + return; + } + + aura->GetTarget()->SendMessageToSet(&data, true); } void Unit::ProcDamageAndSpell(Unit* pVictim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const* procSpell) { - // Not much to do if no flags are set. - if (procAttacker) - ProcDamageAndSpellFor(false, pVictim, procAttacker, procExtra, attType, procSpell, amount); - // Now go on with a victim's events'n'auras - // Not much to do if no flags are set or there is no victim - if (pVictim && pVictim->IsAlive() && procVictim) - pVictim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount); + // Not much to do if no flags are set. + if (procAttacker) + ProcDamageAndSpellFor(false, pVictim, procAttacker, procExtra, attType, procSpell, amount); + // Now go on with a victim's events'n'auras + // Not much to do if no flags are set or there is no victim + if (pVictim && pVictim->IsAlive() && procVictim) + pVictim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount); } void Unit::SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo) { - WorldPacket data(SMSG_SPELLLOGMISS, (4 + 8 + 1 + 4 + 8 + 1)); - data << uint32(spellID); - data << GetObjectGuid(); - data << uint8(0); // can be 0 or 1, flag - data << uint32(1); // target count - // for(i = 0; i < target count; ++i) - data << target->GetObjectGuid(); // target GUID - data << uint8(missInfo); - // end loop - SendMessageToSet(&data, true); + WorldPacket data(SMSG_SPELLLOGMISS, (4 + 8 + 1 + 4 + 8 + 1)); + data << uint32(spellID); + data << GetObjectGuid(); + data << uint8(0); // can be 0 or 1, flag + data << uint32(1); // target count + // for(i = 0; i < target count; ++i) + data << target->GetObjectGuid(); // target GUID + data << uint8(missInfo); + // end loop + SendMessageToSet(&data, true); } void Unit::SendAttackStateUpdate(CalcDamageInfo* damageInfo) { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Sending SMSG_ATTACKERSTATEUPDATE"); - - uint32 targetHealth = damageInfo->target->GetHealth(); - uint32 overkill = damageInfo->damage > targetHealth ? damageInfo->damage - targetHealth : 0; - - uint32 count = 1; - WorldPacket data(SMSG_ATTACKERSTATEUPDATE, 16 + 45); // we guess size - data << uint32(damageInfo->HitInfo); - data << damageInfo->attacker->GetPackGUID(); - data << damageInfo->target->GetPackGUID(); - data << uint32(damageInfo->damage); // Full damage - data << uint32(overkill); // overkill value - data << uint8(count); // Sub damage count - - for (uint32 i = 0; i < count; ++i) - { - data << uint32(damageInfo->damageSchoolMask); // School of sub damage - data << float(damageInfo->damage); // sub damage - data << uint32(damageInfo->damage); // Sub Damage - } - - if (damageInfo->HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2)) - { - for (uint32 i = 0; i < count; ++i) - data << uint32(damageInfo->absorb); // Absorb - } - - if (damageInfo->HitInfo & (HITINFO_RESIST | HITINFO_RESIST2)) - { - for (uint32 i = 0; i < count; ++i) - data << uint32(damageInfo->resist); // Resist - } - - data << uint8(damageInfo->TargetState); - data << uint32(0); // unknown, usually seen with -1, 0 and 1000 - data << uint32(0); // spell id, seen with heroic strike and disarm as examples. - // HITINFO_NOACTION normally set if spell - - if (damageInfo->HitInfo & HITINFO_BLOCK) - data << uint32(damageInfo->blocked_amount); - - if (damageInfo->HitInfo & HITINFO_UNK22) - data << uint32(0); // count of some sort? - - if (damageInfo->HitInfo & HITINFO_UNK0) - { - data << uint32(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - for (uint8 i = 0; i < 5; ++i) - { - data << float(0); - data << float(0); - } - data << uint32(0); - } - - SendMessageToSet(&data, true); /**/ + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Sending SMSG_ATTACKERSTATEUPDATE"); + + uint32 targetHealth = damageInfo->target->GetHealth(); + uint32 overkill = damageInfo->damage > targetHealth ? damageInfo->damage - targetHealth : 0; + + uint32 count = 1; + WorldPacket data(SMSG_ATTACKERSTATEUPDATE, 16 + 45); // we guess size + data << uint32(damageInfo->HitInfo); + data << damageInfo->attacker->GetPackGUID(); + data << damageInfo->target->GetPackGUID(); + data << uint32(damageInfo->damage); // Full damage + data << uint32(overkill); // overkill value + data << uint8(count); // Sub damage count + + for (uint32 i = 0; i < count; ++i) + { + data << uint32(damageInfo->damageSchoolMask); // School of sub damage + data << float(damageInfo->damage); // sub damage + data << uint32(damageInfo->damage); // Sub Damage + } + + if (damageInfo->HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2)) + { + for (uint32 i = 0; i < count; ++i) + data << uint32(damageInfo->absorb); // Absorb + } + + if (damageInfo->HitInfo & (HITINFO_RESIST | HITINFO_RESIST2)) + { + for (uint32 i = 0; i < count; ++i) + data << uint32(damageInfo->resist); // Resist + } + + data << uint8(damageInfo->TargetState); + data << uint32(0); // unknown, usually seen with -1, 0 and 1000 + data << uint32(0); // spell id, seen with heroic strike and disarm as examples. + // HITINFO_NOACTION normally set if spell + + if (damageInfo->HitInfo & HITINFO_BLOCK) + data << uint32(damageInfo->blocked_amount); + + if (damageInfo->HitInfo & HITINFO_UNK22) + data << uint32(0); // count of some sort? + + if (damageInfo->HitInfo & HITINFO_UNK0) + { + data << uint32(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + for (uint8 i = 0; i < 5; ++i) + { + data << float(0); + data << float(0); + } + data << uint32(0); + } + + SendMessageToSet(&data, true); /**/ } void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount) { - CalcDamageInfo dmgInfo; - dmgInfo.HitInfo = HitInfo; - dmgInfo.attacker = this; - dmgInfo.target = target; - dmgInfo.damage = Damage - AbsorbDamage - Resist - BlockedAmount; - dmgInfo.damageSchoolMask = damageSchoolMask; - dmgInfo.absorb = AbsorbDamage; - dmgInfo.resist = Resist; - dmgInfo.TargetState = TargetState; - dmgInfo.blocked_amount = BlockedAmount; - SendAttackStateUpdate(&dmgInfo); + CalcDamageInfo dmgInfo; + dmgInfo.HitInfo = HitInfo; + dmgInfo.attacker = this; + dmgInfo.target = target; + dmgInfo.damage = Damage - AbsorbDamage - Resist - BlockedAmount; + dmgInfo.damageSchoolMask = damageSchoolMask; + dmgInfo.absorb = AbsorbDamage; + dmgInfo.resist = Resist; + dmgInfo.TargetState = TargetState; + dmgInfo.blocked_amount = BlockedAmount; + SendAttackStateUpdate(&dmgInfo); } void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount) { - CalcDamageInfo dmgInfo; - dmgInfo.HitInfo = HitInfo; - dmgInfo.attacker = this; - dmgInfo.target = target; - dmgInfo.damage = Damage - AbsorbDamage - Resist - BlockedAmount; - dmgInfo.damageSchoolMask = damageSchoolMask; - dmgInfo.absorb = AbsorbDamage; - dmgInfo.resist = Resist; - dmgInfo.TargetState = TargetState; - dmgInfo.blocked_amount = BlockedAmount; - SendAttackStateUpdate(&dmgInfo); + CalcDamageInfo dmgInfo; + dmgInfo.HitInfo = HitInfo; + dmgInfo.attacker = this; + dmgInfo.target = target; + dmgInfo.damage = Damage - AbsorbDamage - Resist - BlockedAmount; + dmgInfo.damageSchoolMask = damageSchoolMask; + dmgInfo.absorb = AbsorbDamage; + dmgInfo.resist = Resist; + dmgInfo.TargetState = TargetState; + dmgInfo.blocked_amount = BlockedAmount; + SendAttackStateUpdate(&dmgInfo); } void Unit::SetPowerType(Powers new_powertype) { - // set power type - SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype); - - // group updates - if (GetTypeId() == TYPEID_PLAYER) - { - if (((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE); - } - else if (((Creature*)this)->IsPet()) - { - Pet* pet = ((Pet*)this); - if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE); - } - } - - // special cases for power type switching (druid and pets only) - if (GetTypeId() == TYPEID_PLAYER || (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet())) - { - uint32 maxValue = GetCreatePowers(new_powertype); - uint32 curValue = maxValue; - - // special cases with current power = 0 - switch (new_powertype) - { - case POWER_RAGE: - case POWER_RUNE: - case POWER_RUNIC_POWER: - curValue = 0; - break; - default: - break; - } - - // set power (except for mana) - if (new_powertype != POWER_MANA) - { - SetMaxPower(new_powertype, maxValue); - SetPower(new_powertype, curValue); - } - - // send power type update to client - WorldPacket data(SMSG_POWER_UPDATE); - data << GetPackGUID(); - data << uint32(1); // power count - data << uint8(new_powertype); - data << uint32(curValue); - SendMessageToSet(&data, true); - } + // set power type + SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype); + + // group updates + if (GetTypeId() == TYPEID_PLAYER) + { + if (((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE); + } + else if (((Creature*)this)->IsPet()) + { + Pet* pet = ((Pet*)this); + if (pet->isControlled()) + { + Unit* owner = GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE); + } + } + + // special cases for power type switching (druid and pets only) + if (GetTypeId() == TYPEID_PLAYER || (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet())) + { + uint32 maxValue = GetCreatePowers(new_powertype); + uint32 curValue = maxValue; + + // special cases with current power = 0 + switch (new_powertype) + { + case POWER_RAGE: + case POWER_RUNE: + case POWER_RUNIC_POWER: + curValue = 0; + break; + default: + break; + } + + // set power (except for mana) + if (new_powertype != POWER_MANA) + { + SetMaxPower(new_powertype, maxValue); + SetPower(new_powertype, curValue); + } + + // send power type update to client + WorldPacket data(SMSG_POWER_UPDATE); + data << GetPackGUID(); + data << uint32(1); // power count + data << uint8(new_powertype); + data << uint32(curValue); + SendMessageToSet(&data, true); + } } FactionTemplateEntry const* Unit::getFactionTemplateEntry() const { - FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction()); - if (!entry) - { - static ObjectGuid guid; // prevent repeating spam same faction problem + FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction()); + if (!entry) + { + static ObjectGuid guid; // prevent repeating spam same faction problem - if (GetObjectGuid() != guid) - { - guid = GetObjectGuid(); + if (GetObjectGuid() != guid) + { + guid = GetObjectGuid(); - if (guid.GetHigh() == HIGHGUID_PET) - sLog.outError("%s (base creature entry %u) have invalid faction template id %u, owner %s", GetGuidStr().c_str(), GetEntry(), getFaction(), ((Pet*)this)->GetOwnerGuid().GetString().c_str()); - else - sLog.outError("%s have invalid faction template id %u", GetGuidStr().c_str(), getFaction()); - } - } - return entry; + if (guid.GetHigh() == HIGHGUID_PET) + sLog.outError("%s (base creature entry %u) have invalid faction template id %u, owner %s", GetGuidStr().c_str(), GetEntry(), getFaction(), ((Pet*)this)->GetOwnerGuid().GetString().c_str()); + else + sLog.outError("%s have invalid faction template id %u", GetGuidStr().c_str(), getFaction()); + } + } + return entry; } bool Unit::IsHostileTo(Unit const* unit) const { - // always non-hostile to self - if (unit == this) - { - return false; - } - - // always non-hostile to GM in GM mode - if (unit->GetTypeId() == TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) - { - return false; - } - - // always hostile to enemy - if (getVictim() == unit || unit->getVictim() == this) - { - return true; - } - - // test pet/charm masters instead pers/charmeds - Unit const* testerOwner = GetCharmerOrOwner(); - Unit const* targetOwner = unit->GetCharmerOrOwner(); - - // always hostile to owner's enemy - if (testerOwner && (testerOwner->getVictim() == unit || unit->getVictim() == testerOwner)) - { - return true; - } - - // always hostile to enemy owner - if (targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this)) - { - return true; - } - - // always hostile to owner of owner's enemy - if (testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner)) - { - return true; - } - - Unit const* tester = testerOwner ? testerOwner : this; - Unit const* target = targetOwner ? targetOwner : unit; - - // always non-hostile to target with common owner, or to owner/pet - if (tester == target) - { - return false; - } - - // special cases (Duel, etc) - if (tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER) - { - Player const* pTester = (Player const*)tester; - Player const* pTarget = (Player const*)target; - - // Duel - if (pTester->IsInDuelWith(pTarget)) - { - return true; - } - - // Group - if (pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup()) - { - return false; - } - - // Sanctuary - if (pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) - { - return false; - } - - // PvP FFA state - if (pTester->IsFFAPvP() && pTarget->IsFFAPvP()) - { - return true; - } - - //= PvP states - // Green/Blue (can't attack) - if (pTester->GetTeam() == pTarget->GetTeam()) - { - return false; - } - - // Red (can attack) if true, Blue/Yellow (can't attack) in another case - return pTester->IsPvP() && pTarget->IsPvP(); - } - - // faction base cases - FactionTemplateEntry const* tester_faction = tester->getFactionTemplateEntry(); - FactionTemplateEntry const* target_faction = target->getFactionTemplateEntry(); - if (!tester_faction || !target_faction) - { - return false; - } - - if (target->isAttackingPlayer() && tester->IsContestedGuard()) - { - return true; - } - - // PvC forced reaction and reputation case - if (tester->GetTypeId() == TYPEID_PLAYER) - { - if (target_faction->faction) - { - // forced reaction - if (ReputationRank const* force = ((Player*)tester)->GetReputationMgr().GetForcedRankIfAny(target_faction)) - { - return *force <= REP_HOSTILE; - } - - // if faction have reputation then hostile state for tester at 100% dependent from at_war state - if (FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction)) - if (FactionState const* factionState = ((Player*)tester)->GetReputationMgr().GetState(raw_target_faction)) - { - return (factionState->Flags & FACTION_FLAG_AT_WAR); - } - } - } - // CvP forced reaction and reputation case - else if (target->GetTypeId() == TYPEID_PLAYER) - { - if (tester_faction->faction) - { - // forced reaction - if (ReputationRank const* force = ((Player*)target)->GetReputationMgr().GetForcedRankIfAny(tester_faction)) - { - return *force <= REP_HOSTILE; - } - - // apply reputation state - FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction); - if (raw_tester_faction && raw_tester_faction->reputationListID >= 0) - { - return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) <= REP_HOSTILE; - } - } - } - - // common faction based case (CvC,PvC,CvP) - return tester_faction->IsHostileTo(*target_faction); + // always non-hostile to self + if (unit == this) + { + return false; + } + + // always non-hostile to GM in GM mode + if (unit->GetTypeId() == TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) + { + return false; + } + + // always hostile to enemy + if (getVictim() == unit || unit->getVictim() == this) + { + return true; + } + + // test pet/charm masters instead pers/charmeds + Unit const* testerOwner = GetCharmerOrOwner(); + Unit const* targetOwner = unit->GetCharmerOrOwner(); + + // always hostile to owner's enemy + if (testerOwner && (testerOwner->getVictim() == unit || unit->getVictim() == testerOwner)) + { + return true; + } + + // always hostile to enemy owner + if (targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this)) + { + return true; + } + + // always hostile to owner of owner's enemy + if (testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner)) + { + return true; + } + + Unit const* tester = testerOwner ? testerOwner : this; + Unit const* target = targetOwner ? targetOwner : unit; + + // always non-hostile to target with common owner, or to owner/pet + if (tester == target) + { + return false; + } + + // special cases (Duel, etc) + if (tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER) + { + Player const* pTester = (Player const*)tester; + Player const* pTarget = (Player const*)target; + + // Duel + if (pTester->IsInDuelWith(pTarget)) + { + return true; + } + + // Group + if (pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup()) + { + return false; + } + + // Sanctuary + if (pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) + { + return false; + } + + // PvP FFA state + if (pTester->IsFFAPvP() && pTarget->IsFFAPvP()) + { + return true; + } + + //= PvP states + // Green/Blue (can't attack) + if (pTester->GetTeam() == pTarget->GetTeam()) + { + return false; + } + + // Red (can attack) if true, Blue/Yellow (can't attack) in another case + return pTester->IsPvP() && pTarget->IsPvP(); + } + + // faction base cases + FactionTemplateEntry const* tester_faction = tester->getFactionTemplateEntry(); + FactionTemplateEntry const* target_faction = target->getFactionTemplateEntry(); + if (!tester_faction || !target_faction) + { + return false; + } + + if (target->isAttackingPlayer() && tester->IsContestedGuard()) + { + return true; + } + + // PvC forced reaction and reputation case + if (tester->GetTypeId() == TYPEID_PLAYER) + { + if (target_faction->faction) + { + // forced reaction + if (ReputationRank const* force = ((Player*)tester)->GetReputationMgr().GetForcedRankIfAny(target_faction)) + { + return *force <= REP_HOSTILE; + } + + // if faction have reputation then hostile state for tester at 100% dependent from at_war state + if (FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction)) + if (FactionState const* factionState = ((Player*)tester)->GetReputationMgr().GetState(raw_target_faction)) + { + return (factionState->Flags & FACTION_FLAG_AT_WAR); + } + } + } + // CvP forced reaction and reputation case + else if (target->GetTypeId() == TYPEID_PLAYER) + { + if (tester_faction->faction) + { + // forced reaction + if (ReputationRank const* force = ((Player*)target)->GetReputationMgr().GetForcedRankIfAny(tester_faction)) + { + return *force <= REP_HOSTILE; + } + + // apply reputation state + FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction); + if (raw_tester_faction && raw_tester_faction->reputationListID >= 0) + { + return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) <= REP_HOSTILE; + } + } + } + + // common faction based case (CvC,PvC,CvP) + return tester_faction->IsHostileTo(*target_faction); } bool Unit::IsFriendlyTo(Unit const* unit) const { - // always friendly to self - if (unit == this) - { - return true; - } - - // always friendly to GM in GM mode - if (unit->GetTypeId() == TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) - { - return true; - } - - // always non-friendly to enemy - if (getVictim() == unit || unit->getVictim() == this) - { - return false; - } - - // test pet/charm masters instead pers/charmeds - Unit const* testerOwner = GetCharmerOrOwner(); - Unit const* targetOwner = unit->GetCharmerOrOwner(); - - // always non-friendly to owner's enemy - if (testerOwner && (testerOwner->getVictim() == unit || unit->getVictim() == testerOwner)) - { - return false; - } - - // always non-friendly to enemy owner - if (targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this)) - { - return false; - } - - // always non-friendly to owner of owner's enemy - if (testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner)) - { - return false; - } - - Unit const* tester = testerOwner ? testerOwner : this; - Unit const* target = targetOwner ? targetOwner : unit; - - // always friendly to target with common owner, or to owner/pet - if (tester == target) - { - return true; - } - - // special cases (Duel) - if (tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER) - { - Player const* pTester = (Player const*)tester; - Player const* pTarget = (Player const*)target; - - // Duel - if (pTester->IsInDuelWith(pTarget)) - { - return false; - } - - // Group - if (pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup()) - { - return true; - } - - // Sanctuary - if (pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) - { - return true; - } - - // PvP FFA state - if (pTester->IsFFAPvP() && pTarget->IsFFAPvP()) - { - return false; - } - - //= PvP states - // Green/Blue (non-attackable) - if (pTester->GetTeam() == pTarget->GetTeam()) - { - return true; - } - - // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable) - return !pTarget->IsPvP(); - } - - // faction base cases - FactionTemplateEntry const* tester_faction = tester->getFactionTemplateEntry(); - FactionTemplateEntry const* target_faction = target->getFactionTemplateEntry(); - if (!tester_faction || !target_faction) - { - return false; - } - - if (target->isAttackingPlayer() && tester->IsContestedGuard()) - { - return false; - } - - // PvC forced reaction and reputation case - if (tester->GetTypeId() == TYPEID_PLAYER) - { - if (target_faction->faction) - { - // forced reaction - if (ReputationRank const* force = ((Player*)tester)->GetReputationMgr().GetForcedRankIfAny(target_faction)) - { - return *force >= REP_FRIENDLY; - } - - // if faction have reputation then friendly state for tester at 100% dependent from at_war state - if (FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction)) - if (FactionState const* factionState = ((Player*)tester)->GetReputationMgr().GetState(raw_target_faction)) - { - return !(factionState->Flags & FACTION_FLAG_AT_WAR); - } - } - } - // CvP forced reaction and reputation case - else if (target->GetTypeId() == TYPEID_PLAYER) - { - if (tester_faction->faction) - { - // forced reaction - if (ReputationRank const* force = ((Player*)target)->GetReputationMgr().GetForcedRankIfAny(tester_faction)) - { - return *force >= REP_FRIENDLY; - } - - // apply reputation state - if (FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction)) - if (raw_tester_faction->reputationListID >= 0) - { - return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) >= REP_FRIENDLY; - } - } - } - - // common faction based case (CvC,PvC,CvP) - return tester_faction->IsFriendlyTo(*target_faction); + // always friendly to self + if (unit == this) + { + return true; + } + + // always friendly to GM in GM mode + if (unit->GetTypeId() == TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) + { + return true; + } + + // always non-friendly to enemy + if (getVictim() == unit || unit->getVictim() == this) + { + return false; + } + + // test pet/charm masters instead pers/charmeds + Unit const* testerOwner = GetCharmerOrOwner(); + Unit const* targetOwner = unit->GetCharmerOrOwner(); + + // always non-friendly to owner's enemy + if (testerOwner && (testerOwner->getVictim() == unit || unit->getVictim() == testerOwner)) + { + return false; + } + + // always non-friendly to enemy owner + if (targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this)) + { + return false; + } + + // always non-friendly to owner of owner's enemy + if (testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner)) + { + return false; + } + + Unit const* tester = testerOwner ? testerOwner : this; + Unit const* target = targetOwner ? targetOwner : unit; + + // always friendly to target with common owner, or to owner/pet + if (tester == target) + { + return true; + } + + // special cases (Duel) + if (tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER) + { + Player const* pTester = (Player const*)tester; + Player const* pTarget = (Player const*)target; + + // Duel + if (pTester->IsInDuelWith(pTarget)) + { + return false; + } + + // Group + if (pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup()) + { + return true; + } + + // Sanctuary + if (pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) + { + return true; + } + + // PvP FFA state + if (pTester->IsFFAPvP() && pTarget->IsFFAPvP()) + { + return false; + } + + //= PvP states + // Green/Blue (non-attackable) + if (pTester->GetTeam() == pTarget->GetTeam()) + { + return true; + } + + // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable) + return !pTarget->IsPvP(); + } + + // faction base cases + FactionTemplateEntry const* tester_faction = tester->getFactionTemplateEntry(); + FactionTemplateEntry const* target_faction = target->getFactionTemplateEntry(); + if (!tester_faction || !target_faction) + { + return false; + } + + if (target->isAttackingPlayer() && tester->IsContestedGuard()) + { + return false; + } + + // PvC forced reaction and reputation case + if (tester->GetTypeId() == TYPEID_PLAYER) + { + if (target_faction->faction) + { + // forced reaction + if (ReputationRank const* force = ((Player*)tester)->GetReputationMgr().GetForcedRankIfAny(target_faction)) + { + return *force >= REP_FRIENDLY; + } + + // if faction have reputation then friendly state for tester at 100% dependent from at_war state + if (FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction)) + if (FactionState const* factionState = ((Player*)tester)->GetReputationMgr().GetState(raw_target_faction)) + { + return !(factionState->Flags & FACTION_FLAG_AT_WAR); + } + } + } + // CvP forced reaction and reputation case + else if (target->GetTypeId() == TYPEID_PLAYER) + { + if (tester_faction->faction) + { + // forced reaction + if (ReputationRank const* force = ((Player*)target)->GetReputationMgr().GetForcedRankIfAny(tester_faction)) + { + return *force >= REP_FRIENDLY; + } + + // apply reputation state + if (FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction)) + if (raw_tester_faction->reputationListID >= 0) + { + return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) >= REP_FRIENDLY; + } + } + } + + // common faction based case (CvC,PvC,CvP) + return tester_faction->IsFriendlyTo(*target_faction); } bool Unit::IsHostileToPlayers() const { - FactionTemplateEntry const* my_faction = getFactionTemplateEntry(); - if (!my_faction || !my_faction->faction) - { - return false; - } + FactionTemplateEntry const* my_faction = getFactionTemplateEntry(); + if (!my_faction || !my_faction->faction) + { + return false; + } - FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction); - if (raw_faction && raw_faction->reputationListID >= 0) - { - return false; - } + FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction); + if (raw_faction && raw_faction->reputationListID >= 0) + { + return false; + } - return my_faction->IsHostileToPlayers(); + return my_faction->IsHostileToPlayers(); } bool Unit::IsNeutralToAll() const { - FactionTemplateEntry const* my_faction = getFactionTemplateEntry(); - if (!my_faction || !my_faction->faction) - { - return true; - } + FactionTemplateEntry const* my_faction = getFactionTemplateEntry(); + if (!my_faction || !my_faction->faction) + { + return true; + } - FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction); - if (raw_faction && raw_faction->reputationListID >= 0) - { - return false; - } + FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction); + if (raw_faction && raw_faction->reputationListID >= 0) + { + return false; + } - return my_faction->IsNeutralToAll(); + return my_faction->IsNeutralToAll(); } bool Unit::Attack(Unit* victim, bool meleeAttack) { - if (!victim || victim == this) - { - return false; - } - - // dead units can neither attack nor be attacked - if (!IsAlive() || !victim->IsInWorld() || !victim->IsAlive()) - { - return false; - } - - // player cannot attack in mount state - if (GetTypeId() == TYPEID_PLAYER && IsMounted()) - { - return false; - } - - // nobody can attack GM in GM-mode - if (victim->GetTypeId() == TYPEID_PLAYER) - { - if (((Player*)victim)->isGameMaster()) - { - return false; - } - } - else - { - if (((Creature*)victim)->IsInEvadeMode()) - { - return false; - } - } - - // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack) - if (HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) - RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE); - - // in fighting already - if (m_attacking) - { - if (m_attacking == victim) - { - // switch to melee attack from ranged/magic - if (meleeAttack) - { - if (!hasUnitState(UNIT_STAT_MELEE_ATTACKING)) - { - addUnitState(UNIT_STAT_MELEE_ATTACKING); - SendMeleeAttackStart(victim); - } - return true; - } - return false; - } - - // remove old target data - AttackStop(true); - } - // new battle - else - { - // set position before any AI calls/assistance - if (GetTypeId() == TYPEID_UNIT) - ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); - } - - // Set our target - SetTargetGuid(victim->GetObjectGuid()); - - if (meleeAttack) - addUnitState(UNIT_STAT_MELEE_ATTACKING); - - m_attacking = victim; - m_attacking->_addAttacker(this); - - if (GetTypeId() == TYPEID_UNIT) - { - ((Creature*)this)->SendAIReaction(AI_REACTION_HOSTILE); - ((Creature*)this)->CallAssistance(); - } - - // delay offhand weapon attack to next attack time - if (haveOffhandWeapon()) - resetAttackTimer(OFF_ATTACK); - - if (meleeAttack) - SendMeleeAttackStart(victim); - - return true; + if (!victim || victim == this) + { + return false; + } + + // dead units can neither attack nor be attacked + if (!IsAlive() || !victim->IsInWorld() || !victim->IsAlive()) + { + return false; + } + + // player cannot attack in mount state + if (GetTypeId() == TYPEID_PLAYER && IsMounted()) + { + return false; + } + + // nobody can attack GM in GM-mode + if (victim->GetTypeId() == TYPEID_PLAYER) + { + if (((Player*)victim)->isGameMaster()) + { + return false; + } + } + else + { + if (((Creature*)victim)->IsInEvadeMode()) + { + return false; + } + } + + // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack) + if (HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) + RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE); + + // in fighting already + if (m_attacking) + { + if (m_attacking == victim) + { + // switch to melee attack from ranged/magic + if (meleeAttack) + { + if (!hasUnitState(UNIT_STAT_MELEE_ATTACKING)) + { + addUnitState(UNIT_STAT_MELEE_ATTACKING); + SendMeleeAttackStart(victim); + } + return true; + } + return false; + } + + // remove old target data + AttackStop(true); + } + // new battle + else + { + // set position before any AI calls/assistance + if (GetTypeId() == TYPEID_UNIT) + ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); + } + + // Set our target + SetTargetGuid(victim->GetObjectGuid()); + + if (meleeAttack) + addUnitState(UNIT_STAT_MELEE_ATTACKING); + + m_attacking = victim; + m_attacking->_addAttacker(this); + + if (GetTypeId() == TYPEID_UNIT) + { + ((Creature*)this)->SendAIReaction(AI_REACTION_HOSTILE); + ((Creature*)this)->CallAssistance(); + } + + // delay offhand weapon attack to next attack time + if (haveOffhandWeapon()) + resetAttackTimer(OFF_ATTACK); + + if (meleeAttack) + SendMeleeAttackStart(victim); + + return true; } void Unit::AttackedBy(Unit* attacker) { - // trigger AI reaction - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) - ((Creature*)this)->AI()->AttackedBy(attacker); + // trigger AI reaction + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) + ((Creature*)this)->AI()->AttackedBy(attacker); - // do not pet reaction for self inflicted damage (like environmental) - if (attacker == this) - { - return; - } + // do not pet reaction for self inflicted damage (like environmental) + if (attacker == this) + { + return; + } - // trigger pet AI reaction - if (Pet* pet = GetPet()) - pet->AttackedBy(attacker); + // trigger pet AI reaction + if (Pet* pet = GetPet()) + pet->AttackedBy(attacker); } bool Unit::AttackStop(bool targetSwitch /*=false*/) { - if (!m_attacking) - { - return false; - } + if (!m_attacking) + { + return false; + } - Unit* victim = m_attacking; + Unit* victim = m_attacking; - m_attacking->_removeAttacker(this); - m_attacking = NULL; + m_attacking->_removeAttacker(this); + m_attacking = NULL; - // Clear our target - SetTargetGuid(ObjectGuid()); + // Clear our target + SetTargetGuid(ObjectGuid()); - clearUnitState(UNIT_STAT_MELEE_ATTACKING); + clearUnitState(UNIT_STAT_MELEE_ATTACKING); - InterruptSpell(CURRENT_MELEE_SPELL); + InterruptSpell(CURRENT_MELEE_SPELL); - // reset only at real combat stop - if (!targetSwitch && GetTypeId() == TYPEID_UNIT) - { - ((Creature*)this)->SetNoCallAssistance(false); + // reset only at real combat stop + if (!targetSwitch && GetTypeId() == TYPEID_UNIT) + { + ((Creature*)this)->SetNoCallAssistance(false); - if (((Creature*)this)->HasSearchedAssistance()) - { - ((Creature*)this)->SetNoSearchAssistance(false); - UpdateSpeed(MOVE_RUN, false); - } - } + if (((Creature*)this)->HasSearchedAssistance()) + { + ((Creature*)this)->SetNoSearchAssistance(false); + UpdateSpeed(MOVE_RUN, false); + } + } - SendMeleeAttackStop(victim); + SendMeleeAttackStop(victim); - return true; + return true; } void Unit::CombatStop(bool includingCast) { - if (includingCast && IsNonMeleeSpellCasted(false)) - InterruptNonMeleeSpells(false); + if (includingCast && IsNonMeleeSpellCasted(false)) + InterruptNonMeleeSpells(false); - AttackStop(); - RemoveAllAttackers(); + AttackStop(); + RemoveAllAttackers(); - if (GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel - else if (GetTypeId() == TYPEID_UNIT) - { - if (((Creature*)this)->GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_COMBAT_STOP) - ((Creature*)this)->ClearTemporaryFaction(); - } + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel + else if (GetTypeId() == TYPEID_UNIT) + { + if (((Creature*)this)->GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_COMBAT_STOP) + ((Creature*)this)->ClearTemporaryFaction(); + } - ClearInCombat(); + ClearInCombat(); } struct CombatStopWithPetsHelper { - explicit CombatStopWithPetsHelper(bool _includingCast) : includingCast(_includingCast) {} - void operator()(Unit* unit) const { unit->CombatStop(includingCast); } - bool includingCast; + explicit CombatStopWithPetsHelper(bool _includingCast) : includingCast(_includingCast) {} + void operator()(Unit* unit) const { unit->CombatStop(includingCast); } + bool includingCast; }; void Unit::CombatStopWithPets(bool includingCast) { - CombatStop(includingCast); - CallForAllControlledUnits(CombatStopWithPetsHelper(includingCast), CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); + CombatStop(includingCast); + CallForAllControlledUnits(CombatStopWithPetsHelper(includingCast), CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); } struct IsAttackingPlayerHelper { - explicit IsAttackingPlayerHelper() {} - bool operator()(Unit const* unit) const { return unit->isAttackingPlayer(); } + explicit IsAttackingPlayerHelper() {} + bool operator()(Unit const* unit) const { return unit->isAttackingPlayer(); } }; bool Unit::isAttackingPlayer() const { - if (hasUnitState(UNIT_STAT_ATTACK_PLAYER)) - { - return true; - } + if (hasUnitState(UNIT_STAT_ATTACK_PLAYER)) + { + return true; + } - return CheckAllControlledUnits(IsAttackingPlayerHelper(), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); + return CheckAllControlledUnits(IsAttackingPlayerHelper(), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); } bool Unit::CanAttackByItself() const { - if (!IsVehicle()) - { - return true; - } + if (!IsVehicle()) + { + return true; + } - for (uint8 i = 0; i < MAX_VEHICLE_SEAT; ++i) - { - if (uint32 seatId = m_vehicleInfo->GetVehicleEntry()->m_seatID[i]) - { - if (VehicleSeatEntry const* seatEntry = sVehicleSeatStore.LookupEntry(seatId)) - { - if (seatEntry->m_flags & SEAT_FLAG_CAN_CONTROL) - { - return false; - } - } - } - } + for (uint8 i = 0; i < MAX_VEHICLE_SEAT; ++i) + { + if (uint32 seatId = m_vehicleInfo->GetVehicleEntry()->m_seatID[i]) + { + if (VehicleSeatEntry const* seatEntry = sVehicleSeatStore.LookupEntry(seatId)) + { + if (seatEntry->m_flags & SEAT_FLAG_CAN_CONTROL) + { + return false; + } + } + } + } - return true; + return true; } void Unit::RemoveAllAttackers() { - while (!m_attackers.empty()) - { - AttackerSet::iterator iter = m_attackers.begin(); - if (!(*iter)->AttackStop()) - { - sLog.outError("WORLD: Unit has an attacker that isn't attacking it!"); - m_attackers.erase(iter); - } - } + while (!m_attackers.empty()) + { + AttackerSet::iterator iter = m_attackers.begin(); + if (!(*iter)->AttackStop()) + { + sLog.outError("WORLD: Unit has an attacker that isn't attacking it!"); + m_attackers.erase(iter); + } + } } bool Unit::HasAuraStateForCaster(AuraState flag, ObjectGuid casterGuid) const { - if (!HasAuraState(flag)) - { - return false; - } + if (!HasAuraState(flag)) + { + return false; + } - // single per-caster aura state - if (flag == AURA_STATE_CONFLAGRATE) - { - Unit::AuraList const& dotList = GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for (Unit::AuraList::const_iterator i = dotList.begin(); i != dotList.end(); ++i) - { - if ((*i)->GetCasterGuid() == casterGuid && - // Immolate or Shadowflame - (*i)->GetSpellProto()->IsFitToFamily(SPELLFAMILY_WARLOCK, UI64LIT(0x0000000000000004), 0x00000002)) - { - return true; - } - } + // single per-caster aura state + if (flag == AURA_STATE_CONFLAGRATE) + { + Unit::AuraList const& dotList = GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); + for (Unit::AuraList::const_iterator i = dotList.begin(); i != dotList.end(); ++i) + { + if ((*i)->GetCasterGuid() == casterGuid && + // Immolate or Shadowflame + (*i)->GetSpellProto()->IsFitToFamily(SPELLFAMILY_WARLOCK, UI64LIT(0x0000000000000004), 0x00000002)) + { + return true; + } + } - return false; - } + return false; + } - return true; + return true; } void Unit::ModifyAuraState(AuraState flag, bool apply) { - if (apply) - { - if (!HasFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1))) - { - SetFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1)); - if (GetTypeId() == TYPEID_PLAYER) - { - const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - if (itr->second.state == PLAYERSPELL_REMOVED) continue; - SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); - if (!spellInfo || !IsPassiveSpell(spellInfo)) continue; - if (AuraState(spellInfo->GetCasterAuraState()) == flag) - CastSpell(this, itr->first, true, NULL); - } - } - } - } - else - { - if (HasFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1))) - { - RemoveFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1)); - - if (flag != AURA_STATE_ENRAGE) // enrage aura state triggering continues auras - { - Unit::SpellAuraHolderMap& tAuras = GetSpellAuraHolderMap(); - for (Unit::SpellAuraHolderMap::iterator itr = tAuras.begin(); itr != tAuras.end();) - { - SpellEntry const* spellProto = (*itr).second->GetSpellProto(); - if (AuraState(spellProto->GetCasterAuraState()) == flag) - { - RemoveSpellAuraHolder(itr->second); - itr = tAuras.begin(); - } - else - ++itr; - } - } - } - } + if (apply) + { + if (!HasFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1))) + { + SetFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1)); + if (GetTypeId() == TYPEID_PLAYER) + { + const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + { + if (itr->second.state == PLAYERSPELL_REMOVED) continue; + SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); + if (!spellInfo || !IsPassiveSpell(spellInfo)) continue; + if (AuraState(spellInfo->GetCasterAuraState()) == flag) + CastSpell(this, itr->first, true, NULL); + } + } + } + } + else + { + if (HasFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1))) + { + RemoveFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1)); + + if (flag != AURA_STATE_ENRAGE) // enrage aura state triggering continues auras + { + Unit::SpellAuraHolderMap& tAuras = GetSpellAuraHolderMap(); + for (Unit::SpellAuraHolderMap::iterator itr = tAuras.begin(); itr != tAuras.end();) + { + SpellEntry const* spellProto = (*itr).second->GetSpellProto(); + if (AuraState(spellProto->GetCasterAuraState()) == flag) + { + RemoveSpellAuraHolder(itr->second); + itr = tAuras.begin(); + } + else + ++itr; + } + } + } + } } Unit* Unit::GetOwner() const { - if (ObjectGuid ownerid = GetOwnerGuid()) - { - return ObjectAccessor::GetUnit(*this, ownerid); - } - return NULL; + if (ObjectGuid ownerid = GetOwnerGuid()) + { + return ObjectAccessor::GetUnit(*this, ownerid); + } + return NULL; } Unit* Unit::GetCharmer() const { - if (ObjectGuid charmerid = GetCharmerGuid()) - { - return ObjectAccessor::GetUnit(*this, charmerid); - } - return NULL; + if (ObjectGuid charmerid = GetCharmerGuid()) + { + return ObjectAccessor::GetUnit(*this, charmerid); + } + return NULL; } bool Unit::IsCharmerOrOwnerPlayerOrPlayerItself() const { - if (GetTypeId() == TYPEID_PLAYER) - { - return true; - } + if (GetTypeId() == TYPEID_PLAYER) + { + return true; + } - return GetCharmerOrOwnerGuid().IsPlayer(); + return GetCharmerOrOwnerGuid().IsPlayer(); } Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() { - ObjectGuid guid = GetCharmerOrOwnerGuid(); - if (guid.IsPlayer()) - { - return ObjectAccessor::FindPlayer(guid); - } + ObjectGuid guid = GetCharmerOrOwnerGuid(); + if (guid.IsPlayer()) + { + return ObjectAccessor::FindPlayer(guid); + } - return GetTypeId() == TYPEID_PLAYER ? (Player*)this : NULL; + return GetTypeId() == TYPEID_PLAYER ? (Player*)this : NULL; } Player const* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() const { - ObjectGuid guid = GetCharmerOrOwnerGuid(); - if (guid.IsPlayer()) - { - return ObjectAccessor::FindPlayer(guid); - } + ObjectGuid guid = GetCharmerOrOwnerGuid(); + if (guid.IsPlayer()) + { + return ObjectAccessor::FindPlayer(guid); + } - return GetTypeId() == TYPEID_PLAYER ? (Player const*)this : NULL; + return GetTypeId() == TYPEID_PLAYER ? (Player const*)this : NULL; } Pet* Unit::GetPet() const { - if (ObjectGuid pet_guid = GetPetGuid()) - { - if (Pet* pet = GetMap()->GetPet(pet_guid)) - { - return pet; - } + if (ObjectGuid pet_guid = GetPetGuid()) + { + if (Pet* pet = GetMap()->GetPet(pet_guid)) + { + return pet; + } - sLog.outError("Unit::GetPet: %s not exist.", pet_guid.GetString().c_str()); - const_cast(this)->SetPet(0); - } + sLog.outError("Unit::GetPet: %s not exist.", pet_guid.GetString().c_str()); + const_cast(this)->SetPet(0); + } - return NULL; + return NULL; } Pet* Unit::_GetPet(ObjectGuid guid) const { - return GetMap()->GetPet(guid); + return GetMap()->GetPet(guid); } void Unit::RemoveMiniPet() { - if (Pet* pet = GetMiniPet()) - pet->Unsummon(PET_SAVE_AS_DELETED, this); - else - SetCritterGuid(ObjectGuid()); + if (Pet* pet = GetMiniPet()) + pet->Unsummon(PET_SAVE_AS_DELETED, this); + else + SetCritterGuid(ObjectGuid()); } Pet* Unit::GetMiniPet() const { - if (!GetCritterGuid()) - { - return NULL; - } + if (!GetCritterGuid()) + { + return NULL; + } - return GetMap()->GetPet(GetCritterGuid()); + return GetMap()->GetPet(GetCritterGuid()); } Unit* Unit::GetCharm() const { - if (ObjectGuid charm_guid = GetCharmGuid()) - { - if (Unit* pet = ObjectAccessor::GetUnit(*this, charm_guid)) - { - return pet; - } + if (ObjectGuid charm_guid = GetCharmGuid()) + { + if (Unit* pet = ObjectAccessor::GetUnit(*this, charm_guid)) + { + return pet; + } - sLog.outError("Unit::GetCharm: Charmed %s not exist.", charm_guid.GetString().c_str()); - const_cast(this)->SetCharm(NULL); - } + sLog.outError("Unit::GetCharm: Charmed %s not exist.", charm_guid.GetString().c_str()); + const_cast(this)->SetCharm(NULL); + } - return NULL; + return NULL; } void Unit::Uncharm() { - if (Unit* charm = GetCharm()) - { - charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM); - charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS); - charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS_PET); + if (Unit* charm = GetCharm()) + { + charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM); + charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS); + charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS_PET); - // TODO:: find a way to get rid of this bad hack to remove Raise ally aura - if (charm->GetTypeId() == TYPEID_UNIT) - { - uint32 createdBySpellId = charm->GetUInt32Value(UNIT_CREATED_BY_SPELL); - if (static_cast(charm)->IsTemporarySummon() && createdBySpellId) - RemoveAurasDueToSpell(createdBySpellId); - } - } + // TODO:: find a way to get rid of this bad hack to remove Raise ally aura + if (charm->GetTypeId() == TYPEID_UNIT) + { + uint32 createdBySpellId = charm->GetUInt32Value(UNIT_CREATED_BY_SPELL); + if (static_cast(charm)->IsTemporarySummon() && createdBySpellId) + RemoveAurasDueToSpell(createdBySpellId); + } + } } void Unit::SetPet(Pet* pet) { - SetPetGuid(pet ? pet->GetObjectGuid() : ObjectGuid()); + SetPetGuid(pet ? pet->GetObjectGuid() : ObjectGuid()); - if (pet && GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->SendPetGUIDs(); + if (pet && GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SendPetGUIDs(); } void Unit::SetCharm(Unit* pet) { - SetCharmGuid(pet ? pet->GetObjectGuid() : ObjectGuid()); + SetCharmGuid(pet ? pet->GetObjectGuid() : ObjectGuid()); } void Unit::AddGuardian(Pet* pet) { - m_guardianPets.insert(pet->GetObjectGuid()); + m_guardianPets.insert(pet->GetObjectGuid()); } void Unit::RemoveGuardian(Pet* pet) { - m_guardianPets.erase(pet->GetObjectGuid()); + m_guardianPets.erase(pet->GetObjectGuid()); } void Unit::RemoveGuardians() { - while (!m_guardianPets.empty()) - { - ObjectGuid guid = *m_guardianPets.begin(); + while (!m_guardianPets.empty()) + { + ObjectGuid guid = *m_guardianPets.begin(); - if (Pet* pet = GetMap()->GetPet(guid)) - pet->Unsummon(PET_SAVE_AS_DELETED, this); // can remove pet guid from m_guardianPets + if (Pet* pet = GetMap()->GetPet(guid)) + pet->Unsummon(PET_SAVE_AS_DELETED, this); // can remove pet guid from m_guardianPets - m_guardianPets.erase(guid); - } + m_guardianPets.erase(guid); + } } Pet* Unit::FindGuardianWithEntry(uint32 entry) { - for (GuidSet::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr) - if (Pet* pet = GetMap()->GetPet(*itr)) - if (pet->GetEntry() == entry) - { - return pet; - } + for (GuidSet::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr) + if (Pet* pet = GetMap()->GetPet(*itr)) + if (pet->GetEntry() == entry) + { + return pet; + } - return NULL; + return NULL; } Pet* Unit::GetProtectorPet() { - for (GuidSet::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr) - if (Pet* pet = GetMap()->GetPet(*itr)) - if (pet->getPetType() == PROTECTOR_PET) - { - return pet; - } + for (GuidSet::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr) + if (Pet* pet = GetMap()->GetPet(*itr)) + if (pet->getPetType() == PROTECTOR_PET) + { + return pet; + } - return NULL; + return NULL; } Unit* Unit::_GetTotem(TotemSlot slot) const { - return GetTotem(slot); + return GetTotem(slot); } Totem* Unit::GetTotem(TotemSlot slot) const { - if (slot >= MAX_TOTEM_SLOT || !IsInWorld() || !m_TotemSlot[slot]) - { - return NULL; - } + if (slot >= MAX_TOTEM_SLOT || !IsInWorld() || !m_TotemSlot[slot]) + { + return NULL; + } - Creature* totem = GetMap()->GetCreature(m_TotemSlot[slot]); - return totem && totem->IsTotem() ? (Totem*)totem : NULL; + Creature* totem = GetMap()->GetCreature(m_TotemSlot[slot]); + return totem && totem->IsTotem() ? (Totem*)totem : NULL; } bool Unit::IsAllTotemSlotsUsed() const { - for (int i = 0; i < MAX_TOTEM_SLOT; ++i) - if (!m_TotemSlot[i]) - { - return false; - } - return true; + for (int i = 0; i < MAX_TOTEM_SLOT; ++i) + if (!m_TotemSlot[i]) + { + return false; + } + return true; } void Unit::_AddTotem(TotemSlot slot, Totem* totem) { - m_TotemSlot[slot] = totem->GetObjectGuid(); + m_TotemSlot[slot] = totem->GetObjectGuid(); } void Unit::_RemoveTotem(Totem* totem) { - for (int i = 0; i < MAX_TOTEM_SLOT; ++i) - { - if (m_TotemSlot[i] == totem->GetObjectGuid()) - { - m_TotemSlot[i].Clear(); - break; - } - } + for (int i = 0; i < MAX_TOTEM_SLOT; ++i) + { + if (m_TotemSlot[i] == totem->GetObjectGuid()) + { + m_TotemSlot[i].Clear(); + break; + } + } } void Unit::UnsummonAllTotems() { - for (int i = 0; i < MAX_TOTEM_SLOT; ++i) - if (Totem* totem = GetTotem(TotemSlot(i))) - totem->UnSummon(); + for (int i = 0; i < MAX_TOTEM_SLOT; ++i) + if (Totem* totem = GetTotem(TotemSlot(i))) + totem->UnSummon(); } int32 Unit::DealHeal(Unit* pVictim, uint32 addhealth, SpellEntry const* spellProto, bool critical, uint32 absorb) { - int32 gain = pVictim->ModifyHealth(int32(addhealth)); + int32 gain = pVictim->ModifyHealth(int32(addhealth)); - Unit* unit = this; + Unit* unit = this; - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsTotem() && ((Totem*)this)->GetTotemType() != TOTEM_STATUE) - unit = GetOwner(); + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsTotem() && ((Totem*)this)->GetTotemType() != TOTEM_STATUE) + unit = GetOwner(); - // overheal = addhealth - gain - unit->SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth - gain, critical, absorb); + // overheal = addhealth - gain + unit->SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth - gain, critical, absorb); - if (unit->GetTypeId() == TYPEID_PLAYER) - { - if (BattleGround* bg = ((Player*)unit)->GetBattleGround()) - bg->UpdatePlayerScore((Player*)unit, SCORE_HEALING_DONE, gain); + if (unit->GetTypeId() == TYPEID_PLAYER) + { + if (BattleGround* bg = ((Player*)unit)->GetBattleGround()) + bg->UpdatePlayerScore((Player*)unit, SCORE_HEALING_DONE, gain); - // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria) - if (gain) - ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim); + // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria) + if (gain) + ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim); - ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth); - } + ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth); + } - if (pVictim->GetTypeId() == TYPEID_PLAYER) - { - ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain); - ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth); - } + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain); + ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth); + } - // Script Event HealedBy - if (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->AI()) - ((Creature*)pVictim)->AI()->HealedBy(this, addhealth); + // Script Event HealedBy + if (pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->AI()) + ((Creature*)pVictim)->AI()->HealedBy(this, addhealth); - return gain; + return gain; } Unit* Unit::SelectMagnetTarget(Unit* victim, Spell* spell, SpellEffectIndex eff) { - if (!victim) - { - return NULL; - } - - // Magic case - if (spell && (spell->m_spellInfo->GetDmgClass() == SPELL_DAMAGE_CLASS_NONE || spell->m_spellInfo->GetDmgClass() == SPELL_DAMAGE_CLASS_MAGIC)) - { - Unit::AuraList const& magnetAuras = victim->GetAurasByType(SPELL_AURA_SPELL_MAGNET); - for (Unit::AuraList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr) - { - if (Unit* magnet = (*itr)->GetCaster()) - { - if (magnet->IsAlive() && magnet->IsWithinLOSInMap(this) && spell->CheckTarget(magnet, eff)) - { - return magnet; - } - } - } - } - // Melee && ranged case - else - { - AuraList const& hitTriggerAuras = victim->GetAurasByType(SPELL_AURA_ADD_CASTER_HIT_TRIGGER); - for (AuraList::const_iterator i = hitTriggerAuras.begin(); i != hitTriggerAuras.end(); ++i) - { - if (Unit* magnet = (*i)->GetCaster()) - { - if (magnet->IsAlive() && magnet->IsWithinLOSInMap(this) && (!spell || spell->CheckTarget(magnet, eff))) - { - if (roll_chance_i((*i)->GetModifier()->m_amount)) - { - return magnet; - } - } - } - } - } - - return victim; + if (!victim) + { + return NULL; + } + + // Magic case + if (spell && (spell->m_spellInfo->GetDmgClass() == SPELL_DAMAGE_CLASS_NONE || spell->m_spellInfo->GetDmgClass() == SPELL_DAMAGE_CLASS_MAGIC)) + { + Unit::AuraList const& magnetAuras = victim->GetAurasByType(SPELL_AURA_SPELL_MAGNET); + for (Unit::AuraList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr) + { + if (Unit* magnet = (*itr)->GetCaster()) + { + if (magnet->IsAlive() && magnet->IsWithinLOSInMap(this) && spell->CheckTarget(magnet, eff)) + { + return magnet; + } + } + } + } + // Melee && ranged case + else + { + AuraList const& hitTriggerAuras = victim->GetAurasByType(SPELL_AURA_ADD_CASTER_HIT_TRIGGER); + for (AuraList::const_iterator i = hitTriggerAuras.begin(); i != hitTriggerAuras.end(); ++i) + { + if (Unit* magnet = (*i)->GetCaster()) + { + if (magnet->IsAlive() && magnet->IsWithinLOSInMap(this) && (!spell || spell->CheckTarget(magnet, eff))) + { + if (roll_chance_i((*i)->GetModifier()->m_amount)) + { + return magnet; + } + } + } + } + } + + return victim; } void Unit::SendHealSpellLog(Unit* pVictim, uint32 SpellID, uint32 Damage, uint32 OverHeal, bool critical, uint32 absorb) { - // we guess size - WorldPacket data(SMSG_SPELLHEALLOG, (8 + 8 + 4 + 4 + 1)); - data << pVictim->GetPackGUID(); - data << GetPackGUID(); - data << uint32(SpellID); - data << uint32(Damage); - data << uint32(OverHeal); - data << uint32(absorb); - data << uint8(critical ? 1 : 0); - data << uint8(0); // unused in client? - SendMessageToSet(&data, true); + // we guess size + WorldPacket data(SMSG_SPELLHEALLOG, (8 + 8 + 4 + 4 + 1)); + data << pVictim->GetPackGUID(); + data << GetPackGUID(); + data << uint32(SpellID); + data << uint32(Damage); + data << uint32(OverHeal); + data << uint32(absorb); + data << uint8(critical ? 1 : 0); + data << uint8(0); // unused in client? + SendMessageToSet(&data, true); } void Unit::SendEnergizeSpellLog(Unit* pVictim, uint32 SpellID, uint32 Damage, Powers powertype) { - WorldPacket data(SMSG_SPELLENERGIZELOG, (8 + 8 + 4 + 4 + 4 + 1)); - data << pVictim->GetPackGUID(); - data << GetPackGUID(); - data << uint32(SpellID); - data << uint32(powertype); - data << uint32(Damage); - SendMessageToSet(&data, true); + WorldPacket data(SMSG_SPELLENERGIZELOG, (8 + 8 + 4 + 4 + 4 + 1)); + data << pVictim->GetPackGUID(); + data << GetPackGUID(); + data << uint32(SpellID); + data << uint32(powertype); + data << uint32(Damage); + SendMessageToSet(&data, true); } void Unit::EnergizeBySpell(Unit* pVictim, uint32 SpellID, uint32 Damage, Powers powertype) { - SendEnergizeSpellLog(pVictim, SpellID, Damage, powertype); - // needs to be called after sending spell log - pVictim->ModifyPower(powertype, Damage); + SendEnergizeSpellLog(pVictim, SpellID, Damage, powertype); + // needs to be called after sending spell log + pVictim->ModifyPower(powertype, Damage); } /** Calculate spell coefficents and level penalties for spell/melee damage or heal @@ -7277,54 +7281,54 @@ void Unit::EnergizeBySpell(Unit* pVictim, uint32 SpellID, uint32 Damage, Powers * @param donePart calculate for done or taken * @param defCoeffMod default coefficient for additional scaling (i.e. normal player healing SCALE_SPELLPOWER_HEALING) */ -int32 Unit::SpellBonusWithCoeffs(SpellEntry const* spellProto, int32 total, int32 benefit, int32 ap_benefit, DamageEffectType damagetype, bool donePart, float defCoeffMod) -{ - // Distribute Damage over multiple effects, reduce by AoE - float coeff = 1.0f; - - // Not apply this to creature casted spells - if (GetTypeId() == TYPEID_UNIT && !((Creature*)this)->IsPet()) - coeff = 1.0f; - // Check for table values - else if (SpellBonusEntry const* bonus = sSpellMgr.GetSpellBonusData(spellProto->Id)) - { - coeff = damagetype == DOT ? bonus->dot_damage : bonus->direct_damage; - - // apply ap bonus at done part calculation only (it flat total mod so common with taken) - if (donePart && (bonus->ap_bonus || bonus->ap_dot_bonus)) - { - float ap_bonus = damagetype == DOT ? bonus->ap_dot_bonus : bonus->ap_bonus; - - // Impurity - if (GetTypeId() == TYPEID_PLAYER && spellProto->GetSpellFamilyName() == SPELLFAMILY_DEATHKNIGHT) - { - if (SpellEntry const* spell = ((Player*)this)->GetKnownTalentRankById(2005)) - ap_bonus += ((spell->CalculateSimpleValue(EFFECT_INDEX_0) * ap_bonus) / 100.0f); - } - - total += int32(ap_bonus * (GetTotalAttackPowerValue(IsSpellRequiresRangedAP(spellProto) ? RANGED_ATTACK : BASE_ATTACK) + ap_benefit)); - } - } - // Default calculation - else if (benefit) - coeff = CalculateDefaultCoefficient(spellProto, damagetype) * defCoeffMod; - - if (benefit) - { - float LvlPenalty = CalculateLevelPenalty(spellProto); - - // Spellmod SpellDamage - if (Player* modOwner = GetSpellModOwner()) - { - coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_SPELL_BONUS_DAMAGE, coeff); - coeff /= 100.0f; - } - - total += int32(benefit * coeff * LvlPenalty); - } - - return total; +int32 Unit::SpellBonusWithCoeffs(SpellEntry const* spellProto, int32 total, int32 benefit, int32 ap_benefit, DamageEffectType damagetype, bool donePart, float defCoeffMod) +{ + // Distribute Damage over multiple effects, reduce by AoE + float coeff = 1.0f; + + // Not apply this to creature casted spells + if (GetTypeId() == TYPEID_UNIT && !((Creature*)this)->IsPet()) + coeff = 1.0f; + // Check for table values + else if (SpellBonusEntry const* bonus = sSpellMgr.GetSpellBonusData(spellProto->Id)) + { + coeff = damagetype == DOT ? bonus->dot_damage : bonus->direct_damage; + + // apply ap bonus at done part calculation only (it flat total mod so common with taken) + if (donePart && (bonus->ap_bonus || bonus->ap_dot_bonus)) + { + float ap_bonus = damagetype == DOT ? bonus->ap_dot_bonus : bonus->ap_bonus; + + // Impurity + if (GetTypeId() == TYPEID_PLAYER && spellProto->GetSpellFamilyName() == SPELLFAMILY_DEATHKNIGHT) + { + if (SpellEntry const* spell = ((Player*)this)->GetKnownTalentRankById(2005)) + ap_bonus += ((spell->CalculateSimpleValue(EFFECT_INDEX_0) * ap_bonus) / 100.0f); + } + + total += int32(ap_bonus * (GetTotalAttackPowerValue(IsSpellRequiresRangedAP(spellProto) ? RANGED_ATTACK : BASE_ATTACK) + ap_benefit)); + } + } + // Default calculation + else if (benefit) + coeff = CalculateDefaultCoefficient(spellProto, damagetype) * defCoeffMod; + + if (benefit) + { + float LvlPenalty = CalculateLevelPenalty(spellProto); + + // Spellmod SpellDamage + if (Player* modOwner = GetSpellModOwner()) + { + coeff *= 100.0f; + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_SPELL_BONUS_DAMAGE, coeff); + coeff /= 100.0f; + } + + total += int32(benefit * coeff * LvlPenalty); + } + + return total; }; /** @@ -7333,340 +7337,340 @@ int32 Unit::SpellBonusWithCoeffs(SpellEntry const* spellProto, int32 total, int3 */ uint32 Unit::SpellDamageBonusDone(Unit* pVictim, SpellEntry const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) { - if (!spellProto || !pVictim || damagetype == DIRECT_DAMAGE || spellProto->HasAttribute(SPELL_ATTR_EX6_NO_DMG_MODS)) - { - return pdamage; - } - - // For totems get damage bonus from owner (statue isn't totem in fact) - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsTotem() && ((Totem*)this)->GetTotemType() != TOTEM_STATUE) - { - if (Unit* owner = GetOwner()) - { - return owner->SpellDamageBonusDone(pVictim, spellProto, pdamage, damagetype); - } - } - - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - float DoneTotalMod = 1.0f; - int32 DoneTotal = 0; - - // Creature damage - if (GetTypeId() == TYPEID_UNIT && !((Creature*)this)->IsPet()) - DoneTotalMod *= ((Creature*)this)->_GetSpellDamageMod(((Creature*)this)->GetCreatureInfo()->Rank); - - AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for (AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) - { - SpellEquippedItemsEntry const* spellEquip = (*i)->GetSpellProto()->GetSpellEquippedItems(); - if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) && - (!spellEquip || spellEquip->EquippedItemClass == -1 && - // -1 == any item class (not wand then) - spellEquip->EquippedItemInventoryTypeMask == 0)) - // 0 == any inventory type (not wand then) - { - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - } - } - - // Add flat bonus from spell damage versus - DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask); - - // Add pct bonus from spell damage versus - DoneTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS, creatureTypeMask); - - // Add flat bonus from spell damage creature - DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask); - - if (GetPowerType() == POWER_MANA) - { - Unit::AuraList const& doneFromManaPctAuras = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_FROM_PCT_POWER); - if (!doneFromManaPctAuras.empty()) - { - float powerPct = std::min(float(GetPower(POWER_MANA)) / GetMaxPower(POWER_MANA), 1.0f); - for (Unit::AuraList::const_iterator itr = doneFromManaPctAuras.begin(); itr != doneFromManaPctAuras.end(); ++itr) - { - if (GetSpellSchoolMask(spellProto) & (*itr)->GetModifier()->m_miscvalue) - DoneTotalMod *= (100.0f + (*itr)->GetModifier()->m_amount * powerPct) / 100.0f; - } - } - } - - // done scripted mod (take it from owner) - Unit* owner = GetOwner(); - if (!owner) - owner = this; - - AuraList const& mOverrideClassScript = owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) - { - if (!(*i)->isAffectedOnSpell(spellProto)) - continue; - switch ((*i)->GetModifier()->m_miscvalue) - { - // Molten Fury - case 4920: - case 4919: - case 6917: // Death's Embrace - case 6926: - case 6928: - { - if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) - DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; - break; - } - // Soul Siphon - case 4992: - case 4993: - { - // effect 1 m_amount - int32 maxPercent = (*i)->GetModifier()->m_amount; - // effect 0 m_amount - int32 stepPercent = CalculateSpellDamage(this, (*i)->GetSpellProto(), EFFECT_INDEX_0); - // count affliction effects and calc additional damage in percentage - int32 modPercent = 0; - SpellAuraHolderMap const& victimAuras = pVictim->GetSpellAuraHolderMap(); - for (SpellAuraHolderMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr) - { - SpellEntry const* m_spell = itr->second->GetSpellProto(); - SpellClassOptionsEntry const* itrClassOptions = m_spell->GetSpellClassOptions(); - if (itrClassOptions && (itrClassOptions->SpellFamilyName != SPELLFAMILY_WARLOCK || !(itrClassOptions->SpellFamilyFlags & UI64LIT(0x0004071B8044C402)))) - continue; - modPercent += stepPercent * itr->second->GetStackAmount(); - if (modPercent >= maxPercent) - { - modPercent = maxPercent; - break; - } - } - DoneTotalMod *= (modPercent + 100.0f) / 100.0f; - break; - } - case 6916: // Death's Embrace - case 6925: - case 6927: - if (HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT)) - DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; - break; - case 5481: // Starfire Bonus - { - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, UI64LIT(0x0000000000200002))) - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - case 4418: // Increased Shock Damage - case 4554: // Increased Lightning Damage - case 4555: // Improved Moonfire - case 5142: // Increased Lightning Damage - case 5147: // Improved Consecration / Libram of Resurgence - case 5148: // Idol of the Shooting Star - case 6008: // Increased Lightning Damage - case 8627: // Totem of Hex - { - DoneTotal += (*i)->GetModifier()->m_amount; - break; - } - // Tundra Stalker - // Merciless Combat - case 7277: - { - // Merciless Combat - if ((*i)->GetSpellProto()->GetSpellIconID() == 2656) - { - if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) - DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; - } - else // Tundra Stalker - { - // Frost Fever (target debuff) - if (pVictim->GetAura(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0000000000000000), 0x00000002)) - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - break; - } - case 7293: // Rage of Rivendare - { - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0200000000000000))) - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - // Twisted Faith - case 7377: - { - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, UI64LIT(0x0000000000008000), 0, GetObjectGuid())) - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - // Marked for Death - case 7598: - case 7599: - case 7600: - case 7601: - case 7602: - { - if (pVictim->GetAura(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, UI64LIT(0x0000000000000400))) - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - } - } - - SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); - - // Custom scripted damage - switch(spellProto->GetSpellFamilyName()) - { - case SPELLFAMILY_MAGE: - { - // Ice Lance - if (spellProto->GetSpellIconID() == 186) - { - if (pVictim->IsFrozen() || IsIgnoreUnitState(spellProto, IGNORE_UNIT_TARGET_NON_FROZEN)) - { - float multiplier = 3.0f; - - // if target have higher level - if (pVictim->getLevel() > getLevel()) - // Glyph of Ice Lance - if (Aura* glyph = GetDummyAura(56377)) - multiplier = glyph->GetModifier()->m_amount; - - DoneTotalMod *= multiplier; - } - } - // Torment the weak affected (Arcane Barrage, Arcane Blast, Frostfire Bolt, Arcane Missiles, Fireball) - if (classOptions && (classOptions->SpellFamilyFlags & UI64LIT(0x0000900020200021)) && - (pVictim->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED) || pVictim->HasAuraType(SPELL_AURA_HASTE_ALL))) - { - // Search for Torment the weak dummy aura - Unit::AuraList const& ttw = GetAurasByType(SPELL_AURA_DUMMY); - for (Unit::AuraList::const_iterator i = ttw.begin(); i != ttw.end(); ++i) - { - if ((*i)->GetSpellProto()->GetSpellIconID() == 3263) - { - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - } - } - break; - } - case SPELLFAMILY_WARLOCK: - { - // Drain Soul - if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000004000)) - { - if (pVictim->GetHealth() * 100 / pVictim->GetMaxHealth() <= 25) - DoneTotalMod *= 4; - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Smite - if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000080))) - { - // Holy Fire - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, UI64LIT(0x00100000))) - // Glyph of Smite - if (Aura* aur = GetAura(55692, EFFECT_INDEX_0)) - DoneTotalMod *= (aur->GetModifier()->m_amount + 100.0f) / 100.0f; - } - // Shadow word: Death - else if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000200000000))) - { - // Glyph of Shadow word: Death - if (SpellAuraHolder const* glyph = GetSpellAuraHolder(55682)) - { - Aura const* hpPct = glyph->GetAuraByEffectIndex(EFFECT_INDEX_0); - Aura const* dmPct = glyph->GetAuraByEffectIndex(EFFECT_INDEX_1); - if (hpPct && dmPct && pVictim->GetHealth() * 100 <= pVictim->GetMaxHealth() * hpPct->GetModifier()->m_amount) - DoneTotalMod *= (dmPct->GetModifier()->m_amount + 100.0f) / 100.0f; - } - } - break; - } - case SPELLFAMILY_DRUID: - { - // Improved Insect Swarm (Wrath part) - if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000000001)) - { - // if Insect Swarm on target - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, UI64LIT(0x000000000200000), 0, GetObjectGuid())) - { - Unit::AuraList const& improvedSwarm = GetAurasByType(SPELL_AURA_DUMMY); - for (Unit::AuraList::const_iterator iter = improvedSwarm.begin(); iter != improvedSwarm.end(); ++iter) - { - if ((*iter)->GetSpellProto()->GetSpellIconID() == 1771) - { - DoneTotalMod *= ((*iter)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - } - } - } - break; - } - case SPELLFAMILY_DEATHKNIGHT: - { - // Icy Touch and Howling Blast - if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000200000002)) - { - // search disease - bool found = false; - Unit::SpellAuraHolderMap const& auras = pVictim->GetSpellAuraHolderMap(); - for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - if(itr->second->GetSpellProto()->GetDispel() == DISPEL_DISEASE) - { - found = true; - break; - } - } - if (!found) - break; - - // search for Glacier Rot dummy aura - Unit::AuraList const& dummyAuras = GetAurasByType(SPELL_AURA_DUMMY); - for (Unit::AuraList::const_iterator i = dummyAuras.begin(); i != dummyAuras.end(); ++i) - { - if ((*i)->GetSpellProto()->GetEffectMiscValue((*i)->GetEffIndex()) == 7244) - { - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - } - } - // Death Coil (bonus from Item - Death Knight T8 DPS Relic) - else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x00002000)) - { - if (Aura* sigil = GetDummyAura(64962)) - DoneTotal += sigil->GetModifier()->m_amount; - } - break; - } - default: - break; - } - - // Done fixed damage bonus auras - int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(GetSpellSchoolMask(spellProto)); - - // Pets just add their bonus damage to their spell damage - // note that their spell damage is just gain of their own auras - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) - DoneAdvertisedBenefit += ((Pet*)this)->GetBonusDamage(); - - // apply ap bonus and benefit affected by spell power implicit coeffs and spell level penalties - DoneTotal = SpellBonusWithCoeffs(spellProto, DoneTotal, DoneAdvertisedBenefit, 0, damagetype, true); - - float tmpDamage = (int32(pdamage) + DoneTotal * int32(stack)) * DoneTotalMod; - // apply spellmod to Done damage (flat and pct) - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); - - return tmpDamage > 0 ? uint32(tmpDamage) : 0; + if (!spellProto || !pVictim || damagetype == DIRECT_DAMAGE || spellProto->HasAttribute(SPELL_ATTR_EX6_NO_DMG_MODS)) + { + return pdamage; + } + + // For totems get damage bonus from owner (statue isn't totem in fact) + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsTotem() && ((Totem*)this)->GetTotemType() != TOTEM_STATUE) + { + if (Unit* owner = GetOwner()) + { + return owner->SpellDamageBonusDone(pVictim, spellProto, pdamage, damagetype); + } + } + + uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); + float DoneTotalMod = 1.0f; + int32 DoneTotal = 0; + + // Creature damage + if (GetTypeId() == TYPEID_UNIT && !((Creature*)this)->IsPet()) + DoneTotalMod *= ((Creature*)this)->_GetSpellDamageMod(((Creature*)this)->GetCreatureInfo()->Rank); + + AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + for (AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) + { + SpellEquippedItemsEntry const* spellEquip = (*i)->GetSpellProto()->GetSpellEquippedItems(); + if (((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) && + (!spellEquip || spellEquip->EquippedItemClass == -1 && + // -1 == any item class (not wand then) + spellEquip->EquippedItemInventoryTypeMask == 0)) + // 0 == any inventory type (not wand then) + { + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + } + } + + // Add flat bonus from spell damage versus + DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask); + + // Add pct bonus from spell damage versus + DoneTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS, creatureTypeMask); + + // Add flat bonus from spell damage creature + DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask); + + if (GetPowerType() == POWER_MANA) + { + Unit::AuraList const& doneFromManaPctAuras = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_FROM_PCT_POWER); + if (!doneFromManaPctAuras.empty()) + { + float powerPct = std::min(float(GetPower(POWER_MANA)) / GetMaxPower(POWER_MANA), 1.0f); + for (Unit::AuraList::const_iterator itr = doneFromManaPctAuras.begin(); itr != doneFromManaPctAuras.end(); ++itr) + { + if (GetSpellSchoolMask(spellProto) & (*itr)->GetModifier()->m_miscvalue) + DoneTotalMod *= (100.0f + (*itr)->GetModifier()->m_amount * powerPct) / 100.0f; + } + } + } + + // done scripted mod (take it from owner) + Unit* owner = GetOwner(); + if (!owner) + owner = this; + + AuraList const& mOverrideClassScript = owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + { + if (!(*i)->isAffectedOnSpell(spellProto)) + continue; + switch ((*i)->GetModifier()->m_miscvalue) + { + // Molten Fury + case 4920: + case 4919: + case 6917: // Death's Embrace + case 6926: + case 6928: + { + if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) + DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; + break; + } + // Soul Siphon + case 4992: + case 4993: + { + // effect 1 m_amount + int32 maxPercent = (*i)->GetModifier()->m_amount; + // effect 0 m_amount + int32 stepPercent = CalculateSpellDamage(this, (*i)->GetSpellProto(), EFFECT_INDEX_0); + // count affliction effects and calc additional damage in percentage + int32 modPercent = 0; + SpellAuraHolderMap const& victimAuras = pVictim->GetSpellAuraHolderMap(); + for (SpellAuraHolderMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr) + { + SpellEntry const* m_spell = itr->second->GetSpellProto(); + SpellClassOptionsEntry const* itrClassOptions = m_spell->GetSpellClassOptions(); + if (itrClassOptions && (itrClassOptions->SpellFamilyName != SPELLFAMILY_WARLOCK || !(itrClassOptions->SpellFamilyFlags & UI64LIT(0x0004071B8044C402)))) + continue; + modPercent += stepPercent * itr->second->GetStackAmount(); + if (modPercent >= maxPercent) + { + modPercent = maxPercent; + break; + } + } + DoneTotalMod *= (modPercent + 100.0f) / 100.0f; + break; + } + case 6916: // Death's Embrace + case 6925: + case 6927: + if (HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT)) + DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; + break; + case 5481: // Starfire Bonus + { + if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, UI64LIT(0x0000000000200002))) + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + case 4418: // Increased Shock Damage + case 4554: // Increased Lightning Damage + case 4555: // Improved Moonfire + case 5142: // Increased Lightning Damage + case 5147: // Improved Consecration / Libram of Resurgence + case 5148: // Idol of the Shooting Star + case 6008: // Increased Lightning Damage + case 8627: // Totem of Hex + { + DoneTotal += (*i)->GetModifier()->m_amount; + break; + } + // Tundra Stalker + // Merciless Combat + case 7277: + { + // Merciless Combat + if ((*i)->GetSpellProto()->GetSpellIconID() == 2656) + { + if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) + DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; + } + else // Tundra Stalker + { + // Frost Fever (target debuff) + if (pVictim->GetAura(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0000000000000000), 0x00000002)) + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + break; + } + case 7293: // Rage of Rivendare + { + if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0200000000000000))) + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + // Twisted Faith + case 7377: + { + if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, UI64LIT(0x0000000000008000), 0, GetObjectGuid())) + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + // Marked for Death + case 7598: + case 7599: + case 7600: + case 7601: + case 7602: + { + if (pVictim->GetAura(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, UI64LIT(0x0000000000000400))) + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + } + } + + SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); + + // Custom scripted damage + switch (spellProto->GetSpellFamilyName()) + { + case SPELLFAMILY_MAGE: + { + // Ice Lance + if (spellProto->GetSpellIconID() == 186) + { + if (pVictim->IsFrozen() || IsIgnoreUnitState(spellProto, IGNORE_UNIT_TARGET_NON_FROZEN)) + { + float multiplier = 3.0f; + + // if target have higher level + if (pVictim->getLevel() > getLevel()) + // Glyph of Ice Lance + if (Aura* glyph = GetDummyAura(56377)) + multiplier = glyph->GetModifier()->m_amount; + + DoneTotalMod *= multiplier; + } + } + // Torment the weak affected (Arcane Barrage, Arcane Blast, Frostfire Bolt, Arcane Missiles, Fireball) + if (classOptions && (classOptions->SpellFamilyFlags & UI64LIT(0x0000900020200021)) && + (pVictim->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED) || pVictim->HasAuraType(SPELL_AURA_HASTE_ALL))) + { + // Search for Torment the weak dummy aura + Unit::AuraList const& ttw = GetAurasByType(SPELL_AURA_DUMMY); + for (Unit::AuraList::const_iterator i = ttw.begin(); i != ttw.end(); ++i) + { + if ((*i)->GetSpellProto()->GetSpellIconID() == 3263) + { + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + } + } + break; + } + case SPELLFAMILY_WARLOCK: + { + // Drain Soul + if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000004000)) + { + if (pVictim->GetHealth() * 100 / pVictim->GetMaxHealth() <= 25) + DoneTotalMod *= 4; + } + break; + } + case SPELLFAMILY_PRIEST: + { + // Smite + if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000080))) + { + // Holy Fire + if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, UI64LIT(0x00100000))) + // Glyph of Smite + if (Aura* aur = GetAura(55692, EFFECT_INDEX_0)) + DoneTotalMod *= (aur->GetModifier()->m_amount + 100.0f) / 100.0f; + } + // Shadow word: Death + else if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000200000000))) + { + // Glyph of Shadow word: Death + if (SpellAuraHolder const* glyph = GetSpellAuraHolder(55682)) + { + Aura const* hpPct = glyph->GetAuraByEffectIndex(EFFECT_INDEX_0); + Aura const* dmPct = glyph->GetAuraByEffectIndex(EFFECT_INDEX_1); + if (hpPct && dmPct && pVictim->GetHealth() * 100 <= pVictim->GetMaxHealth() * hpPct->GetModifier()->m_amount) + DoneTotalMod *= (dmPct->GetModifier()->m_amount + 100.0f) / 100.0f; + } + } + break; + } + case SPELLFAMILY_DRUID: + { + // Improved Insect Swarm (Wrath part) + if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000000001)) + { + // if Insect Swarm on target + if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, UI64LIT(0x000000000200000), 0, GetObjectGuid())) + { + Unit::AuraList const& improvedSwarm = GetAurasByType(SPELL_AURA_DUMMY); + for (Unit::AuraList::const_iterator iter = improvedSwarm.begin(); iter != improvedSwarm.end(); ++iter) + { + if ((*iter)->GetSpellProto()->GetSpellIconID() == 1771) + { + DoneTotalMod *= ((*iter)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + } + } + } + break; + } + case SPELLFAMILY_DEATHKNIGHT: + { + // Icy Touch and Howling Blast + if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000200000002)) + { + // search disease + bool found = false; + Unit::SpellAuraHolderMap const& auras = pVictim->GetSpellAuraHolderMap(); + for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + if (itr->second->GetSpellProto()->GetDispel() == DISPEL_DISEASE) + { + found = true; + break; + } + } + if (!found) + break; + + // search for Glacier Rot dummy aura + Unit::AuraList const& dummyAuras = GetAurasByType(SPELL_AURA_DUMMY); + for (Unit::AuraList::const_iterator i = dummyAuras.begin(); i != dummyAuras.end(); ++i) + { + if ((*i)->GetSpellProto()->GetEffectMiscValue((*i)->GetEffIndex()) == 7244) + { + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + } + } + // Death Coil (bonus from Item - Death Knight T8 DPS Relic) + else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x00002000)) + { + if (Aura* sigil = GetDummyAura(64962)) + DoneTotal += sigil->GetModifier()->m_amount; + } + break; + } + default: + break; + } + + // Done fixed damage bonus auras + int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(GetSpellSchoolMask(spellProto)); + + // Pets just add their bonus damage to their spell damage + // note that their spell damage is just gain of their own auras + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) + DoneAdvertisedBenefit += ((Pet*)this)->GetBonusDamage(); + + // apply ap bonus and benefit affected by spell power implicit coeffs and spell level penalties + DoneTotal = SpellBonusWithCoeffs(spellProto, DoneTotal, DoneAdvertisedBenefit, 0, damagetype, true); + + float tmpDamage = (int32(pdamage) + DoneTotal * int32(stack)) * DoneTotalMod; + // apply spellmod to Done damage (flat and pct) + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); + + return tmpDamage > 0 ? uint32(tmpDamage) : 0; } /* @@ -7675,409 +7679,409 @@ uint32 Unit::SpellDamageBonusDone(Unit* pVictim, SpellEntry const* spellProto, u */ uint32 Unit::SpellDamageBonusTaken(Unit* pCaster, SpellEntry const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) { - if (!spellProto || !pCaster || damagetype == DIRECT_DAMAGE) - { - return pdamage; - } - - uint32 schoolMask = spellProto->GetSchoolMask(); - - // Taken total percent damage auras - float TakenTotalMod = 1.0f; - int32 TakenTotal = 0; - - // ..taken - TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, schoolMask); - - // .. taken pct: dummy auras - AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_DUMMY); - for (AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - { - switch ((*i)->GetId()) - { - case 45182: // Cheating Death - if ((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) - { - if (GetTypeId() != TYPEID_PLAYER) - continue; - - TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - } - break; - case 20911: // Blessing of Sanctuary - case 25899: // Greater Blessing of Sanctuary - TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - case 47580: // Pain and Suffering (Rank 1) TODO: can be pct modifier aura - case 47581: // Pain and Suffering (Rank 2) - case 47582: // Pain and Suffering (Rank 3) - // Shadow Word: Death - if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000200000000))) - TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - } - - // From caster spells - AuraList const& mOwnerTaken = GetAurasByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER); - for (AuraList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i) - { - if ((*i)->GetCasterGuid() == pCaster->GetObjectGuid() && (*i)->isAffectedOnSpell(spellProto)) - TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - } - - // Mod damage from spell mechanic - TakenTotalMod *= GetTotalAuraMultiplierByMiscValueForMask(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, GetAllSpellMechanicMask(spellProto)); - - // Mod damage taken from AoE spells - if (IsAreaOfEffectSpell(spellProto)) - { - TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask); - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) - TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_PET_AOE_DAMAGE_AVOIDANCE, schoolMask); - } - - // Taken fixed damage bonus auras - int32 TakenAdvertisedBenefit = SpellBaseDamageBonusTaken(GetSpellSchoolMask(spellProto)); - - // apply benefit affected by spell power implicit coeffs and spell level penalties - TakenTotal = pCaster->SpellBonusWithCoeffs(spellProto, TakenTotal, TakenAdvertisedBenefit, 0, damagetype, false); - - float tmpDamage = (int32(pdamage) + TakenTotal * int32(stack)) * TakenTotalMod; - - return tmpDamage > 0 ? uint32(tmpDamage) : 0; + if (!spellProto || !pCaster || damagetype == DIRECT_DAMAGE) + { + return pdamage; + } + + uint32 schoolMask = spellProto->GetSchoolMask(); + + // Taken total percent damage auras + float TakenTotalMod = 1.0f; + int32 TakenTotal = 0; + + // ..taken + TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, schoolMask); + + // .. taken pct: dummy auras + AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_DUMMY); + for (AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) + { + switch ((*i)->GetId()) + { + case 45182: // Cheating Death + if ((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) + { + if (GetTypeId() != TYPEID_PLAYER) + continue; + + TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + } + break; + case 20911: // Blessing of Sanctuary + case 25899: // Greater Blessing of Sanctuary + TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + case 47580: // Pain and Suffering (Rank 1) TODO: can be pct modifier aura + case 47581: // Pain and Suffering (Rank 2) + case 47582: // Pain and Suffering (Rank 3) + // Shadow Word: Death + if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000200000000))) + TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + } + + // From caster spells + AuraList const& mOwnerTaken = GetAurasByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER); + for (AuraList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i) + { + if ((*i)->GetCasterGuid() == pCaster->GetObjectGuid() && (*i)->isAffectedOnSpell(spellProto)) + TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + } + + // Mod damage from spell mechanic + TakenTotalMod *= GetTotalAuraMultiplierByMiscValueForMask(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, GetAllSpellMechanicMask(spellProto)); + + // Mod damage taken from AoE spells + if (IsAreaOfEffectSpell(spellProto)) + { + TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask); + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) + TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_PET_AOE_DAMAGE_AVOIDANCE, schoolMask); + } + + // Taken fixed damage bonus auras + int32 TakenAdvertisedBenefit = SpellBaseDamageBonusTaken(GetSpellSchoolMask(spellProto)); + + // apply benefit affected by spell power implicit coeffs and spell level penalties + TakenTotal = pCaster->SpellBonusWithCoeffs(spellProto, TakenTotal, TakenAdvertisedBenefit, 0, damagetype, false); + + float tmpDamage = (int32(pdamage) + TakenTotal * int32(stack)) * TakenTotalMod; + + return tmpDamage > 0 ? uint32(tmpDamage) : 0; } int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) { - int32 DoneAdvertisedBenefit = 0; - - Unit::AuraList const& mOverrideSpellPowerAuras = GetAurasByType(SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT); - if (!mOverrideSpellPowerAuras.empty()) - { - for (Unit::AuraList::const_iterator itr = mOverrideSpellPowerAuras.begin(); itr != mOverrideSpellPowerAuras.end(); ++itr) - if (schoolMask & (*itr)->GetModifier()->m_miscvalue) - DoneAdvertisedBenefit += (*itr)->GetModifier()->m_amount; - - return int32(GetTotalAttackPowerValue(BASE_ATTACK) * (100.0f + DoneAdvertisedBenefit) / 100.0f); - } - - // ..done - AuraList const& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE); - for (AuraList::const_iterator i = mDamageDone.begin(); i != mDamageDone.end(); ++i) - { - SpellEquippedItemsEntry const* spellEquip = (*i)->GetSpellProto()->GetSpellEquippedItems(); - if (((*i)->GetModifier()->m_miscvalue & schoolMask) != 0 && - (!spellEquip || spellEquip->EquippedItemClass == -1 && // -1 == any item class (not wand then) - spellEquip->EquippedItemInventoryTypeMask == 0)) // 0 == any inventory type (not wand then) - DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount; - } - - if (GetTypeId() == TYPEID_PLAYER) - { - // Base value - DoneAdvertisedBenefit += ((Player*)this)->GetBaseSpellPowerBonus(); - - if (GetPowerIndex(POWER_MANA) != INVALID_POWER_INDEX) - DoneAdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect - - // Damage bonus from stats - AuraList const& mDamageDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT); - for (AuraList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i) - { - if ((*i)->GetModifier()->m_miscvalue & schoolMask) - { - // stat used stored in miscValueB for this aura - Stats usedStat = Stats((*i)->GetMiscBValue()); - DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f); - } - } - // ... and attack power - AuraList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER); - for (AuraList::const_iterator i = mDamageDonebyAP.begin(); i != mDamageDonebyAP.end(); ++i) - { - if ((*i)->GetModifier()->m_miscvalue & schoolMask) - DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f); - } - } - - // pct spell power modifier - Unit::AuraList const& mSpellPowerPctAuras = GetAurasByType(SPELL_AURA_MOD_INCREASE_SPELL_POWER_PCT); - for (Unit::AuraList::const_iterator itr = mSpellPowerPctAuras.begin(); itr != mSpellPowerPctAuras.end(); ++itr) - { - if (!(*itr)->GetModifier()->m_miscvalue || (*itr)->GetModifier()->m_miscvalue & schoolMask) - DoneAdvertisedBenefit = int32(DoneAdvertisedBenefit * (100.0f + (*itr)->GetModifier()->m_amount) / 100.0f); - } - - return DoneAdvertisedBenefit; + int32 DoneAdvertisedBenefit = 0; + + Unit::AuraList const& mOverrideSpellPowerAuras = GetAurasByType(SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT); + if (!mOverrideSpellPowerAuras.empty()) + { + for (Unit::AuraList::const_iterator itr = mOverrideSpellPowerAuras.begin(); itr != mOverrideSpellPowerAuras.end(); ++itr) + if (schoolMask & (*itr)->GetModifier()->m_miscvalue) + DoneAdvertisedBenefit += (*itr)->GetModifier()->m_amount; + + return int32(GetTotalAttackPowerValue(BASE_ATTACK) * (100.0f + DoneAdvertisedBenefit) / 100.0f); + } + + // ..done + AuraList const& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE); + for (AuraList::const_iterator i = mDamageDone.begin(); i != mDamageDone.end(); ++i) + { + SpellEquippedItemsEntry const* spellEquip = (*i)->GetSpellProto()->GetSpellEquippedItems(); + if (((*i)->GetModifier()->m_miscvalue & schoolMask) != 0 && + (!spellEquip || spellEquip->EquippedItemClass == -1 && // -1 == any item class (not wand then) + spellEquip->EquippedItemInventoryTypeMask == 0)) // 0 == any inventory type (not wand then) + DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount; + } + + if (GetTypeId() == TYPEID_PLAYER) + { + // Base value + DoneAdvertisedBenefit += ((Player*)this)->GetBaseSpellPowerBonus(); + + if (GetPowerIndex(POWER_MANA) != INVALID_POWER_INDEX) + DoneAdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect + + // Damage bonus from stats + AuraList const& mDamageDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT); + for (AuraList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i) + { + if ((*i)->GetModifier()->m_miscvalue & schoolMask) + { + // stat used stored in miscValueB for this aura + Stats usedStat = Stats((*i)->GetMiscBValue()); + DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f); + } + } + // ... and attack power + AuraList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER); + for (AuraList::const_iterator i = mDamageDonebyAP.begin(); i != mDamageDonebyAP.end(); ++i) + { + if ((*i)->GetModifier()->m_miscvalue & schoolMask) + DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f); + } + } + + // pct spell power modifier + Unit::AuraList const& mSpellPowerPctAuras = GetAurasByType(SPELL_AURA_MOD_INCREASE_SPELL_POWER_PCT); + for (Unit::AuraList::const_iterator itr = mSpellPowerPctAuras.begin(); itr != mSpellPowerPctAuras.end(); ++itr) + { + if (!(*itr)->GetModifier()->m_miscvalue || (*itr)->GetModifier()->m_miscvalue & schoolMask) + DoneAdvertisedBenefit = int32(DoneAdvertisedBenefit * (100.0f + (*itr)->GetModifier()->m_amount) / 100.0f); + } + + return DoneAdvertisedBenefit; } int32 Unit::SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) { - int32 TakenAdvertisedBenefit = 0; + int32 TakenAdvertisedBenefit = 0; - // ..taken - AuraList const& mDamageTaken = GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN); - for (AuraList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i) - { - if (((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) - TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount; - } + // ..taken + AuraList const& mDamageTaken = GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN); + for (AuraList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i) + { + if (((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) + TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount; + } - return TakenAdvertisedBenefit; + return TakenAdvertisedBenefit; } bool Unit::IsSpellCrit(Unit* pVictim, SpellEntry const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) { - // not critting spell - if (spellProto->HasAttribute(SPELL_ATTR_EX2_CANT_CRIT)) - { - return false; - } - - // Creatures do not crit with their spells or abilities, unless it is owned by a player (pet, totem, etc) - if (GetTypeId() != TYPEID_PLAYER) - { - Unit* owner = GetOwner(); - if (!owner || owner->GetTypeId() != TYPEID_PLAYER) - { - return false; - } - } - - float crit_chance = 0.0f; - switch(spellProto->GetDmgClass()) - { - case SPELL_DAMAGE_CLASS_NONE: - return false; - case SPELL_DAMAGE_CLASS_MAGIC: - { - if (schoolMask & SPELL_SCHOOL_MASK_NORMAL) - crit_chance = 0.0f; - // For other schools - else if (GetTypeId() == TYPEID_PLAYER) - crit_chance = GetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask)); - else - { - crit_chance = float(m_baseSpellCritChance); - crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); - } - // taken - if (pVictim) - { - if (!IsPositiveSpell(spellProto->Id)) - { - // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE - crit_chance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask); - // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE - crit_chance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); - } - - // scripted (increase crit chance ... against ... target by x%) - // scripted (Increases the critical effect chance of your .... by x% on targets ...) - AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) - { - if (!((*i)->isAffectedOnSpell(spellProto))) - continue; - switch ((*i)->GetModifier()->m_miscvalue) - { - case 849: // Shatter Rank 1 - if (pVictim->IsFrozen() || IsIgnoreUnitState(spellProto, IGNORE_UNIT_TARGET_NON_FROZEN)) - crit_chance += 17.0f; - break; - case 910: // Shatter Rank 2 - if (pVictim->IsFrozen() || IsIgnoreUnitState(spellProto, IGNORE_UNIT_TARGET_NON_FROZEN)) - crit_chance += 34.0f; - break; - case 911: // Shatter Rank 3 - if (pVictim->IsFrozen() || IsIgnoreUnitState(spellProto, IGNORE_UNIT_TARGET_NON_FROZEN)) - crit_chance += 50.0f; - break; - case 7917: // Glyph of Shadowburn - if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) - crit_chance += (*i)->GetModifier()->m_amount; - break; - case 7997: // Renewed Hope - case 7998: - if (pVictim->HasAura(6788)) - crit_chance += (*i)->GetModifier()->m_amount; - break; - default: - break; - } - } - - SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); - // Custom crit by class - switch(spellProto->GetSpellFamilyName()) - { - case SPELLFAMILY_MAGE: - { - // Fire Blast - if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000002)) && spellProto->GetSpellIconID() == 12) - { - // Glyph of Fire Blast - if (pVictim->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED) || pVictim->IsInRoots()) - if (Aura* aura = GetAura(56369, EFFECT_INDEX_0)) - crit_chance += aura->GetModifier()->m_amount; - } - break; - } - case SPELLFAMILY_PRIEST: - // Flash Heal - if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000800))) - { - if (pVictim->GetHealth() > pVictim->GetMaxHealth() / 2) - break; - AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_DUMMY); - for (AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - { - // Improved Flash Heal - if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_PRIEST && - (*i)->GetSpellProto()->GetSpellIconID() == 2542) - { - crit_chance += (*i)->GetModifier()->m_amount; - break; - } - } - } - break; - case SPELLFAMILY_DRUID: - // Improved Insect Swarm (Starfire part) - if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000004))) - { - // search for Moonfire on target - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, UI64LIT(0x000000000000002), 0, GetObjectGuid())) - { - Unit::AuraList const& improvedSwarm = GetAurasByType(SPELL_AURA_DUMMY); - for (Unit::AuraList::const_iterator iter = improvedSwarm.begin(); iter != improvedSwarm.end(); ++iter) - { - if ((*iter)->GetSpellProto()->GetSpellIconID() == 1771) - { - crit_chance += (*iter)->GetModifier()->m_amount; - break; - } - } - } - } - break; - case SPELLFAMILY_PALADIN: - // Sacred Shield - if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000040000000)) - { - Aura* aura = pVictim->GetDummyAura(58597); - if (aura && aura->GetCasterGuid() == GetObjectGuid()) - crit_chance += aura->GetModifier()->m_amount; - } - // Exorcism - else if (spellProto->GetCategory() == 19) - { - if (pVictim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD) - { - return true; - } - } - break; - case SPELLFAMILY_SHAMAN: - // Lava Burst - if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000100000000000))) - { - // Flame Shock - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, UI64LIT(0x0000000010000000), 0, GetObjectGuid())) - { - return true; - } - } - break; - } - } - break; - } - case SPELL_DAMAGE_CLASS_MELEE: - case SPELL_DAMAGE_CLASS_RANGED: - { - if (pVictim) - crit_chance = GetUnitCriticalChance(attackType, pVictim); - - crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); - break; - } - default: - return false; - } - // percent done - // only players use intelligence for critical chance computations - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); - - crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f; - if (roll_chance_f(crit_chance)) - { - return true; - } - return false; + // not critting spell + if (spellProto->HasAttribute(SPELL_ATTR_EX2_CANT_CRIT)) + { + return false; + } + + // Creatures do not crit with their spells or abilities, unless it is owned by a player (pet, totem, etc) + if (GetTypeId() != TYPEID_PLAYER) + { + Unit* owner = GetOwner(); + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + { + return false; + } + } + + float crit_chance = 0.0f; + switch (spellProto->GetDmgClass()) + { + case SPELL_DAMAGE_CLASS_NONE: + return false; + case SPELL_DAMAGE_CLASS_MAGIC: + { + if (schoolMask & SPELL_SCHOOL_MASK_NORMAL) + crit_chance = 0.0f; + // For other schools + else if (GetTypeId() == TYPEID_PLAYER) + crit_chance = GetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask)); + else + { + crit_chance = float(m_baseSpellCritChance); + crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); + } + // taken + if (pVictim) + { + if (!IsPositiveSpell(spellProto->Id)) + { + // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE + crit_chance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask); + // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE + crit_chance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); + } + + // scripted (increase crit chance ... against ... target by x%) + // scripted (Increases the critical effect chance of your .... by x% on targets ...) + AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + { + if (!((*i)->isAffectedOnSpell(spellProto))) + continue; + switch ((*i)->GetModifier()->m_miscvalue) + { + case 849: // Shatter Rank 1 + if (pVictim->IsFrozen() || IsIgnoreUnitState(spellProto, IGNORE_UNIT_TARGET_NON_FROZEN)) + crit_chance += 17.0f; + break; + case 910: // Shatter Rank 2 + if (pVictim->IsFrozen() || IsIgnoreUnitState(spellProto, IGNORE_UNIT_TARGET_NON_FROZEN)) + crit_chance += 34.0f; + break; + case 911: // Shatter Rank 3 + if (pVictim->IsFrozen() || IsIgnoreUnitState(spellProto, IGNORE_UNIT_TARGET_NON_FROZEN)) + crit_chance += 50.0f; + break; + case 7917: // Glyph of Shadowburn + if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) + crit_chance += (*i)->GetModifier()->m_amount; + break; + case 7997: // Renewed Hope + case 7998: + if (pVictim->HasAura(6788)) + crit_chance += (*i)->GetModifier()->m_amount; + break; + default: + break; + } + } + + SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); + // Custom crit by class + switch (spellProto->GetSpellFamilyName()) + { + case SPELLFAMILY_MAGE: + { + // Fire Blast + if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000002)) && spellProto->GetSpellIconID() == 12) + { + // Glyph of Fire Blast + if (pVictim->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED) || pVictim->IsInRoots()) + if (Aura* aura = GetAura(56369, EFFECT_INDEX_0)) + crit_chance += aura->GetModifier()->m_amount; + } + break; + } + case SPELLFAMILY_PRIEST: + // Flash Heal + if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000800))) + { + if (pVictim->GetHealth() > pVictim->GetMaxHealth() / 2) + break; + AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_DUMMY); + for (AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) + { + // Improved Flash Heal + if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_PRIEST && + (*i)->GetSpellProto()->GetSpellIconID() == 2542) + { + crit_chance += (*i)->GetModifier()->m_amount; + break; + } + } + } + break; + case SPELLFAMILY_DRUID: + // Improved Insect Swarm (Starfire part) + if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000004))) + { + // search for Moonfire on target + if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, UI64LIT(0x000000000000002), 0, GetObjectGuid())) + { + Unit::AuraList const& improvedSwarm = GetAurasByType(SPELL_AURA_DUMMY); + for (Unit::AuraList::const_iterator iter = improvedSwarm.begin(); iter != improvedSwarm.end(); ++iter) + { + if ((*iter)->GetSpellProto()->GetSpellIconID() == 1771) + { + crit_chance += (*iter)->GetModifier()->m_amount; + break; + } + } + } + } + break; + case SPELLFAMILY_PALADIN: + // Sacred Shield + if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000040000000)) + { + Aura* aura = pVictim->GetDummyAura(58597); + if (aura && aura->GetCasterGuid() == GetObjectGuid()) + crit_chance += aura->GetModifier()->m_amount; + } + // Exorcism + else if (spellProto->GetCategory() == 19) + { + if (pVictim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD) + { + return true; + } + } + break; + case SPELLFAMILY_SHAMAN: + // Lava Burst + if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000100000000000))) + { + // Flame Shock + if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, UI64LIT(0x0000000010000000), 0, GetObjectGuid())) + { + return true; + } + } + break; + } + } + break; + } + case SPELL_DAMAGE_CLASS_MELEE: + case SPELL_DAMAGE_CLASS_RANGED: + { + if (pVictim) + crit_chance = GetUnitCriticalChance(attackType, pVictim); + + crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); + break; + } + default: + return false; + } + // percent done + // only players use intelligence for critical chance computations + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); + + crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f; + if (roll_chance_f(crit_chance)) + { + return true; + } + return false; } uint32 Unit::SpellCriticalDamageBonus(SpellEntry const* spellProto, uint32 damage, Unit* pVictim) { - // Calculate critical bonus - int32 crit_bonus; - switch(spellProto->GetDmgClass()) - { - case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100% - case SPELL_DAMAGE_CLASS_RANGED: - crit_bonus = damage; - break; - default: - crit_bonus = damage / 2; // for spells is 50% - break; - } - - // Apply SPELL_AURA_MOD_CRIT_DAMAGE_BONUS modifier first - const int32 pctBonus = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellProto)); - crit_bonus += int32((damage + crit_bonus) * float(pctBonus / 100.0f)); - - // adds additional damage to crit_bonus (from talents) - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); - - if (!pVictim) - { - return damage += crit_bonus; - } - - int32 critPctDamageMod = 0; - if(spellProto->GetDmgClass() >= SPELL_DAMAGE_CLASS_MELEE) - { - if (GetWeaponAttackType(spellProto) == RANGED_ATTACK) - critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); - else - critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); - } - else - critPctDamageMod += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_DAMAGE, GetSpellSchoolMask(spellProto)); - - if (critPctDamageMod != 0) - crit_bonus = int32(crit_bonus * float((100.0f + critPctDamageMod) / 100.0f)); - - if (crit_bonus > 0) - damage += crit_bonus; - - return damage; + // Calculate critical bonus + int32 crit_bonus; + switch (spellProto->GetDmgClass()) + { + case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100% + case SPELL_DAMAGE_CLASS_RANGED: + crit_bonus = damage; + break; + default: + crit_bonus = damage / 2; // for spells is 50% + break; + } + + // Apply SPELL_AURA_MOD_CRIT_DAMAGE_BONUS modifier first + const int32 pctBonus = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellProto)); + crit_bonus += int32((damage + crit_bonus) * float(pctBonus / 100.0f)); + + // adds additional damage to crit_bonus (from talents) + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); + + if (!pVictim) + { + return damage += crit_bonus; + } + + int32 critPctDamageMod = 0; + if (spellProto->GetDmgClass() >= SPELL_DAMAGE_CLASS_MELEE) + { + if (GetWeaponAttackType(spellProto) == RANGED_ATTACK) + critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); + else + critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); + } + else + critPctDamageMod += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_DAMAGE, GetSpellSchoolMask(spellProto)); + + if (critPctDamageMod != 0) + crit_bonus = int32(crit_bonus * float((100.0f + critPctDamageMod) / 100.0f)); + + if (crit_bonus > 0) + damage += crit_bonus; + + return damage; } uint32 Unit::SpellCriticalHealingBonus(SpellEntry const* spellProto, uint32 damage, Unit* pVictim) { - // Calculate critical bonus - int32 crit_bonus = damage; + // Calculate critical bonus + int32 crit_bonus = damage; - if (crit_bonus > 0) - damage += crit_bonus; + if (crit_bonus > 0) + damage += crit_bonus; - damage = int32(damage * GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT)); + damage = int32(damage * GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT)); - return damage; + return damage; } /** @@ -8086,147 +8090,147 @@ uint32 Unit::SpellCriticalHealingBonus(SpellEntry const* spellProto, uint32 dama */ uint32 Unit::SpellHealingBonusDone(Unit* pVictim, SpellEntry const* spellProto, int32 healamount, DamageEffectType damagetype, uint32 stack) { - // For totems get healing bonus from owner (statue isn't totem in fact) - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsTotem() && ((Totem*)this)->GetTotemType() != TOTEM_STATUE) - if (Unit* owner = GetOwner()) - { - return owner->SpellHealingBonusDone(pVictim, spellProto, healamount, damagetype, stack); - } - - // No heal amount for this class spells - if (spellProto->GetDmgClass() == SPELL_DAMAGE_CLASS_NONE) - { - return healamount < 0 ? 0 : healamount; - } - - // Healing Done - // Done total percent damage auras - float DoneTotalMod = 1.0f; - int32 DoneTotal = 0; - - // Healing done percent - AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT); - for (AuraList::const_iterator i = mHealingDonePct.begin(); i != mHealingDonePct.end(); ++i) - { - DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; - } - - AuraList const& mHealingFromHealthPct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_FROM_PCT_HEALTH); - if (!mHealingFromHealthPct.empty()) - { - float healthPct = std::max(0.0f, 1.0f - float(pVictim->GetHealth()) / pVictim->GetMaxHealth()); - for (AuraList::const_iterator i = mHealingFromHealthPct.begin();i != mHealingFromHealthPct.end(); ++i) - if ((*i)->isAffectedOnSpell(spellProto)) - DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount * healthPct) / 100.0f; - } - - // done scripted mod (take it from owner) - Unit* owner = GetOwner(); - if (!owner) owner = this; - AuraList const& mOverrideClassScript = owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) - { - if (!(*i)->isAffectedOnSpell(spellProto)) - continue; - switch ((*i)->GetModifier()->m_miscvalue) - { - case 4415: // Increased Rejuvenation Healing - case 4953: - case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind - DoneTotal += (*i)->GetModifier()->m_amount; - break; - case 7997: // Renewed Hope - case 7998: - if (pVictim->HasAura(6788)) - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - case 21: // Test of Faith - case 6935: - case 6918: - if (pVictim->GetHealth() < pVictim->GetMaxHealth() / 2) - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - case 7798: // Glyph of Regrowth - { - if (pVictim->GetAura(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, UI64LIT(0x0000000000000040))) - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - case 8477: // Nourish Heal Boost - { - int32 stepPercent = (*i)->GetModifier()->m_amount; - - int ownHotCount = 0; // counted HoT types amount, not stacks - - Unit::AuraList const& RejorRegr = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); - for (Unit::AuraList::const_iterator itr = RejorRegr.begin(); itr != RejorRegr.end(); ++itr) - if ((*itr)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DRUID && - (*itr)->GetCasterGuid() == GetObjectGuid()) - ++ownHotCount; - - if (ownHotCount) - DoneTotalMod *= (stepPercent * ownHotCount + 100.0f) / 100.0f; - break; - } - case 7871: // Glyph of Lesser Healing Wave - { - if (pVictim->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, UI64LIT(0x0000040000000000), 0, GetObjectGuid())) - DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - default: - break; - } - } - - // Nourish 20% of heal increase if target is affected by Druids HOTs - SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); - if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_DRUID && (classOptions->SpellFamilyFlags & UI64LIT(0x0200000000000000))) - { - int ownHotCount = 0; // counted HoT types amount, not stacks - Unit::AuraList const& RejorRegr = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); - for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) - if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DRUID && - (*i)->GetCasterGuid() == GetObjectGuid()) - ++ownHotCount; - - if (ownHotCount) - { - DoneTotalMod *= 1.2f; // base bonus at HoTs - - if (Aura* glyph = GetAura(62971, EFFECT_INDEX_0))// Glyph of Nourish - DoneTotalMod *= (glyph->GetModifier()->m_amount * ownHotCount + 100.0f) / 100.0f; - } - // Lifebloom - else if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000001000000000))) - { - AuraList const& dummyList = owner->GetAurasByType(SPELL_AURA_DUMMY); - for (AuraList::const_iterator i = dummyList.begin(); i != dummyList.end(); ++i) - { - switch ((*i)->GetId()) - { - case 34246: // Idol of the Emerald Queen TODO: can be flat modifier aura - case 60779: // Idol of Lush Moss - DoneTotal += (*i)->GetModifier()->m_amount / 7; - break; - } - } - } - } - - // Done fixed damage bonus auras - int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(GetSpellSchoolMask(spellProto)); - - // apply ap bonus and benefit affected by spell power implicit coeffs and spell level penalties - DoneTotal = SpellBonusWithCoeffs(spellProto, DoneTotal, DoneAdvertisedBenefit, 0, damagetype, true, SCALE_SPELLPOWER_HEALING); - - // use float as more appropriate for negative values and percent applying - float heal = (healamount + DoneTotal * int32(stack)) * DoneTotalMod; - // apply spellmod to Done amount - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal); - - return heal < 0 ? 0 : uint32(heal); + // For totems get healing bonus from owner (statue isn't totem in fact) + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsTotem() && ((Totem*)this)->GetTotemType() != TOTEM_STATUE) + if (Unit* owner = GetOwner()) + { + return owner->SpellHealingBonusDone(pVictim, spellProto, healamount, damagetype, stack); + } + + // No heal amount for this class spells + if (spellProto->GetDmgClass() == SPELL_DAMAGE_CLASS_NONE) + { + return healamount < 0 ? 0 : healamount; + } + + // Healing Done + // Done total percent damage auras + float DoneTotalMod = 1.0f; + int32 DoneTotal = 0; + + // Healing done percent + AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT); + for (AuraList::const_iterator i = mHealingDonePct.begin(); i != mHealingDonePct.end(); ++i) + { + DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; + } + + AuraList const& mHealingFromHealthPct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_FROM_PCT_HEALTH); + if (!mHealingFromHealthPct.empty()) + { + float healthPct = std::max(0.0f, 1.0f - float(pVictim->GetHealth()) / pVictim->GetMaxHealth()); + for (AuraList::const_iterator i = mHealingFromHealthPct.begin(); i != mHealingFromHealthPct.end(); ++i) + if ((*i)->isAffectedOnSpell(spellProto)) + DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount * healthPct) / 100.0f; + } + + // done scripted mod (take it from owner) + Unit* owner = GetOwner(); + if (!owner) owner = this; + AuraList const& mOverrideClassScript = owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + { + if (!(*i)->isAffectedOnSpell(spellProto)) + continue; + switch ((*i)->GetModifier()->m_miscvalue) + { + case 4415: // Increased Rejuvenation Healing + case 4953: + case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind + DoneTotal += (*i)->GetModifier()->m_amount; + break; + case 7997: // Renewed Hope + case 7998: + if (pVictim->HasAura(6788)) + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + case 21: // Test of Faith + case 6935: + case 6918: + if (pVictim->GetHealth() < pVictim->GetMaxHealth() / 2) + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + case 7798: // Glyph of Regrowth + { + if (pVictim->GetAura(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, UI64LIT(0x0000000000000040))) + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + case 8477: // Nourish Heal Boost + { + int32 stepPercent = (*i)->GetModifier()->m_amount; + + int ownHotCount = 0; // counted HoT types amount, not stacks + + Unit::AuraList const& RejorRegr = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); + for (Unit::AuraList::const_iterator itr = RejorRegr.begin(); itr != RejorRegr.end(); ++itr) + if ((*itr)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DRUID && + (*itr)->GetCasterGuid() == GetObjectGuid()) + ++ownHotCount; + + if (ownHotCount) + DoneTotalMod *= (stepPercent * ownHotCount + 100.0f) / 100.0f; + break; + } + case 7871: // Glyph of Lesser Healing Wave + { + if (pVictim->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, UI64LIT(0x0000040000000000), 0, GetObjectGuid())) + DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + default: + break; + } + } + + // Nourish 20% of heal increase if target is affected by Druids HOTs + SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); + if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_DRUID && (classOptions->SpellFamilyFlags & UI64LIT(0x0200000000000000))) + { + int ownHotCount = 0; // counted HoT types amount, not stacks + Unit::AuraList const& RejorRegr = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); + for (Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) + if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DRUID && + (*i)->GetCasterGuid() == GetObjectGuid()) + ++ownHotCount; + + if (ownHotCount) + { + DoneTotalMod *= 1.2f; // base bonus at HoTs + + if (Aura* glyph = GetAura(62971, EFFECT_INDEX_0))// Glyph of Nourish + DoneTotalMod *= (glyph->GetModifier()->m_amount * ownHotCount + 100.0f) / 100.0f; + } + // Lifebloom + else if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000001000000000))) + { + AuraList const& dummyList = owner->GetAurasByType(SPELL_AURA_DUMMY); + for (AuraList::const_iterator i = dummyList.begin(); i != dummyList.end(); ++i) + { + switch ((*i)->GetId()) + { + case 34246: // Idol of the Emerald Queen TODO: can be flat modifier aura + case 60779: // Idol of Lush Moss + DoneTotal += (*i)->GetModifier()->m_amount / 7; + break; + } + } + } + } + + // Done fixed damage bonus auras + int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(GetSpellSchoolMask(spellProto)); + + // apply ap bonus and benefit affected by spell power implicit coeffs and spell level penalties + DoneTotal = SpellBonusWithCoeffs(spellProto, DoneTotal, DoneAdvertisedBenefit, 0, damagetype, true, SCALE_SPELLPOWER_HEALING); + + // use float as more appropriate for negative values and percent applying + float heal = (healamount + DoneTotal * int32(stack)) * DoneTotalMod; + // apply spellmod to Done amount + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal); + + return heal < 0 ? 0 : uint32(heal); } /** @@ -8235,239 +8239,239 @@ uint32 Unit::SpellHealingBonusDone(Unit* pVictim, SpellEntry const* spellProto, */ uint32 Unit::SpellHealingBonusTaken(Unit* pCaster, SpellEntry const* spellProto, int32 healamount, DamageEffectType damagetype, uint32 stack) { - float TakenTotalMod = 1.0f; + float TakenTotalMod = 1.0f; - // Healing taken percent - float minval = float(GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT)); - if (minval) - TakenTotalMod *= (100.0f + minval) / 100.0f; + // Healing taken percent + float minval = float(GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT)); + if (minval) + TakenTotalMod *= (100.0f + minval) / 100.0f; - float maxval = float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT)); - // no SPELL_AURA_MOD_PERIODIC_HEAL positive cases - if (maxval) - TakenTotalMod *= (100.0f + maxval) / 100.0f; + float maxval = float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT)); + // no SPELL_AURA_MOD_PERIODIC_HEAL positive cases + if (maxval) + TakenTotalMod *= (100.0f + maxval) / 100.0f; - // No heal amount for this class spells - if (spellProto->GetDmgClass() == SPELL_DAMAGE_CLASS_NONE) - { - healamount = int32(healamount * TakenTotalMod); - return healamount < 0 ? 0 : healamount; - } + // No heal amount for this class spells + if (spellProto->GetDmgClass() == SPELL_DAMAGE_CLASS_NONE) + { + healamount = int32(healamount * TakenTotalMod); + return healamount < 0 ? 0 : healamount; + } - // Healing Done - // Done total percent damage auras - int32 TakenTotal = 0; + // Healing Done + // Done total percent damage auras + int32 TakenTotal = 0; - // Taken fixed damage bonus auras - int32 TakenAdvertisedBenefit = SpellBaseHealingBonusTaken(GetSpellSchoolMask(spellProto)); + // Taken fixed damage bonus auras + int32 TakenAdvertisedBenefit = SpellBaseHealingBonusTaken(GetSpellSchoolMask(spellProto)); - // apply benefit affected by spell power implicit coeffs and spell level penalties - TakenTotal = pCaster->SpellBonusWithCoeffs(spellProto, TakenTotal, TakenAdvertisedBenefit, 0, damagetype, false, SCALE_SPELLPOWER_HEALING); + // apply benefit affected by spell power implicit coeffs and spell level penalties + TakenTotal = pCaster->SpellBonusWithCoeffs(spellProto, TakenTotal, TakenAdvertisedBenefit, 0, damagetype, false, SCALE_SPELLPOWER_HEALING); - AuraList const& mHealingGet = GetAurasByType(SPELL_AURA_MOD_HEALING_RECEIVED); - for (AuraList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i) - if ((*i)->isAffectedOnSpell(spellProto)) - TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + AuraList const& mHealingGet = GetAurasByType(SPELL_AURA_MOD_HEALING_RECEIVED); + for (AuraList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i) + if ((*i)->isAffectedOnSpell(spellProto)) + TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - // use float as more appropriate for negative values and percent applying - float heal = (healamount + TakenTotal * int32(stack)) * TakenTotalMod; + // use float as more appropriate for negative values and percent applying + float heal = (healamount + TakenTotal * int32(stack)) * TakenTotalMod; - return heal < 0 ? 0 : uint32(heal); + return heal < 0 ? 0 : uint32(heal); } int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) { - int32 AdvertisedBenefit = 0; - - Unit::AuraList const& mOverrideSpellPowerAuras = GetAurasByType(SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT); - if (!mOverrideSpellPowerAuras.empty()) - { - for (Unit::AuraList::const_iterator itr = mOverrideSpellPowerAuras.begin(); itr != mOverrideSpellPowerAuras.end(); ++itr) - if (schoolMask & (*itr)->GetModifier()->m_miscvalue) - AdvertisedBenefit += (*itr)->GetModifier()->m_amount; - - return int32(GetTotalAttackPowerValue(BASE_ATTACK) * (100.0f + AdvertisedBenefit) / 100.0f); - } - - AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE); - for (AuraList::const_iterator i = mHealingDone.begin(); i != mHealingDone.end(); ++i) - if (!(*i)->GetModifier()->m_miscvalue || ((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) - AdvertisedBenefit += (*i)->GetModifier()->m_amount; - - // Healing bonus of spirit, intellect and strength - if (GetTypeId() == TYPEID_PLAYER) - { - // Base value - AdvertisedBenefit += ((Player*)this)->GetBaseSpellPowerBonus(); - - if (GetPowerIndex(POWER_MANA) != INVALID_POWER_INDEX) - AdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect - - // Healing bonus from stats - AuraList const& mHealingDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT); - for (AuraList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i) - { - // stat used dependent from misc value (stat index) - Stats usedStat = Stats((*i)->GetSpellProto()->GetEffectMiscValue((*i)->GetEffIndex())); - AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f); - } - - // ... and attack power - AuraList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER); - for (AuraList::const_iterator i = mHealingDonebyAP.begin(); i != mHealingDonebyAP.end(); ++i) - if ((*i)->GetModifier()->m_miscvalue & schoolMask) - AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f); - } - - // pct spell power modifier - Unit::AuraList const& mSpellPowerPctAuras = GetAurasByType(SPELL_AURA_MOD_INCREASE_SPELL_POWER_PCT); - for (Unit::AuraList::const_iterator itr = mSpellPowerPctAuras.begin(); itr != mSpellPowerPctAuras.end(); ++itr) - { - if (!(*itr)->GetModifier()->m_miscvalue || (*itr)->GetModifier()->m_miscvalue & schoolMask) - AdvertisedBenefit = int32(AdvertisedBenefit * (100.0f + (*itr)->GetModifier()->m_amount) / 100.0f); - } - - return AdvertisedBenefit; + int32 AdvertisedBenefit = 0; + + Unit::AuraList const& mOverrideSpellPowerAuras = GetAurasByType(SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT); + if (!mOverrideSpellPowerAuras.empty()) + { + for (Unit::AuraList::const_iterator itr = mOverrideSpellPowerAuras.begin(); itr != mOverrideSpellPowerAuras.end(); ++itr) + if (schoolMask & (*itr)->GetModifier()->m_miscvalue) + AdvertisedBenefit += (*itr)->GetModifier()->m_amount; + + return int32(GetTotalAttackPowerValue(BASE_ATTACK) * (100.0f + AdvertisedBenefit) / 100.0f); + } + + AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE); + for (AuraList::const_iterator i = mHealingDone.begin(); i != mHealingDone.end(); ++i) + if (!(*i)->GetModifier()->m_miscvalue || ((*i)->GetModifier()->m_miscvalue & schoolMask) != 0) + AdvertisedBenefit += (*i)->GetModifier()->m_amount; + + // Healing bonus of spirit, intellect and strength + if (GetTypeId() == TYPEID_PLAYER) + { + // Base value + AdvertisedBenefit += ((Player*)this)->GetBaseSpellPowerBonus(); + + if (GetPowerIndex(POWER_MANA) != INVALID_POWER_INDEX) + AdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect + + // Healing bonus from stats + AuraList const& mHealingDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT); + for (AuraList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i) + { + // stat used dependent from misc value (stat index) + Stats usedStat = Stats((*i)->GetSpellProto()->GetEffectMiscValue((*i)->GetEffIndex())); + AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f); + } + + // ... and attack power + AuraList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER); + for (AuraList::const_iterator i = mHealingDonebyAP.begin(); i != mHealingDonebyAP.end(); ++i) + if ((*i)->GetModifier()->m_miscvalue & schoolMask) + AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f); + } + + // pct spell power modifier + Unit::AuraList const& mSpellPowerPctAuras = GetAurasByType(SPELL_AURA_MOD_INCREASE_SPELL_POWER_PCT); + for (Unit::AuraList::const_iterator itr = mSpellPowerPctAuras.begin(); itr != mSpellPowerPctAuras.end(); ++itr) + { + if (!(*itr)->GetModifier()->m_miscvalue || (*itr)->GetModifier()->m_miscvalue & schoolMask) + AdvertisedBenefit = int32(AdvertisedBenefit * (100.0f + (*itr)->GetModifier()->m_amount) / 100.0f); + } + + return AdvertisedBenefit; } int32 Unit::SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) { - int32 AdvertisedBenefit = 0; - AuraList const& mDamageTaken = GetAurasByType(SPELL_AURA_MOD_HEALING); - for (AuraList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i) - if ((*i)->GetModifier()->m_miscvalue & schoolMask) - AdvertisedBenefit += (*i)->GetModifier()->m_amount; + int32 AdvertisedBenefit = 0; + AuraList const& mDamageTaken = GetAurasByType(SPELL_AURA_MOD_HEALING); + for (AuraList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i) + if ((*i)->GetModifier()->m_miscvalue & schoolMask) + AdvertisedBenefit += (*i)->GetModifier()->m_amount; - return AdvertisedBenefit; + return AdvertisedBenefit; } bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) { - // If m_immuneToSchool type contain this school type, IMMUNE damage. - SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; - for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) - if (itr->type & shoolMask) - { - return true; - } + // If m_immuneToSchool type contain this school type, IMMUNE damage. + SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; + for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) + if (itr->type & shoolMask) + { + return true; + } - // If m_immuneToDamage type contain magic, IMMUNE damage. - SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE]; - for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr) - if (itr->type & shoolMask) - { - return true; - } + // If m_immuneToDamage type contain magic, IMMUNE damage. + SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE]; + for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr) + if (itr->type & shoolMask) + { + return true; + } - return false; + return false; } bool Unit::IsImmuneToSpell(SpellEntry const* spellInfo, bool castOnSelf) { - if (!spellInfo) - { - return false; - } - - // TODO add spellEffect immunity checks!, player with flag in bg is immune to immunity buffs from other friendly players! - // SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_EFFECT]; - - SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL]; - for (SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr) - if (itr->type == spellInfo->GetDispel()) - { - return true; - } - - if (!spellInfo->HasAttribute(SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE) && // unaffected by school immunity - !spellInfo->HasAttribute(SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)) // can remove immune (by dispell or immune it) - { - SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; - for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) - if (!(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id)) && - (itr->type & GetSpellSchoolMask(spellInfo))) - return true; - } - - if(uint32 mechanic = spellInfo->GetMechanic()) - { - SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; - for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) - if (itr->type == mechanic) - { - return true; - } - - AuraList const& immuneAuraApply = GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY_MASK); - for (AuraList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter) - if ((*iter)->GetModifier()->m_miscvalue & (1 << (mechanic - 1))) - { - return true; - } - } - - return false; + if (!spellInfo) + { + return false; + } + + // TODO add spellEffect immunity checks!, player with flag in bg is immune to immunity buffs from other friendly players! + // SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_EFFECT]; + + SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL]; + for (SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr) + if (itr->type == spellInfo->GetDispel()) + { + return true; + } + + if (!spellInfo->HasAttribute(SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE) && // unaffected by school immunity + !spellInfo->HasAttribute(SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)) // can remove immune (by dispell or immune it) + { + SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; + for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) + if (!(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id)) && + (itr->type & GetSpellSchoolMask(spellInfo))) + return true; + } + + if (uint32 mechanic = spellInfo->GetMechanic()) + { + SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; + for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) + if (itr->type == mechanic) + { + return true; + } + + AuraList const& immuneAuraApply = GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY_MASK); + for (AuraList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter) + if ((*iter)->GetModifier()->m_miscvalue & (1 << (mechanic - 1))) + { + return true; + } + } + + return false; } bool Unit::IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectIndex index, bool castOnSelf) const { - // If m_immuneToEffect type contain this effect type, IMMUNE effect. - SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(index); - if(!spellEffect) - { - return false; - } - - uint32 effect = spellEffect->Effect; - SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT]; - for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr) - if (itr->type == effect) - { - return true; - } - - if(uint32 mechanic = spellEffect->EffectMechanic) - { - SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; - for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) - if (itr->type == mechanic) - { - return true; - } - - AuraList const& immuneAuraApply = GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY_MASK); - for (AuraList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter) - if ((*iter)->GetModifier()->m_miscvalue & (1 << (mechanic - 1))) - { - return true; - } - } - - if(uint32 aura = spellEffect->EffectApplyAuraName) - { - SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE]; - for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr) - if (itr->type == aura) - { - return true; - } - - // Check for immune to application of harmful magical effects - AuraList const& immuneAuraApply = GetAurasByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL); - if (!immuneAuraApply.empty() && - spellInfo->GetDispel() == DISPEL_MAGIC && // Magic debuff) - !IsPositiveEffect(spellInfo, index)) // Harmful - { - // Check school - SpellSchoolMask schoolMask = GetSpellSchoolMask(spellInfo); - for (AuraList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter) - if ((*iter)->GetModifier()->m_miscvalue & schoolMask) - { - return true; - } - } - } - return false; + // If m_immuneToEffect type contain this effect type, IMMUNE effect. + SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(index); + if (!spellEffect) + { + return false; + } + + uint32 effect = spellEffect->Effect; + SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT]; + for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr) + if (itr->type == effect) + { + return true; + } + + if (uint32 mechanic = spellEffect->EffectMechanic) + { + SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; + for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) + if (itr->type == mechanic) + { + return true; + } + + AuraList const& immuneAuraApply = GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY_MASK); + for (AuraList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter) + if ((*iter)->GetModifier()->m_miscvalue & (1 << (mechanic - 1))) + { + return true; + } + } + + if (uint32 aura = spellEffect->EffectApplyAuraName) + { + SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE]; + for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr) + if (itr->type == aura) + { + return true; + } + + // Check for immune to application of harmful magical effects + AuraList const& immuneAuraApply = GetAurasByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL); + if (!immuneAuraApply.empty() && + spellInfo->GetDispel() == DISPEL_MAGIC && // Magic debuff) + !IsPositiveEffect(spellInfo, index)) // Harmful + { + // Check school + SpellSchoolMask schoolMask = GetSpellSchoolMask(spellInfo); + for (AuraList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter) + if ((*iter)->GetModifier()->m_miscvalue & schoolMask) + { + return true; + } + } + } + return false; } /** @@ -8476,268 +8480,268 @@ bool Unit::IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectIndex i */ uint32 Unit::MeleeDamageBonusDone(Unit* pVictim, uint32 pdamage, WeaponAttackType attType, SpellEntry const* spellProto, DamageEffectType damagetype, uint32 stack) { - if (!pVictim || pdamage == 0 || (spellProto && spellProto->HasAttribute(SPELL_ATTR_EX6_NO_DMG_MODS))) - { - return pdamage; - } - - // differentiate for weapon damage based spells - bool isWeaponDamageBasedSpell = !(spellProto && (damagetype == DOT || IsSpellHaveEffect(spellProto, SPELL_EFFECT_SCHOOL_DAMAGE))); - Item* pWeapon = GetTypeId() == TYPEID_PLAYER ? ((Player*)this)->GetWeaponForAttack(attType, true, false) : NULL; - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - uint32 schoolMask = spellProto ? spellProto->GetSchoolMask() : uint32(GetMeleeDamageSchoolMask()); - - // FLAT damage bonus auras - // ======================= - int32 DoneFlat = 0; - int32 APbonus = 0; - - // ..done flat, already included in weapon damage based spells - if (!isWeaponDamageBasedSpell) - { - AuraList const& mModDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE); - for (AuraList::const_iterator i = mModDamageDone.begin(); i != mModDamageDone.end(); ++i) - { - if (((*i)->GetModifier()->m_miscvalue & schoolMask && // schoolmask has to fit with the intrinsic spell school - (*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask() && // AND schoolmask has to fit with weapon damage school (essential for non-physical spells) - ((*i)->GetSpellProto()->GetEquippedItemClass() == -1) || // general, weapon independent - (pWeapon && pWeapon->IsFitToSpellRequirements((*i)->GetSpellProto())))) // OR used weapon fits aura requirements - { - DoneFlat += (*i)->GetModifier()->m_amount; - } - } - - // Pets just add their bonus damage to their melee damage - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) - DoneFlat += ((Pet*)this)->GetBonusDamage(); - } - - // ..done flat (by creature type mask) - DoneFlat += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask); - - // ..done flat (base at attack power for marked target and base at attack power for creature type) - if (attType == RANGED_ATTACK) - { - APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS); - APbonus += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS, creatureTypeMask); - } - else - { - APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS); - APbonus += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS, creatureTypeMask); - } - - // PERCENT damage auras - // ==================== - float DonePercent = 1.0f; - - // ..done pct, already included in weapon damage based spells - if (!isWeaponDamageBasedSpell) - { - AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for (AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) - { - if (((*i)->GetModifier()->m_miscvalue & schoolMask && // schoolmask has to fit with the intrinsic spell school - (*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask() && // AND schoolmask has to fit with weapon damage school (essential for non-physical spells) - ((*i)->GetSpellProto()->GetEquippedItemClass()) == -1 || // general, weapon independent - (pWeapon && pWeapon->IsFitToSpellRequirements((*i)->GetSpellProto())))) // OR used weapon fits aura requirements - { - DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - } - } - - if (attType == OFF_ATTACK) - DonePercent *= GetModifierValue(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT); // no school check required - } - - if (!spellProto) - { - // apply SPELL_AURA_MOD_AUTOATTACK_DAMAGE for white damage - AuraList const& mModAutoAttackDamageAuras = GetAurasByType(SPELL_AURA_MOD_AUTOATTACK_DAMAGE); - for (AuraList::const_iterator i = mModAutoAttackDamageAuras.begin(); i != mModAutoAttackDamageAuras.end(); ++i) - { - if ((*i)->GetSpellProto()->GetEquippedItemClass() == -1 || // general, weapon independent - pWeapon && pWeapon->IsFitToSpellRequirements((*i)->GetSpellProto())) // OR used weapon fits aura requirements - { - DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - } - } - } - - // ..done pct (by creature type mask) - DonePercent *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS, creatureTypeMask); - - // special dummys/class scripts and other effects - // ============================================= - Unit* owner = GetOwner(); - if (!owner) - owner = this; - - // ..done (class scripts) - if (spellProto) - { - AuraList const& mOverrideClassScript = owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) - { - if (!(*i)->isAffectedOnSpell(spellProto)) - continue; - - switch ((*i)->GetModifier()->m_miscvalue) - { - // Tundra Stalker - // Merciless Combat - case 7277: - { - // Merciless Combat - if ((*i)->GetSpellProto()->GetSpellIconID() == 2656) - { - if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) - DonePercent *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; - } - else // Tundra Stalker - { - // Frost Fever (target debuff) - if (pVictim->GetAura(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0000000000000000), 0x00000002)) - DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - break; - } - case 7293: // Rage of Rivendare - { - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0200000000000000))) - DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - // Marked for Death - case 7598: - case 7599: - case 7600: - case 7601: - case 7602: - { - if (pVictim->GetAura(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, UI64LIT(0x0000000000000400))) - DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - } - } - } - - // .. done (class scripts) - AuraList const& mclassScritAuras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (AuraList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i) - { - switch ((*i)->GetMiscValue()) - { - // Dirty Deeds - case 6427: - case 6428: - if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) - { - Aura* eff0 = GetAura((*i)->GetId(), EFFECT_INDEX_0); - if (!eff0 || (*i)->GetEffIndex() != EFFECT_INDEX_1) - { - sLog.outError("Spell structure of DD (%u) changed.", (*i)->GetId()); - continue; - } - - // effect 0 have expected value but in negative state - DonePercent *= (-eff0->GetModifier()->m_amount + 100.0f) / 100.0f; - } - break; - } - } - - if (spellProto) - { - SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); - - // Frost Strike - if (classOptions && classOptions->IsFitToFamily(SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0000000400000000))) - { - // search disease - bool found = false; - Unit::SpellAuraHolderMap const& auras = pVictim->GetSpellAuraHolderMap(); - for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - if(itr->second->GetSpellProto()->GetDispel() == DISPEL_DISEASE) - { - found = true; - break; - } - } - - if (found) - { - // search for Glacier Rot dummy aura - Unit::AuraList const& dummyAuras = GetAurasByType(SPELL_AURA_DUMMY); - for (Unit::AuraList::const_iterator i = dummyAuras.begin(); i != dummyAuras.end(); ++i) - { - if ((*i)->GetSpellProto()->GetEffectMiscValue((*i)->GetEffIndex()) == 7244) - { - DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - } - } - } - // Glyph of Steady Shot (Steady Shot check) - else if (classOptions && classOptions->IsFitToFamily(SPELLFAMILY_HUNTER, UI64LIT(0x0000000100000000))) - { - // search for glyph dummy aura - if (Aura* aur = GetDummyAura(56826)) - // check for Serpent Sting at target - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_HUNTER, UI64LIT(0x0000000000004000))) - DonePercent *= (aur->GetModifier()->m_amount + 100.0f) / 100.0f; - } - } - - // final calculation - // ================= - - float DoneTotal = 0.0f; - - // scaling of non weapon based spells - if (!isWeaponDamageBasedSpell) - { - // apply ap bonus and benefit affected by spell power implicit coeffs and spell level penalties - DoneTotal = SpellBonusWithCoeffs(spellProto, DoneTotal, DoneFlat, APbonus, damagetype, true); - } - // weapon damage based spells - else if (APbonus || DoneFlat) - { - bool normalized = spellProto ? IsSpellHaveEffect(spellProto, SPELL_EFFECT_NORMALIZED_WEAPON_DMG) : false; - DoneTotal += int32(APbonus / 14.0f * GetAPMultiplier(attType, normalized)); - - // for weapon damage based spells we still have to apply damage done percent mods - // (that are already included into pdamage) to not-yet included DoneFlat - // e.g. from doneVersusCreature, apBonusVs... - UnitMods unitMod; - switch (attType) - { - default: - case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; - case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; - case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; - } - - DoneTotal += DoneFlat; - - DoneTotal *= GetModifierValue(unitMod, TOTAL_PCT); - } - - float tmpDamage = float(int32(pdamage) + DoneTotal * int32(stack)) * DonePercent; - - // apply spellmod to Done damage - if (spellProto) - { - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); - } - - // bonus result can be negative - return tmpDamage > 0 ? uint32(tmpDamage) : 0; + if (!pVictim || pdamage == 0 || (spellProto && spellProto->HasAttribute(SPELL_ATTR_EX6_NO_DMG_MODS))) + { + return pdamage; + } + + // differentiate for weapon damage based spells + bool isWeaponDamageBasedSpell = !(spellProto && (damagetype == DOT || IsSpellHaveEffect(spellProto, SPELL_EFFECT_SCHOOL_DAMAGE))); + Item* pWeapon = GetTypeId() == TYPEID_PLAYER ? ((Player*)this)->GetWeaponForAttack(attType, true, false) : NULL; + uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); + uint32 schoolMask = spellProto ? spellProto->GetSchoolMask() : uint32(GetMeleeDamageSchoolMask()); + + // FLAT damage bonus auras + // ======================= + int32 DoneFlat = 0; + int32 APbonus = 0; + + // ..done flat, already included in weapon damage based spells + if (!isWeaponDamageBasedSpell) + { + AuraList const& mModDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE); + for (AuraList::const_iterator i = mModDamageDone.begin(); i != mModDamageDone.end(); ++i) + { + if (((*i)->GetModifier()->m_miscvalue & schoolMask && // schoolmask has to fit with the intrinsic spell school + (*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask() && // AND schoolmask has to fit with weapon damage school (essential for non-physical spells) + ((*i)->GetSpellProto()->GetEquippedItemClass() == -1) || // general, weapon independent + (pWeapon && pWeapon->IsFitToSpellRequirements((*i)->GetSpellProto())))) // OR used weapon fits aura requirements + { + DoneFlat += (*i)->GetModifier()->m_amount; + } + } + + // Pets just add their bonus damage to their melee damage + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) + DoneFlat += ((Pet*)this)->GetBonusDamage(); + } + + // ..done flat (by creature type mask) + DoneFlat += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask); + + // ..done flat (base at attack power for marked target and base at attack power for creature type) + if (attType == RANGED_ATTACK) + { + APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS); + APbonus += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS, creatureTypeMask); + } + else + { + APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS); + APbonus += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS, creatureTypeMask); + } + + // PERCENT damage auras + // ==================== + float DonePercent = 1.0f; + + // ..done pct, already included in weapon damage based spells + if (!isWeaponDamageBasedSpell) + { + AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + for (AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) + { + if (((*i)->GetModifier()->m_miscvalue & schoolMask && // schoolmask has to fit with the intrinsic spell school + (*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask() && // AND schoolmask has to fit with weapon damage school (essential for non-physical spells) + ((*i)->GetSpellProto()->GetEquippedItemClass()) == -1 || // general, weapon independent + (pWeapon && pWeapon->IsFitToSpellRequirements((*i)->GetSpellProto())))) // OR used weapon fits aura requirements + { + DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + } + } + + if (attType == OFF_ATTACK) + DonePercent *= GetModifierValue(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT); // no school check required + } + + if (!spellProto) + { + // apply SPELL_AURA_MOD_AUTOATTACK_DAMAGE for white damage + AuraList const& mModAutoAttackDamageAuras = GetAurasByType(SPELL_AURA_MOD_AUTOATTACK_DAMAGE); + for (AuraList::const_iterator i = mModAutoAttackDamageAuras.begin(); i != mModAutoAttackDamageAuras.end(); ++i) + { + if ((*i)->GetSpellProto()->GetEquippedItemClass() == -1 || // general, weapon independent + pWeapon && pWeapon->IsFitToSpellRequirements((*i)->GetSpellProto())) // OR used weapon fits aura requirements + { + DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + } + } + } + + // ..done pct (by creature type mask) + DonePercent *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS, creatureTypeMask); + + // special dummys/class scripts and other effects + // ============================================= + Unit* owner = GetOwner(); + if (!owner) + owner = this; + + // ..done (class scripts) + if (spellProto) + { + AuraList const& mOverrideClassScript = owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + { + if (!(*i)->isAffectedOnSpell(spellProto)) + continue; + + switch ((*i)->GetModifier()->m_miscvalue) + { + // Tundra Stalker + // Merciless Combat + case 7277: + { + // Merciless Combat + if ((*i)->GetSpellProto()->GetSpellIconID() == 2656) + { + if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) + DonePercent *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f; + } + else // Tundra Stalker + { + // Frost Fever (target debuff) + if (pVictim->GetAura(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0000000000000000), 0x00000002)) + DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + break; + } + case 7293: // Rage of Rivendare + { + if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0200000000000000))) + DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + // Marked for Death + case 7598: + case 7599: + case 7600: + case 7601: + case 7602: + { + if (pVictim->GetAura(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, UI64LIT(0x0000000000000400))) + DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + } + } + } + + // .. done (class scripts) + AuraList const& mclassScritAuras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for (AuraList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i) + { + switch ((*i)->GetMiscValue()) + { + // Dirty Deeds + case 6427: + case 6428: + if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) + { + Aura* eff0 = GetAura((*i)->GetId(), EFFECT_INDEX_0); + if (!eff0 || (*i)->GetEffIndex() != EFFECT_INDEX_1) + { + sLog.outError("Spell structure of DD (%u) changed.", (*i)->GetId()); + continue; + } + + // effect 0 have expected value but in negative state + DonePercent *= (-eff0->GetModifier()->m_amount + 100.0f) / 100.0f; + } + break; + } + } + + if (spellProto) + { + SpellClassOptionsEntry const* classOptions = spellProto->GetSpellClassOptions(); + + // Frost Strike + if (classOptions && classOptions->IsFitToFamily(SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0000000400000000))) + { + // search disease + bool found = false; + Unit::SpellAuraHolderMap const& auras = pVictim->GetSpellAuraHolderMap(); + for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + if (itr->second->GetSpellProto()->GetDispel() == DISPEL_DISEASE) + { + found = true; + break; + } + } + + if (found) + { + // search for Glacier Rot dummy aura + Unit::AuraList const& dummyAuras = GetAurasByType(SPELL_AURA_DUMMY); + for (Unit::AuraList::const_iterator i = dummyAuras.begin(); i != dummyAuras.end(); ++i) + { + if ((*i)->GetSpellProto()->GetEffectMiscValue((*i)->GetEffIndex()) == 7244) + { + DonePercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + } + } + } + // Glyph of Steady Shot (Steady Shot check) + else if (classOptions && classOptions->IsFitToFamily(SPELLFAMILY_HUNTER, UI64LIT(0x0000000100000000))) + { + // search for glyph dummy aura + if (Aura* aur = GetDummyAura(56826)) + // check for Serpent Sting at target + if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_HUNTER, UI64LIT(0x0000000000004000))) + DonePercent *= (aur->GetModifier()->m_amount + 100.0f) / 100.0f; + } + } + + // final calculation + // ================= + + float DoneTotal = 0.0f; + + // scaling of non weapon based spells + if (!isWeaponDamageBasedSpell) + { + // apply ap bonus and benefit affected by spell power implicit coeffs and spell level penalties + DoneTotal = SpellBonusWithCoeffs(spellProto, DoneTotal, DoneFlat, APbonus, damagetype, true); + } + // weapon damage based spells + else if (APbonus || DoneFlat) + { + bool normalized = spellProto ? IsSpellHaveEffect(spellProto, SPELL_EFFECT_NORMALIZED_WEAPON_DMG) : false; + DoneTotal += int32(APbonus / 14.0f * GetAPMultiplier(attType, normalized)); + + // for weapon damage based spells we still have to apply damage done percent mods + // (that are already included into pdamage) to not-yet included DoneFlat + // e.g. from doneVersusCreature, apBonusVs... + UnitMods unitMod; + switch (attType) + { + default: + case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; + case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; + case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; + } + + DoneTotal += DoneFlat; + + DoneTotal *= GetModifierValue(unitMod, TOTAL_PCT); + } + + float tmpDamage = float(int32(pdamage) + DoneTotal * int32(stack)) * DonePercent; + + // apply spellmod to Done damage + if (spellProto) + { + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); + } + + // bonus result can be negative + return tmpDamage > 0 ? uint32(tmpDamage) : 0; } /** @@ -8746,1349 +8750,1349 @@ uint32 Unit::MeleeDamageBonusDone(Unit* pVictim, uint32 pdamage, WeaponAttackTyp */ uint32 Unit::MeleeDamageBonusTaken(Unit* pCaster, uint32 pdamage, WeaponAttackType attType, SpellEntry const* spellProto, DamageEffectType damagetype, uint32 stack) { - if (!pCaster) - { - return pdamage; - } - - if (pdamage == 0) - { - return pdamage; - } - - // differentiate for weapon damage based spells - bool isWeaponDamageBasedSpell = !(spellProto && (damagetype == DOT || IsSpellHaveEffect(spellProto, SPELL_EFFECT_SCHOOL_DAMAGE))); - uint32 schoolMask = spellProto ? spellProto->GetSchoolMask() : uint32(GetMeleeDamageSchoolMask()); - uint32 mechanicMask = spellProto ? GetAllSpellMechanicMask(spellProto) : 0; - - // Shred also have bonus as MECHANIC_BLEED damages - SpellClassOptionsEntry const* classOptions = spellProto ? spellProto->GetSpellClassOptions() : NULL; - if (classOptions && classOptions->SpellFamilyName==SPELLFAMILY_DRUID && classOptions->SpellFamilyFlags & UI64LIT(0x00008000)) - mechanicMask |= (1 << (MECHANIC_BLEED-1)); - - // FLAT damage bonus auras - // ======================= - int32 TakenFlat = 0; - - // ..taken flat (base at attack power for marked target and base at attack power for creature type) - if (attType == RANGED_ATTACK) - TakenFlat += GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN); - else - TakenFlat += GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN); - - // ..taken flat (by school mask) - TakenFlat += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, schoolMask); - - // PERCENT damage auras - // ==================== - float TakenPercent = 1.0f; - - // ..taken pct (by school mask) - TakenPercent *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, schoolMask); - - // ..taken pct (by mechanic mask) - TakenPercent *= GetTotalAuraMultiplierByMiscValueForMask(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, mechanicMask); - - // ..taken pct (melee/ranged) - if (attType == RANGED_ATTACK) - TakenPercent *= GetTotalAuraMultiplier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT); - else - TakenPercent *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT); - - // ..taken pct (aoe avoidance) - if (spellProto && IsAreaOfEffectSpell(spellProto)) - { - TakenPercent *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask); - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) - TakenPercent *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_PET_AOE_DAMAGE_AVOIDANCE, schoolMask); - } - - // special dummys/class scripts and other effects - // ============================================= - - // .. taken (dummy auras) - AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_DUMMY); - for (AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - { - switch ((*i)->GetId()) - { - case 45182: // Cheating Death - if ((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) - { - if (GetTypeId() != TYPEID_PLAYER) - continue; - - TakenPercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - } - break; - case 20911: // Blessing of Sanctuary - case 25899: // Greater Blessing of Sanctuary - TakenPercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; - break; - } - } - - // final calculation - // ================= - - // scaling of non weapon based spells - if (!isWeaponDamageBasedSpell) - { - // apply benefit affected by spell power implicit coeffs and spell level penalties - TakenFlat = pCaster->SpellBonusWithCoeffs(spellProto, 0, TakenFlat, 0, damagetype, false); - } - - float tmpDamage = float(int32(pdamage) + TakenFlat * int32(stack)) * TakenPercent; - - // bonus result can be negative - return tmpDamage > 0 ? uint32(tmpDamage) : 0; + if (!pCaster) + { + return pdamage; + } + + if (pdamage == 0) + { + return pdamage; + } + + // differentiate for weapon damage based spells + bool isWeaponDamageBasedSpell = !(spellProto && (damagetype == DOT || IsSpellHaveEffect(spellProto, SPELL_EFFECT_SCHOOL_DAMAGE))); + uint32 schoolMask = spellProto ? spellProto->GetSchoolMask() : uint32(GetMeleeDamageSchoolMask()); + uint32 mechanicMask = spellProto ? GetAllSpellMechanicMask(spellProto) : 0; + + // Shred also have bonus as MECHANIC_BLEED damages + SpellClassOptionsEntry const* classOptions = spellProto ? spellProto->GetSpellClassOptions() : NULL; + if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_DRUID && classOptions->SpellFamilyFlags & UI64LIT(0x00008000)) + mechanicMask |= (1 << (MECHANIC_BLEED - 1)); + + // FLAT damage bonus auras + // ======================= + int32 TakenFlat = 0; + + // ..taken flat (base at attack power for marked target and base at attack power for creature type) + if (attType == RANGED_ATTACK) + TakenFlat += GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN); + else + TakenFlat += GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN); + + // ..taken flat (by school mask) + TakenFlat += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, schoolMask); + + // PERCENT damage auras + // ==================== + float TakenPercent = 1.0f; + + // ..taken pct (by school mask) + TakenPercent *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, schoolMask); + + // ..taken pct (by mechanic mask) + TakenPercent *= GetTotalAuraMultiplierByMiscValueForMask(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, mechanicMask); + + // ..taken pct (melee/ranged) + if (attType == RANGED_ATTACK) + TakenPercent *= GetTotalAuraMultiplier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT); + else + TakenPercent *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT); + + // ..taken pct (aoe avoidance) + if (spellProto && IsAreaOfEffectSpell(spellProto)) + { + TakenPercent *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask); + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) + TakenPercent *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_PET_AOE_DAMAGE_AVOIDANCE, schoolMask); + } + + // special dummys/class scripts and other effects + // ============================================= + + // .. taken (dummy auras) + AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_DUMMY); + for (AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) + { + switch ((*i)->GetId()) + { + case 45182: // Cheating Death + if ((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) + { + if (GetTypeId() != TYPEID_PLAYER) + continue; + + TakenPercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + } + break; + case 20911: // Blessing of Sanctuary + case 25899: // Greater Blessing of Sanctuary + TakenPercent *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; + } + } + + // final calculation + // ================= + + // scaling of non weapon based spells + if (!isWeaponDamageBasedSpell) + { + // apply benefit affected by spell power implicit coeffs and spell level penalties + TakenFlat = pCaster->SpellBonusWithCoeffs(spellProto, 0, TakenFlat, 0, damagetype, false); + } + + float tmpDamage = float(int32(pdamage) + TakenFlat * int32(stack)) * TakenPercent; + + // bonus result can be negative + return tmpDamage > 0 ? uint32(tmpDamage) : 0; } void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply) { - if (apply) - { - for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next) - { - next = itr; ++next; - if (itr->type == type) - { - m_spellImmune[op].erase(itr); - next = m_spellImmune[op].begin(); - } - } - SpellImmune Immune; - Immune.spellId = spellId; - Immune.type = type; - m_spellImmune[op].push_back(Immune); - } - else - { - for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr) - { - if (itr->spellId == spellId) - { - m_spellImmune[op].erase(itr); - break; - } - } - } + if (apply) + { + for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next) + { + next = itr; ++next; + if (itr->type == type) + { + m_spellImmune[op].erase(itr); + next = m_spellImmune[op].begin(); + } + } + SpellImmune Immune; + Immune.spellId = spellId; + Immune.type = type; + m_spellImmune[op].push_back(Immune); + } + else + { + for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr) + { + if (itr->spellId == spellId) + { + m_spellImmune[op].erase(itr); + break; + } + } + } } void Unit::ApplySpellDispelImmunity(const SpellEntry* spellProto, DispelType type, bool apply) { - ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply); + ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply); - if (apply && spellProto->HasAttribute(SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)) - RemoveAurasWithDispelType(type); + if (apply && spellProto->HasAttribute(SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)) + RemoveAurasWithDispelType(type); } float Unit::GetWeaponProcChance() const { - // normalized proc chance for weapon attack speed - // (odd formula...) - if (isAttackReady(BASE_ATTACK)) - { - return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f); - } - else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) - { - return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f); - } + // normalized proc chance for weapon attack speed + // (odd formula...) + if (isAttackReady(BASE_ATTACK)) + { + return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f); + } + else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) + { + return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f); + } - return 0.0f; + return 0.0f; } float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const { - // proc per minute chance calculation - if (PPM <= 0.0f) - { - return 0.0f; - } - return WeaponSpeed * PPM / 600.0f; // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) + // proc per minute chance calculation + if (PPM <= 0.0f) + { + return 0.0f; + } + return WeaponSpeed * PPM / 600.0f; // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) } void Unit::Mount(uint32 mount, uint32 spellId) { - if (!mount) - { - return; - } - - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING); - - SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount); - - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT); - - if (GetTypeId() == TYPEID_PLAYER) - { - // Called by Taxi system / GM command - if (!spellId) - ((Player*)this)->UnsummonPetTemporaryIfAny(); - // Called by mount aura - else if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId)) - { - // Flying case (Unsummon any pet) - if (IsSpellHaveAura(spellInfo, SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED)) - ((Player*)this)->UnsummonPetTemporaryIfAny(); - // Normal case (Unsummon only permanent pet) - else if (Pet* pet = GetPet()) - { - if (pet->isControlled() && (!(pet->isTemporarySummoned() || ((Player*)this)->InArena()) - || sWorld.getConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT))) - ((Player*)this)->UnsummonPetTemporaryIfAny(); - else - pet->SetModeFlags(PET_MODE_DISABLE_ACTIONS); - } - } - - float height = ((Player*)this)->GetCollisionHeight(true); - if (height) - SendCollisionHeightUpdate(height); - } + if (!mount) + { + return; + } + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING); + + SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount); + + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT); + + if (GetTypeId() == TYPEID_PLAYER) + { + // Called by Taxi system / GM command + if (!spellId) + ((Player*)this)->UnsummonPetTemporaryIfAny(); + // Called by mount aura + else if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId)) + { + // Flying case (Unsummon any pet) + if (IsSpellHaveAura(spellInfo, SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED)) + ((Player*)this)->UnsummonPetTemporaryIfAny(); + // Normal case (Unsummon only permanent pet) + else if (Pet* pet = GetPet()) + { + if (pet->isControlled() && (!(pet->isTemporarySummoned() || ((Player*)this)->InArena()) + || sWorld.getConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT))) + ((Player*)this)->UnsummonPetTemporaryIfAny(); + else + pet->SetModeFlags(PET_MODE_DISABLE_ACTIONS); + } + } + + float height = ((Player*)this)->GetCollisionHeight(true); + if (height) + SendCollisionHeightUpdate(height); + } } void Unit::Unmount(bool from_aura) { - if (!IsMounted()) - { - return; - } - - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED); - - SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT); - - // Called NOT by Taxi system / GM command - if (from_aura) - { - WorldPacket data(SMSG_DISMOUNT, 8); - data << GetPackGUID(); - SendMessageToSet(&data, true); - } - - // only resummon old pet if the player is already added to a map - // this prevents adding a pet to a not created map which would otherwise cause a crash - // (it could probably happen when logging in after a previous crash) - if (GetTypeId() == TYPEID_PLAYER) - { - if (Pet* pet = GetPet()) - { - // Get reaction state and display appropriately - if (CharmInfo* charmInfo = pet->GetCharmInfo()) - pet->SetModeFlags(PetModeFlags(charmInfo->GetReactState() | charmInfo->GetCommandState() * 0x100)); - } - else - ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny(); - - float height = ((Player*)this)->GetCollisionHeight(false); - if (height) - SendCollisionHeightUpdate(height); - } + if (!IsMounted()) + { + return; + } + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED); + + SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT); + + // Called NOT by Taxi system / GM command + if (from_aura) + { + WorldPacket data(SMSG_DISMOUNT, 8); + data << GetPackGUID(); + SendMessageToSet(&data, true); + } + + // only resummon old pet if the player is already added to a map + // this prevents adding a pet to a not created map which would otherwise cause a crash + // (it could probably happen when logging in after a previous crash) + if (GetTypeId() == TYPEID_PLAYER) + { + if (Pet* pet = GetPet()) + { + // Get reaction state and display appropriately + if (CharmInfo* charmInfo = pet->GetCharmInfo()) + pet->SetModeFlags(PetModeFlags(charmInfo->GetReactState() | charmInfo->GetCommandState() * 0x100)); + } + else + ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny(); + + float height = ((Player*)this)->GetCollisionHeight(false); + if (height) + SendCollisionHeightUpdate(height); + } } bool Unit::IsNearWaypoint(float currentPositionX, float currentPositionY, float currentPositionZ, float destinationPostionX, float destinationPostionY, float destinationPostionZ, float distanceX, float distanceY, float distanceZ) { - // actual distance between the creature's X ordinate and destination X ordinate - float xDifference = 0; - // actual distance between the creature's Y ordinate and destination Y ordinate - float yDifference = 0; - // actual distance between the creature's Z ordinate and destination Y ordinate - float zDifference = 0; - - // distanceX == 0, means do not test the distance between the creature's current X ordinate and the destination X ordinate - // A test for 0 is used, because it is not worth testing for exact coordinates, seeing as we have to use an integar in the database for the event parameters that holds the cordinates. - // Therefore a test for the distance between waypoints does the job more than well enough - if (distanceX > 0) - { - if (currentPositionX > destinationPostionX) - xDifference = currentPositionX - destinationPostionX; - else - xDifference = destinationPostionX - currentPositionX; - } - // distanceY == 0, means do not test the distance between the creature's current Y ordinate and the destination Y ordinate - if (distanceY > 0) - { - if (currentPositionY > destinationPostionY) - yDifference = currentPositionY - destinationPostionY; - else - yDifference = destinationPostionY - currentPositionY; - } - // distanceZ == 0, means do not test the distance between the creature's current Z ordinate and the destination Z ordinate - if (distanceZ > 0) - { - if (currentPositionZ > destinationPostionZ) - zDifference = currentPositionZ - destinationPostionZ; - else - zDifference = destinationPostionZ - currentPositionZ; - } - - // check based on which ordinates to test the current distance from (distance along the X, and/or Y, and/or Z ordinates) - if (((distanceX > 0 && xDifference < distanceX) && (distanceY > 0 && yDifference < distanceY) && (distanceZ > 0 && zDifference < distanceZ)) || - ((distanceX == 0) && (distanceY > 0 && yDifference < distanceY) && (distanceZ > 0 && zDifference < distanceZ)) || - ((distanceX > 0 && xDifference < distanceX) && (distanceY == 0) && (distanceZ > 0 && zDifference < distanceZ)) || - ((distanceX > 0 && xDifference < distanceX) && (distanceY > 0 && yDifference < distanceY) && (distanceZ == 0)) || - ((distanceX > 0 && xDifference < distanceX) && (distanceY == 0) && (distanceZ == 0)) || - ((distanceX == 0) && (distanceY > 0 && yDifference < distanceY) && (distanceZ == 0)) || - ((distanceX == 0) && (distanceY == 0) && (distanceZ > 0 && zDifference < distanceZ)) - ) - return true; - - return false; + // actual distance between the creature's X ordinate and destination X ordinate + float xDifference = 0; + // actual distance between the creature's Y ordinate and destination Y ordinate + float yDifference = 0; + // actual distance between the creature's Z ordinate and destination Y ordinate + float zDifference = 0; + + // distanceX == 0, means do not test the distance between the creature's current X ordinate and the destination X ordinate + // A test for 0 is used, because it is not worth testing for exact coordinates, seeing as we have to use an integar in the database for the event parameters that holds the cordinates. + // Therefore a test for the distance between waypoints does the job more than well enough + if (distanceX > 0) + { + if (currentPositionX > destinationPostionX) + xDifference = currentPositionX - destinationPostionX; + else + xDifference = destinationPostionX - currentPositionX; + } + // distanceY == 0, means do not test the distance between the creature's current Y ordinate and the destination Y ordinate + if (distanceY > 0) + { + if (currentPositionY > destinationPostionY) + yDifference = currentPositionY - destinationPostionY; + else + yDifference = destinationPostionY - currentPositionY; + } + // distanceZ == 0, means do not test the distance between the creature's current Z ordinate and the destination Z ordinate + if (distanceZ > 0) + { + if (currentPositionZ > destinationPostionZ) + zDifference = currentPositionZ - destinationPostionZ; + else + zDifference = destinationPostionZ - currentPositionZ; + } + + // check based on which ordinates to test the current distance from (distance along the X, and/or Y, and/or Z ordinates) + if (((distanceX > 0 && xDifference < distanceX) && (distanceY > 0 && yDifference < distanceY) && (distanceZ > 0 && zDifference < distanceZ)) || + ((distanceX == 0) && (distanceY > 0 && yDifference < distanceY) && (distanceZ > 0 && zDifference < distanceZ)) || + ((distanceX > 0 && xDifference < distanceX) && (distanceY == 0) && (distanceZ > 0 && zDifference < distanceZ)) || + ((distanceX > 0 && xDifference < distanceX) && (distanceY > 0 && yDifference < distanceY) && (distanceZ == 0)) || + ((distanceX > 0 && xDifference < distanceX) && (distanceY == 0) && (distanceZ == 0)) || + ((distanceX == 0) && (distanceY > 0 && yDifference < distanceY) && (distanceZ == 0)) || + ((distanceX == 0) && (distanceY == 0) && (distanceZ > 0 && zDifference < distanceZ)) + ) + return true; + + return false; } MountCapabilityEntry const* Unit::GetMountCapability(uint32 mountType) const { - if (!mountType) - { - return NULL; - } - - MountTypeEntry const* mountTypeEntry = sMountTypeStore.LookupEntry(mountType); - if (!mountTypeEntry) - { - return NULL; - } - - uint32 zoneId, areaId; - GetZoneAndAreaId(zoneId, areaId); - uint32 ridingSkill = 5000; - if (GetTypeId() == TYPEID_PLAYER) - { - Player* plr = (Player*)(this); - ridingSkill = plr->GetSkillValue(SKILL_RIDING); - } - - for (uint32 i = MAX_MOUNT_CAPABILITIES; i > 0; --i) - { - MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(mountTypeEntry->MountCapability[i - 1]); - if (!mountCapability) - continue; - - if (ridingSkill < mountCapability->RequiredRidingSkill) - continue; - - if (m_movementInfo.HasMovementFlag2(MOVEFLAG2_FULLSPEEDPITCHING)) - { - if (!(mountCapability->Flags & MOUNT_FLAG_CAN_PITCH)) - continue; - } - else if (m_movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING)) - { - if (!(mountCapability->Flags & MOUNT_FLAG_CAN_SWIM)) - continue; - } - else if (!(mountCapability->Flags & 0x1)) // unknown flags, checked in 4.2.2 14545 client - { - if (!(mountCapability->Flags & 0x2)) - continue; - } - - if (mountCapability->RequiredMap != -1 && int32(GetMapId()) != mountCapability->RequiredMap) - continue; - - if (mountCapability->RequiredArea && (mountCapability->RequiredArea != zoneId && mountCapability->RequiredArea != areaId)) - continue; - - if (mountCapability->RequiredAura && !HasAura(mountCapability->RequiredAura)) - continue; - - if (mountCapability->RequiredSpell && (GetTypeId() != TYPEID_PLAYER || !(Player*)(this)->HasSpell(mountCapability->RequiredSpell))) - continue; - - return mountCapability; - } - - return NULL; + if (!mountType) + { + return NULL; + } + + MountTypeEntry const* mountTypeEntry = sMountTypeStore.LookupEntry(mountType); + if (!mountTypeEntry) + { + return NULL; + } + + uint32 zoneId, areaId; + GetZoneAndAreaId(zoneId, areaId); + uint32 ridingSkill = 5000; + if (GetTypeId() == TYPEID_PLAYER) + { + Player* plr = (Player*)(this); + ridingSkill = plr->GetSkillValue(SKILL_RIDING); + } + + for (uint32 i = MAX_MOUNT_CAPABILITIES; i > 0; --i) + { + MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(mountTypeEntry->MountCapability[i - 1]); + if (!mountCapability) + continue; + + if (ridingSkill < mountCapability->RequiredRidingSkill) + continue; + + if (m_movementInfo.HasMovementFlag2(MOVEFLAG2_FULLSPEEDPITCHING)) + { + if (!(mountCapability->Flags & MOUNT_FLAG_CAN_PITCH)) + continue; + } + else if (m_movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING)) + { + if (!(mountCapability->Flags & MOUNT_FLAG_CAN_SWIM)) + continue; + } + else if (!(mountCapability->Flags & 0x1)) // unknown flags, checked in 4.2.2 14545 client + { + if (!(mountCapability->Flags & 0x2)) + continue; + } + + if (mountCapability->RequiredMap != -1 && int32(GetMapId()) != mountCapability->RequiredMap) + continue; + + if (mountCapability->RequiredArea && (mountCapability->RequiredArea != zoneId && mountCapability->RequiredArea != areaId)) + continue; + + if (mountCapability->RequiredAura && !HasAura(mountCapability->RequiredAura)) + continue; + + if (mountCapability->RequiredSpell && (GetTypeId() != TYPEID_PLAYER || !(Player*)(this)->HasSpell(mountCapability->RequiredSpell))) + continue; + + return mountCapability; + } + + return NULL; } void Unit::PlayOneShotAnimKit(uint32 id) { - WorldPacket data(SMSG_PLAY_ONE_SHOT_ANIM_KIT, 7+2); - data << GetPackGUID(); - data << uint16(id); - SendMessageToSet(&data, true); + WorldPacket data(SMSG_PLAY_ONE_SHOT_ANIM_KIT, 7 + 2); + data << GetPackGUID(); + data << uint16(id); + SendMessageToSet(&data, true); } void Unit::SetInCombatWith(Unit* enemy) { - Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf(); - if (eOwner->IsPvP()) - { - SetInCombatState(true, enemy); - return; - } - - // check for duel - if (eOwner->GetTypeId() == TYPEID_PLAYER && ((Player*)eOwner)->duel) - { - if (Player const* myOwner = GetCharmerOrOwnerPlayerOrPlayerItself()) - { - if (myOwner->IsInDuelWith((Player const*)eOwner)) - { - SetInCombatState(true, enemy); - return; - } - } - } - - SetInCombatState(false, enemy); + Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf(); + if (eOwner->IsPvP()) + { + SetInCombatState(true, enemy); + return; + } + + // check for duel + if (eOwner->GetTypeId() == TYPEID_PLAYER && ((Player*)eOwner)->duel) + { + if (Player const* myOwner = GetCharmerOrOwnerPlayerOrPlayerItself()) + { + if (myOwner->IsInDuelWith((Player const*)eOwner)) + { + SetInCombatState(true, enemy); + return; + } + } + } + + SetInCombatState(false, enemy); } void Unit::SetInCombatState(bool PvP, Unit* enemy) { - // only alive units can be in combat - if (!IsAlive()) - { - return; - } - - if (PvP) - { - m_CombatTimer = 5000; - } - - bool creatureNotInCombat = GetTypeId() == TYPEID_UNIT && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - - if (IsCharmed() || (GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->IsPet())) - { - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); - } - - // interrupt all delayed non-combat casts - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) - if (Spell* spell = GetCurrentSpell(CurrentSpellTypes(i))) - if (IsNonCombatSpell(spell->m_spellInfo)) - { - InterruptSpell(CurrentSpellTypes(i), false); - } - - if (getRace() == RACE_WORGEN && !IsInWorgenForm(true) && HasWorgenForm()) - CastSpell(this, 97709, true); // cast Altered Form - - if (creatureNotInCombat) - { - // should probably be removed for the attacked (+ it's party/group) only, not global - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); - - // client does not handle this state on it's own (reset to default at LoadCreatureAddon) - if (getStandState() == UNIT_STAND_STATE_CUSTOM) - SetStandState(UNIT_STAND_STATE_STAND); - - Creature* pCreature = (Creature*)this; - - if (pCreature->AI()) - { - pCreature->AI()->EnterCombat(enemy); - } - - // Some bosses are set into combat with zone - if (GetMap()->IsDungeon() && (pCreature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_AGGRO_ZONE) && enemy && enemy->IsControlledByPlayer()) - { - pCreature->SetInCombatWithZone(); - } - - if (InstanceData* mapInstance = GetInstanceData()) - { - mapInstance->OnCreatureEnterCombat(pCreature); - } - - if (m_isCreatureLinkingTrigger) - { - GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_AGGRO, pCreature, enemy); - } - } - - // Used by Eluna + // only alive units can be in combat + if (!IsAlive()) + { + return; + } + + if (PvP) + { + m_CombatTimer = 5000; + } + + bool creatureNotInCombat = GetTypeId() == TYPEID_UNIT && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + + if (IsCharmed() || (GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->IsPet())) + { + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); + } + + // interrupt all delayed non-combat casts + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) + if (Spell* spell = GetCurrentSpell(CurrentSpellTypes(i))) + if (IsNonCombatSpell(spell->m_spellInfo)) + { + InterruptSpell(CurrentSpellTypes(i), false); + } + + if (getRace() == RACE_WORGEN && !IsInWorgenForm(true) && HasWorgenForm()) + CastSpell(this, 97709, true); // cast Altered Form + + if (creatureNotInCombat) + { + // should probably be removed for the attacked (+ it's party/group) only, not global + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + + // client does not handle this state on it's own (reset to default at LoadCreatureAddon) + if (getStandState() == UNIT_STAND_STATE_CUSTOM) + SetStandState(UNIT_STAND_STATE_STAND); + + Creature* pCreature = (Creature*)this; + + if (pCreature->AI()) + { + pCreature->AI()->EnterCombat(enemy); + } + + // Some bosses are set into combat with zone + if (GetMap()->IsDungeon() && (pCreature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_AGGRO_ZONE) && enemy && enemy->IsControlledByPlayer()) + { + pCreature->SetInCombatWithZone(); + } + + if (InstanceData* mapInstance = GetInstanceData()) + { + mapInstance->OnCreatureEnterCombat(pCreature); + } + + if (m_isCreatureLinkingTrigger) + { + GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_AGGRO, pCreature, enemy); + } + } + + // Used by Eluna #ifdef ENABLE_ELUNA - if (GetTypeId() == TYPEID_PLAYER) - sEluna->OnPlayerEnterCombat(ToPlayer(), enemy); + if (GetTypeId() == TYPEID_PLAYER) + sEluna->OnPlayerEnterCombat(ToPlayer(), enemy); #endif /* ENABLE_ELUNA */ } void Unit::ClearInCombat() { - m_CombatTimer = 0; - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + m_CombatTimer = 0; + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - if (IsCharmed() || (GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->IsPet())) - { - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); - } + if (IsCharmed() || (GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->IsPet())) + { + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); + } - // Used by Eluna + // Used by Eluna #ifdef ENABLE_ELUNA - if (GetTypeId() == TYPEID_PLAYER) - sEluna->OnPlayerLeaveCombat(ToPlayer()); + if (GetTypeId() == TYPEID_PLAYER) + sEluna->OnPlayerLeaveCombat(ToPlayer()); #endif /* ENABLE_ELUNA */ - // Player's state will be cleared in Player::UpdateContestedPvP - if (GetTypeId() == TYPEID_UNIT) - { - Creature* cThis = static_cast(this); - if (cThis->GetCreatureInfo()->UnitFlags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !(cThis->GetTemporaryFactionFlags() & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK)) - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + // Player's state will be cleared in Player::UpdateContestedPvP + if (GetTypeId() == TYPEID_UNIT) + { + Creature* cThis = static_cast(this); + if (cThis->GetCreatureInfo()->UnitFlags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !(cThis->GetTemporaryFactionFlags() & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK)) + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); - clearUnitState(UNIT_STAT_ATTACK_PLAYER); - } - else - ((Player*)this)->UpdatePotionCooldown(); + clearUnitState(UNIT_STAT_ATTACK_PLAYER); + } + else + ((Player*)this)->UpdatePotionCooldown(); } bool Unit::IsTargetableForAttack(bool inverseAlive /*=false*/) const { - if (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isGameMaster()) - { - return false; - } + if (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isGameMaster()) + { + return false; + } - if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) - { - return false; - } + if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) + { + return false; + } - // to be removed if unit by any reason enter combat - if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) - { - return false; - } + // to be removed if unit by any reason enter combat + if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + { + return false; + } - // inversealive is needed for some spells which need to be casted at dead targets (aoe) - if (IsAlive() == inverseAlive) - { - return false; - } + // inversealive is needed for some spells which need to be casted at dead targets (aoe) + if (IsAlive() == inverseAlive) + { + return false; + } - return IsInWorld() && !hasUnitState(UNIT_STAT_DIED) && !IsTaxiFlying(); + return IsInWorld() && !hasUnitState(UNIT_STAT_DIED) && !IsTaxiFlying(); } int32 Unit::ModifyHealth(int32 dVal) { - int32 gain = 0; + int32 gain = 0; - if (dVal == 0) - { - return 0; - } + if (dVal == 0) + { + return 0; + } - int32 curHealth = (int32)GetHealth(); + int32 curHealth = (int32)GetHealth(); - int32 val = dVal + curHealth; - if (val <= 0) - { - SetHealth(0); - return -curHealth; - } + int32 val = dVal + curHealth; + if (val <= 0) + { + SetHealth(0); + return -curHealth; + } - int32 maxHealth = (int32)GetMaxHealth(); + int32 maxHealth = (int32)GetMaxHealth(); - if (val < maxHealth) - { - SetHealth(val); - gain = val - curHealth; - } - else - { - SetHealth(maxHealth); - gain = maxHealth - curHealth; - } + if (val < maxHealth) + { + SetHealth(val); + gain = val - curHealth; + } + else + { + SetHealth(maxHealth); + gain = maxHealth - curHealth; + } - return gain; + return gain; } int32 Unit::ModifyPower(Powers power, int32 dVal) { - int32 gain = 0; + int32 gain = 0; - if (dVal == 0) - { - return 0; - } + if (dVal == 0) + { + return 0; + } - int32 curPower = (int32)GetPower(power); + int32 curPower = (int32)GetPower(power); - int32 val = dVal + curPower; - if (val <= 0) - { - SetPower(power, 0); - return -curPower; - } + int32 val = dVal + curPower; + if (val <= 0) + { + SetPower(power, 0); + return -curPower; + } - int32 maxPower = (int32)GetMaxPower(power); + int32 maxPower = (int32)GetMaxPower(power); - if (val < maxPower) - { - SetPower(power, val); - gain = val - curPower; - } - else - { - SetPower(power, maxPower); - gain = maxPower - curPower; - } + if (val < maxPower) + { + SetPower(power, val); + gain = val - curPower; + } + else + { + SetPower(power, maxPower); + gain = maxPower - curPower; + } - return gain; + return gain; } bool Unit::IsVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, bool detect, bool inVisibleList, bool is3dDistance) const { - if (!u || !IsInMap(u)) - { - return false; - } - - // Always can see self - if (u == this) - { - return true; - } - - // player visible for other player if not logout and at same transport - // including case when player is out of world - bool at_same_transport = - GetTypeId() == TYPEID_PLAYER && u->GetTypeId() == TYPEID_PLAYER && - !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() && - !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() && - ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport(); - - // not in world - if (!at_same_transport && (!IsInWorld() || !u->IsInWorld())) - { - return false; - } - - // forbidden to seen (while Removing corpse) - if (m_Visibility == VISIBILITY_REMOVE_CORPSE) - { - return false; - } - - Map& _map = *u->GetMap(); - // Grid dead/alive checks - if (u->GetTypeId() == TYPEID_PLAYER) - { - // non visible at grid for any stealth state - if (!IsVisibleInGridForPlayer((Player*)u)) - { - return false; - } - - // if player is dead then he can't detect anyone in any cases - if (!u->IsAlive()) - detect = false; - } - else - { - // all dead creatures/players not visible for any creatures - if (!u->IsAlive() || !IsAlive()) - { - return false; - } - } - - // different visible distance checks - if (u->IsTaxiFlying()) // what see player in flight - { - // use object grey distance for all (only see objects any way) - if (!IsWithinDistInMap(viewPoint, World::GetMaxVisibleDistanceInFlight() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance)) - { - return false; - } - } - else if (!at_same_transport) // distance for show player/pet/creature (no transport case) - { - // Any units far than max visible distance for viewer or not in our map are not visible too - if (!IsWithinDistInMap(viewPoint, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) - { - return false; - } - } - - // always seen by owner - if (GetCharmerOrOwnerGuid() == u->GetObjectGuid()) - { - return true; - } - - // isInvisibleForAlive() those units can only be seen by dead or if other - // unit is also invisible for alive.. if an isinvisibleforalive unit dies we - // should be able to see it too - if (u->IsAlive() && IsAlive() && isInvisibleForAlive() != u->isInvisibleForAlive()) - if (u->GetTypeId() != TYPEID_PLAYER || !((Player*)u)->isGameMaster()) - { - return false; - } - - // Visible units, always are visible for all units, except for units under invisibility and phases - if (m_Visibility == VISIBILITY_ON && u->m_invisibilityMask == 0) - { - return true; - } - - // GMs see any players, not higher GMs and all units in any phase - if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->isGameMaster()) - { - if (GetTypeId() == TYPEID_PLAYER) - { - return ((Player*)this)->GetSession()->GetSecurity() <= ((Player*)u)->GetSession()->GetSecurity(); - } - else - { - return true; - } - } - - // non faction visibility non-breakable for non-GMs - if (m_Visibility == VISIBILITY_OFF) - { - return false; - } - - // grouped players should always see stealthed party members - if (GetTypeId() == TYPEID_PLAYER && u->GetTypeId() == TYPEID_PLAYER) - if (((Player*)this)->IsGroupVisibleFor(((Player*)u)) && u->IsFriendlyTo(this)) - { - return true; - } - - // raw invisibility - bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask != 0); - if (u->GetTypeId() == TYPEID_PLAYER) // if object is player with mover, use its visibility masks, so that an invisible player MCing a creature can see stuff - { - if (Player* player = (Player*)u) - { - if (Unit* mover=player->GetMover()) - { - invisible= (m_invisibilityMask != 0 || mover->m_invisibilityMask != 0); - } - } - } - - // detectable invisibility case - if (invisible && ( - // Invisible units, always are visible for units under same invisibility type - (m_invisibilityMask & u->m_invisibilityMask) != 0 || - // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect) - u->canDetectInvisibilityOf(this) || - // Units that can detect invisibility always are visible for units that can be detected - canDetectInvisibilityOf(u))) - { - invisible = false; - } - - // special cases for always overwrite invisibility/stealth - if (invisible || m_Visibility == VISIBILITY_GROUP_STEALTH) - { - if (u->IsHostileTo(this)) - { - // Hunter mark functionality - AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); - for (AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) - if ((*iter)->GetCasterGuid() == u->GetObjectGuid()) - { - return true; - } - } - - // none other cases for detect invisibility, so invisible - if (invisible) - { - return false; - } - } - - // unit got in stealth in this moment and must ignore old detected state - if (m_Visibility == VISIBILITY_GROUP_NO_DETECT) - { - return false; - } - - // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible - if (m_Visibility != VISIBILITY_GROUP_STEALTH) - { - return true; - } - - // NOW ONLY STEALTH CASE - - // if in non-detect mode then invisible for unit - // mobs always detect players (detect == true)... return 'false' for those mobs which have (detect == false) - // players detect players only in Player::HandleStealthedUnitsDetection() - if (!detect) - { - return (u->GetTypeId() == TYPEID_PLAYER) ? ((Player*)u)->HaveAtClient(this) : false; - } - - // Special cases - - // If is attacked then stealth is lost, some creature can use stealth too - if (!getAttackers().empty()) - { - return true; - } - - // If there is collision rogue is seen regardless of level difference - if (IsWithinDist(u, 0.24f)) - { - return true; - } - - // If a mob or player is stunned he will not be able to detect stealth - if (u->hasUnitState(UNIT_STAT_STUNNED) && (u != this)) - { - return false; - } - - // set max ditance - float visibleDistance = (u->GetTypeId() == TYPEID_PLAYER) ? MAX_PLAYER_STEALTH_DETECT_RANGE : ((Creature const*)u)->GetAttackDistance(this); - - // Always invisible from back (when stealth detection is on), also filter max distance cases - bool isInFront = viewPoint->IsInFrontInMap(this, visibleDistance); - if (!isInFront) - { - return false; - } - - // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los - if (!u->HasAuraType(SPELL_AURA_DETECT_STEALTH)) - { - // Calculation if target is in front - - // Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) - visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH) / 100.0f); - - // Visible distance is modified by - //-Level Diff (every level diff = 1.0f in visible distance) - visibleDistance += int32(u->GetLevelForTarget(this)) - int32(GetLevelForTarget(u)); - - // This allows to check talent tree and will add addition stealth dependent on used points) - int32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL); - if (stealthMod < 0) - stealthMod = 0; - - //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) - // based on wowwiki every 5 mod we have 1 more level diff in calculation - visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_DETECT)) - stealthMod) / 5.0f; - visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance; - - // recheck new distance - if (visibleDistance <= 0 || !IsWithinDist(viewPoint, visibleDistance)) - { - return false; - } - } - - // Now check is target visible with LoS - float ox, oy, oz; - viewPoint->GetPosition(ox, oy, oz); - return IsWithinLOS(ox, oy, oz); + if (!u || !IsInMap(u)) + { + return false; + } + + // Always can see self + if (u == this) + { + return true; + } + + // player visible for other player if not logout and at same transport + // including case when player is out of world + bool at_same_transport = + GetTypeId() == TYPEID_PLAYER && u->GetTypeId() == TYPEID_PLAYER && + !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() && + !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() && + ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport(); + + // not in world + if (!at_same_transport && (!IsInWorld() || !u->IsInWorld())) + { + return false; + } + + // forbidden to seen (while Removing corpse) + if (m_Visibility == VISIBILITY_REMOVE_CORPSE) + { + return false; + } + + Map& _map = *u->GetMap(); + // Grid dead/alive checks + if (u->GetTypeId() == TYPEID_PLAYER) + { + // non visible at grid for any stealth state + if (!IsVisibleInGridForPlayer((Player*)u)) + { + return false; + } + + // if player is dead then he can't detect anyone in any cases + if (!u->IsAlive()) + detect = false; + } + else + { + // all dead creatures/players not visible for any creatures + if (!u->IsAlive() || !IsAlive()) + { + return false; + } + } + + // different visible distance checks + if (u->IsTaxiFlying()) // what see player in flight + { + // use object grey distance for all (only see objects any way) + if (!IsWithinDistInMap(viewPoint, World::GetMaxVisibleDistanceInFlight() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance)) + { + return false; + } + } + else if (!at_same_transport) // distance for show player/pet/creature (no transport case) + { + // Any units far than max visible distance for viewer or not in our map are not visible too + if (!IsWithinDistInMap(viewPoint, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) + { + return false; + } + } + + // always seen by owner + if (GetCharmerOrOwnerGuid() == u->GetObjectGuid()) + { + return true; + } + + // isInvisibleForAlive() those units can only be seen by dead or if other + // unit is also invisible for alive.. if an isinvisibleforalive unit dies we + // should be able to see it too + if (u->IsAlive() && IsAlive() && isInvisibleForAlive() != u->isInvisibleForAlive()) + if (u->GetTypeId() != TYPEID_PLAYER || !((Player*)u)->isGameMaster()) + { + return false; + } + + // Visible units, always are visible for all units, except for units under invisibility and phases + if (m_Visibility == VISIBILITY_ON && u->m_invisibilityMask == 0) + { + return true; + } + + // GMs see any players, not higher GMs and all units in any phase + if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->isGameMaster()) + { + if (GetTypeId() == TYPEID_PLAYER) + { + return ((Player*)this)->GetSession()->GetSecurity() <= ((Player*)u)->GetSession()->GetSecurity(); + } + else + { + return true; + } + } + + // non faction visibility non-breakable for non-GMs + if (m_Visibility == VISIBILITY_OFF) + { + return false; + } + + // grouped players should always see stealthed party members + if (GetTypeId() == TYPEID_PLAYER && u->GetTypeId() == TYPEID_PLAYER) + if (((Player*)this)->IsGroupVisibleFor(((Player*)u)) && u->IsFriendlyTo(this)) + { + return true; + } + + // raw invisibility + bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask != 0); + if (u->GetTypeId() == TYPEID_PLAYER) // if object is player with mover, use its visibility masks, so that an invisible player MCing a creature can see stuff + { + if (Player* player = (Player*)u) + { + if (Unit* mover = player->GetMover()) + { + invisible = (m_invisibilityMask != 0 || mover->m_invisibilityMask != 0); + } + } + } + + // detectable invisibility case + if (invisible && ( + // Invisible units, always are visible for units under same invisibility type + (m_invisibilityMask & u->m_invisibilityMask) != 0 || + // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect) + u->canDetectInvisibilityOf(this) || + // Units that can detect invisibility always are visible for units that can be detected + canDetectInvisibilityOf(u))) + { + invisible = false; + } + + // special cases for always overwrite invisibility/stealth + if (invisible || m_Visibility == VISIBILITY_GROUP_STEALTH) + { + if (u->IsHostileTo(this)) + { + // Hunter mark functionality + AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); + for (AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) + if ((*iter)->GetCasterGuid() == u->GetObjectGuid()) + { + return true; + } + } + + // none other cases for detect invisibility, so invisible + if (invisible) + { + return false; + } + } + + // unit got in stealth in this moment and must ignore old detected state + if (m_Visibility == VISIBILITY_GROUP_NO_DETECT) + { + return false; + } + + // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible + if (m_Visibility != VISIBILITY_GROUP_STEALTH) + { + return true; + } + + // NOW ONLY STEALTH CASE + + // if in non-detect mode then invisible for unit + // mobs always detect players (detect == true)... return 'false' for those mobs which have (detect == false) + // players detect players only in Player::HandleStealthedUnitsDetection() + if (!detect) + { + return (u->GetTypeId() == TYPEID_PLAYER) ? ((Player*)u)->HaveAtClient(this) : false; + } + + // Special cases + + // If is attacked then stealth is lost, some creature can use stealth too + if (!getAttackers().empty()) + { + return true; + } + + // If there is collision rogue is seen regardless of level difference + if (IsWithinDist(u, 0.24f)) + { + return true; + } + + // If a mob or player is stunned he will not be able to detect stealth + if (u->hasUnitState(UNIT_STAT_STUNNED) && (u != this)) + { + return false; + } + + // set max ditance + float visibleDistance = (u->GetTypeId() == TYPEID_PLAYER) ? MAX_PLAYER_STEALTH_DETECT_RANGE : ((Creature const*)u)->GetAttackDistance(this); + + // Always invisible from back (when stealth detection is on), also filter max distance cases + bool isInFront = viewPoint->IsInFrontInMap(this, visibleDistance); + if (!isInFront) + { + return false; + } + + // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los + if (!u->HasAuraType(SPELL_AURA_DETECT_STEALTH)) + { + // Calculation if target is in front + + // Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) + visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH) / 100.0f); + + // Visible distance is modified by + //-Level Diff (every level diff = 1.0f in visible distance) + visibleDistance += int32(u->GetLevelForTarget(this)) - int32(GetLevelForTarget(u)); + + // This allows to check talent tree and will add addition stealth dependent on used points) + int32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL); + if (stealthMod < 0) + stealthMod = 0; + + //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) + // based on wowwiki every 5 mod we have 1 more level diff in calculation + visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_DETECT)) - stealthMod) / 5.0f; + visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance; + + // recheck new distance + if (visibleDistance <= 0 || !IsWithinDist(viewPoint, visibleDistance)) + { + return false; + } + } + + // Now check is target visible with LoS + float ox, oy, oz; + viewPoint->GetPosition(ox, oy, oz); + return IsWithinLOS(ox, oy, oz); } void Unit::UpdateVisibilityAndView() { - static const AuraType auratypes[] = {SPELL_AURA_BIND_SIGHT, SPELL_AURA_FAR_SIGHT, SPELL_AURA_NONE}; - for (AuraType const* type = &auratypes[0]; *type != SPELL_AURA_NONE; ++type) - { - AuraList& alist = m_modAuras[*type]; - if (alist.empty()) - continue; + static const AuraType auratypes[] = { SPELL_AURA_BIND_SIGHT, SPELL_AURA_FAR_SIGHT, SPELL_AURA_NONE }; + for (AuraType const* type = &auratypes[0]; *type != SPELL_AURA_NONE; ++type) + { + AuraList& alist = m_modAuras[*type]; + if (alist.empty()) + continue; - for (AuraList::iterator it = alist.begin(); it != alist.end();) - { - Aura* aura = (*it); - Unit* owner = aura->GetCaster(); + for (AuraList::iterator it = alist.begin(); it != alist.end();) + { + Aura* aura = (*it); + Unit* owner = aura->GetCaster(); - if (!owner || !IsVisibleForOrDetect(owner, this, false)) - { - alist.erase(it); - RemoveAura(aura); - it = alist.begin(); - } - else - ++it; - } - } + if (!owner || !IsVisibleForOrDetect(owner, this, false)) + { + alist.erase(it); + RemoveAura(aura); + it = alist.begin(); + } + else + ++it; + } + } - GetViewPoint().Call_UpdateVisibilityForOwner(); - UpdateObjectVisibility(); - ScheduleAINotify(0); - GetViewPoint().Event_ViewPointVisibilityChanged(); + GetViewPoint().Call_UpdateVisibilityForOwner(); + UpdateObjectVisibility(); + ScheduleAINotify(0); + GetViewPoint().Event_ViewPointVisibilityChanged(); } void Unit::SetVisibility(UnitVisibility x) { - m_Visibility = x; + m_Visibility = x; - if (IsInWorld()) - UpdateVisibilityAndView(); + if (IsInWorld()) + UpdateVisibilityAndView(); } bool Unit::canDetectInvisibilityOf(Unit const* u) const { - if (uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask)) - { - for (int32 i = 0; i < 32; ++i) - { - if (((1 << i) & mask) == 0) - continue; + if (uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask)) + { + for (int32 i = 0; i < 32; ++i) + { + if (((1 << i) & mask) == 0) + continue; - // find invisibility level - int32 invLevel = 0; - Unit::AuraList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY); - for (Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr) - if ((*itr)->GetModifier()->m_miscvalue == i && invLevel < (*itr)->GetModifier()->m_amount) - invLevel = (*itr)->GetModifier()->m_amount; + // find invisibility level + int32 invLevel = 0; + Unit::AuraList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY); + for (Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr) + if ((*itr)->GetModifier()->m_miscvalue == i && invLevel < (*itr)->GetModifier()->m_amount) + invLevel = (*itr)->GetModifier()->m_amount; - // find invisibility detect level - int32 detectLevel = 0; - Unit::AuraList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION); - for (Unit::AuraList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr) - if ((*itr)->GetModifier()->m_miscvalue == i && detectLevel < (*itr)->GetModifier()->m_amount) - detectLevel = (*itr)->GetModifier()->m_amount; + // find invisibility detect level + int32 detectLevel = 0; + Unit::AuraList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION); + for (Unit::AuraList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr) + if ((*itr)->GetModifier()->m_miscvalue == i && detectLevel < (*itr)->GetModifier()->m_amount) + detectLevel = (*itr)->GetModifier()->m_amount; - if (i == 6 && GetTypeId() == TYPEID_PLAYER) // special drunk detection case - detectLevel = ((Player*)this)->GetDrunkValue(); + if (i == 6 && GetTypeId() == TYPEID_PLAYER) // special drunk detection case + detectLevel = ((Player*)this)->GetDrunkValue(); - if (invLevel <= detectLevel) - { - return true; - } - } - } + if (invLevel <= detectLevel) + { + return true; + } + } + } - return false; + return false; } void Unit::UpdateSpeed(UnitMoveType mtype, bool forced, float ratio, bool ignoreChange) { - // not in combat pet have same speed as owner - switch (mtype) - { - case MOVE_RUN: - case MOVE_WALK: - case MOVE_SWIM: - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet() && hasUnitState(UNIT_STAT_FOLLOW)) - { - if (Unit* owner = GetOwner()) - { - SetSpeedRate(mtype, owner->GetSpeedRate(mtype), forced, ignoreChange); - return; - } - } - break; - default: - break; - } - - int32 main_speed_mod = 0; - float stack_bonus = 1.0f; - float non_stack_bonus = 1.0f; - - switch (mtype) - { - case MOVE_WALK: - break; - case MOVE_RUN: - { - if (IsMounted()) // Use on mount auras - { - main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED); - stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS); - non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK)) / 100.0f; - } - else - { - main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED); - stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS); - non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK)) / 100.0f; - } - break; - } - case MOVE_RUN_BACK: - return; - case MOVE_SWIM: - { - main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED); - break; - } - case MOVE_SWIM_BACK: - return; - case MOVE_FLIGHT: - { - if (IsMounted()) // Use on mount auras - { - main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED); - stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED_STACKING); - non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED_NOT_STACKING)) / 100.0f; - } - else // Use not mount (shapeshift for example) auras (should stack) - { - main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED); - stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_STACKING); - non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACKING)) / 100.0f; - } - break; - } - case MOVE_FLIGHT_BACK: - return; - default: - sLog.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype); - return; - } - - float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus; - // now we ready for speed calculation - float speed = main_speed_mod ? bonus * (100.0f + main_speed_mod) / 100.0f : bonus; - - switch (mtype) - { - case MOVE_RUN: - case MOVE_SWIM: - case MOVE_FLIGHT: - { - // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need - // TODO: possible affect only on MOVE_RUN - if (int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED)) - { - // Use speed from aura - float max_speed = normalization / baseMoveSpeed[mtype]; - if (speed > max_speed) - speed = max_speed; - } - break; - } - default: - break; - } - - // for creature case, we check explicit if mob searched for assistance - if (GetTypeId() == TYPEID_UNIT) - { - if (((Creature*)this)->HasSearchedAssistance()) - speed *= 0.66f; // best guessed value, so this will be 33% reduction. Based off initial speed, mob can then "run", "walk fast" or "walk". - } - // for player case, we look for some custom rates - else - { - if (getDeathState() == CORPSE) - speed *= sWorld.getConfig(((Player*)this)->InBattleGround() ? CONFIG_FLOAT_GHOST_RUN_SPEED_BG : CONFIG_FLOAT_GHOST_RUN_SPEED_WORLD); - } - - // Apply strongest slow aura mod to speed - int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); - if (slow) - { - speed *= (100.0f + slow) / 100.0f; - float min_speed = (float)GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MINIMUM_SPEED) / 100.0f; - if (speed < min_speed) - speed = min_speed; - } - - if (GetTypeId() == TYPEID_UNIT) - { - switch (mtype) - { - case MOVE_RUN: - speed *= ((Creature*)this)->GetCreatureInfo()->SpeedRun; - break; - case MOVE_WALK: - speed *= ((Creature*)this)->GetCreatureInfo()->SpeedWalk; - break; - default: - break; - } - } - - SetSpeedRate(mtype, speed * ratio, forced, ignoreChange); + // not in combat pet have same speed as owner + switch (mtype) + { + case MOVE_RUN: + case MOVE_WALK: + case MOVE_SWIM: + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet() && hasUnitState(UNIT_STAT_FOLLOW)) + { + if (Unit* owner = GetOwner()) + { + SetSpeedRate(mtype, owner->GetSpeedRate(mtype), forced, ignoreChange); + return; + } + } + break; + default: + break; + } + + int32 main_speed_mod = 0; + float stack_bonus = 1.0f; + float non_stack_bonus = 1.0f; + + switch (mtype) + { + case MOVE_WALK: + break; + case MOVE_RUN: + { + if (IsMounted()) // Use on mount auras + { + main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED); + stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS); + non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK)) / 100.0f; + } + else + { + main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED); + stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS); + non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK)) / 100.0f; + } + break; + } + case MOVE_RUN_BACK: + return; + case MOVE_SWIM: + { + main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED); + break; + } + case MOVE_SWIM_BACK: + return; + case MOVE_FLIGHT: + { + if (IsMounted()) // Use on mount auras + { + main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED); + stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED_STACKING); + non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED_NOT_STACKING)) / 100.0f; + } + else // Use not mount (shapeshift for example) auras (should stack) + { + main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED); + stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_STACKING); + non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACKING)) / 100.0f; + } + break; + } + case MOVE_FLIGHT_BACK: + return; + default: + sLog.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype); + return; + } + + float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus; + // now we ready for speed calculation + float speed = main_speed_mod ? bonus * (100.0f + main_speed_mod) / 100.0f : bonus; + + switch (mtype) + { + case MOVE_RUN: + case MOVE_SWIM: + case MOVE_FLIGHT: + { + // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need + // TODO: possible affect only on MOVE_RUN + if (int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED)) + { + // Use speed from aura + float max_speed = normalization / baseMoveSpeed[mtype]; + if (speed > max_speed) + speed = max_speed; + } + break; + } + default: + break; + } + + // for creature case, we check explicit if mob searched for assistance + if (GetTypeId() == TYPEID_UNIT) + { + if (((Creature*)this)->HasSearchedAssistance()) + speed *= 0.66f; // best guessed value, so this will be 33% reduction. Based off initial speed, mob can then "run", "walk fast" or "walk". + } + // for player case, we look for some custom rates + else + { + if (getDeathState() == CORPSE) + speed *= sWorld.getConfig(((Player*)this)->InBattleGround() ? CONFIG_FLOAT_GHOST_RUN_SPEED_BG : CONFIG_FLOAT_GHOST_RUN_SPEED_WORLD); + } + + // Apply strongest slow aura mod to speed + int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); + if (slow) + { + speed *= (100.0f + slow) / 100.0f; + float min_speed = (float)GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MINIMUM_SPEED) / 100.0f; + if (speed < min_speed) + speed = min_speed; + } + + if (GetTypeId() == TYPEID_UNIT) + { + switch (mtype) + { + case MOVE_RUN: + speed *= ((Creature*)this)->GetCreatureInfo()->SpeedRun; + break; + case MOVE_WALK: + speed *= ((Creature*)this)->GetCreatureInfo()->SpeedWalk; + break; + default: + break; + } + } + + SetSpeedRate(mtype, speed * ratio, forced, ignoreChange); } float Unit::GetSpeed(UnitMoveType mtype) const { - return m_speed_rate[mtype] * baseMoveSpeed[mtype]; + return m_speed_rate[mtype] * baseMoveSpeed[mtype]; } struct SetSpeedRateHelper { - explicit SetSpeedRateHelper(UnitMoveType _mtype, bool _forced, bool _ignoreChange) : mtype(_mtype), forced(_forced), ignoreChange(_ignoreChange) {} - void operator()(Unit* unit) const { unit->UpdateSpeed(mtype, forced, 1.0f, ignoreChange); } - UnitMoveType mtype; - bool forced, ignoreChange; + explicit SetSpeedRateHelper(UnitMoveType _mtype, bool _forced, bool _ignoreChange) : mtype(_mtype), forced(_forced), ignoreChange(_ignoreChange) {} + void operator()(Unit* unit) const { unit->UpdateSpeed(mtype, forced, 1.0f, ignoreChange); } + UnitMoveType mtype; + bool forced, ignoreChange; }; void Unit::SetSpeedRate(UnitMoveType mtype, float rate, bool forced, bool ignoreChange) { - if (rate < 0) - rate = 0.0f; - - // Update speed only on change - if (m_speed_rate[mtype] != rate || ignoreChange) - { - m_speed_rate[mtype] = rate; - - propagateSpeedChange(); - - WorldPacket data; - ObjectGuid guid = GetObjectGuid(); - - if (forced && GetTypeId() == TYPEID_PLAYER) - { - // register forced speed changes for WorldSession::HandleForceSpeedChangeAck - // and do it only for real sent packets and use run for run/mounted as client expected - ++((Player*)this)->m_forced_speed_changes[mtype]; - switch (mtype) - { - case MOVE_WALK: - { - data.Initialize(SMSG_MOVE_SET_WALK_SPEED, 1 + 8 + 4 + 4); - data.WriteGuidMask<0, 4, 5, 2, 3, 1, 6, 7>(guid); - data.WriteGuidBytes<6, 1, 5>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<2>(guid); - data << uint32(0); - data.WriteGuidBytes<4, 0, 7, 3>(guid); - break; - } - case MOVE_RUN: - { - data.Initialize(SMSG_MOVE_SET_RUN_SPEED, 1 + 8 + 4 + 4 ); - data.WriteGuidMask<6, 1, 5, 2, 7, 0, 3, 4>(guid); - data.WriteGuidBytes<5, 3, 1, 4>(guid); - data << uint32(0); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<6, 0, 7, 2>(guid); - break; - } - case MOVE_RUN_BACK: - { - data.Initialize(SMSG_MOVE_SET_RUN_BACK_SPEED, 1 + 8 + 4 + 4 ); - data.WriteGuidMask<0, 6, 2, 1, 3, 5, 4, 7>(guid); - data.WriteGuidBytes<5>(guid); - data << uint32(0); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<0, 4, 7, 3, 1, 2, 6>(guid); - break; - } - case MOVE_SWIM: - { - data.Initialize(SMSG_MOVE_SET_SWIM_SPEED, 1 + 8 + 4 + 4 ); - data.WriteGuidMask<5, 4, 7, 3, 2, 0, 1, 6>(guid); - data.WriteGuidBytes<0>(guid); - data << uint32(0); - data.WriteGuidBytes<6, 3, 5, 2>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<1, 7, 4>(guid); - break; - } - case MOVE_SWIM_BACK: - { - data.Initialize(SMSG_MOVE_SET_SWIM_BACK_SPEED, 1 + 8 + 4 + 4 ); - data.WriteGuidMask<4, 2, 3, 6, 5, 1, 0, 7>(guid); - data << uint32(0); - data.WriteGuidBytes<0, 3, 4, 6, 5, 1>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<0, 7>(guid); - break; - } - case MOVE_TURN_RATE: - { - data.Initialize(SMSG_MOVE_SET_TURN_RATE, 1 + 8 + 4 + 4 ); - data.WriteGuidMask<7, 2, 1, 0, 4, 5, 6, 3>(guid); - data.WriteGuidBytes<5, 7, 2>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<3, 1, 0>(guid); - data << uint32(0); - data.WriteGuidBytes<6, 4>(guid); - break; - } - case MOVE_FLIGHT: - { - data.Initialize(SMSG_MOVE_SET_FLIGHT_SPEED, 1 + 8 + 4 + 4 ); - data.WriteGuidMask<0, 5, 1, 6, 3, 2, 7, 4>(guid); - data.WriteGuidBytes<0, 1, 7, 5>(guid); - data << float(GetSpeed(mtype)); - data << uint32(0); - data.WriteGuidBytes<2, 6, 3, 4>(guid); - break; - } - case MOVE_FLIGHT_BACK: - { - data.Initialize(SMSG_MOVE_SET_FLIGHT_BACK_SPEED, 1 + 8 + 4 + 4 ); - data.WriteGuidMask<1, 2, 6, 4, 7, 3, 0, 5>(guid); - - data.WriteGuidBytes<3>(guid); - data << uint32(0); - data.WriteGuidBytes<6>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<1, 2, 4, 0, 5, 7>(guid); - break; - } - case MOVE_PITCH_RATE: - { - data.Initialize(SMSG_MOVE_SET_PITCH_RATE, 1 + 8 + 4 + 4 ); - data.WriteGuidMask<1, 2, 6, 7, 0, 3, 5, 4>(guid); - - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<6, 4, 0>(guid); - data << uint32(0); - data.WriteGuidBytes<1, 2, 7, 3, 5>(guid); - break; - } - default: - sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.", mtype); - return; - } - - ((Player*)this)->GetSession()->SendPacket(&data); - } - - m_movementInfo.UpdateTime(WorldTimer::getMSTime()); - - // TODO: Actually such opcodes should (always?) be packed with SMSG_COMPRESSED_MOVES - switch (mtype) - { - case MOVE_WALK: - { - data.Initialize(SMSG_SPLINE_MOVE_SET_WALK_SPEED, 1 + 8 + 4); - data.WriteGuidMask<0, 6, 7, 3, 5, 1, 2, 4>(guid); - data.WriteGuidBytes<0, 4, 7, 1, 5, 3>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<6, 2>(guid); - break; - } - case MOVE_RUN: - { - data.Initialize(SMSG_SPLINE_MOVE_SET_RUN_SPEED, 1 + 8 + 4); - data.WriteGuidMask<4, 0, 5, 7, 6, 3, 1, 2>(guid); - data.WriteGuidBytes<0, 7, 6, 5, 3, 4>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<2, 1>(guid); - break; - } - case MOVE_RUN_BACK: - { - data.Initialize(SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED, 1 + 8 + 4); - data.WriteGuidMask<1, 2, 6, 0, 3, 7, 5, 4>(guid); - data.WriteGuidBytes<1>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<2, 4, 0, 3, 6, 5, 7>(guid); - break; - } - case MOVE_SWIM: - { - data.Initialize(SMSG_SPLINE_MOVE_SET_SWIM_SPEED, 1 + 8 + 4); - data.WriteGuidMask<4, 2, 5, 0, 7, 6, 3, 1>(guid); - data.WriteGuidBytes<5, 6, 1, 0, 2, 4>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<7, 3>(guid); - break; - } - case MOVE_SWIM_BACK: - { - data.Initialize(SMSG_SPLINE_MOVE_SET_SWIM_BACK_SPEED, 1 + 8 + 4); - data.WriteGuidMask<0, 1, 3, 6, 4, 5, 7, 2>(guid); - data.WriteGuidBytes<5, 3, 1, 0, 7, 6>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<4, 2>(guid); - break; - } - case MOVE_TURN_RATE: - { - data.Initialize(SMSG_SPLINE_MOVE_SET_TURN_RATE, 1 + 8 + 4); - data.WriteGuidMask<2, 4, 6, 1, 3, 5, 7, 0>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<1, 5, 3, 2, 7, 4, 6, 0>(guid); - break; - } - case MOVE_FLIGHT: - { - data.Initialize(SMSG_SPLINE_MOVE_SET_FLIGHT_SPEED, 1 + 8 + 4); - data.WriteGuidMask<7, 4, 0, 1, 3, 6, 5, 2>(guid); - data.WriteGuidBytes<0, 5, 4, 7, 3, 2, 1, 6>(guid); - data << float(GetSpeed(mtype)); - break; - } - case MOVE_FLIGHT_BACK: - { - data.Initialize(SMSG_SPLINE_MOVE_SET_FLIGHT_BACK_SPEED, 1 + 8 + 4); - data.WriteGuidMask<2, 1, 6, 5, 0, 3, 4, 7>(guid); - data.WriteGuidBytes<5>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<6, 1, 0, 2, 3, 7, 4>(guid); - break; - } - case MOVE_PITCH_RATE: - { - data.Initialize(SMSG_SPLINE_MOVE_SET_PITCH_RATE, 1 + 8 + 4); - data.WriteGuidMask<3, 5, 6, 1, 0, 4, 7, 2>(guid); - data.WriteGuidBytes<1, 5, 7, 0, 6, 3, 2>(guid); - data << float(GetSpeed(mtype)); - data.WriteGuidBytes<4>(guid); - break; - } - default: - sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.", mtype); - return; - } - - SendMessageToSet(&data, false); - } - - CallForAllControlledUnits(SetSpeedRateHelper(mtype, forced, ignoreChange), CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_CHARM | CONTROLLED_MINIPET); + if (rate < 0) + rate = 0.0f; + + // Update speed only on change + if (m_speed_rate[mtype] != rate || ignoreChange) + { + m_speed_rate[mtype] = rate; + + propagateSpeedChange(); + + WorldPacket data; + ObjectGuid guid = GetObjectGuid(); + + if (forced && GetTypeId() == TYPEID_PLAYER) + { + // register forced speed changes for WorldSession::HandleForceSpeedChangeAck + // and do it only for real sent packets and use run for run/mounted as client expected + ++((Player*)this)->m_forced_speed_changes[mtype]; + switch (mtype) + { + case MOVE_WALK: + { + data.Initialize(SMSG_MOVE_SET_WALK_SPEED, 1 + 8 + 4 + 4); + data.WriteGuidMask<0, 4, 5, 2, 3, 1, 6, 7>(guid); + data.WriteGuidBytes<6, 1, 5>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<2>(guid); + data << uint32(0); + data.WriteGuidBytes<4, 0, 7, 3>(guid); + break; + } + case MOVE_RUN: + { + data.Initialize(SMSG_MOVE_SET_RUN_SPEED, 1 + 8 + 4 + 4); + data.WriteGuidMask<6, 1, 5, 2, 7, 0, 3, 4>(guid); + data.WriteGuidBytes<5, 3, 1, 4>(guid); + data << uint32(0); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<6, 0, 7, 2>(guid); + break; + } + case MOVE_RUN_BACK: + { + data.Initialize(SMSG_MOVE_SET_RUN_BACK_SPEED, 1 + 8 + 4 + 4); + data.WriteGuidMask<0, 6, 2, 1, 3, 5, 4, 7>(guid); + data.WriteGuidBytes<5>(guid); + data << uint32(0); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<0, 4, 7, 3, 1, 2, 6>(guid); + break; + } + case MOVE_SWIM: + { + data.Initialize(SMSG_MOVE_SET_SWIM_SPEED, 1 + 8 + 4 + 4); + data.WriteGuidMask<5, 4, 7, 3, 2, 0, 1, 6>(guid); + data.WriteGuidBytes<0>(guid); + data << uint32(0); + data.WriteGuidBytes<6, 3, 5, 2>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<1, 7, 4>(guid); + break; + } + case MOVE_SWIM_BACK: + { + data.Initialize(SMSG_MOVE_SET_SWIM_BACK_SPEED, 1 + 8 + 4 + 4); + data.WriteGuidMask<4, 2, 3, 6, 5, 1, 0, 7>(guid); + data << uint32(0); + data.WriteGuidBytes<0, 3, 4, 6, 5, 1>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<0, 7>(guid); + break; + } + case MOVE_TURN_RATE: + { + data.Initialize(SMSG_MOVE_SET_TURN_RATE, 1 + 8 + 4 + 4); + data.WriteGuidMask<7, 2, 1, 0, 4, 5, 6, 3>(guid); + data.WriteGuidBytes<5, 7, 2>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<3, 1, 0>(guid); + data << uint32(0); + data.WriteGuidBytes<6, 4>(guid); + break; + } + case MOVE_FLIGHT: + { + data.Initialize(SMSG_MOVE_SET_FLIGHT_SPEED, 1 + 8 + 4 + 4); + data.WriteGuidMask<0, 5, 1, 6, 3, 2, 7, 4>(guid); + data.WriteGuidBytes<0, 1, 7, 5>(guid); + data << float(GetSpeed(mtype)); + data << uint32(0); + data.WriteGuidBytes<2, 6, 3, 4>(guid); + break; + } + case MOVE_FLIGHT_BACK: + { + data.Initialize(SMSG_MOVE_SET_FLIGHT_BACK_SPEED, 1 + 8 + 4 + 4); + data.WriteGuidMask<1, 2, 6, 4, 7, 3, 0, 5>(guid); + + data.WriteGuidBytes<3>(guid); + data << uint32(0); + data.WriteGuidBytes<6>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<1, 2, 4, 0, 5, 7>(guid); + break; + } + case MOVE_PITCH_RATE: + { + data.Initialize(SMSG_MOVE_SET_PITCH_RATE, 1 + 8 + 4 + 4); + data.WriteGuidMask<1, 2, 6, 7, 0, 3, 5, 4>(guid); + + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<6, 4, 0>(guid); + data << uint32(0); + data.WriteGuidBytes<1, 2, 7, 3, 5>(guid); + break; + } + default: + sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.", mtype); + return; + } + + ((Player*)this)->GetSession()->SendPacket(&data); + } + + m_movementInfo.UpdateTime(WorldTimer::getMSTime()); + + // TODO: Actually such opcodes should (always?) be packed with SMSG_COMPRESSED_MOVES + switch (mtype) + { + case MOVE_WALK: + { + data.Initialize(SMSG_SPLINE_MOVE_SET_WALK_SPEED, 1 + 8 + 4); + data.WriteGuidMask<0, 6, 7, 3, 5, 1, 2, 4>(guid); + data.WriteGuidBytes<0, 4, 7, 1, 5, 3>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<6, 2>(guid); + break; + } + case MOVE_RUN: + { + data.Initialize(SMSG_SPLINE_MOVE_SET_RUN_SPEED, 1 + 8 + 4); + data.WriteGuidMask<4, 0, 5, 7, 6, 3, 1, 2>(guid); + data.WriteGuidBytes<0, 7, 6, 5, 3, 4>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<2, 1>(guid); + break; + } + case MOVE_RUN_BACK: + { + data.Initialize(SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED, 1 + 8 + 4); + data.WriteGuidMask<1, 2, 6, 0, 3, 7, 5, 4>(guid); + data.WriteGuidBytes<1>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<2, 4, 0, 3, 6, 5, 7>(guid); + break; + } + case MOVE_SWIM: + { + data.Initialize(SMSG_SPLINE_MOVE_SET_SWIM_SPEED, 1 + 8 + 4); + data.WriteGuidMask<4, 2, 5, 0, 7, 6, 3, 1>(guid); + data.WriteGuidBytes<5, 6, 1, 0, 2, 4>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<7, 3>(guid); + break; + } + case MOVE_SWIM_BACK: + { + data.Initialize(SMSG_SPLINE_MOVE_SET_SWIM_BACK_SPEED, 1 + 8 + 4); + data.WriteGuidMask<0, 1, 3, 6, 4, 5, 7, 2>(guid); + data.WriteGuidBytes<5, 3, 1, 0, 7, 6>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<4, 2>(guid); + break; + } + case MOVE_TURN_RATE: + { + data.Initialize(SMSG_SPLINE_MOVE_SET_TURN_RATE, 1 + 8 + 4); + data.WriteGuidMask<2, 4, 6, 1, 3, 5, 7, 0>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<1, 5, 3, 2, 7, 4, 6, 0>(guid); + break; + } + case MOVE_FLIGHT: + { + data.Initialize(SMSG_SPLINE_MOVE_SET_FLIGHT_SPEED, 1 + 8 + 4); + data.WriteGuidMask<7, 4, 0, 1, 3, 6, 5, 2>(guid); + data.WriteGuidBytes<0, 5, 4, 7, 3, 2, 1, 6>(guid); + data << float(GetSpeed(mtype)); + break; + } + case MOVE_FLIGHT_BACK: + { + data.Initialize(SMSG_SPLINE_MOVE_SET_FLIGHT_BACK_SPEED, 1 + 8 + 4); + data.WriteGuidMask<2, 1, 6, 5, 0, 3, 4, 7>(guid); + data.WriteGuidBytes<5>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<6, 1, 0, 2, 3, 7, 4>(guid); + break; + } + case MOVE_PITCH_RATE: + { + data.Initialize(SMSG_SPLINE_MOVE_SET_PITCH_RATE, 1 + 8 + 4); + data.WriteGuidMask<3, 5, 6, 1, 0, 4, 7, 2>(guid); + data.WriteGuidBytes<1, 5, 7, 0, 6, 3, 2>(guid); + data << float(GetSpeed(mtype)); + data.WriteGuidBytes<4>(guid); + break; + } + default: + sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.", mtype); + return; + } + + SendMessageToSet(&data, false); + } + + CallForAllControlledUnits(SetSpeedRateHelper(mtype, forced, ignoreChange), CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_CHARM | CONTROLLED_MINIPET); } void Unit::SetDeathState(DeathState s) { - if (s != ALIVE && s != JUST_ALIVED) - { - CombatStop(); - DeleteThreatList(); - ClearComboPointHolders(); // any combo points pointed to unit lost at it death - - if (IsNonMeleeSpellCasted(false)) - InterruptNonMeleeSpells(false); - } - - if (s == JUST_DIED) - { - RemoveAllAurasOnDeath(); - RemoveGuardians(); - RemoveMiniPet(); - UnsummonAllTotems(); - - StopMoving(); - i_motionMaster.Clear(false, true); - i_motionMaster.MoveIdle(); - - // Unsummon vehicle accessories - if (IsVehicle()) - m_vehicleInfo->RemoveAccessoriesFromMap(); - - // Unboard from transport - if (GetTransportInfo() && ((Unit*)GetTransportInfo()->GetTransport())->IsVehicle()) - ((Unit*)GetTransportInfo()->GetTransport())->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, GetObjectGuid()); - - ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); - ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); - // remove aurastates allowing special moves - ClearAllReactives(); - ClearDiminishings(); - } - else if (s == JUST_ALIVED) - { - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground) - } - - if (m_deathState != ALIVE && s == ALIVE) - { - //_ApplyAllAuraMods(); - } - m_deathState = s; + if (s != ALIVE && s != JUST_ALIVED) + { + CombatStop(); + DeleteThreatList(); + ClearComboPointHolders(); // any combo points pointed to unit lost at it death + + if (IsNonMeleeSpellCasted(false)) + InterruptNonMeleeSpells(false); + } + + if (s == JUST_DIED) + { + RemoveAllAurasOnDeath(); + RemoveGuardians(); + RemoveMiniPet(); + UnsummonAllTotems(); + + StopMoving(); + i_motionMaster.Clear(false, true); + i_motionMaster.MoveIdle(); + + // Unsummon vehicle accessories + if (IsVehicle()) + m_vehicleInfo->RemoveAccessoriesFromMap(); + + // Unboard from transport + if (GetTransportInfo() && ((Unit*)GetTransportInfo()->GetTransport())->IsVehicle()) + ((Unit*)GetTransportInfo()->GetTransport())->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, GetObjectGuid()); + + ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + // remove aurastates allowing special moves + ClearAllReactives(); + ClearDiminishings(); + } + else if (s == JUST_ALIVED) + { + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground) + } + + if (m_deathState != ALIVE && s == ALIVE) + { + //_ApplyAllAuraMods(); + } + m_deathState = s; } /*######################################## @@ -10099,322 +10103,322 @@ void Unit::SetDeathState(DeathState s) bool Unit::CanHaveThreatList(bool ignoreAliveState/*=false*/) const { - // only creatures can have threat list - if (GetTypeId() != TYPEID_UNIT) - { - return false; - } + // only creatures can have threat list + if (GetTypeId() != TYPEID_UNIT) + { + return false; + } - // only alive units can have threat list - if (!IsAlive() && !ignoreAliveState) - { - return false; - } + // only alive units can have threat list + if (!IsAlive() && !ignoreAliveState) + { + return false; + } - Creature const* creature = ((Creature const*)this); + Creature const* creature = ((Creature const*)this); - // totems can not have threat list - if (creature->IsTotem()) - { - return false; - } + // totems can not have threat list + if (creature->IsTotem()) + { + return false; + } - // pets can not have a threat list, unless they are controlled by a creature - if (creature->IsPet() && creature->GetOwnerGuid().IsPlayer()) - { - return false; - } + // pets can not have a threat list, unless they are controlled by a creature + if (creature->IsPet() && creature->GetOwnerGuid().IsPlayer()) + { + return false; + } - // charmed units can not have a threat list if charmed by player - if (creature->GetCharmerGuid().IsPlayer()) - { - return false; - } + // charmed units can not have a threat list if charmed by player + if (creature->GetCharmerGuid().IsPlayer()) + { + return false; + } - return true; + return true; } //====================================================================== float Unit::ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask) { - if (!HasAuraType(SPELL_AURA_MOD_THREAT)) - { - return threat; - } + if (!HasAuraType(SPELL_AURA_MOD_THREAT)) + { + return threat; + } - if (schoolMask == SPELL_SCHOOL_MASK_NONE) - { - return threat; - } + if (schoolMask == SPELL_SCHOOL_MASK_NONE) + { + return threat; + } - SpellSchools school = GetFirstSchoolInMask(schoolMask); + SpellSchools school = GetFirstSchoolInMask(schoolMask); - return threat * m_threatModifier[school]; + return threat * m_threatModifier[school]; } //====================================================================== void Unit::AddThreat(Unit* pVictim, float threat /*= 0.0f*/, bool crit /*= false*/, SpellSchoolMask schoolMask /*= SPELL_SCHOOL_MASK_NONE*/, SpellEntry const* threatSpell /*= NULL*/) { - // Only mobs can manage threat lists - if (CanHaveThreatList()) - m_ThreatManager.addThreat(pVictim, threat, crit, schoolMask, threatSpell); + // Only mobs can manage threat lists + if (CanHaveThreatList()) + m_ThreatManager.addThreat(pVictim, threat, crit, schoolMask, threatSpell); } //====================================================================== void Unit::DeleteThreatList() { - if (CanHaveThreatList(true) && !m_ThreatManager.isThreatListEmpty()) - SendThreatClear(); + if (CanHaveThreatList(true) && !m_ThreatManager.isThreatListEmpty()) + SendThreatClear(); - m_ThreatManager.clearReferences(); + m_ThreatManager.clearReferences(); } //====================================================================== void Unit::TauntApply(Unit* taunter) { - MANGOS_ASSERT(GetTypeId() == TYPEID_UNIT); + MANGOS_ASSERT(GetTypeId() == TYPEID_UNIT); - if (!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster())) - { - return; - } + if (!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster())) + { + return; + } - if (!CanHaveThreatList()) - { - return; - } + if (!CanHaveThreatList()) + { + return; + } - Unit* target = getVictim(); + Unit* target = getVictim(); - if (target && target == taunter) - { - return; - } + if (target && target == taunter) + { + return; + } - // Only attack taunter if this is a valid target - if (!hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED) && !IsSecondChoiceTarget(taunter, true)) - { - if (GetTargetGuid() || !target) - SetInFront(taunter); + // Only attack taunter if this is a valid target + if (!hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED) && !IsSecondChoiceTarget(taunter, true)) + { + if (GetTargetGuid() || !target) + SetInFront(taunter); - if (((Creature*)this)->AI()) - ((Creature*)this)->AI()->AttackStart(taunter); - } + if (((Creature*)this)->AI()) + ((Creature*)this)->AI()->AttackStart(taunter); + } - m_ThreatManager.tauntApply(taunter); + m_ThreatManager.tauntApply(taunter); } //====================================================================== void Unit::TauntFadeOut(Unit* taunter) { - MANGOS_ASSERT(GetTypeId() == TYPEID_UNIT); + MANGOS_ASSERT(GetTypeId() == TYPEID_UNIT); - if (!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster())) - { - return; - } + if (!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster())) + { + return; + } - if (!CanHaveThreatList()) - { - return; - } + if (!CanHaveThreatList()) + { + return; + } - Unit* target = getVictim(); + Unit* target = getVictim(); - if (!target || target != taunter) - { - return; - } + if (!target || target != taunter) + { + return; + } - if (m_ThreatManager.isThreatListEmpty()) - { - m_fixateTargetGuid.Clear(); + if (m_ThreatManager.isThreatListEmpty()) + { + m_fixateTargetGuid.Clear(); - if (((Creature*)this)->AI()) - ((Creature*)this)->AI()->EnterEvadeMode(); + if (((Creature*)this)->AI()) + ((Creature*)this)->AI()->EnterEvadeMode(); - if (InstanceData* mapInstance = GetInstanceData()) - mapInstance->OnCreatureEvade((Creature*)this); + if (InstanceData* mapInstance = GetInstanceData()) + mapInstance->OnCreatureEvade((Creature*)this); - if (m_isCreatureLinkingTrigger) - GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_EVADE, (Creature*)this); + if (m_isCreatureLinkingTrigger) + GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_EVADE, (Creature*)this); - return; - } + return; + } - m_ThreatManager.tauntFadeOut(taunter); - target = m_ThreatManager.getHostileTarget(); + m_ThreatManager.tauntFadeOut(taunter); + target = m_ThreatManager.getHostileTarget(); - if (target && target != taunter) - { - if (GetTargetGuid()) - SetInFront(target); + if (target && target != taunter) + { + if (GetTargetGuid()) + SetInFront(target); - if (((Creature*)this)->AI()) - ((Creature*)this)->AI()->AttackStart(target); - } + if (((Creature*)this)->AI()) + ((Creature*)this)->AI()->AttackStart(target); + } } //====================================================================== /// if pVictim is given, the npc will fixate onto pVictim, if NULL it will remove current fixation void Unit::FixateTarget(Unit* pVictim) { - if (!pVictim) // Remove Fixation - m_fixateTargetGuid.Clear(); - else if (pVictim->IsTargetableForAttack()) // Apply Fixation - m_fixateTargetGuid = pVictim->GetObjectGuid(); + if (!pVictim) // Remove Fixation + m_fixateTargetGuid.Clear(); + else if (pVictim->IsTargetableForAttack()) // Apply Fixation + m_fixateTargetGuid = pVictim->GetObjectGuid(); - // Start attacking the fixated target or the next proper one - SelectHostileTarget(); + // Start attacking the fixated target or the next proper one + SelectHostileTarget(); } //====================================================================== bool Unit::IsSecondChoiceTarget(Unit* pTarget, bool checkThreatArea) const { - MANGOS_ASSERT(pTarget && GetTypeId() == TYPEID_UNIT); + MANGOS_ASSERT(pTarget && GetTypeId() == TYPEID_UNIT); - return - pTarget->IsImmunedToDamage(GetMeleeDamageSchoolMask()) || - pTarget->hasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_DAMAGE) || - checkThreatArea && ((Creature*)this)->IsOutOfThreatArea(pTarget); + return + pTarget->IsImmunedToDamage(GetMeleeDamageSchoolMask()) || + pTarget->hasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_DAMAGE) || + checkThreatArea && ((Creature*)this)->IsOutOfThreatArea(pTarget); } //====================================================================== bool Unit::SelectHostileTarget() { - // function provides main threat functionality - // next-victim-selection algorithm and evade mode are called - // threat list sorting etc. - - MANGOS_ASSERT(GetTypeId() == TYPEID_UNIT); - - if (!this->IsAlive()) - { - return false; - } - - // This function only useful once AI has been initialized - if (!((Creature*)this)->AI()) - { - return false; - } - - Unit* target = NULL; - Unit* oldTarget = getVictim(); - - // first check if we should fixate a target - if (m_fixateTargetGuid) - { - if (oldTarget && oldTarget->GetObjectGuid() == m_fixateTargetGuid) - target = oldTarget; - else - { - Unit* pFixateTarget = GetMap()->GetUnit(m_fixateTargetGuid); - if (pFixateTarget && pFixateTarget->IsAlive() && !IsSecondChoiceTarget(pFixateTarget, true)) - target = pFixateTarget; - } - } - // then checking if we have some taunt on us - if (!target) - { - const AuraList& tauntAuras = GetAurasByType(SPELL_AURA_MOD_TAUNT); - Unit* caster; - - // Find first available taunter target - // Auras are pushed_back, last caster will be on the end - for (AuraList::const_reverse_iterator aura = tauntAuras.rbegin(); aura != tauntAuras.rend(); ++aura) - { - if ((caster = (*aura)->GetCaster()) && caster->IsInMap(this) && - caster->IsTargetableForAttack() && caster->isInAccessablePlaceFor((Creature*)this) && - !IsSecondChoiceTarget(caster, true)) - { - target = caster; - break; - } - } - } - - // No valid fixate target, taunt aura or taunt aura caster is dead, standard target selection - if (!target && !m_ThreatManager.isThreatListEmpty()) - target = m_ThreatManager.getHostileTarget(); - - if (target) - { - if (!hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED)) - { - SetInFront(target); - if (oldTarget != target) - ((Creature*)this)->AI()->AttackStart(target); - - // check if currently selected target is reachable - // NOTE: path alrteady generated from AttackStart() - if (!GetMotionMaster()->GetCurrent()->IsReachable()) - { - // remove all taunts - RemoveSpellsCausingAura(SPELL_AURA_MOD_TAUNT); - - if (m_ThreatManager.getThreatList().size() < 2) - { - // only one target in list, we have to evade after timer - // TODO: make timer - inside Creature class - ((Creature*)this)->AI()->EnterEvadeMode(); - } - else - { - // remove unreachable target from our threat list - // next iteration we will select next possible target - m_HostileRefManager.deleteReference(target); - m_ThreatManager.modifyThreatPercent(target, -101); - - // remove target from current attacker, do not exit combat settings - AttackStop(true); - } - - return false; - } - } - return true; - } - - // no target but something prevent go to evade mode - if (!IsInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT)) - { - return false; - } - - // last case when creature don't must go to evade mode: - // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list - // for example at owner command to pet attack some far away creature - // Note: creature not have targeted movement generator but have attacker in this case - if (GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) - { - for (AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr) - { - if ((*itr)->IsInMap(this) && (*itr)->IsTargetableForAttack() && (*itr)->isInAccessablePlaceFor((Creature*)this)) - { - return false; - } - } - } - - // enter in evade mode in other case - m_fixateTargetGuid.Clear(); - ((Creature*)this)->AI()->EnterEvadeMode(); - - if (InstanceData* mapInstance = GetInstanceData()) - mapInstance->OnCreatureEvade((Creature*)this); - - if (m_isCreatureLinkingTrigger) - GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_EVADE, (Creature*)this); - - return false; + // function provides main threat functionality + // next-victim-selection algorithm and evade mode are called + // threat list sorting etc. + + MANGOS_ASSERT(GetTypeId() == TYPEID_UNIT); + + if (!this->IsAlive()) + { + return false; + } + + // This function only useful once AI has been initialized + if (!((Creature*)this)->AI()) + { + return false; + } + + Unit* target = NULL; + Unit* oldTarget = getVictim(); + + // first check if we should fixate a target + if (m_fixateTargetGuid) + { + if (oldTarget && oldTarget->GetObjectGuid() == m_fixateTargetGuid) + target = oldTarget; + else + { + Unit* pFixateTarget = GetMap()->GetUnit(m_fixateTargetGuid); + if (pFixateTarget && pFixateTarget->IsAlive() && !IsSecondChoiceTarget(pFixateTarget, true)) + target = pFixateTarget; + } + } + // then checking if we have some taunt on us + if (!target) + { + const AuraList& tauntAuras = GetAurasByType(SPELL_AURA_MOD_TAUNT); + Unit* caster; + + // Find first available taunter target + // Auras are pushed_back, last caster will be on the end + for (AuraList::const_reverse_iterator aura = tauntAuras.rbegin(); aura != tauntAuras.rend(); ++aura) + { + if ((caster = (*aura)->GetCaster()) && caster->IsInMap(this) && + caster->IsTargetableForAttack() && caster->isInAccessablePlaceFor((Creature*)this) && + !IsSecondChoiceTarget(caster, true)) + { + target = caster; + break; + } + } + } + + // No valid fixate target, taunt aura or taunt aura caster is dead, standard target selection + if (!target && !m_ThreatManager.isThreatListEmpty()) + target = m_ThreatManager.getHostileTarget(); + + if (target) + { + if (!hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED)) + { + SetInFront(target); + if (oldTarget != target) + ((Creature*)this)->AI()->AttackStart(target); + + // check if currently selected target is reachable + // NOTE: path alrteady generated from AttackStart() + if (!GetMotionMaster()->GetCurrent()->IsReachable()) + { + // remove all taunts + RemoveSpellsCausingAura(SPELL_AURA_MOD_TAUNT); + + if (m_ThreatManager.getThreatList().size() < 2) + { + // only one target in list, we have to evade after timer + // TODO: make timer - inside Creature class + ((Creature*)this)->AI()->EnterEvadeMode(); + } + else + { + // remove unreachable target from our threat list + // next iteration we will select next possible target + m_HostileRefManager.deleteReference(target); + m_ThreatManager.modifyThreatPercent(target, -101); + + // remove target from current attacker, do not exit combat settings + AttackStop(true); + } + + return false; + } + } + return true; + } + + // no target but something prevent go to evade mode + if (!IsInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT)) + { + return false; + } + + // last case when creature don't must go to evade mode: + // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list + // for example at owner command to pet attack some far away creature + // Note: creature not have targeted movement generator but have attacker in this case + if (GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) + { + for (AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr) + { + if ((*itr)->IsInMap(this) && (*itr)->IsTargetableForAttack() && (*itr)->isInAccessablePlaceFor((Creature*)this)) + { + return false; + } + } + } + + // enter in evade mode in other case + m_fixateTargetGuid.Clear(); + ((Creature*)this)->AI()->EnterEvadeMode(); + + if (InstanceData* mapInstance = GetInstanceData()) + mapInstance->OnCreatureEvade((Creature*)this); + + if (m_isCreatureLinkingTrigger) + GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_EVADE, (Creature*)this); + + return false; } //====================================================================== @@ -10423,373 +10427,373 @@ bool Unit::SelectHostileTarget() int32 Unit::CalculateSpellDamage(Unit const* target, SpellEntry const* spellProto, SpellEffectIndex effect_index, int32 const* effBasePoints) { - SpellEffectEntry const* spellEffect = spellProto->GetSpellEffect(effect_index); - if(!spellEffect) - { - return 0; - } - - switch (spellEffect->EffectApplyAuraName) - { - case SPELL_AURA_MOUNTED: - if (MountCapabilityEntry const* mountCapability = GetMountCapability(uint32(spellEffect->EffectMiscValueB))) - { - return int32(mountCapability->Id); - } - break; - default: - break; - } - - Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL; - uint32 level = getLevel(); - - // calculate basepoints dependent on mastery - if (unitPlayer && spellProto->HasAttribute(SPELL_ATTR_EX8_MASTERY) && !spellProto->CalculateSimpleValue(effect_index)) - { - if (int32 masteryCoef = GetMasteryCoefficient(spellProto)) - { - return int32(GetFloatValue(PLAYER_MASTERY) * masteryCoef / 100.0f); - } - } - - // calculate basepoints for armor specialization spells - if (unitPlayer && spellProto->HasAttribute(SPELL_ATTR_EX8_ARMOR_SPECIALIZATION)) - { - // check spells not valid for current talent tree or insufficient equipped items - if (!unitPlayer->FitArmorSpecializationRules(spellProto)) - { - return 0; - } - } - - uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0; - - int32 basePoints = 0; - uint32 spellLevel = 0; - float comboDamage = 0.0f; - - SpellScalingEntry const* scalingEntry = spellProto->GetSpellScaling(); - GtSpellScalingEntry const* gtScalingEntry = NULL; - //if (scalingEntry && scalingEntry->IsScalableEffect(effect_index)) - //{ - // if (target && IsAuraApplyEffect(spellProto, effect_index) && IsPositiveEffect(spellProto, effect_index)) - // level = target->getLevel(); - - // uint32 gtSpellScalingId = level - 1; - // if (scalingEntry->playerClass == -1) - // gtSpellScalingId += (MAX_CLASSES - 1) * GT_MAX_LEVEL; - // else - // gtSpellScalingId += (scalingEntry->playerClass - 1) * GT_MAX_LEVEL; - - // gtScalingEntry = sGtSpellScalingStore.LookupEntry(gtSpellScalingId); - //} - - if (gtScalingEntry) - { - float Scale = gtScalingEntry->value; - if (uint32(scalingEntry->castTimeMax) > 0 && uint32(scalingEntry->castScalingMaxLevel) > level) - Scale *= float(scalingEntry->castTimeMin + float(level - 1) * (scalingEntry->castTimeMax - scalingEntry->castTimeMin) / (scalingEntry->castScalingMaxLevel - 1)) / float(scalingEntry->castTimeMax); - //if (uint32(scalingEntry->coefLevelBase) > level) - // Scale *= (1.0f - scalingEntry->coefBase) * (level - 1) / (scalingEntry->coefLevelBase - 1) + scalingEntry->coefBase; - - //basePoints = int32(scalingEntry->coeff1[effect_index] * Scale); - //int32 randomPoints = int32(scalingEntry->coeff1[effect_index] * Scale * scalingEntry->coeff2[effect_index]); - //basePoints += irand(-randomPoints, randomPoints) / 2; - //comboDamage = uint32(scalingEntry->coeff3[effect_index] * Scale); - } - else - { - spellLevel = spellProto->GetSpellLevel(); - uint32 maxLevel = spellProto->GetMaxLevel(); - uint32 baseLevel = spellProto->GetBaseLevel(); - - if (maxLevel) - level = std::min(level, maxLevel); - level = std::max(level, baseLevel); - level = std::max(level, spellLevel) - spellLevel; - - float basePointsPerLevel = spellEffect->EffectRealPointsPerLevel; - basePoints = effBasePoints ? *effBasePoints - 1 : spellEffect->EffectBasePoints; - basePoints += int32(level * basePointsPerLevel); - int32 randomPoints = int32(spellEffect->EffectDieSides); - comboDamage = spellEffect->EffectPointsPerComboPoint; - - switch (randomPoints) - { - case 0: // not used - case 1: basePoints += 1; break; // range 1..1 - default: - { - // range can have positive (1..rand) and negative (rand..1) values, so order its for irand - int32 randvalue = (randomPoints >= 1) - ? irand(1, randomPoints) - : irand(randomPoints, 1); - - basePoints += randvalue; - break; - } - } - } - - int32 value = basePoints; - - // random damage - if (comboDamage != 0 && unitPlayer && - (target && target->GetObjectGuid() == unitPlayer->GetComboTargetGuid() || spellProto->HasAttribute(SPELL_ATTR_EX8_IGNORE_TARGET_FOR_COMBO_POINTS))) - value += (int32)(comboDamage * comboPoints); - - if (Player* modOwner = GetSpellModOwner()) - { - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_ALL_EFFECTS, value); - - switch (effect_index) - { - case EFFECT_INDEX_0: - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT1, value); - break; - case EFFECT_INDEX_1: - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT2, value); - break; - case EFFECT_INDEX_2: - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT3, value); - break; - } - } - - if (!gtScalingEntry && spellProto->HasAttribute(SPELL_ATTR_LEVEL_DAMAGE_CALCULATION) && spellLevel && - spellEffect->Effect != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE && - spellEffect->Effect != SPELL_EFFECT_KNOCK_BACK && - (spellEffect->Effect != SPELL_EFFECT_APPLY_AURA || spellEffect->EffectApplyAuraName != SPELL_AURA_MOD_DECREASE_SPEED)) - value = int32(value * 0.25f * exp(level * (70 - spellLevel) / 1000.0f)); - - return value; + SpellEffectEntry const* spellEffect = spellProto->GetSpellEffect(effect_index); + if (!spellEffect) + { + return 0; + } + + switch (spellEffect->EffectApplyAuraName) + { + case SPELL_AURA_MOUNTED: + if (MountCapabilityEntry const* mountCapability = GetMountCapability(uint32(spellEffect->EffectMiscValueB))) + { + return int32(mountCapability->Id); + } + break; + default: + break; + } + + Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL; + uint32 level = getLevel(); + + // calculate basepoints dependent on mastery + if (unitPlayer && spellProto->HasAttribute(SPELL_ATTR_EX8_MASTERY) && !spellProto->CalculateSimpleValue(effect_index)) + { + if (int32 masteryCoef = GetMasteryCoefficient(spellProto)) + { + return int32(GetFloatValue(PLAYER_MASTERY) * masteryCoef / 100.0f); + } + } + + // calculate basepoints for armor specialization spells + if (unitPlayer && spellProto->HasAttribute(SPELL_ATTR_EX8_ARMOR_SPECIALIZATION)) + { + // check spells not valid for current talent tree or insufficient equipped items + if (!unitPlayer->FitArmorSpecializationRules(spellProto)) + { + return 0; + } + } + + uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0; + + int32 basePoints = 0; + uint32 spellLevel = 0; + float comboDamage = 0.0f; + + SpellScalingEntry const* scalingEntry = spellProto->GetSpellScaling(); + GtSpellScalingEntry const* gtScalingEntry = NULL; + //if (scalingEntry && scalingEntry->IsScalableEffect(effect_index)) + //{ + // if (target && IsAuraApplyEffect(spellProto, effect_index) && IsPositiveEffect(spellProto, effect_index)) + // level = target->getLevel(); + + // uint32 gtSpellScalingId = level - 1; + // if (scalingEntry->playerClass == -1) + // gtSpellScalingId += (MAX_CLASSES - 1) * GT_MAX_LEVEL; + // else + // gtSpellScalingId += (scalingEntry->playerClass - 1) * GT_MAX_LEVEL; + + // gtScalingEntry = sGtSpellScalingStore.LookupEntry(gtSpellScalingId); + //} + + if (gtScalingEntry) + { + float Scale = gtScalingEntry->value; + if (uint32(scalingEntry->castTimeMax) > 0 && uint32(scalingEntry->castScalingMaxLevel) > level) + Scale *= float(scalingEntry->castTimeMin + float(level - 1) * (scalingEntry->castTimeMax - scalingEntry->castTimeMin) / (scalingEntry->castScalingMaxLevel - 1)) / float(scalingEntry->castTimeMax); + //if (uint32(scalingEntry->coefLevelBase) > level) + // Scale *= (1.0f - scalingEntry->coefBase) * (level - 1) / (scalingEntry->coefLevelBase - 1) + scalingEntry->coefBase; + + //basePoints = int32(scalingEntry->coeff1[effect_index] * Scale); + //int32 randomPoints = int32(scalingEntry->coeff1[effect_index] * Scale * scalingEntry->coeff2[effect_index]); + //basePoints += irand(-randomPoints, randomPoints) / 2; + //comboDamage = uint32(scalingEntry->coeff3[effect_index] * Scale); + } + else + { + spellLevel = spellProto->GetSpellLevel(); + uint32 maxLevel = spellProto->GetMaxLevel(); + uint32 baseLevel = spellProto->GetBaseLevel(); + + if (maxLevel) + level = std::min(level, maxLevel); + level = std::max(level, baseLevel); + level = std::max(level, spellLevel) - spellLevel; + + float basePointsPerLevel = spellEffect->EffectRealPointsPerLevel; + basePoints = effBasePoints ? *effBasePoints - 1 : spellEffect->EffectBasePoints; + basePoints += int32(level * basePointsPerLevel); + int32 randomPoints = int32(spellEffect->EffectDieSides); + comboDamage = spellEffect->EffectPointsPerComboPoint; + + switch (randomPoints) + { + case 0: // not used + case 1: basePoints += 1; break; // range 1..1 + default: + { + // range can have positive (1..rand) and negative (rand..1) values, so order its for irand + int32 randvalue = (randomPoints >= 1) + ? irand(1, randomPoints) + : irand(randomPoints, 1); + + basePoints += randvalue; + break; + } + } + } + + int32 value = basePoints; + + // random damage + if (comboDamage != 0 && unitPlayer && + (target && target->GetObjectGuid() == unitPlayer->GetComboTargetGuid() || spellProto->HasAttribute(SPELL_ATTR_EX8_IGNORE_TARGET_FOR_COMBO_POINTS))) + value += (int32)(comboDamage * comboPoints); + + if (Player* modOwner = GetSpellModOwner()) + { + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_ALL_EFFECTS, value); + + switch (effect_index) + { + case EFFECT_INDEX_0: + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT1, value); + break; + case EFFECT_INDEX_1: + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT2, value); + break; + case EFFECT_INDEX_2: + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT3, value); + break; + } + } + + if (!gtScalingEntry && spellProto->HasAttribute(SPELL_ATTR_LEVEL_DAMAGE_CALCULATION) && spellLevel && + spellEffect->Effect != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE && + spellEffect->Effect != SPELL_EFFECT_KNOCK_BACK && + (spellEffect->Effect != SPELL_EFFECT_APPLY_AURA || spellEffect->EffectApplyAuraName != SPELL_AURA_MOD_DECREASE_SPEED)) + value = int32(value * 0.25f * exp(level * (70 - spellLevel) / 1000.0f)); + + return value; } int32 Unit::CalculateAuraDuration(SpellEntry const* spellProto, uint32 effectMask, int32 duration, Unit const* caster, Spell const* spell /*=NULL*/) { - if (duration <= 0) - { - return duration; - } - - int32 mechanicMod = 0; - uint32 mechanicMask = GetSpellMechanicMask(spellProto, effectMask); - - for (int32 mechanic = FIRST_MECHANIC; mechanic < MAX_MECHANIC; ++mechanic) - { - if (!(mechanicMask & (1 << (mechanic - 1)))) - continue; - - int32 stackingMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic); - int32 nonStackingMod = GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic); - - mechanicMod = std::min(mechanicMod, std::min(stackingMod, nonStackingMod)); - } - - int32 dispelMod = 0; - int32 dmgClassMod = 0; - - if (!IsPositiveSpell(spellProto)) - { - dispelMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->GetDispel()); - dmgClassMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS, spellProto->GetDmgClass()); - } - - int32 durationMod = std::min(mechanicMod, std::min(dispelMod, dmgClassMod)); - - if (durationMod != 0) - { - duration = int32(int64(duration) * (100 + durationMod) / 100); - - if (duration < 0) - duration = 0; - } - - if (caster == this) - { - switch(spellProto->GetSpellFamilyName()) - { - case SPELLFAMILY_DRUID: - // Thorns - if (spellProto->GetSpellIconID() == 53 && spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000100))) - { - // Glyph of Thorns - if (Aura* aur = GetAura(57862, EFFECT_INDEX_0)) - duration += aur->GetModifier()->m_amount * MINUTE * IN_MILLISECONDS; - } - break; - case SPELLFAMILY_PALADIN: - // Blessing of Might - if (spellProto->GetSpellIconID() == 298 && spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000002))) - { - // Glyph of Blessing of Might - if (Aura* aur = GetAura(57958, EFFECT_INDEX_0)) - duration += aur->GetModifier()->m_amount * MINUTE * IN_MILLISECONDS; - } - // Blessing of Wisdom - else if (spellProto->GetSpellIconID() == 306 && spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000010000))) - { - // Glyph of Blessing of Wisdom - if (Aura* aur = GetAura(57979, EFFECT_INDEX_0)) - duration += aur->GetModifier()->m_amount * MINUTE * IN_MILLISECONDS; - } - // Inquisition - else if (spellProto->Id == 84963) - { - if (spell && GetPowerIndex(POWER_HOLY_POWER) != INVALID_POWER_INDEX) - duration *= spell->GetUsedHolyPower(); - } - break; - default: - break; - } - } - - return duration; + if (duration <= 0) + { + return duration; + } + + int32 mechanicMod = 0; + uint32 mechanicMask = GetSpellMechanicMask(spellProto, effectMask); + + for (int32 mechanic = FIRST_MECHANIC; mechanic < MAX_MECHANIC; ++mechanic) + { + if (!(mechanicMask & (1 << (mechanic - 1)))) + continue; + + int32 stackingMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic); + int32 nonStackingMod = GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic); + + mechanicMod = std::min(mechanicMod, std::min(stackingMod, nonStackingMod)); + } + + int32 dispelMod = 0; + int32 dmgClassMod = 0; + + if (!IsPositiveSpell(spellProto)) + { + dispelMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->GetDispel()); + dmgClassMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS, spellProto->GetDmgClass()); + } + + int32 durationMod = std::min(mechanicMod, std::min(dispelMod, dmgClassMod)); + + if (durationMod != 0) + { + duration = int32(int64(duration) * (100 + durationMod) / 100); + + if (duration < 0) + duration = 0; + } + + if (caster == this) + { + switch (spellProto->GetSpellFamilyName()) + { + case SPELLFAMILY_DRUID: + // Thorns + if (spellProto->GetSpellIconID() == 53 && spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000100))) + { + // Glyph of Thorns + if (Aura* aur = GetAura(57862, EFFECT_INDEX_0)) + duration += aur->GetModifier()->m_amount * MINUTE * IN_MILLISECONDS; + } + break; + case SPELLFAMILY_PALADIN: + // Blessing of Might + if (spellProto->GetSpellIconID() == 298 && spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000002))) + { + // Glyph of Blessing of Might + if (Aura* aur = GetAura(57958, EFFECT_INDEX_0)) + duration += aur->GetModifier()->m_amount * MINUTE * IN_MILLISECONDS; + } + // Blessing of Wisdom + else if (spellProto->GetSpellIconID() == 306 && spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000010000))) + { + // Glyph of Blessing of Wisdom + if (Aura* aur = GetAura(57979, EFFECT_INDEX_0)) + duration += aur->GetModifier()->m_amount * MINUTE * IN_MILLISECONDS; + } + // Inquisition + else if (spellProto->Id == 84963) + { + if (spell && GetPowerIndex(POWER_HOLY_POWER) != INVALID_POWER_INDEX) + duration *= spell->GetUsedHolyPower(); + } + break; + default: + break; + } + } + + return duration; } DiminishingLevels Unit::GetDiminishing(DiminishingGroup group) { - for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) - { - if (i->DRGroup != group) - continue; - - if (!i->hitCount) - { - return DIMINISHING_LEVEL_1; - } - - if (!i->hitTime) - { - return DIMINISHING_LEVEL_1; - } - - // If last spell was casted more than 15 seconds ago - reset the count. - if (i->stack == 0 && WorldTimer::getMSTimeDiff(i->hitTime, WorldTimer::getMSTime()) > 15 * IN_MILLISECONDS) - { - i->hitCount = DIMINISHING_LEVEL_1; - return DIMINISHING_LEVEL_1; - } - // or else increase the count. - else - { - return DiminishingLevels(i->hitCount); - } - } - return DIMINISHING_LEVEL_1; + for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) + { + if (i->DRGroup != group) + continue; + + if (!i->hitCount) + { + return DIMINISHING_LEVEL_1; + } + + if (!i->hitTime) + { + return DIMINISHING_LEVEL_1; + } + + // If last spell was casted more than 15 seconds ago - reset the count. + if (i->stack == 0 && WorldTimer::getMSTimeDiff(i->hitTime, WorldTimer::getMSTime()) > 15 * IN_MILLISECONDS) + { + i->hitCount = DIMINISHING_LEVEL_1; + return DIMINISHING_LEVEL_1; + } + // or else increase the count. + else + { + return DiminishingLevels(i->hitCount); + } + } + return DIMINISHING_LEVEL_1; } void Unit::IncrDiminishing(DiminishingGroup group) { - // Checking for existing in the table - for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) - { - if (i->DRGroup != group) - continue; - if (i->hitCount < DIMINISHING_LEVEL_IMMUNE) - i->hitCount += 1; - return; - } - m_Diminishing.push_back(DiminishingReturn(group, WorldTimer::getMSTime(), DIMINISHING_LEVEL_2)); + // Checking for existing in the table + for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) + { + if (i->DRGroup != group) + continue; + if (i->hitCount < DIMINISHING_LEVEL_IMMUNE) + i->hitCount += 1; + return; + } + m_Diminishing.push_back(DiminishingReturn(group, WorldTimer::getMSTime(), DIMINISHING_LEVEL_2)); } void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32& duration, Unit* caster, DiminishingLevels Level, int32 limitduration, bool isReflected) { - if (duration == -1 || group == DIMINISHING_NONE || (!isReflected && caster->IsFriendlyTo(this))) - { - return; - } + if (duration == -1 || group == DIMINISHING_NONE || (!isReflected && caster->IsFriendlyTo(this))) + { + return; + } - // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0) - if (limitduration > 0 && duration > limitduration) - { - // test pet/charm masters instead pets/charmeds - Unit const* targetOwner = GetCharmerOrOwner(); - Unit const* casterOwner = caster->GetCharmerOrOwner(); + // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0) + if (limitduration > 0 && duration > limitduration) + { + // test pet/charm masters instead pets/charmeds + Unit const* targetOwner = GetCharmerOrOwner(); + Unit const* casterOwner = caster->GetCharmerOrOwner(); - Unit const* target = targetOwner ? targetOwner : this; - Unit const* source = casterOwner ? casterOwner : caster; + Unit const* target = targetOwner ? targetOwner : this; + Unit const* source = casterOwner ? casterOwner : caster; - if (target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER) - duration = limitduration; - } + if (target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER) + duration = limitduration; + } - float mod = 1.0f; + float mod = 1.0f; - // Some diminishings applies to mobs too (for example, Stun) - if ((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL) - { - DiminishingLevels diminish = Level; - switch (diminish) - { - case DIMINISHING_LEVEL_1: break; - case DIMINISHING_LEVEL_2: mod = 0.5f; break; - case DIMINISHING_LEVEL_3: mod = 0.25f; break; - case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break; - default: break; - } - } + // Some diminishings applies to mobs too (for example, Stun) + if ((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL) + { + DiminishingLevels diminish = Level; + switch (diminish) + { + case DIMINISHING_LEVEL_1: break; + case DIMINISHING_LEVEL_2: mod = 0.5f; break; + case DIMINISHING_LEVEL_3: mod = 0.25f; break; + case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break; + default: break; + } + } - duration = int32(duration * mod); + duration = int32(duration * mod); } void Unit::ApplyDiminishingAura(DiminishingGroup group, bool apply) { - // Checking for existing in the table - for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) - { - if (i->DRGroup != group) - continue; - - if (apply) - i->stack += 1; - else if (i->stack) - { - i->stack -= 1; - // Remember time after last aura from group removed - if (i->stack == 0) - i->hitTime = WorldTimer::getMSTime(); - } - break; - } + // Checking for existing in the table + for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i) + { + if (i->DRGroup != group) + continue; + + if (apply) + i->stack += 1; + else if (i->stack) + { + i->stack -= 1; + // Remember time after last aura from group removed + if (i->stack == 0) + i->hitTime = WorldTimer::getMSTime(); + } + break; + } } bool Unit::isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const { - return IsVisibleForOrDetect(u, viewPoint, false, inVisibleList, false); + return IsVisibleForOrDetect(u, viewPoint, false, inVisibleList, false); } /// returns true if creature can't be seen by alive units bool Unit::isInvisibleForAlive() const { - if (m_AuraFlags & UNIT_AURAFLAG_ALIVE_INVISIBLE) - { - return true; - } - // TODO: maybe spiritservices also have just an aura - return IsSpiritService(); + if (m_AuraFlags & UNIT_AURAFLAG_ALIVE_INVISIBLE) + { + return true; + } + // TODO: maybe spiritservices also have just an aura + return IsSpiritService(); } uint32 Unit::GetCreatureType() const { - if (GetTypeId() == TYPEID_PLAYER) - { - SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm()); - if (ssEntry && ssEntry->creatureType > 0) - { - return ssEntry->creatureType; - } - else - { - return CREATURE_TYPE_HUMANOID; - } - } - else - { - return ((Creature*)this)->GetCreatureInfo()->CreatureType; - } + if (GetTypeId() == TYPEID_PLAYER) + { + SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm()); + if (ssEntry && ssEntry->creatureType > 0) + { + return ssEntry->creatureType; + } + else + { + return CREATURE_TYPE_HUMANOID; + } + } + else + { + return ((Creature*)this)->GetCreatureInfo()->CreatureType; + } } /*####################################### @@ -10800,855 +10804,855 @@ uint32 Unit::GetCreatureType() const bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply) { - if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) - { - sLog.outError("ERROR in HandleStatModifier(): nonexistent UnitMods or wrong UnitModifierType!"); - return false; - } - - float val = 1.0f; - - switch (modifierType) - { - case BASE_VALUE: - case TOTAL_VALUE: - m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; - break; - case BASE_PCT: - case TOTAL_PCT: - if (amount <= -100.0f) // small hack-fix for -100% modifiers - amount = -200.0f; - - val = (100.0f + amount) / 100.0f; - m_auraModifiersGroup[unitMod][modifierType] *= apply ? val : (1.0f / val); - break; - - default: - break; - } - - if (!CanModifyStats()) - { - return false; - } - - switch (unitMod) - { - case UNIT_MOD_STAT_STRENGTH: - case UNIT_MOD_STAT_AGILITY: - case UNIT_MOD_STAT_STAMINA: - case UNIT_MOD_STAT_INTELLECT: - case UNIT_MOD_STAT_SPIRIT: UpdateStats(GetStatByAuraGroup(unitMod)); break; - - case UNIT_MOD_ARMOR: UpdateArmor(); break; - case UNIT_MOD_HEALTH: UpdateMaxHealth(); break; - - case UNIT_MOD_MANA: - case UNIT_MOD_RAGE: - case UNIT_MOD_FOCUS: - case UNIT_MOD_ENERGY: - case UNIT_MOD_RUNE: - case UNIT_MOD_RUNIC_POWER: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break; - - case UNIT_MOD_RESISTANCE_HOLY: - case UNIT_MOD_RESISTANCE_FIRE: - case UNIT_MOD_RESISTANCE_NATURE: - case UNIT_MOD_RESISTANCE_FROST: - case UNIT_MOD_RESISTANCE_SHADOW: - case UNIT_MOD_RESISTANCE_ARCANE: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod)); break; - - case UNIT_MOD_ATTACK_POWER: UpdateAttackPowerAndDamage(); break; - case UNIT_MOD_ATTACK_POWER_RANGED: UpdateAttackPowerAndDamage(true); break; - - case UNIT_MOD_DAMAGE_MAINHAND: UpdateDamagePhysical(BASE_ATTACK); break; - case UNIT_MOD_DAMAGE_OFFHAND: UpdateDamagePhysical(OFF_ATTACK); break; - case UNIT_MOD_DAMAGE_RANGED: UpdateDamagePhysical(RANGED_ATTACK); break; - - default: - break; - } - - return true; + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) + { + sLog.outError("ERROR in HandleStatModifier(): nonexistent UnitMods or wrong UnitModifierType!"); + return false; + } + + float val = 1.0f; + + switch (modifierType) + { + case BASE_VALUE: + case TOTAL_VALUE: + m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; + break; + case BASE_PCT: + case TOTAL_PCT: + if (amount <= -100.0f) // small hack-fix for -100% modifiers + amount = -200.0f; + + val = (100.0f + amount) / 100.0f; + m_auraModifiersGroup[unitMod][modifierType] *= apply ? val : (1.0f / val); + break; + + default: + break; + } + + if (!CanModifyStats()) + { + return false; + } + + switch (unitMod) + { + case UNIT_MOD_STAT_STRENGTH: + case UNIT_MOD_STAT_AGILITY: + case UNIT_MOD_STAT_STAMINA: + case UNIT_MOD_STAT_INTELLECT: + case UNIT_MOD_STAT_SPIRIT: UpdateStats(GetStatByAuraGroup(unitMod)); break; + + case UNIT_MOD_ARMOR: UpdateArmor(); break; + case UNIT_MOD_HEALTH: UpdateMaxHealth(); break; + + case UNIT_MOD_MANA: + case UNIT_MOD_RAGE: + case UNIT_MOD_FOCUS: + case UNIT_MOD_ENERGY: + case UNIT_MOD_RUNE: + case UNIT_MOD_RUNIC_POWER: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break; + + case UNIT_MOD_RESISTANCE_HOLY: + case UNIT_MOD_RESISTANCE_FIRE: + case UNIT_MOD_RESISTANCE_NATURE: + case UNIT_MOD_RESISTANCE_FROST: + case UNIT_MOD_RESISTANCE_SHADOW: + case UNIT_MOD_RESISTANCE_ARCANE: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod)); break; + + case UNIT_MOD_ATTACK_POWER: UpdateAttackPowerAndDamage(); break; + case UNIT_MOD_ATTACK_POWER_RANGED: UpdateAttackPowerAndDamage(true); break; + + case UNIT_MOD_DAMAGE_MAINHAND: UpdateDamagePhysical(BASE_ATTACK); break; + case UNIT_MOD_DAMAGE_OFFHAND: UpdateDamagePhysical(OFF_ATTACK); break; + case UNIT_MOD_DAMAGE_RANGED: UpdateDamagePhysical(RANGED_ATTACK); break; + + default: + break; + } + + return true; } float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const { - if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) - { - sLog.outError("attempt to access nonexistent modifier value from UnitMods!"); - return 0.0f; - } + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) + { + sLog.outError("attempt to access nonexistent modifier value from UnitMods!"); + return 0.0f; + } - if (modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f) - { - return 0.0f; - } + if (modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f) + { + return 0.0f; + } - return m_auraModifiersGroup[unitMod][modifierType]; + return m_auraModifiersGroup[unitMod][modifierType]; } float Unit::GetTotalStatValue(Stats stat) const { - UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat); + UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat); - if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) - { - return 0.0f; - } + if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) + { + return 0.0f; + } - // value = ((base_value * base_pct) + total_value) * total_pct - float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat); - value *= m_auraModifiersGroup[unitMod][BASE_PCT]; - value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; - value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; + // value = ((base_value * base_pct) + total_value) * total_pct + float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat); + value *= m_auraModifiersGroup[unitMod][BASE_PCT]; + value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; + value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; - return value; + return value; } float Unit::GetTotalAuraModValue(UnitMods unitMod) const { - if (unitMod >= UNIT_MOD_END) - { - sLog.outError("attempt to access nonexistent UnitMods in GetTotalAuraModValue()!"); - return 0.0f; - } + if (unitMod >= UNIT_MOD_END) + { + sLog.outError("attempt to access nonexistent UnitMods in GetTotalAuraModValue()!"); + return 0.0f; + } - if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) - { - return 0.0f; - } + if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) + { + return 0.0f; + } - float value = m_auraModifiersGroup[unitMod][BASE_VALUE]; - value *= m_auraModifiersGroup[unitMod][BASE_PCT]; - value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; - value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; + float value = m_auraModifiersGroup[unitMod][BASE_VALUE]; + value *= m_auraModifiersGroup[unitMod][BASE_PCT]; + value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; + value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; - return value; + return value; } SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const { - SpellSchools school = SPELL_SCHOOL_NORMAL; + SpellSchools school = SPELL_SCHOOL_NORMAL; - switch (unitMod) - { - case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break; - case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break; - case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break; - case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break; - case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break; - case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break; + switch (unitMod) + { + case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break; + case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break; + case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break; + case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break; + case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break; + case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break; - default: - break; - } + default: + break; + } - return school; + return school; } Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const { - Stats stat = STAT_STRENGTH; + Stats stat = STAT_STRENGTH; - switch (unitMod) - { - case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break; - case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break; - case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break; - case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break; - case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break; + switch (unitMod) + { + case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break; + case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break; + case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break; + case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break; + case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break; - default: - break; - } + default: + break; + } - return stat; + return stat; } Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const { - switch (unitMod) - { - case UNIT_MOD_MANA: return POWER_MANA; - case UNIT_MOD_RAGE: return POWER_RAGE; - case UNIT_MOD_FOCUS: return POWER_FOCUS; - case UNIT_MOD_ENERGY: return POWER_ENERGY; - case UNIT_MOD_RUNE: return POWER_RUNE; - case UNIT_MOD_RUNIC_POWER: return POWER_RUNIC_POWER; - default: return POWER_MANA; - } + switch (unitMod) + { + case UNIT_MOD_MANA: return POWER_MANA; + case UNIT_MOD_RAGE: return POWER_RAGE; + case UNIT_MOD_FOCUS: return POWER_FOCUS; + case UNIT_MOD_ENERGY: return POWER_ENERGY; + case UNIT_MOD_RUNE: return POWER_RUNE; + case UNIT_MOD_RUNIC_POWER: return POWER_RUNIC_POWER; + default: return POWER_MANA; + } } float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const { - if (attType == RANGED_ATTACK) - { - int32 ap = GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MOD_POS); - if (ap < 0) - { - return 0.0f; - } - return ap * (1.0f + GetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER)); - } - else - { - int32 ap = GetInt32Value(UNIT_FIELD_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_ATTACK_POWER_MOD_POS); - if (ap < 0) - { - return 0.0f; - } - return ap * (1.0f + GetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER)); - } + if (attType == RANGED_ATTACK) + { + int32 ap = GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MOD_POS); + if (ap < 0) + { + return 0.0f; + } + return ap * (1.0f + GetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER)); + } + else + { + int32 ap = GetInt32Value(UNIT_FIELD_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_ATTACK_POWER_MOD_POS); + if (ap < 0) + { + return 0.0f; + } + return ap * (1.0f + GetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER)); + } } -float Unit::GetWeaponDamageRange(WeaponAttackType attType , WeaponDamageRange type) const +float Unit::GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const { - if (attType == OFF_ATTACK && !haveOffhandWeapon()) - { - return 0.0f; - } + if (attType == OFF_ATTACK && !haveOffhandWeapon()) + { + return 0.0f; + } - return m_weaponDamage[attType][type]; + return m_weaponDamage[attType][type]; } void Unit::SetLevel(uint32 lvl) { - SetUInt32Value(UNIT_FIELD_LEVEL, lvl); + SetUInt32Value(UNIT_FIELD_LEVEL, lvl); - // group update - if ((GetTypeId() == TYPEID_PLAYER) && ((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL); + // group update + if ((GetTypeId() == TYPEID_PLAYER) && ((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL); } void Unit::SetHealth(uint32 val) { - uint32 maxHealth = GetMaxHealth(); - if (maxHealth < val) - val = maxHealth; - - SetUInt32Value(UNIT_FIELD_HEALTH, val); - - // group update - if (GetTypeId() == TYPEID_PLAYER) - { - if (((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP); - } - else if (((Creature*)this)->IsPet()) - { - Pet* pet = ((Pet*)this); - if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP); - } - } + uint32 maxHealth = GetMaxHealth(); + if (maxHealth < val) + val = maxHealth; + + SetUInt32Value(UNIT_FIELD_HEALTH, val); + + // group update + if (GetTypeId() == TYPEID_PLAYER) + { + if (((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP); + } + else if (((Creature*)this)->IsPet()) + { + Pet* pet = ((Pet*)this); + if (pet->isControlled()) + { + Unit* owner = GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP); + } + } } void Unit::SetMaxHealth(uint32 val) { - uint32 health = GetHealth(); - SetUInt32Value(UNIT_FIELD_MAXHEALTH, val); - - // group update - if (GetTypeId() == TYPEID_PLAYER) - { - if (((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP); - } - else if (((Creature*)this)->IsPet()) - { - Pet* pet = ((Pet*)this); - if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP); - } - } - - if (val < health) - SetHealth(val); + uint32 health = GetHealth(); + SetUInt32Value(UNIT_FIELD_MAXHEALTH, val); + + // group update + if (GetTypeId() == TYPEID_PLAYER) + { + if (((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP); + } + else if (((Creature*)this)->IsPet()) + { + Pet* pet = ((Pet*)this); + if (pet->isControlled()) + { + Unit* owner = GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP); + } + } + + if (val < health) + SetHealth(val); } void Unit::SetHealthPercent(float percent) { - uint32 newHealth = GetMaxHealth() * percent / 100.0f; - SetHealth(newHealth); + uint32 newHealth = GetMaxHealth() * percent / 100.0f; + SetHealth(newHealth); } uint32 Unit::GetPowerIndexByClass(Powers powerId, uint32 classId) { - MANGOS_ASSERT(powerId < MAX_POWERS); - MANGOS_ASSERT(classId < MAX_CLASSES); + MANGOS_ASSERT(powerId < MAX_POWERS); + MANGOS_ASSERT(classId < MAX_CLASSES); - return sChrClassXPowerTypesStore[classId][uint32(powerId)]; + return sChrClassXPowerTypesStore[classId][uint32(powerId)]; }; Powers Unit::GetPowerTypeByIndex(uint32 index, uint32 classId) { - MANGOS_ASSERT(index < MAX_STORED_POWERS); - MANGOS_ASSERT(classId < MAX_CLASSES); + MANGOS_ASSERT(index < MAX_STORED_POWERS); + MANGOS_ASSERT(classId < MAX_CLASSES); - return Powers(sChrClassXPowerIndexStore[classId][index]); + return Powers(sChrClassXPowerIndexStore[classId][index]); } uint32 Unit::GetPower(Powers power) const { - if (power == POWER_HEALTH) - { - return GetHealth(); - } + if (power == POWER_HEALTH) + { + return GetHealth(); + } - uint32 powerIndex = GetPowerIndex(power); - if (powerIndex == INVALID_POWER_INDEX) - { - return 0; - } + uint32 powerIndex = GetPowerIndex(power); + if (powerIndex == INVALID_POWER_INDEX) + { + return 0; + } - return GetUInt32Value(UNIT_FIELD_POWER1 + powerIndex); + return GetUInt32Value(UNIT_FIELD_POWER1 + powerIndex); } uint32 Unit::GetPowerByIndex(uint32 index) const { - MANGOS_ASSERT(index < MAX_STORED_POWERS); + MANGOS_ASSERT(index < MAX_STORED_POWERS); - return GetUInt32Value(UNIT_FIELD_POWER1 + index); + return GetUInt32Value(UNIT_FIELD_POWER1 + index); } uint32 Unit::GetMaxPower(Powers power) const { - if (power == POWER_HEALTH) - { - return GetMaxHealth(); - } + if (power == POWER_HEALTH) + { + return GetMaxHealth(); + } - uint32 powerIndex = GetPowerIndex(power); - if (powerIndex == INVALID_POWER_INDEX) - { - return 0; - } + uint32 powerIndex = GetPowerIndex(power); + if (powerIndex == INVALID_POWER_INDEX) + { + return 0; + } - return GetUInt32Value(UNIT_FIELD_MAXPOWER1 + powerIndex); + return GetUInt32Value(UNIT_FIELD_MAXPOWER1 + powerIndex); } uint32 Unit::GetMaxPowerByIndex(uint32 index) const { - MANGOS_ASSERT(index < MAX_STORED_POWERS); + MANGOS_ASSERT(index < MAX_STORED_POWERS); - return GetUInt32Value(UNIT_FIELD_MAXPOWER1 + index); + return GetUInt32Value(UNIT_FIELD_MAXPOWER1 + index); } void Unit::SetPower(Powers power, int32 val) { - if (power == POWER_HEALTH) - { - return SetHealth(val >= 0 ? val : 0); - } + if (power == POWER_HEALTH) + { + return SetHealth(val >= 0 ? val : 0); + } - uint32 powerIndex = GetPowerIndex(power); - if (powerIndex == INVALID_POWER_INDEX) - { - return; - } + uint32 powerIndex = GetPowerIndex(power); + if (powerIndex == INVALID_POWER_INDEX) + { + return; + } - return SetPowerByIndex(powerIndex, val); + return SetPowerByIndex(powerIndex, val); } void Unit::SetPowerByIndex(uint32 powerIndex, int32 val) { - int32 maxPower = GetMaxPowerByIndex(powerIndex); - if (val > maxPower) - val = maxPower; - - if (val < 0) - val = 0; - - if (GetPowerByIndex(powerIndex) == val) - { - return; - } - - MANGOS_ASSERT(powerIndex < MAX_STORED_POWERS); - SetInt32Value(UNIT_FIELD_POWER1 + powerIndex, val); - - Powers power = getPowerType(powerIndex); - MANGOS_ASSERT(power != INVALID_POWER); - - if (IsInWorld()) - { - WorldPacket data(SMSG_POWER_UPDATE); - data << GetPackGUID(); - data << uint32(1); // iteration count - // for (int i = 0; i < count; ++i) - data << uint8(power); - data << uint32(val); - SendMessageToSet(&data, true); - } - - // group update - if (GetTypeId() == TYPEID_PLAYER) - { - if (((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); - } - else if (((Creature*)this)->IsPet()) - { - Pet* pet = ((Pet*)this); - if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); - } - } - - // modifying holy power resets it's fade timer - if (power == POWER_HOLY_POWER) - ResetHolyPowerRegenTimer(); + int32 maxPower = GetMaxPowerByIndex(powerIndex); + if (val > maxPower) + val = maxPower; + + if (val < 0) + val = 0; + + if (GetPowerByIndex(powerIndex) == val) + { + return; + } + + MANGOS_ASSERT(powerIndex < MAX_STORED_POWERS); + SetInt32Value(UNIT_FIELD_POWER1 + powerIndex, val); + + Powers power = getPowerType(powerIndex); + MANGOS_ASSERT(power != INVALID_POWER); + + if (IsInWorld()) + { + WorldPacket data(SMSG_POWER_UPDATE); + data << GetPackGUID(); + data << uint32(1); // iteration count + // for (int i = 0; i < count; ++i) + data << uint8(power); + data << uint32(val); + SendMessageToSet(&data, true); + } + + // group update + if (GetTypeId() == TYPEID_PLAYER) + { + if (((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); + } + else if (((Creature*)this)->IsPet()) + { + Pet* pet = ((Pet*)this); + if (pet->isControlled()) + { + Unit* owner = GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); + } + } + + // modifying holy power resets it's fade timer + if (power == POWER_HOLY_POWER) + ResetHolyPowerRegenTimer(); } void Unit::SetMaxPower(Powers power, int32 val) { - if (power == POWER_HEALTH) - { - return SetMaxHealth(val >= 0 ? val : 0); - } + if (power == POWER_HEALTH) + { + return SetMaxHealth(val >= 0 ? val : 0); + } - uint32 powerIndex = GetPowerIndex(power); - if (powerIndex == INVALID_POWER_INDEX) - { - return; - } + uint32 powerIndex = GetPowerIndex(power); + if (powerIndex == INVALID_POWER_INDEX) + { + return; + } - return SetMaxPowerByIndex(powerIndex, val); + return SetMaxPowerByIndex(powerIndex, val); } void Unit::SetMaxPowerByIndex(uint32 powerIndex, int32 val) { - int32 cur_power = GetPowerByIndex(powerIndex); + int32 cur_power = GetPowerByIndex(powerIndex); - SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + powerIndex, val); + SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + powerIndex, val); - // group update - if (GetTypeId() == TYPEID_PLAYER) - { - if (((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); - } - else if (((Creature*)this)->IsPet()) - { - Pet* pet = ((Pet*)this); - if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); - } - } + // group update + if (GetTypeId() == TYPEID_PLAYER) + { + if (((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); + } + else if (((Creature*)this)->IsPet()) + { + Pet* pet = ((Pet*)this); + if (pet->isControlled()) + { + Unit* owner = GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); + } + } - if (val < cur_power) - SetPowerByIndex(powerIndex, val); + if (val < cur_power) + SetPowerByIndex(powerIndex, val); } void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply) { - ApplyModUInt32Value(UNIT_FIELD_POWER1 + power, val, apply); - - // group update - if (GetTypeId() == TYPEID_PLAYER) - { - if (((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); - } - else if (((Creature*)this)->IsPet()) - { - Pet* pet = ((Pet*)this); - if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); - } - } + ApplyModUInt32Value(UNIT_FIELD_POWER1 + power, val, apply); + + // group update + if (GetTypeId() == TYPEID_PLAYER) + { + if (((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); + } + else if (((Creature*)this)->IsPet()) + { + Pet* pet = ((Pet*)this); + if (pet->isControlled()) + { + Unit* owner = GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); + } + } } void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply) { - ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1 + power, val, apply); - - // group update - if (GetTypeId() == TYPEID_PLAYER) - { - if (((Player*)this)->GetGroup()) - ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); - } - else if (((Creature*)this)->IsPet()) - { - Pet* pet = ((Pet*)this); - if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); - } - } + ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1 + power, val, apply); + + // group update + if (GetTypeId() == TYPEID_PLAYER) + { + if (((Player*)this)->GetGroup()) + ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); + } + else if (((Creature*)this)->IsPet()) + { + Pet* pet = ((Pet*)this); + if (pet->isControlled()) + { + Unit* owner = GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); + } + } } void Unit::ApplyAuraProcTriggerDamage(Aura* aura, bool apply) { - AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE]; - if (apply) - tAuraProcTriggerDamage.push_back(aura); - else - tAuraProcTriggerDamage.remove(aura); + AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE]; + if (apply) + tAuraProcTriggerDamage.push_back(aura); + else + tAuraProcTriggerDamage.remove(aura); } uint32 Unit::GetCreatePowers(Powers power) const { - switch (power) - { - case POWER_HEALTH: return 0; // is it really should be here? - case POWER_MANA: return GetCreateMana(); - case POWER_RAGE: return POWER_RAGE_DEFAULT; - case POWER_FOCUS: - if(GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_HUNTER) - { - return POWER_FOCUS_DEFAULT; - } - return (GetTypeId() == TYPEID_PLAYER || !((Creature const*)this)->IsPet() || ((Pet const*)this)->getPetType() != HUNTER_PET ? 0 : POWER_FOCUS_DEFAULT); - case POWER_ENERGY: return POWER_ENERGY_DEFAULT; - case POWER_RUNE: return GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_DEATH_KNIGHT ? POWER_RUNE_DEFAULT : 0; - case POWER_RUNIC_POWER: return GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_DEATH_KNIGHT ? POWER_RUNIC_POWER_DEFAULT : 0; - case POWER_SOUL_SHARDS: return 0; - case POWER_ECLIPSE: return 0; // TODO: fix me - case POWER_HOLY_POWER: return 0; - } - - return 0; + switch (power) + { + case POWER_HEALTH: return 0; // is it really should be here? + case POWER_MANA: return GetCreateMana(); + case POWER_RAGE: return POWER_RAGE_DEFAULT; + case POWER_FOCUS: + if (GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_HUNTER) + { + return POWER_FOCUS_DEFAULT; + } + return (GetTypeId() == TYPEID_PLAYER || !((Creature const*)this)->IsPet() || ((Pet const*)this)->getPetType() != HUNTER_PET ? 0 : POWER_FOCUS_DEFAULT); + case POWER_ENERGY: return POWER_ENERGY_DEFAULT; + case POWER_RUNE: return GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_DEATH_KNIGHT ? POWER_RUNE_DEFAULT : 0; + case POWER_RUNIC_POWER: return GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_DEATH_KNIGHT ? POWER_RUNIC_POWER_DEFAULT : 0; + case POWER_SOUL_SHARDS: return 0; + case POWER_ECLIPSE: return 0; // TODO: fix me + case POWER_HOLY_POWER: return 0; + } + + return 0; } uint32 Unit::GetCreateMaxPowers(Powers power) const { - switch (power) - { - case POWER_HOLY_POWER: - return GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_PALADIN ? POWER_HOLY_POWER_DEFAULT : 0; - case POWER_SOUL_SHARDS: - return GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_WARLOCK ? POWER_SOUL_SHARDS_DEFAULT : 0; - default: - return GetCreatePowers(power); - } + switch (power) + { + case POWER_HOLY_POWER: + return GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_PALADIN ? POWER_HOLY_POWER_DEFAULT : 0; + case POWER_SOUL_SHARDS: + return GetTypeId() == TYPEID_PLAYER && ((Player const*)this)->getClass() == CLASS_WARLOCK ? POWER_SOUL_SHARDS_DEFAULT : 0; + default: + return GetCreatePowers(power); + } - return 0; + return 0; } void Unit::AddToWorld() { - Object::AddToWorld(); - ScheduleAINotify(0); + Object::AddToWorld(); + ScheduleAINotify(0); } void Unit::RemoveFromWorld() { - // cleanup - if (IsInWorld()) - { - Uncharm(); - RemoveNotOwnTrackedTargetAuras(); - RemoveGuardians(); - RemoveMiniPet(); - UnsummonAllTotems(); - RemoveAllGameObjects(); - RemoveAllDynObjects(); - CleanupDeletedAuras(); - GetViewPoint().Event_RemovedFromWorld(); - } + // cleanup + if (IsInWorld()) + { + Uncharm(); + RemoveNotOwnTrackedTargetAuras(); + RemoveGuardians(); + RemoveMiniPet(); + UnsummonAllTotems(); + RemoveAllGameObjects(); + RemoveAllDynObjects(); + CleanupDeletedAuras(); + GetViewPoint().Event_RemovedFromWorld(); + } - Object::RemoveFromWorld(); + Object::RemoveFromWorld(); } void Unit::CleanupsBeforeDelete() { - if (m_uint32Values) // only for fully created object - { - InterruptNonMeleeSpells(true); - m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList - CombatStop(); - ClearComboPointHolders(); - DeleteThreatList(); - if (GetTypeId() == TYPEID_PLAYER) - GetHostileRefManager().setOnlineOfflineState(false); - else - GetHostileRefManager().deleteReferences(); - RemoveAllAuras(AURA_REMOVE_BY_DELETE); - } - WorldObject::CleanupsBeforeDelete(); + if (m_uint32Values) // only for fully created object + { + InterruptNonMeleeSpells(true); + m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList + CombatStop(); + ClearComboPointHolders(); + DeleteThreatList(); + if (GetTypeId() == TYPEID_PLAYER) + GetHostileRefManager().setOnlineOfflineState(false); + else + GetHostileRefManager().deleteReferences(); + RemoveAllAuras(AURA_REMOVE_BY_DELETE); + } + WorldObject::CleanupsBeforeDelete(); } CharmInfo* Unit::InitCharmInfo(Unit* charm) { - if (!m_charmInfo) - m_charmInfo = new CharmInfo(charm); - return m_charmInfo; + if (!m_charmInfo) + m_charmInfo = new CharmInfo(charm); + return m_charmInfo; } CharmInfo::CharmInfo(Unit* unit) - : m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0) + : m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0) { - for (int i = 0; i < CREATURE_MAX_SPELLS; ++i) - { - m_charmspells[i].SetActionAndType(0, ACT_DISABLED); - } + for (int i = 0; i < CREATURE_MAX_SPELLS; ++i) + { + m_charmspells[i].SetActionAndType(0, ACT_DISABLED); + } } void CharmInfo::InitPetActionBar() { - // the first 3 SpellOrActions are attack, follow and stay - for (uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_START - ACTION_BAR_INDEX_START; ++i) - { - SetActionBar(ACTION_BAR_INDEX_START + i, COMMAND_ATTACK - i, ACT_COMMAND); - } + // the first 3 SpellOrActions are attack, follow and stay + for (uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_START - ACTION_BAR_INDEX_START; ++i) + { + SetActionBar(ACTION_BAR_INDEX_START + i, COMMAND_ATTACK - i, ACT_COMMAND); + } - // middle 4 SpellOrActions are spells/special attacks/abilities - for (uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_END - ACTION_BAR_INDEX_PET_SPELL_START; ++i) - { - SetActionBar(ACTION_BAR_INDEX_PET_SPELL_START + i, 0, ACT_DISABLED); - } + // middle 4 SpellOrActions are spells/special attacks/abilities + for (uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_END - ACTION_BAR_INDEX_PET_SPELL_START; ++i) + { + SetActionBar(ACTION_BAR_INDEX_PET_SPELL_START + i, 0, ACT_DISABLED); + } - // last 3 SpellOrActions are reactions - for (uint32 i = 0; i < ACTION_BAR_INDEX_END - ACTION_BAR_INDEX_PET_SPELL_END; ++i) - { - SetActionBar(ACTION_BAR_INDEX_PET_SPELL_END + i, COMMAND_ATTACK - i, ACT_REACTION); - } + // last 3 SpellOrActions are reactions + for (uint32 i = 0; i < ACTION_BAR_INDEX_END - ACTION_BAR_INDEX_PET_SPELL_END; ++i) + { + SetActionBar(ACTION_BAR_INDEX_PET_SPELL_END + i, COMMAND_ATTACK - i, ACT_REACTION); + } } void CharmInfo::InitEmptyActionBar() { - for (uint32 x = ACTION_BAR_INDEX_START; x < ACTION_BAR_INDEX_END; ++x) - { - SetActionBar(x, 0, ACT_PASSIVE); - } + for (uint32 x = ACTION_BAR_INDEX_START; x < ACTION_BAR_INDEX_END; ++x) + { + SetActionBar(x, 0, ACT_PASSIVE); + } } void CharmInfo::InitVehicleCreateSpells() { - InitEmptyActionBar(); + InitEmptyActionBar(); - if (m_unit->GetTypeId() == TYPEID_PLAYER) // player vehicles don't have spells, keep the action bar empty - { - return; - } + if (m_unit->GetTypeId() == TYPEID_PLAYER) // player vehicles don't have spells, keep the action bar empty + { + return; + } - for (uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) - { - if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) - m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); - else - AddSpellToActionBar(((Creature*)m_unit)->m_spells[x], ActiveStates(0x8 + x)); - } + for (uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) + { + if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) + m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); + else + AddSpellToActionBar(((Creature*)m_unit)->m_spells[x], ActiveStates(0x8 + x)); + } } void CharmInfo::InitPossessCreateSpells() { - InitEmptyActionBar(); // charm action bar + InitEmptyActionBar(); // charm action bar - if (m_unit->GetTypeId() == TYPEID_PLAYER) // possessed players don't have spells, keep the action bar empty - { - return; - } + if (m_unit->GetTypeId() == TYPEID_PLAYER) // possessed players don't have spells, keep the action bar empty + { + return; + } - SetActionBar(ACTION_BAR_INDEX_START, COMMAND_ATTACK, ACT_COMMAND); + SetActionBar(ACTION_BAR_INDEX_START, COMMAND_ATTACK, ACT_COMMAND); - for (uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) - { - if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) - m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); - else - AddSpellToActionBar(((Creature*)m_unit)->m_spells[x], ACT_PASSIVE); - } + for (uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) + { + if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) + m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); + else + AddSpellToActionBar(((Creature*)m_unit)->m_spells[x], ACT_PASSIVE); + } } void CharmInfo::InitCharmCreateSpells() { - if (m_unit->GetTypeId() == TYPEID_PLAYER) // charmed players don't have spells - { - InitEmptyActionBar(); - return; - } - - InitPetActionBar(); - - for (uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) - { - uint32 spellId = ((Creature*)m_unit)->m_spells[x]; - - if (!spellId) - { - m_charmspells[x].SetActionAndType(spellId, ACT_DISABLED); - continue; - } - - if (IsPassiveSpell(spellId)) - { - m_unit->CastSpell(m_unit, spellId, true); - m_charmspells[x].SetActionAndType(spellId, ACT_PASSIVE); - } - else - { - m_charmspells[x].SetActionAndType(spellId, ACT_DISABLED); - - ActiveStates newstate; - bool onlyselfcast = true; - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); - - for (uint32 i = 0; i < 3 && onlyselfcast; ++i) // nonexistent spell will not make any problems as onlyselfcast would be false -> break right away - { - SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(SpellEffectIndex(i)); - if(!spellEffect) - continue; - if(spellEffect->EffectImplicitTargetA != TARGET_SELF && spellEffect->EffectImplicitTargetA != 0) - onlyselfcast = false; - } - - if (onlyselfcast || !IsPositiveSpell(spellId)) // only self cast and spells versus enemies are autocastable - newstate = ACT_DISABLED; - else - newstate = ACT_PASSIVE; - - AddSpellToActionBar(spellId, newstate); - } - } + if (m_unit->GetTypeId() == TYPEID_PLAYER) // charmed players don't have spells + { + InitEmptyActionBar(); + return; + } + + InitPetActionBar(); + + for (uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) + { + uint32 spellId = ((Creature*)m_unit)->m_spells[x]; + + if (!spellId) + { + m_charmspells[x].SetActionAndType(spellId, ACT_DISABLED); + continue; + } + + if (IsPassiveSpell(spellId)) + { + m_unit->CastSpell(m_unit, spellId, true); + m_charmspells[x].SetActionAndType(spellId, ACT_PASSIVE); + } + else + { + m_charmspells[x].SetActionAndType(spellId, ACT_DISABLED); + + ActiveStates newstate; + bool onlyselfcast = true; + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); + + for (uint32 i = 0; i < 3 && onlyselfcast; ++i) // nonexistent spell will not make any problems as onlyselfcast would be false -> break right away + { + SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if (!spellEffect) + continue; + if (spellEffect->EffectImplicitTargetA != TARGET_SELF && spellEffect->EffectImplicitTargetA != 0) + onlyselfcast = false; + } + + if (onlyselfcast || !IsPositiveSpell(spellId)) // only self cast and spells versus enemies are autocastable + newstate = ACT_DISABLED; + else + newstate = ACT_PASSIVE; + + AddSpellToActionBar(spellId, newstate); + } + } } bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate) { - uint32 first_id = sSpellMgr.GetFirstSpellInChain(spell_id); - - // new spell rank can be already listed - for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) - { - if (uint32 action = PetActionBar[i].GetAction()) - { - if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr.GetFirstSpellInChain(action) == first_id) - { - PetActionBar[i].SetAction(spell_id); - return true; - } - } - } - - // or use empty slot in other case - for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) - { - if (!PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell()) - { - SetActionBar(i, spell_id, newstate == ACT_DECIDE ? ACT_DISABLED : newstate); - return true; - } - } - return false; + uint32 first_id = sSpellMgr.GetFirstSpellInChain(spell_id); + + // new spell rank can be already listed + for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if (uint32 action = PetActionBar[i].GetAction()) + { + if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr.GetFirstSpellInChain(action) == first_id) + { + PetActionBar[i].SetAction(spell_id); + return true; + } + } + } + + // or use empty slot in other case + for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if (!PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell()) + { + SetActionBar(i, spell_id, newstate == ACT_DECIDE ? ACT_DISABLED : newstate); + return true; + } + } + return false; } bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id) { - uint32 first_id = sSpellMgr.GetFirstSpellInChain(spell_id); + uint32 first_id = sSpellMgr.GetFirstSpellInChain(spell_id); - for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) - { - if (uint32 action = PetActionBar[i].GetAction()) - { - if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr.GetFirstSpellInChain(action) == first_id) - { - SetActionBar(i, 0, ACT_DISABLED); - return true; - } - } - } + for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if (uint32 action = PetActionBar[i].GetAction()) + { + if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr.GetFirstSpellInChain(action) == first_id) + { + SetActionBar(i, 0, ACT_DISABLED); + return true; + } + } + } - return false; + return false; } void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply) { - if (IsPassiveSpell(spellid)) - { - return; - } + if (IsPassiveSpell(spellid)) + { + return; + } - for (uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) - if (spellid == m_charmspells[x].GetAction()) - m_charmspells[x].SetType(apply ? ACT_ENABLED : ACT_DISABLED); + for (uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) + if (spellid == m_charmspells[x].GetAction()) + m_charmspells[x].SetType(apply ? ACT_ENABLED : ACT_DISABLED); } void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow) { - m_petnumber = petnumber; - if (statwindow) - m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber); - else - m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0); + m_petnumber = petnumber; + if (statwindow) + m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber); + else + m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0); } void CharmInfo::LoadPetActionBar(const std::string& data) { - InitPetActionBar(); + InitPetActionBar(); - Tokens tokens = StrSplit(data, " "); + Tokens tokens = StrSplit(data, " "); - if (tokens.size() != (ACTION_BAR_INDEX_END - ACTION_BAR_INDEX_START) * 2) - return; // non critical, will reset to default + if (tokens.size() != (ACTION_BAR_INDEX_END - ACTION_BAR_INDEX_START) * 2) + return; // non critical, will reset to default - int index; - Tokens::iterator iter; - for (iter = tokens.begin(), index = ACTION_BAR_INDEX_START; index < ACTION_BAR_INDEX_END; ++iter, ++index) - { - // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion - uint8 type = (uint8)std::stoul((*iter).c_str()); - ++iter; - uint32 action = std::stoul((*iter).c_str()); + int index; + Tokens::iterator iter; + for (iter = tokens.begin(), index = ACTION_BAR_INDEX_START; index < ACTION_BAR_INDEX_END; ++iter, ++index) + { + // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion + uint8 type = (uint8)std::stoul((*iter).c_str()); + ++iter; + uint32 action = std::stoul((*iter).c_str()); - PetActionBar[index].SetActionAndType(action, ActiveStates(type)); + PetActionBar[index].SetActionAndType(action, ActiveStates(type)); - // check correctness - if (PetActionBar[index].IsActionBarForSpell() && !sSpellStore.LookupEntry(PetActionBar[index].GetAction())) - SetActionBar(index, 0, ACT_DISABLED); - } + // check correctness + if (PetActionBar[index].IsActionBarForSpell() && !sSpellStore.LookupEntry(PetActionBar[index].GetAction())) + SetActionBar(index, 0, ACT_DISABLED); + } } void CharmInfo::BuildActionBar(WorldPacket* data) { - for (uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) - { - *data << uint32(PetActionBar[i].packedData); - } + for (uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + *data << uint32(PetActionBar[i].packedData); + } } void CharmInfo::SetSpellAutocast(uint32 spell_id, bool state) { - for (int i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) - { - if (spell_id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell()) - { - PetActionBar[i].SetType(state ? ACT_ENABLED : ACT_DISABLED); - break; - } - } + for (int i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if (spell_id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell()) + { + PetActionBar[i].SetType(state ? ACT_ENABLED : ACT_DISABLED); + break; + } + } } bool Unit::IsFrozen() const { - return HasAuraState(AURA_STATE_FROZEN); + return HasAuraState(AURA_STATE_FROZEN); } struct ProcTriggeredData { - ProcTriggeredData(SpellProcEventEntry const* _spellProcEvent, SpellAuraHolder* _triggeredByHolder) - : spellProcEvent(_spellProcEvent), triggeredByHolder(_triggeredByHolder) - {} - SpellProcEventEntry const* spellProcEvent; - SpellAuraHolder* triggeredByHolder; + ProcTriggeredData(SpellProcEventEntry const* _spellProcEvent, SpellAuraHolder* _triggeredByHolder) + : spellProcEvent(_spellProcEvent), triggeredByHolder(_triggeredByHolder) + {} + SpellProcEventEntry const* spellProcEvent; + SpellAuraHolder* triggeredByHolder; }; typedef std::list< ProcTriggeredData > ProcTriggeredList; @@ -11656,1287 +11660,1287 @@ typedef std::list< uint32> RemoveSpellList; uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition) { - uint32 procEx = PROC_EX_NONE; - // Check victim state - if (missCondition != SPELL_MISS_NONE) - switch (missCondition) - { - case SPELL_MISS_MISS: procEx |= PROC_EX_MISS; break; - case SPELL_MISS_RESIST: procEx |= PROC_EX_RESIST; break; - case SPELL_MISS_DODGE: procEx |= PROC_EX_DODGE; break; - case SPELL_MISS_PARRY: procEx |= PROC_EX_PARRY; break; - case SPELL_MISS_BLOCK: procEx |= PROC_EX_BLOCK; break; - case SPELL_MISS_EVADE: procEx |= PROC_EX_EVADE; break; - case SPELL_MISS_IMMUNE: procEx |= PROC_EX_IMMUNE; break; - case SPELL_MISS_IMMUNE2: procEx |= PROC_EX_IMMUNE; break; - case SPELL_MISS_DEFLECT: procEx |= PROC_EX_DEFLECT; break; - case SPELL_MISS_ABSORB: procEx |= PROC_EX_ABSORB; break; - case SPELL_MISS_REFLECT: procEx |= PROC_EX_REFLECT; break; - default: - break; - } - else - { - // On block - if (damageInfo->blocked) - procEx |= PROC_EX_BLOCK; - // On absorb - if (damageInfo->absorb) - procEx |= PROC_EX_ABSORB; - // On crit - if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) - procEx |= PROC_EX_CRITICAL_HIT; - else - procEx |= PROC_EX_NORMAL_HIT; - } - return procEx; + uint32 procEx = PROC_EX_NONE; + // Check victim state + if (missCondition != SPELL_MISS_NONE) + switch (missCondition) + { + case SPELL_MISS_MISS: procEx |= PROC_EX_MISS; break; + case SPELL_MISS_RESIST: procEx |= PROC_EX_RESIST; break; + case SPELL_MISS_DODGE: procEx |= PROC_EX_DODGE; break; + case SPELL_MISS_PARRY: procEx |= PROC_EX_PARRY; break; + case SPELL_MISS_BLOCK: procEx |= PROC_EX_BLOCK; break; + case SPELL_MISS_EVADE: procEx |= PROC_EX_EVADE; break; + case SPELL_MISS_IMMUNE: procEx |= PROC_EX_IMMUNE; break; + case SPELL_MISS_IMMUNE2: procEx |= PROC_EX_IMMUNE; break; + case SPELL_MISS_DEFLECT: procEx |= PROC_EX_DEFLECT; break; + case SPELL_MISS_ABSORB: procEx |= PROC_EX_ABSORB; break; + case SPELL_MISS_REFLECT: procEx |= PROC_EX_REFLECT; break; + default: + break; + } + else + { + // On block + if (damageInfo->blocked) + procEx |= PROC_EX_BLOCK; + // On absorb + if (damageInfo->absorb) + procEx |= PROC_EX_ABSORB; + // On crit + if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) + procEx |= PROC_EX_CRITICAL_HIT; + else + procEx |= PROC_EX_NORMAL_HIT; + } + return procEx; } void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const* procSpell, uint32 damage) { - // For melee/ranged based attack need update skills and set some Aura states - if (!(procExtra & PROC_EX_CAST_END) && procFlag & MELEE_BASED_TRIGGER_MASK) - { - // If exist crit/parry/dodge/block need update aura state (for victim and attacker) - if (procExtra & (PROC_EX_CRITICAL_HIT | PROC_EX_PARRY | PROC_EX_DODGE | PROC_EX_BLOCK)) - { - // for victim - if (isVictim) - { - // if victim and dodge attack - if (procExtra & PROC_EX_DODGE) - { - // Update AURA_STATE on dodge - if (getClass() != CLASS_ROGUE) // skip Rogue Riposte - { - ModifyAuraState(AURA_STATE_DEFENSE, true); - StartReactiveTimer(REACTIVE_DEFENSE); - } - } - // if victim and parry attack - if (procExtra & PROC_EX_PARRY) - { - // For Hunters only Counterattack (skip Mongoose bite) - if (getClass() == CLASS_HUNTER) - { - ModifyAuraState(AURA_STATE_HUNTER_PARRY, true); - StartReactiveTimer(REACTIVE_HUNTER_PARRY); - } - else - { - ModifyAuraState(AURA_STATE_DEFENSE, true); - StartReactiveTimer(REACTIVE_DEFENSE); - } - } - // if and victim block attack - if (procExtra & PROC_EX_BLOCK) - { - ModifyAuraState(AURA_STATE_DEFENSE, true); - StartReactiveTimer(REACTIVE_DEFENSE); - } - } - else // For attacker - { - // Overpower on victim dodge - if (procExtra & PROC_EX_DODGE && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) - { - ((Player*)this)->AddComboPoints(pTarget, 1); - StartReactiveTimer(REACTIVE_OVERPOWER); - } - } - } - } - - RemoveSpellList removedSpells; - ProcTriggeredList procTriggered; - // Fill procTriggered list - for (SpellAuraHolderMap::const_iterator itr = GetSpellAuraHolderMap().begin(); itr != GetSpellAuraHolderMap().end(); ++itr) - { - // skip deleted auras (possible at recursive triggered call - if (itr->second->GetState() != SPELLAURAHOLDER_STATE_READY || itr->second->IsDeleted()) - continue; - - SpellProcEventEntry const* spellProcEvent = NULL; - // check if that aura is triggered by proc event (then it will be managed by proc handler) - if (!IsTriggeredAtSpellProcEvent(pTarget, itr->second, procSpell, procFlag, procExtra, attType, isVictim, spellProcEvent)) - { - // spell seem not managed by proc system, although some case need to be handled - - // only process damage case on victim - if (!isVictim || !(procFlag & PROC_FLAG_TAKEN_ANY_DAMAGE)) - continue; - - const SpellEntry* se = itr->second->GetSpellProto(); - - // check if the aura is interruptible by damage and if its not just added by this spell (spell who is responsible for this damage is procSpell) - if (se->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DAMAGE && (!procSpell || procSpell->Id != se->Id)) - { - DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "ProcDamageAndSpell: Added Spell %u to 'remove aura due to spell' list! Reason: Damage received.", se->Id); - removedSpells.push_back(se->Id); - } - continue; - } - - itr->second->SetInUse(true); // prevent holder deletion - procTriggered.push_back(ProcTriggeredData(spellProcEvent, itr->second)); - } - - if (!procTriggered.empty()) - { - // Handle effects proceed this time - for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr) - { - // Some auras can be deleted in function called in this loop (except first, ofc) - SpellAuraHolder* triggeredByHolder = itr->triggeredByHolder; - if (triggeredByHolder->IsDeleted()) - continue; - - SpellProcEventEntry const* spellProcEvent = itr->spellProcEvent; - bool useCharges = triggeredByHolder->GetAuraCharges() > 0; - bool procSuccess = true; - bool anyAuraProc = false; - - // For players set spell cooldown if need - uint32 cooldown = 0; - if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown) - cooldown = spellProcEvent->cooldown; - - for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) - { - Aura* triggeredByAura = triggeredByHolder->GetAuraByEffectIndex(SpellEffectIndex(i)); - if (!triggeredByAura) - continue; - - SpellEffectEntry const* spellEffect = triggeredByHolder->GetSpellProto()->GetSpellEffect(SpellEffectIndex(i)); - if (!spellEffect) - continue; - - if (procSpell) - { - if (spellProcEvent) - { - if (spellProcEvent->spellFamilyMask[i]) - { - if (!procSpell->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i])) - continue; - - // don't allow proc from cast end for non modifier spells - // unless they have proc ex defined for that - if (IsCastEndProcModifierAura(triggeredByHolder->GetSpellProto(), SpellEffectIndex(i), procSpell)) - { - if (useCharges && procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE) - continue; - } - else if (spellProcEvent->procEx == PROC_EX_NONE && procExtra == PROC_EX_CAST_END) - continue; - } - // don't check dbc FamilyFlags if schoolMask exists - else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask)) - continue; - } - else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, PROC_EX_NONE, procExtra, damage != 0, true)) - continue; - } - - SpellAuraProcResult procResult = (*this.*AuraProcHandler[spellEffect->EffectApplyAuraName])(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown); - switch (procResult) - { - case SPELL_AURA_PROC_CANT_TRIGGER: - continue; - case SPELL_AURA_PROC_FAILED: - procSuccess = false; - break; - case SPELL_AURA_PROC_OK: - break; - } - - anyAuraProc = true; - } - - // Remove charge (aura can be removed by triggers) - if (useCharges && procSuccess && anyAuraProc && !triggeredByHolder->IsDeleted()) - { - // If last charge dropped add spell to remove list - if (triggeredByHolder->DropAuraCharge()) - removedSpells.push_back(triggeredByHolder->GetId()); - } - - triggeredByHolder->SetInUse(false); - } - } - - if (!removedSpells.empty()) - { - // Sort spells and remove duplicates - removedSpells.sort(); - removedSpells.unique(); - // Remove auras from removedAuras - for (RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end(); ++i) - { - RemoveAurasDueToSpell(*i); - } - } + // For melee/ranged based attack need update skills and set some Aura states + if (!(procExtra & PROC_EX_CAST_END) && procFlag & MELEE_BASED_TRIGGER_MASK) + { + // If exist crit/parry/dodge/block need update aura state (for victim and attacker) + if (procExtra & (PROC_EX_CRITICAL_HIT | PROC_EX_PARRY | PROC_EX_DODGE | PROC_EX_BLOCK)) + { + // for victim + if (isVictim) + { + // if victim and dodge attack + if (procExtra & PROC_EX_DODGE) + { + // Update AURA_STATE on dodge + if (getClass() != CLASS_ROGUE) // skip Rogue Riposte + { + ModifyAuraState(AURA_STATE_DEFENSE, true); + StartReactiveTimer(REACTIVE_DEFENSE); + } + } + // if victim and parry attack + if (procExtra & PROC_EX_PARRY) + { + // For Hunters only Counterattack (skip Mongoose bite) + if (getClass() == CLASS_HUNTER) + { + ModifyAuraState(AURA_STATE_HUNTER_PARRY, true); + StartReactiveTimer(REACTIVE_HUNTER_PARRY); + } + else + { + ModifyAuraState(AURA_STATE_DEFENSE, true); + StartReactiveTimer(REACTIVE_DEFENSE); + } + } + // if and victim block attack + if (procExtra & PROC_EX_BLOCK) + { + ModifyAuraState(AURA_STATE_DEFENSE, true); + StartReactiveTimer(REACTIVE_DEFENSE); + } + } + else // For attacker + { + // Overpower on victim dodge + if (procExtra & PROC_EX_DODGE && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) + { + ((Player*)this)->AddComboPoints(pTarget, 1); + StartReactiveTimer(REACTIVE_OVERPOWER); + } + } + } + } + + RemoveSpellList removedSpells; + ProcTriggeredList procTriggered; + // Fill procTriggered list + for (SpellAuraHolderMap::const_iterator itr = GetSpellAuraHolderMap().begin(); itr != GetSpellAuraHolderMap().end(); ++itr) + { + // skip deleted auras (possible at recursive triggered call + if (itr->second->GetState() != SPELLAURAHOLDER_STATE_READY || itr->second->IsDeleted()) + continue; + + SpellProcEventEntry const* spellProcEvent = NULL; + // check if that aura is triggered by proc event (then it will be managed by proc handler) + if (!IsTriggeredAtSpellProcEvent(pTarget, itr->second, procSpell, procFlag, procExtra, attType, isVictim, spellProcEvent)) + { + // spell seem not managed by proc system, although some case need to be handled + + // only process damage case on victim + if (!isVictim || !(procFlag & PROC_FLAG_TAKEN_ANY_DAMAGE)) + continue; + + const SpellEntry* se = itr->second->GetSpellProto(); + + // check if the aura is interruptible by damage and if its not just added by this spell (spell who is responsible for this damage is procSpell) + if (se->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DAMAGE && (!procSpell || procSpell->Id != se->Id)) + { + DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "ProcDamageAndSpell: Added Spell %u to 'remove aura due to spell' list! Reason: Damage received.", se->Id); + removedSpells.push_back(se->Id); + } + continue; + } + + itr->second->SetInUse(true); // prevent holder deletion + procTriggered.push_back(ProcTriggeredData(spellProcEvent, itr->second)); + } + + if (!procTriggered.empty()) + { + // Handle effects proceed this time + for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr) + { + // Some auras can be deleted in function called in this loop (except first, ofc) + SpellAuraHolder* triggeredByHolder = itr->triggeredByHolder; + if (triggeredByHolder->IsDeleted()) + continue; + + SpellProcEventEntry const* spellProcEvent = itr->spellProcEvent; + bool useCharges = triggeredByHolder->GetAuraCharges() > 0; + bool procSuccess = true; + bool anyAuraProc = false; + + // For players set spell cooldown if need + uint32 cooldown = 0; + if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown) + cooldown = spellProcEvent->cooldown; + + for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) + { + Aura* triggeredByAura = triggeredByHolder->GetAuraByEffectIndex(SpellEffectIndex(i)); + if (!triggeredByAura) + continue; + + SpellEffectEntry const* spellEffect = triggeredByHolder->GetSpellProto()->GetSpellEffect(SpellEffectIndex(i)); + if (!spellEffect) + continue; + + if (procSpell) + { + if (spellProcEvent) + { + if (spellProcEvent->spellFamilyMask[i]) + { + if (!procSpell->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i])) + continue; + + // don't allow proc from cast end for non modifier spells + // unless they have proc ex defined for that + if (IsCastEndProcModifierAura(triggeredByHolder->GetSpellProto(), SpellEffectIndex(i), procSpell)) + { + if (useCharges && procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE) + continue; + } + else if (spellProcEvent->procEx == PROC_EX_NONE && procExtra == PROC_EX_CAST_END) + continue; + } + // don't check dbc FamilyFlags if schoolMask exists + else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask)) + continue; + } + else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, PROC_EX_NONE, procExtra, damage != 0, true)) + continue; + } + + SpellAuraProcResult procResult = (*this.*AuraProcHandler[spellEffect->EffectApplyAuraName])(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown); + switch (procResult) + { + case SPELL_AURA_PROC_CANT_TRIGGER: + continue; + case SPELL_AURA_PROC_FAILED: + procSuccess = false; + break; + case SPELL_AURA_PROC_OK: + break; + } + + anyAuraProc = true; + } + + // Remove charge (aura can be removed by triggers) + if (useCharges && procSuccess && anyAuraProc && !triggeredByHolder->IsDeleted()) + { + // If last charge dropped add spell to remove list + if (triggeredByHolder->DropAuraCharge()) + removedSpells.push_back(triggeredByHolder->GetId()); + } + + triggeredByHolder->SetInUse(false); + } + } + + if (!removedSpells.empty()) + { + // Sort spells and remove duplicates + removedSpells.sort(); + removedSpells.unique(); + // Remove auras from removedAuras + for (RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end(); ++i) + { + RemoveAurasDueToSpell(*i); + } + } } SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const { - return SPELL_SCHOOL_MASK_NORMAL; + return SPELL_SCHOOL_MASK_NORMAL; } Player* Unit::GetSpellModOwner() const { - if (GetTypeId() == TYPEID_PLAYER) - { - return (Player*)this; - } - if (((Creature*)this)->IsPet() || ((Creature*)this)->IsTotem()) - { - Unit* owner = GetOwner(); - if (owner && owner->GetTypeId() == TYPEID_PLAYER) - { - return (Player*)owner; - } - } - return NULL; + if (GetTypeId() == TYPEID_PLAYER) + { + return (Player*)this; + } + if (((Creature*)this)->IsPet() || ((Creature*)this)->IsTotem()) + { + Unit* owner = GetOwner(); + if (owner && owner->GetTypeId() == TYPEID_PLAYER) + { + return (Player*)owner; + } + } + return NULL; } ///----------Pet responses methods----------------- void Unit::SendPetActionFeedback(uint8 msg) { - Unit* owner = GetOwner(); - if (!owner || owner->GetTypeId() != TYPEID_PLAYER) - { - return; - } + Unit* owner = GetOwner(); + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + { + return; + } - WorldPacket data(SMSG_PET_ACTION_FEEDBACK, 1); - data << uint8(msg); - ((Player*)owner)->GetSession()->SendPacket(&data); + WorldPacket data(SMSG_PET_ACTION_FEEDBACK, 1); + data << uint8(msg); + ((Player*)owner)->GetSession()->SendPacket(&data); } void Unit::SendPetTalk(uint32 pettalk) { - Unit* owner = GetOwner(); - if (!owner || owner->GetTypeId() != TYPEID_PLAYER) - { - return; - } + Unit* owner = GetOwner(); + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + { + return; + } - WorldPacket data(SMSG_PET_ACTION_SOUND, 8 + 4); - data << GetObjectGuid(); - data << uint32(pettalk); - ((Player*)owner)->GetSession()->SendPacket(&data); + WorldPacket data(SMSG_PET_ACTION_SOUND, 8 + 4); + data << GetObjectGuid(); + data << uint32(pettalk); + ((Player*)owner)->GetSession()->SendPacket(&data); } void Unit::SendPetAIReaction() { - Unit* owner = GetOwner(); - if (!owner || owner->GetTypeId() != TYPEID_PLAYER) - { - return; - } + Unit* owner = GetOwner(); + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + { + return; + } - WorldPacket data(SMSG_AI_REACTION, 8 + 4); - data << GetObjectGuid(); - data << uint32(AI_REACTION_HOSTILE); - ((Player*)owner)->GetSession()->SendPacket(&data); + WorldPacket data(SMSG_AI_REACTION, 8 + 4); + data << GetObjectGuid(); + data << uint32(AI_REACTION_HOSTILE); + ((Player*)owner)->GetSession()->SendPacket(&data); } ///----------End of Pet responses methods---------- void Unit::StopMoving(bool forceSendStop /*=false*/) { - if (IsStopped() && !forceSendStop) - { - return; - } + if (IsStopped() && !forceSendStop) + { + return; + } - clearUnitState(UNIT_STAT_MOVING); + clearUnitState(UNIT_STAT_MOVING); - // not need send any packets if not in world - if (!IsInWorld()) - { - return; - } + // not need send any packets if not in world + if (!IsInWorld()) + { + return; + } - Movement::MoveSplineInit init(*this); - init.Stop(); + Movement::MoveSplineInit init(*this); + init.Stop(); } void Unit::InterruptMoving(bool forceSendStop /*=false*/) { - bool isMoving = false; + bool isMoving = false; - if (!movespline->Finalized()) - { - Movement::Location loc = movespline->ComputePosition(); - movespline->_Interrupt(); - Relocate(loc.x, loc.y, loc.z, loc.orientation); - isMoving = true; - } + if (!movespline->Finalized()) + { + Movement::Location loc = movespline->ComputePosition(); + movespline->_Interrupt(); + Relocate(loc.x, loc.y, loc.z, loc.orientation); + isMoving = true; + } - StopMoving(forceSendStop || isMoving); + StopMoving(forceSendStop || isMoving); } void Unit::SetFeared(bool apply, ObjectGuid casterGuid, uint32 spellID, uint32 time) { - if (apply) - { - if (HasAuraType(SPELL_AURA_PREVENTS_FLEEING)) - { - return; - } + if (apply) + { + if (HasAuraType(SPELL_AURA_PREVENTS_FLEEING)) + { + return; + } - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - GetMotionMaster()->MovementExpired(false); - CastStop(GetObjectGuid() == casterGuid ? spellID : 0); + GetMotionMaster()->MovementExpired(false); + CastStop(GetObjectGuid() == casterGuid ? spellID : 0); - Unit* caster = IsInWorld() ? GetMap()->GetUnit(casterGuid) : NULL; + Unit* caster = IsInWorld() ? GetMap()->GetUnit(casterGuid) : NULL; - GetMotionMaster()->MoveFleeing(caster, time); // caster==NULL processed in MoveFleeing - } - else - { - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); + GetMotionMaster()->MoveFleeing(caster, time); // caster==NULL processed in MoveFleeing + } + else + { + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - GetMotionMaster()->MovementExpired(false); + GetMotionMaster()->MovementExpired(false); - if (GetTypeId() != TYPEID_PLAYER && IsAlive()) - { - Creature* c = ((Creature*)this); - // restore appropriate movement generator - if (getVictim()) - GetMotionMaster()->MoveChase(getVictim()); - else - GetMotionMaster()->Initialize(); + if (GetTypeId() != TYPEID_PLAYER && IsAlive()) + { + Creature* c = ((Creature*)this); + // restore appropriate movement generator + if (getVictim()) + GetMotionMaster()->MoveChase(getVictim()); + else + GetMotionMaster()->Initialize(); - // attack caster if can - if (Unit* caster = IsInWorld() ? GetMap()->GetUnit(casterGuid) : NULL) - c->AttackedBy(caster); - } - } + // attack caster if can + if (Unit* caster = IsInWorld() ? GetMap()->GetUnit(casterGuid) : NULL) + c->AttackedBy(caster); + } + } - if (GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->SetClientControl(this, !apply); + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SetClientControl(this, !apply); } void Unit::SetConfused(bool apply, ObjectGuid casterGuid, uint32 spellID) { - if (apply) - { - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + if (apply) + { + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - CastStop(GetObjectGuid() == casterGuid ? spellID : 0); + CastStop(GetObjectGuid() == casterGuid ? spellID : 0); - GetMotionMaster()->MoveConfused(); - } - else - { - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + GetMotionMaster()->MoveConfused(); + } + else + { + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - GetMotionMaster()->MovementExpired(false); + GetMotionMaster()->MovementExpired(false); - if (GetTypeId() != TYPEID_PLAYER && IsAlive()) - { - // restore appropriate movement generator - if (getVictim()) - GetMotionMaster()->MoveChase(getVictim()); - else - GetMotionMaster()->Initialize(); - } - } + if (GetTypeId() != TYPEID_PLAYER && IsAlive()) + { + // restore appropriate movement generator + if (getVictim()) + GetMotionMaster()->MoveChase(getVictim()); + else + GetMotionMaster()->Initialize(); + } + } - if (GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->SetClientControl(this, !apply); + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SetClientControl(this, !apply); } void Unit::SetFeignDeath(bool apply, ObjectGuid casterGuid, uint32 /*spellID*/) { - if (apply) - { - /* - WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); - data<m_movementInfo.SetMovementFlags(MOVEFLAG_NONE); - - // blizz like 2.0.x - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); - // blizz like 2.0.x - SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH); - // blizz like 2.0.x - SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); - - addUnitState(UNIT_STAT_DIED); - CombatStop(); - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); - - // prevent interrupt message - if (casterGuid == GetObjectGuid()) - FinishSpell(CURRENT_GENERIC_SPELL, false); - InterruptNonMeleeSpells(true); - GetHostileRefManager().deleteReferences(); - } - else - { - /* - WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); - data<MoveChase(getVictim()); - else - GetMotionMaster()->Initialize(); - } - } + if (apply) + { + /* + WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); + data<m_movementInfo.SetMovementFlags(MOVEFLAG_NONE); + + // blizz like 2.0.x + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); + // blizz like 2.0.x + SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH); + // blizz like 2.0.x + SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); + + addUnitState(UNIT_STAT_DIED); + CombatStop(); + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + + // prevent interrupt message + if (casterGuid == GetObjectGuid()) + FinishSpell(CURRENT_GENERIC_SPELL, false); + InterruptNonMeleeSpells(true); + GetHostileRefManager().deleteReferences(); + } + else + { + /* + WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); + data<MoveChase(getVictim()); + else + GetMotionMaster()->Initialize(); + } + } } bool Unit::IsSitState() const { - uint8 s = getStandState(); - return - s == UNIT_STAND_STATE_SIT_CHAIR || s == UNIT_STAND_STATE_SIT_LOW_CHAIR || - s == UNIT_STAND_STATE_SIT_MEDIUM_CHAIR || s == UNIT_STAND_STATE_SIT_HIGH_CHAIR || - s == UNIT_STAND_STATE_SIT; + uint8 s = getStandState(); + return + s == UNIT_STAND_STATE_SIT_CHAIR || s == UNIT_STAND_STATE_SIT_LOW_CHAIR || + s == UNIT_STAND_STATE_SIT_MEDIUM_CHAIR || s == UNIT_STAND_STATE_SIT_HIGH_CHAIR || + s == UNIT_STAND_STATE_SIT; } bool Unit::IsStandState() const { - uint8 s = getStandState(); - return !IsSitState() && s != UNIT_STAND_STATE_SLEEP && s != UNIT_STAND_STATE_KNEEL; + uint8 s = getStandState(); + return !IsSitState() && s != UNIT_STAND_STATE_SLEEP && s != UNIT_STAND_STATE_KNEEL; } void Unit::SetStandState(uint8 state) { - SetByteValue(UNIT_FIELD_BYTES_1, 0, state); + SetByteValue(UNIT_FIELD_BYTES_1, 0, state); - if (IsStandState()) - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED); + if (IsStandState()) + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED); - if (GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_STANDSTATE_UPDATE, 1); - data << (uint8)state; - ((Player*)this)->GetSession()->SendPacket(&data); - } + if (GetTypeId() == TYPEID_PLAYER) + { + WorldPacket data(SMSG_STANDSTATE_UPDATE, 1); + data << (uint8)state; + ((Player*)this)->GetSession()->SendPacket(&data); + } } bool Unit::IsPolymorphed() const { - return GetSpellSpecific(getTransForm()) == SPELL_MAGE_POLYMORPH; + return GetSpellSpecific(getTransForm()) == SPELL_MAGE_POLYMORPH; } void Unit::SetDisplayId(uint32 modelId) { - SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId); + SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId); - UpdateModelData(); + UpdateModelData(); - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) - { - Pet* pet = ((Pet*)this); - if (!pet->isControlled()) - { - return; - } - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID); - } + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) + { + Pet* pet = ((Pet*)this); + if (!pet->isControlled()) + { + return; + } + Unit* owner = GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID); + } } void Unit::UpdateModelData() { - if (CreatureModelInfo const* modelInfo = sObjectMgr.GetCreatureModelInfo(GetDisplayId())) - { - // we expect values in database to be relative to Scale = 1.0 - SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, GetObjectScale() * modelInfo->bounding_radius); + if (CreatureModelInfo const* modelInfo = sObjectMgr.GetCreatureModelInfo(GetDisplayId())) + { + // we expect values in database to be relative to Scale = 1.0 + SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, GetObjectScale() * modelInfo->bounding_radius); - // never actually update combat_reach for player, it's always the same. Below player case is for initialization - if (GetTypeId() == TYPEID_PLAYER) - SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f); - else - SetFloatValue(UNIT_FIELD_COMBATREACH, GetObjectScale() * modelInfo->combat_reach); - } + // never actually update combat_reach for player, it's always the same. Below player case is for initialization + if (GetTypeId() == TYPEID_PLAYER) + SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f); + else + SetFloatValue(UNIT_FIELD_COMBATREACH, GetObjectScale() * modelInfo->combat_reach); + } } void Unit::ClearComboPointHolders() { - while (!m_ComboPointHolders.empty()) - { - uint32 lowguid = *m_ComboPointHolders.begin(); + while (!m_ComboPointHolders.empty()) + { + uint32 lowguid = *m_ComboPointHolders.begin(); - Player* plr = sObjectMgr.GetPlayer(ObjectGuid(HIGHGUID_PLAYER, lowguid)); - if (plr && plr->GetComboTargetGuid() == GetObjectGuid())// recheck for safe - plr->ClearComboPoints(); // remove also guid from m_ComboPointHolders; - else - m_ComboPointHolders.erase(lowguid); // or remove manually - } + Player* plr = sObjectMgr.GetPlayer(ObjectGuid(HIGHGUID_PLAYER, lowguid)); + if (plr && plr->GetComboTargetGuid() == GetObjectGuid())// recheck for safe + plr->ClearComboPoints(); // remove also guid from m_ComboPointHolders; + else + m_ComboPointHolders.erase(lowguid); // or remove manually + } } void Unit::ClearAllReactives() { - for (int i = 0; i < MAX_REACTIVE; ++i) - { - m_reactiveTimer[i] = 0; - } + for (int i = 0; i < MAX_REACTIVE; ++i) + { + m_reactiveTimer[i] = 0; + } - if (HasAuraState(AURA_STATE_DEFENSE)) - ModifyAuraState(AURA_STATE_DEFENSE, false); - if (getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY)) - ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); + if (HasAuraState(AURA_STATE_DEFENSE)) + ModifyAuraState(AURA_STATE_DEFENSE, false); + if (getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY)) + ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); - if (getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->ClearComboPoints(); + if (getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->ClearComboPoints(); } void Unit::UpdateReactives(uint32 p_time) { - for (int i = 0; i < MAX_REACTIVE; ++i) - { - ReactiveType reactive = ReactiveType(i); - - if (!m_reactiveTimer[reactive]) - continue; - - if (m_reactiveTimer[reactive] <= p_time) - { - m_reactiveTimer[reactive] = 0; - - switch (reactive) - { - case REACTIVE_DEFENSE: - if (HasAuraState(AURA_STATE_DEFENSE)) - ModifyAuraState(AURA_STATE_DEFENSE, false); - break; - case REACTIVE_HUNTER_PARRY: - if (getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY)) - ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); - break; - case REACTIVE_OVERPOWER: - if (getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->ClearComboPoints(); - break; - default: - break; - } - } - else - { - m_reactiveTimer[reactive] -= p_time; - } - } + for (int i = 0; i < MAX_REACTIVE; ++i) + { + ReactiveType reactive = ReactiveType(i); + + if (!m_reactiveTimer[reactive]) + continue; + + if (m_reactiveTimer[reactive] <= p_time) + { + m_reactiveTimer[reactive] = 0; + + switch (reactive) + { + case REACTIVE_DEFENSE: + if (HasAuraState(AURA_STATE_DEFENSE)) + ModifyAuraState(AURA_STATE_DEFENSE, false); + break; + case REACTIVE_HUNTER_PARRY: + if (getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY)) + ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); + break; + case REACTIVE_OVERPOWER: + if (getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->ClearComboPoints(); + break; + default: + break; + } + } + else + { + m_reactiveTimer[reactive] -= p_time; + } + } } Unit* Unit::SelectRandomUnfriendlyTarget(Unit* except /*= NULL*/, float radius /*= ATTACK_DISTANCE*/) const { - std::list targets; - - MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, radius); - MaNGOS::UnitListSearcher searcher(targets, u_check); - Cell::VisitAllObjects(this, searcher, radius); - - // remove current target - if (except) - targets.remove(except); - - // remove not LoS targets - for (std::list::iterator tIter = targets.begin(); tIter != targets.end();) - { - if (!IsWithinLOSInMap(*tIter)) - { - std::list::iterator tIter2 = tIter; - ++tIter; - targets.erase(tIter2); - } - else - ++tIter; - } - - // no appropriate targets - if (targets.empty()) - { - return NULL; - } - - // select random - uint32 rIdx = urand(0, targets.size() - 1); - std::list::const_iterator tcIter = targets.begin(); - for (uint32 i = 0; i < rIdx; ++i) - { - ++tcIter; - } - - return *tcIter; + std::list targets; + + MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, radius); + MaNGOS::UnitListSearcher searcher(targets, u_check); + Cell::VisitAllObjects(this, searcher, radius); + + // remove current target + if (except) + targets.remove(except); + + // remove not LoS targets + for (std::list::iterator tIter = targets.begin(); tIter != targets.end();) + { + if (!IsWithinLOSInMap(*tIter)) + { + std::list::iterator tIter2 = tIter; + ++tIter; + targets.erase(tIter2); + } + else + ++tIter; + } + + // no appropriate targets + if (targets.empty()) + { + return NULL; + } + + // select random + uint32 rIdx = urand(0, targets.size() - 1); + std::list::const_iterator tcIter = targets.begin(); + for (uint32 i = 0; i < rIdx; ++i) + { + ++tcIter; + } + + return *tcIter; } Unit* Unit::SelectRandomFriendlyTarget(Unit* except /*= NULL*/, float radius /*= ATTACK_DISTANCE*/) const { - std::list targets; + std::list targets; - MaNGOS::AnyFriendlyUnitInObjectRangeCheck u_check(this, radius); - MaNGOS::UnitListSearcher searcher(targets, u_check); + MaNGOS::AnyFriendlyUnitInObjectRangeCheck u_check(this, radius); + MaNGOS::UnitListSearcher searcher(targets, u_check); - Cell::VisitAllObjects(this, searcher, radius); + Cell::VisitAllObjects(this, searcher, radius); - // remove current target - if (except) - targets.remove(except); + // remove current target + if (except) + targets.remove(except); - // remove not LoS targets - for (std::list::iterator tIter = targets.begin(); tIter != targets.end();) - { - if (!IsWithinLOSInMap(*tIter)) - { - std::list::iterator tIter2 = tIter; - ++tIter; - targets.erase(tIter2); - } - else - ++tIter; - } + // remove not LoS targets + for (std::list::iterator tIter = targets.begin(); tIter != targets.end();) + { + if (!IsWithinLOSInMap(*tIter)) + { + std::list::iterator tIter2 = tIter; + ++tIter; + targets.erase(tIter2); + } + else + ++tIter; + } - // no appropriate targets - if (targets.empty()) - { - return NULL; - } + // no appropriate targets + if (targets.empty()) + { + return NULL; + } - // select random - uint32 rIdx = urand(0, targets.size() - 1); - std::list::const_iterator tcIter = targets.begin(); - for (uint32 i = 0; i < rIdx; ++i) - { - ++tcIter; - } + // select random + uint32 rIdx = urand(0, targets.size() - 1); + std::list::const_iterator tcIter = targets.begin(); + for (uint32 i = 0; i < rIdx; ++i) + { + ++tcIter; + } - return *tcIter; + return *tcIter; } bool Unit::hasNegativeAuraWithInterruptFlag(uint32 flag) { - for (SpellAuraHolderMap::const_iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end(); ++iter) - { - if (!iter->second->IsPositive() && iter->second->GetSpellProto()->GetAuraInterruptFlags() & flag) - { - return true; - } - } - return false; + for (SpellAuraHolderMap::const_iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end(); ++iter) + { + if (!iter->second->IsPositive() && iter->second->GetSpellProto()->GetAuraInterruptFlags() & flag) + { + return true; + } + } + return false; } void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply) { - if (val > 0) - { - ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply); - ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME + att, val, !apply); - } - else - { - ApplyPercentModFloatVar(m_modAttackSpeedPct[att], -val, apply); - ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME + att, -val, apply); - } + if (val > 0) + { + ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply); + ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME + att, val, !apply); + } + else + { + ApplyPercentModFloatVar(m_modAttackSpeedPct[att], -val, apply); + ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME + att, -val, apply); + } } void Unit::ApplyCastTimePercentMod(float val, bool apply) { - if (val > 0) - ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, val, !apply); - else - ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, -val, apply); + if (val > 0) + ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, val, !apply); + else + ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, -val, apply); } void Unit::UpdateAuraForGroup(uint8 slot) { - if (GetTypeId() == TYPEID_PLAYER) - { - Player* player = (Player*)this; - if (player->GetGroup()) - { - player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS); - player->SetAuraUpdateMask(slot); - } - } - else if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) - { - Pet* pet = ((Pet*)this); - if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) - { - ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS); - pet->SetAuraUpdateMask(slot); - } - } - } + if (GetTypeId() == TYPEID_PLAYER) + { + Player* player = (Player*)this; + if (player->GetGroup()) + { + player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS); + player->SetAuraUpdateMask(slot); + } + } + else if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()) + { + Pet* pet = ((Pet*)this); + if (pet->isControlled()) + { + Unit* owner = GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup()) + { + ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS); + pet->SetAuraUpdateMask(slot); + } + } + } } float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) { - if (!normalized || GetTypeId() != TYPEID_PLAYER) - { - return float(GetAttackTime(attType)) / 1000.0f; - } - - Item* Weapon = ((Player*)this)->GetWeaponForAttack(attType, true, false); - if (!Weapon) - return 2.4f; // fist attack - - switch (Weapon->GetProto()->InventoryType) - { - case INVTYPE_2HWEAPON: - return 3.3f; - case INVTYPE_RANGED: - case INVTYPE_RANGEDRIGHT: - case INVTYPE_THROWN: - return 2.8f; - case INVTYPE_WEAPON: - case INVTYPE_WEAPONMAINHAND: - case INVTYPE_WEAPONOFFHAND: - default: - return Weapon->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER ? 1.7f : 2.4f; - } + if (!normalized || GetTypeId() != TYPEID_PLAYER) + { + return float(GetAttackTime(attType)) / 1000.0f; + } + + Item* Weapon = ((Player*)this)->GetWeaponForAttack(attType, true, false); + if (!Weapon) + return 2.4f; // fist attack + + switch (Weapon->GetProto()->InventoryType) + { + case INVTYPE_2HWEAPON: + return 3.3f; + case INVTYPE_RANGED: + case INVTYPE_RANGEDRIGHT: + case INVTYPE_THROWN: + return 2.8f; + case INVTYPE_WEAPON: + case INVTYPE_WEAPONMAINHAND: + case INVTYPE_WEAPONOFFHAND: + default: + return Weapon->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER ? 1.7f : 2.4f; + } } Aura* Unit::GetDummyAura(uint32 spell_id) const { - Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); - for (Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) - if ((*itr)->GetId() == spell_id) - { - return *itr; - } + Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); + for (Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) + if ((*itr)->GetId() == spell_id) + { + return *itr; + } - return NULL; + return NULL; } void Unit::SetContestedPvP(Player* attackedPlayer) { - Player* player = GetCharmerOrOwnerPlayerOrPlayerItself(); + Player* player = GetCharmerOrOwnerPlayerOrPlayerItself(); - if (!player || (attackedPlayer && (attackedPlayer == player || player->IsInDuelWith(attackedPlayer)))) - { - return; - } + if (!player || (attackedPlayer && (attackedPlayer == player || player->IsInDuelWith(attackedPlayer)))) + { + return; + } - player->SetContestedPvPTimer(30000); + player->SetContestedPvPTimer(30000); - if (!player->hasUnitState(UNIT_STAT_ATTACK_PLAYER)) - { - player->addUnitState(UNIT_STAT_ATTACK_PLAYER); - player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP); - // call MoveInLineOfSight for nearby contested guards - UpdateVisibilityAndView(); - } + if (!player->hasUnitState(UNIT_STAT_ATTACK_PLAYER)) + { + player->addUnitState(UNIT_STAT_ATTACK_PLAYER); + player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP); + // call MoveInLineOfSight for nearby contested guards + UpdateVisibilityAndView(); + } - if (!hasUnitState(UNIT_STAT_ATTACK_PLAYER)) - { - addUnitState(UNIT_STAT_ATTACK_PLAYER); - // call MoveInLineOfSight for nearby contested guards - UpdateVisibilityAndView(); - } + if (!hasUnitState(UNIT_STAT_ATTACK_PLAYER)) + { + addUnitState(UNIT_STAT_ATTACK_PLAYER); + // call MoveInLineOfSight for nearby contested guards + UpdateVisibilityAndView(); + } } void Unit::AddPetAura(PetAura const* petSpell) { - m_petAuras.insert(petSpell); - if (Pet* pet = GetPet()) - pet->CastPetAura(petSpell); + m_petAuras.insert(petSpell); + if (Pet* pet = GetPet()) + pet->CastPetAura(petSpell); } void Unit::RemovePetAura(PetAura const* petSpell) { - m_petAuras.erase(petSpell); - if (Pet* pet = GetPet()) - pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry())); + m_petAuras.erase(petSpell); + if (Pet* pet = GetPet()) + pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry())); } void Unit::RemoveAurasAtMechanicImmunity(uint32 mechMask, uint32 exceptSpellId, bool non_positive /*= false*/) { - Unit::SpellAuraHolderMap& auras = GetSpellAuraHolderMap(); - for (Unit::SpellAuraHolderMap::iterator iter = auras.begin(); iter != auras.end();) - { - SpellEntry const* spell = iter->second->GetSpellProto(); - if (spell->Id == exceptSpellId) - ++iter; - else if (non_positive && iter->second->IsPositive()) - ++iter; - else if (spell->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)) - ++iter; - else if (iter->second->HasMechanicMask(mechMask)) - { - RemoveAurasDueToSpell(spell->Id); - - if (auras.empty()) - break; - else - iter = auras.begin(); - } - else - ++iter; - } + Unit::SpellAuraHolderMap& auras = GetSpellAuraHolderMap(); + for (Unit::SpellAuraHolderMap::iterator iter = auras.begin(); iter != auras.end();) + { + SpellEntry const* spell = iter->second->GetSpellProto(); + if (spell->Id == exceptSpellId) + ++iter; + else if (non_positive && iter->second->IsPositive()) + ++iter; + else if (spell->HasAttribute(SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)) + ++iter; + else if (iter->second->HasMechanicMask(mechMask)) + { + RemoveAurasDueToSpell(spell->Id); + + if (auras.empty()) + break; + else + iter = auras.begin(); + } + else + ++iter; + } } struct SetPhaseMaskHelper { - explicit SetPhaseMaskHelper(uint32 _phaseMask) : phaseMask(_phaseMask) {} - void operator()(Unit* unit) const { unit->SetPhaseMask(phaseMask, true); } - uint32 phaseMask; + explicit SetPhaseMaskHelper(uint32 _phaseMask) : phaseMask(_phaseMask) {} + void operator()(Unit* unit) const { unit->SetPhaseMask(phaseMask, true); } + uint32 phaseMask; }; void Unit::SetPhaseMask(uint32 newPhaseMask, bool update) { - if (newPhaseMask == GetPhaseMask()) - { - return; - } + if (newPhaseMask == GetPhaseMask()) + { + return; + } - // first move to both phase for proper update controlled units - WorldObject::SetPhaseMask(GetPhaseMask() | newPhaseMask, false); + // first move to both phase for proper update controlled units + WorldObject::SetPhaseMask(GetPhaseMask() | newPhaseMask, false); - if (IsInWorld()) - { - RemoveNotOwnTrackedTargetAuras(newPhaseMask); // we can lost access to caster or target + if (IsInWorld()) + { + RemoveNotOwnTrackedTargetAuras(newPhaseMask); // we can lost access to caster or target - // all controlled except not owned charmed units - CallForAllControlledUnits(SetPhaseMaskHelper(newPhaseMask), CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_MINIPET | CONTROLLED_TOTEMS); - } + // all controlled except not owned charmed units + CallForAllControlledUnits(SetPhaseMaskHelper(newPhaseMask), CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_MINIPET | CONTROLLED_TOTEMS); + } - WorldObject::SetPhaseMask(newPhaseMask, update); + WorldObject::SetPhaseMask(newPhaseMask, update); } void Unit::NearTeleportTo(float x, float y, float z, float orientation, bool casting /*= false*/) { - DisableSpline(); + DisableSpline(); - if (GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0)); - else - { - Creature* c = (Creature*)this; - // Creature relocation acts like instant movement generator, so current generator expects interrupt/reset calls to react properly - if (!c->GetMotionMaster()->empty()) - if (MovementGenerator* movgen = c->GetMotionMaster()->top()) - movgen->Interrupt(*c); + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0)); + else + { + Creature* c = (Creature*)this; + // Creature relocation acts like instant movement generator, so current generator expects interrupt/reset calls to react properly + if (!c->GetMotionMaster()->empty()) + if (MovementGenerator* movgen = c->GetMotionMaster()->top()) + movgen->Interrupt(*c); - GetMap()->CreatureRelocation((Creature*)this, x, y, z, orientation); + GetMap()->CreatureRelocation((Creature*)this, x, y, z, orientation); - SendHeartBeat(); + SendHeartBeat(); - // finished relocation, movegen can different from top before creature relocation, - // but apply Reset expected to be safe in any case - if (!c->GetMotionMaster()->empty()) - if (MovementGenerator* movgen = c->GetMotionMaster()->top()) - movgen->Reset(*c); - } + // finished relocation, movegen can different from top before creature relocation, + // but apply Reset expected to be safe in any case + if (!c->GetMotionMaster()->empty()) + if (MovementGenerator* movgen = c->GetMotionMaster()->top()) + movgen->Reset(*c); + } } void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination) { - Movement::MoveSplineInit init(*this); - init.MoveTo(x, y, z, generatePath, forceDestination); - init.SetVelocity(speed); - init.Launch(); + Movement::MoveSplineInit init(*this); + init.MoveTo(x, y, z, generatePath, forceDestination); + init.SetVelocity(speed); + init.Launch(); } struct SetPvPHelper { - explicit SetPvPHelper(bool _state) : state(_state) {} - void operator()(Unit* unit) const { unit->SetPvP(state); } - bool state; + explicit SetPvPHelper(bool _state) : state(_state) {} + void operator()(Unit* unit) const { unit->SetPvP(state); } + bool state; }; void Unit::SetPvP(bool state) { - if (state) - SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); - else - RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); + if (state) + SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); + else + RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); - CallForAllControlledUnits(SetPvPHelper(state), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); + CallForAllControlledUnits(SetPvPHelper(state), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); } struct SetFFAPvPHelper { - explicit SetFFAPvPHelper(bool _state) : state(_state) {} - void operator()(Unit* unit) const { unit->SetFFAPvP(state); } - bool state; + explicit SetFFAPvPHelper(bool _state) : state(_state) {} + void operator()(Unit* unit) const { unit->SetFFAPvP(state); } + bool state; }; void Unit::SetFFAPvP(bool state) { - if (state) - SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); - else - RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + if (state) + SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + else + RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); - CallForAllControlledUnits(SetFFAPvPHelper(state), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); + CallForAllControlledUnits(SetFFAPvPHelper(state), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); } void Unit::RestoreOriginalFaction() { - if (GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->setFactionForRace(getRace()); - else - { - Creature* creature = (Creature*)this; + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->setFactionForRace(getRace()); + else + { + Creature* creature = (Creature*)this; - if (creature->IsPet() || creature->IsTotem()) - { - if (Unit* owner = GetOwner()) - setFaction(owner->getFaction()); - } - else - setFaction(creature->GetCreatureInfo()->FactionAlliance); - } + if (creature->IsPet() || creature->IsTotem()) + { + if (Unit* owner = GetOwner()) + setFaction(owner->getFaction()); + } + else + setFaction(creature->GetCreatureInfo()->FactionAlliance); + } } void Unit::KnockBackFrom(Unit* target, float horizontalSpeed, float verticalSpeed) { - float angle = this == target ? GetOrientation() + M_PI_F : target->GetAngle(this); - KnockBackWithAngle(angle, horizontalSpeed, verticalSpeed); + float angle = this == target ? GetOrientation() + M_PI_F : target->GetAngle(this); + KnockBackWithAngle(angle, horizontalSpeed, verticalSpeed); } void Unit::KnockBackWithAngle(float angle, float horizontalSpeed, float verticalSpeed) { - if (GetTypeId() == TYPEID_PLAYER) - { - ((Player*)this)->GetSession()->SendKnockBack(angle, horizontalSpeed, verticalSpeed); - } - else - { - float vsin = sin(angle); - float vcos = cos(angle); - float moveTimeHalf = verticalSpeed / Movement::gravity; - float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -verticalSpeed); - - float dis = 2 * moveTimeHalf * horizontalSpeed; - float ox, oy, oz; - GetPosition(ox, oy, oz); - float fx = ox + dis * vcos; - float fy = oy + dis * vsin; - float fz = oz + 0.5f; - GetMap()->GetHitPosition(ox, oy, oz + 0.5f, fx, fy, fz, GetPhaseMask(), -0.5f); - UpdateAllowedPositionZ(fx, fy, fz); - GetMotionMaster()->MoveJump(fx, fy, fz, horizontalSpeed, max_height); - } + if (GetTypeId() == TYPEID_PLAYER) + { + ((Player*)this)->GetSession()->SendKnockBack(angle, horizontalSpeed, verticalSpeed); + } + else + { + float vsin = sin(angle); + float vcos = cos(angle); + float moveTimeHalf = verticalSpeed / Movement::gravity; + float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -verticalSpeed); + + float dis = 2 * moveTimeHalf * horizontalSpeed; + float ox, oy, oz; + GetPosition(ox, oy, oz); + float fx = ox + dis * vcos; + float fy = oy + dis * vsin; + float fz = oz + 0.5f; + GetMap()->GetHitPosition(ox, oy, oz + 0.5f, fx, fy, fz, GetPhaseMask(), -0.5f); + UpdateAllowedPositionZ(fx, fy, fz); + GetMotionMaster()->MoveJump(fx, fy, fz, horizontalSpeed, max_height); + } } float Unit::GetCombatRatingReduction(CombatRating cr) const { - if (GetTypeId() == TYPEID_PLAYER) - { - return ((Player const*)this)->GetRatingBonusValue(cr); - } - else if (((Creature const*)this)->IsPet()) - { - // Player's pet get 100% resilience from owner - if (Unit* owner = GetOwner()) - if (owner->GetTypeId() == TYPEID_PLAYER) - { - return ((Player*)owner)->GetRatingBonusValue(cr); - } - } + if (GetTypeId() == TYPEID_PLAYER) + { + return ((Player const*)this)->GetRatingBonusValue(cr); + } + else if (((Creature const*)this)->IsPet()) + { + // Player's pet get 100% resilience from owner + if (Unit* owner = GetOwner()) + if (owner->GetTypeId() == TYPEID_PLAYER) + { + return ((Player*)owner)->GetRatingBonusValue(cr); + } + } - return 0.0f; + return 0.0f; } uint32 Unit::GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const { - float percent = GetCombatRatingReduction(cr) * rate; - if (percent > cap) - percent = cap; - return uint32(percent * damage / 100.0f); + float percent = GetCombatRatingReduction(cr) * rate; + if (percent > cap) + percent = cap; + return uint32(percent * damage / 100.0f); } void Unit::SendThreatUpdate() { - ThreatList const& tlist = GetThreatManager().getThreatList(); - if (uint32 count = tlist.size()) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Send SMSG_THREAT_UPDATE Message"); - WorldPacket data(SMSG_THREAT_UPDATE, 8 + count * 8); - data << GetPackGUID(); - data << uint32(count); - for (ThreatList::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr) - { - data << (*itr)->getUnitGuid().WriteAsPacked(); - data << uint32((*itr)->getThreat()); - } - SendMessageToSet(&data, false); - } + ThreatList const& tlist = GetThreatManager().getThreatList(); + if (uint32 count = tlist.size()) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Send SMSG_THREAT_UPDATE Message"); + WorldPacket data(SMSG_THREAT_UPDATE, 8 + count * 8); + data << GetPackGUID(); + data << uint32(count); + for (ThreatList::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr) + { + data << (*itr)->getUnitGuid().WriteAsPacked(); + data << uint32((*itr)->getThreat()); + } + SendMessageToSet(&data, false); + } } void Unit::SendHighestThreatUpdate(HostileReference* pHostilReference) { - ThreatList const& tlist = GetThreatManager().getThreatList(); - if (uint32 count = tlist.size()) - { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Send SMSG_HIGHEST_THREAT_UPDATE Message"); - WorldPacket data(SMSG_HIGHEST_THREAT_UPDATE, 8 + 8 + count * 8); - data << GetPackGUID(); - data << pHostilReference->getUnitGuid().WriteAsPacked(); - data << uint32(count); - for (ThreatList::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr) - { - data << (*itr)->getUnitGuid().WriteAsPacked(); - data << uint32((*itr)->getThreat()); - } - SendMessageToSet(&data, false); - } + ThreatList const& tlist = GetThreatManager().getThreatList(); + if (uint32 count = tlist.size()) + { + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Send SMSG_HIGHEST_THREAT_UPDATE Message"); + WorldPacket data(SMSG_HIGHEST_THREAT_UPDATE, 8 + 8 + count * 8); + data << GetPackGUID(); + data << pHostilReference->getUnitGuid().WriteAsPacked(); + data << uint32(count); + for (ThreatList::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr) + { + data << (*itr)->getUnitGuid().WriteAsPacked(); + data << uint32((*itr)->getThreat()); + } + SendMessageToSet(&data, false); + } } void Unit::SendThreatClear() { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Send SMSG_THREAT_CLEAR Message"); - WorldPacket data(SMSG_THREAT_CLEAR, 8); - data << GetPackGUID(); - SendMessageToSet(&data, false); + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Send SMSG_THREAT_CLEAR Message"); + WorldPacket data(SMSG_THREAT_CLEAR, 8); + data << GetPackGUID(); + SendMessageToSet(&data, false); } void Unit::SendThreatRemove(HostileReference* pHostileReference) { - DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Send SMSG_THREAT_REMOVE Message"); - WorldPacket data(SMSG_THREAT_REMOVE, 8 + 8); - data << GetPackGUID(); - data << pHostileReference->getUnitGuid().WriteAsPacked(); - SendMessageToSet(&data, false); + DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Send SMSG_THREAT_REMOVE Message"); + WorldPacket data(SMSG_THREAT_REMOVE, 8 + 8); + data << GetPackGUID(); + data << pHostileReference->getUnitGuid().WriteAsPacked(); + SendMessageToSet(&data, false); } struct StopAttackFactionHelper { - explicit StopAttackFactionHelper(uint32 _faction_id) : faction_id(_faction_id) {} - void operator()(Unit* unit) const { unit->StopAttackFaction(faction_id); } - uint32 faction_id; + explicit StopAttackFactionHelper(uint32 _faction_id) : faction_id(_faction_id) {} + void operator()(Unit* unit) const { unit->StopAttackFaction(faction_id); } + uint32 faction_id; }; void Unit::StopAttackFaction(uint32 faction_id) { - if (Unit* victim = getVictim()) - { - if (victim->getFactionTemplateEntry()->faction == faction_id) - { - AttackStop(); - if (IsNonMeleeSpellCasted(false)) - InterruptNonMeleeSpells(false); - - // melee and ranged forced attack cancel - if (GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->SendAttackSwingCancelAttack(); - } - } - - AttackerSet const& attackers = getAttackers(); - for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();) - { - if ((*itr)->getFactionTemplateEntry()->faction == faction_id) - { - (*itr)->AttackStop(); - itr = attackers.begin(); - } - else - ++itr; - } - - GetHostileRefManager().deleteReferencesForFaction(faction_id); - - CallForAllControlledUnits(StopAttackFactionHelper(faction_id), CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); + if (Unit* victim = getVictim()) + { + if (victim->getFactionTemplateEntry()->faction == faction_id) + { + AttackStop(); + if (IsNonMeleeSpellCasted(false)) + InterruptNonMeleeSpells(false); + + // melee and ranged forced attack cancel + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SendAttackSwingCancelAttack(); + } + } + + AttackerSet const& attackers = getAttackers(); + for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();) + { + if ((*itr)->getFactionTemplateEntry()->faction == faction_id) + { + (*itr)->AttackStop(); + itr = attackers.begin(); + } + else + ++itr; + } + + GetHostileRefManager().deleteReferencesForFaction(faction_id); + + CallForAllControlledUnits(StopAttackFactionHelper(faction_id), CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); } bool Unit::IsIgnoreUnitState(SpellEntry const* spell, IgnoreUnitState ignoreState) { - Unit::AuraList const& stateAuras = GetAurasByType(SPELL_AURA_IGNORE_UNIT_STATE); - for (Unit::AuraList::const_iterator itr = stateAuras.begin(); itr != stateAuras.end(); ++itr) - { - if ((*itr)->GetModifier()->m_miscvalue == ignoreState) - { - // frozen state absent ignored for all spells - if (ignoreState == IGNORE_UNIT_TARGET_NON_FROZEN) - { - return true; - } + Unit::AuraList const& stateAuras = GetAurasByType(SPELL_AURA_IGNORE_UNIT_STATE); + for (Unit::AuraList::const_iterator itr = stateAuras.begin(); itr != stateAuras.end(); ++itr) + { + if ((*itr)->GetModifier()->m_miscvalue == ignoreState) + { + // frozen state absent ignored for all spells + if (ignoreState == IGNORE_UNIT_TARGET_NON_FROZEN) + { + return true; + } - if ((*itr)->isAffectedOnSpell(spell)) - { - return true; - } - } - } + if ((*itr)->isAffectedOnSpell(spell)) + { + return true; + } + } + } - return false; + return false; } void Unit::CleanupDeletedAuras() { - for (SpellAuraHolderList::const_iterator iter = m_deletedHolders.begin(); iter != m_deletedHolders.end(); ++iter) - { - delete *iter; - } - m_deletedHolders.clear(); + for (SpellAuraHolderList::const_iterator iter = m_deletedHolders.begin(); iter != m_deletedHolders.end(); ++iter) + { + delete *iter; + } + m_deletedHolders.clear(); - // really delete auras "deleted" while processing its ApplyModify code - for (AuraList::const_iterator itr = m_deletedAuras.begin(); itr != m_deletedAuras.end(); ++itr) - { - delete *itr; - } - m_deletedAuras.clear(); + // really delete auras "deleted" while processing its ApplyModify code + for (AuraList::const_iterator itr = m_deletedAuras.begin(); itr != m_deletedAuras.end(); ++itr) + { + delete *itr; + } + m_deletedAuras.clear(); } bool Unit::CheckAndIncreaseCastCounter() { - uint32 maxCasts = sWorld.getConfig(CONFIG_UINT32_MAX_SPELL_CASTS_IN_CHAIN); + uint32 maxCasts = sWorld.getConfig(CONFIG_UINT32_MAX_SPELL_CASTS_IN_CHAIN); - if (maxCasts && m_castCounter >= maxCasts) - { - return false; - } + if (maxCasts && m_castCounter >= maxCasts) + { + return false; + } - ++m_castCounter; - return true; + ++m_castCounter; + return true; } SpellAuraHolder* Unit::GetSpellAuraHolder(uint32 spellid) const { - SpellAuraHolderMap::const_iterator itr = m_spellAuraHolders.find(spellid); - return itr != m_spellAuraHolders.end() ? itr->second : NULL; + SpellAuraHolderMap::const_iterator itr = m_spellAuraHolders.find(spellid); + return itr != m_spellAuraHolders.end() ? itr->second : NULL; } SpellAuraHolder* Unit::GetSpellAuraHolder(uint32 spellid, ObjectGuid casterGuid) const { - SpellAuraHolderConstBounds bounds = GetSpellAuraHolderBounds(spellid); - for (SpellAuraHolderMap::const_iterator iter = bounds.first; iter != bounds.second; ++iter) - if (iter->second->GetCasterGuid() == casterGuid) - { - return iter->second; - } + SpellAuraHolderConstBounds bounds = GetSpellAuraHolderBounds(spellid); + for (SpellAuraHolderMap::const_iterator iter = bounds.first; iter != bounds.second; ++iter) + if (iter->second->GetCasterGuid() == casterGuid) + { + return iter->second; + } - return NULL; + return NULL; } bool Unit::IsAllowedDamageInArea(Unit* pVictim) const { - // can damage self anywhere - if (pVictim == this) - { - return true; - } - - // can damage own pet anywhere - if (pVictim->GetOwnerGuid() == GetObjectGuid()) - { - return true; - } - - // non player controlled unit can damage anywhere - Player const* pOwner = GetCharmerOrOwnerPlayerOrPlayerItself(); - if (!pOwner) - { - return true; - } - - // can damage non player controlled victim anywhere - Player const* vOwner = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself(); - if (!vOwner) - { - return true; - } - - // can damage opponent in duel - if (pOwner->IsInDuelWith(vOwner)) - { - return true; - } - - // can't damage player controlled unit by player controlled unit in sanctuary - AreaTableEntry const* area = GetAreaEntryByAreaID(pVictim->GetAreaId()); - if (area && area->flags & AREA_FLAG_SANCTUARY) - { - return false; - } - - return true; + // can damage self anywhere + if (pVictim == this) + { + return true; + } + + // can damage own pet anywhere + if (pVictim->GetOwnerGuid() == GetObjectGuid()) + { + return true; + } + + // non player controlled unit can damage anywhere + Player const* pOwner = GetCharmerOrOwnerPlayerOrPlayerItself(); + if (!pOwner) + { + return true; + } + + // can damage non player controlled victim anywhere + Player const* vOwner = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (!vOwner) + { + return true; + } + + // can damage opponent in duel + if (pOwner->IsInDuelWith(vOwner)) + { + return true; + } + + // can't damage player controlled unit by player controlled unit in sanctuary + AreaTableEntry const* area = GetAreaEntryByAreaID(pVictim->GetAreaId()); + if (area && area->flags & AREA_FLAG_SANCTUARY) + { + return false; + } + + return true; } class RelocationNotifyEvent : public BasicEvent { - public: - RelocationNotifyEvent(Unit& owner) : BasicEvent(), m_owner(owner) - { - m_owner._SetAINotifyScheduled(true); - } - - bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) - { - float radius = MAX_CREATURE_ATTACK_RADIUS * sWorld.getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO); - if (m_owner.GetTypeId() == TYPEID_PLAYER) - { - MaNGOS::PlayerRelocationNotifier notify((Player&)m_owner); - Cell::VisitAllObjects(&m_owner, notify, radius); - } - else // if(m_owner.GetTypeId() == TYPEID_UNIT) - { - MaNGOS::CreatureRelocationNotifier notify((Creature&)m_owner); - Cell::VisitAllObjects(&m_owner, notify, radius); - } - m_owner._SetAINotifyScheduled(false); - return true; - } - - void Abort(uint64) - { - m_owner._SetAINotifyScheduled(false); - } - - private: - Unit& m_owner; +public: + RelocationNotifyEvent(Unit& owner) : BasicEvent(), m_owner(owner) + { + m_owner._SetAINotifyScheduled(true); + } + + bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) + { + float radius = MAX_CREATURE_ATTACK_RADIUS * sWorld.getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO); + if (m_owner.GetTypeId() == TYPEID_PLAYER) + { + MaNGOS::PlayerRelocationNotifier notify((Player&)m_owner); + Cell::VisitAllObjects(&m_owner, notify, radius); + } + else // if(m_owner.GetTypeId() == TYPEID_UNIT) + { + MaNGOS::CreatureRelocationNotifier notify((Creature&)m_owner); + Cell::VisitAllObjects(&m_owner, notify, radius); + } + m_owner._SetAINotifyScheduled(false); + return true; + } + + void Abort(uint64) + { + m_owner._SetAINotifyScheduled(false); + } + +private: + Unit& m_owner; }; void Unit::ScheduleAINotify(uint32 delay) { - if (!IsAINotifyScheduled()) - m_Events.AddEvent(new RelocationNotifyEvent(*this), m_Events.CalculateTime(delay)); + if (!IsAINotifyScheduled()) + m_Events.AddEvent(new RelocationNotifyEvent(*this), m_Events.CalculateTime(delay)); } void Unit::OnRelocated() { - // switch to use G3D::Vector3 is good idea, maybe - float dx = m_last_notified_position.x - GetPositionX(); - float dy = m_last_notified_position.y - GetPositionY(); - float dz = m_last_notified_position.z - GetPositionZ(); - float distsq = dx * dx + dy * dy + dz * dz; - if (distsq > World::GetRelocationLowerLimitSq()) - { - m_last_notified_position.x = GetPositionX(); - m_last_notified_position.y = GetPositionY(); - m_last_notified_position.z = GetPositionZ(); + // switch to use G3D::Vector3 is good idea, maybe + float dx = m_last_notified_position.x - GetPositionX(); + float dy = m_last_notified_position.y - GetPositionY(); + float dz = m_last_notified_position.z - GetPositionZ(); + float distsq = dx * dx + dy * dy + dz * dz; + if (distsq > World::GetRelocationLowerLimitSq()) + { + m_last_notified_position.x = GetPositionX(); + m_last_notified_position.y = GetPositionY(); + m_last_notified_position.z = GetPositionZ(); - GetViewPoint().Call_UpdateVisibilityForOwner(); - UpdateObjectVisibility(); - } - ScheduleAINotify(World::GetRelocationAINotifyDelay()); + GetViewPoint().Call_UpdateVisibilityForOwner(); + UpdateObjectVisibility(); + } + ScheduleAINotify(World::GetRelocationAINotifyDelay()); } /* @@ -12945,458 +12949,457 @@ void Unit::OnRelocated() */ void Unit::SetVehicleId(uint32 entry, uint32 overwriteNpcEntry) { - delete m_vehicleInfo; + delete m_vehicleInfo; - if (entry) - { - VehicleEntry const* ventry = sVehicleStore.LookupEntry(entry); - MANGOS_ASSERT(ventry != NULL); + if (entry) + { + VehicleEntry const* ventry = sVehicleStore.LookupEntry(entry); + MANGOS_ASSERT(ventry != NULL); - m_vehicleInfo = new VehicleInfo(this, ventry, overwriteNpcEntry); - m_updateFlag |= UPDATEFLAG_VEHICLE; - } - else - { - m_vehicleInfo = NULL; - m_updateFlag &= ~UPDATEFLAG_VEHICLE; - } + m_vehicleInfo = new VehicleInfo(this, ventry, overwriteNpcEntry); + m_updateFlag |= UPDATEFLAG_VEHICLE; + } + else + { + m_vehicleInfo = NULL; + m_updateFlag &= ~UPDATEFLAG_VEHICLE; + } - if (GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_SET_VEHICLE_REC_ID, 16); - data << GetPackGUID(); - data << uint32(entry); - SendMessageToSet(&data, true); - } + if (GetTypeId() == TYPEID_PLAYER) + { + WorldPacket data(SMSG_SET_VEHICLE_REC_ID, 16); + data << GetPackGUID(); + data << uint32(entry); + SendMessageToSet(&data, true); + } } void Unit::UpdateSplineMovement(uint32 t_diff) { - enum - { - POSITION_UPDATE_DELAY = 400, - }; + enum + { + POSITION_UPDATE_DELAY = 400, + }; - if (movespline->Finalized()) - { - return; - } + if (movespline->Finalized()) + { + return; + } - movespline->updateState(t_diff); - bool arrived = movespline->Finalized(); + movespline->updateState(t_diff); + bool arrived = movespline->Finalized(); - if (arrived) - DisableSpline(); + if (arrived) + DisableSpline(); - m_movesplineTimer.Update(t_diff); - if (m_movesplineTimer.Passed() || arrived) - { - m_movesplineTimer.Reset(POSITION_UPDATE_DELAY); - Movement::Location loc = movespline->ComputePosition(); + m_movesplineTimer.Update(t_diff); + if (m_movesplineTimer.Passed() || arrived) + { + m_movesplineTimer.Reset(POSITION_UPDATE_DELAY); + Movement::Location loc = movespline->ComputePosition(); - if (IsBoarded()) - GetTransportInfo()->SetLocalPosition(loc.x, loc.y, loc.z, loc.orientation); - else if (GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->SetPosition(loc.x, loc.y, loc.z, loc.orientation); - else - GetMap()->CreatureRelocation((Creature*)this, loc.x, loc.y, loc.z, loc.orientation); - } + if (IsBoarded()) + GetTransportInfo()->SetLocalPosition(loc.x, loc.y, loc.z, loc.orientation); + else if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SetPosition(loc.x, loc.y, loc.z, loc.orientation); + else + GetMap()->CreatureRelocation((Creature*)this, loc.x, loc.y, loc.z, loc.orientation); + } } void Unit::DisableSpline() { - m_movementInfo.RemoveMovementFlag(MOVEFLAG_FORWARD); - movespline->_Interrupt(); + m_movementInfo.RemoveMovementFlag(MOVEFLAG_FORWARD); + movespline->_Interrupt(); } bool Unit::IsSplineEnabled() const { - return movespline->Initialized(); + return movespline->Initialized(); } bool Unit::IsInWorgenForm(bool inPermanent) const { - AuraList const& vTransformAuras = GetAurasByType(SPELL_AURA_WORGEN_TRANSFORM); - for (AuraList::const_iterator itr = vTransformAuras.begin(); itr != vTransformAuras.end(); ++itr) - if (!inPermanent || (*itr)->GetHolder()->IsPermanent()) - { - return true; - } + AuraList const& vTransformAuras = GetAurasByType(SPELL_AURA_WORGEN_TRANSFORM); + for (AuraList::const_iterator itr = vTransformAuras.begin(); itr != vTransformAuras.end(); ++itr) + if (!inPermanent || (*itr)->GetHolder()->IsPermanent()) + { + return true; + } - return false; + return false; } bool Unit::HasWorgenForm() const { - return HasAuraType(SPELL_AURA_ALLOW_WORGEN_TRANSFORM); + return HasAuraType(SPELL_AURA_ALLOW_WORGEN_TRANSFORM); } void Unit::BuildForceMoveRootPacket(WorldPacket* data, bool apply, uint32 value) { - if (apply) - { - data->Initialize(SMSG_FORCE_MOVE_ROOT, 13); - data->WriteGuidMask<2, 7, 6, 0, 5, 4, 1, 3>(GetObjectGuid()); - data->WriteGuidBytes<1, 0, 2, 5>(GetObjectGuid()); - *data << uint32(value); - data->WriteGuidBytes<3, 4, 7, 6>(GetObjectGuid()); - } - else - { - data->Initialize(SMSG_FORCE_MOVE_UNROOT, 13); - data->WriteGuidMask<0, 1, 3, 7, 5, 2, 4, 6>(GetObjectGuid()); - data->WriteGuidBytes<3, 6, 1>(GetObjectGuid()); - *data << uint32(value); - data->WriteGuidBytes<2, 0, 7, 4, 5>(GetObjectGuid()); - } + if (apply) + { + data->Initialize(SMSG_FORCE_MOVE_ROOT, 13); + data->WriteGuidMask<2, 7, 6, 0, 5, 4, 1, 3>(GetObjectGuid()); + data->WriteGuidBytes<1, 0, 2, 5>(GetObjectGuid()); + *data << uint32(value); + data->WriteGuidBytes<3, 4, 7, 6>(GetObjectGuid()); + } + else + { + data->Initialize(SMSG_FORCE_MOVE_UNROOT, 13); + data->WriteGuidMask<0, 1, 3, 7, 5, 2, 4, 6>(GetObjectGuid()); + data->WriteGuidBytes<3, 6, 1>(GetObjectGuid()); + *data << uint32(value); + data->WriteGuidBytes<2, 0, 7, 4, 5>(GetObjectGuid()); + } } void Unit::BuildMoveSetCanFlyPacket(WorldPacket* data, bool apply, uint32 value) { - if (apply) - { - data->Initialize(SMSG_MOVE_SET_CAN_FLY, 13); - data->WriteGuidMask<1, 6, 5, 0, 7, 4, 2, 3>(GetObjectGuid()); - data->WriteGuidBytes<6, 3>(GetObjectGuid()); - *data << uint32(value); - data->WriteGuidBytes<2, 1, 4, 7, 0, 5>(GetObjectGuid()); - } - else - { - data->Initialize(SMSG_MOVE_UNSET_CAN_FLY, 13); - data->WriteGuidMask<1, 4, 2, 5, 0, 3, 6, 7>(GetObjectGuid()); - data->WriteGuidBytes<4, 6>(GetObjectGuid()); - *data << uint32(value); - data->WriteGuidBytes<1, 0, 2, 3, 5, 7>(GetObjectGuid()); - } + if (apply) + { + data->Initialize(SMSG_MOVE_SET_CAN_FLY, 13); + data->WriteGuidMask<1, 6, 5, 0, 7, 4, 2, 3>(GetObjectGuid()); + data->WriteGuidBytes<6, 3>(GetObjectGuid()); + *data << uint32(value); + data->WriteGuidBytes<2, 1, 4, 7, 0, 5>(GetObjectGuid()); + } + else + { + data->Initialize(SMSG_MOVE_UNSET_CAN_FLY, 13); + data->WriteGuidMask<1, 4, 2, 5, 0, 3, 6, 7>(GetObjectGuid()); + data->WriteGuidBytes<4, 6>(GetObjectGuid()); + *data << uint32(value); + data->WriteGuidBytes<1, 0, 2, 3, 5, 7>(GetObjectGuid()); + } } void Unit::BuildSendPlayVisualPacket(WorldPacket* data, uint32 value, bool impact) { - data->Initialize(SMSG_PLAY_SPELL_VISUAL, 21); - *data << uint32(0); // unk, seems always 0 - *data << uint32(value); - *data << uint32(impact ? 1 : 0); + data->Initialize(SMSG_PLAY_SPELL_VISUAL, 21); + *data << uint32(0); // unk, seems always 0 + *data << uint32(value); + *data << uint32(impact ? 1 : 0); - data->WriteGuidMask<4, 7, 5, 3, 1, 2, 0, 6>(GetObjectGuid()); - data->WriteGuidBytes<0, 4, 1, 6, 7, 2, 3, 5>(GetObjectGuid()); + data->WriteGuidMask<4, 7, 5, 3, 1, 2, 0, 6>(GetObjectGuid()); + data->WriteGuidBytes<0, 4, 1, 6, 7, 2, 3, 5>(GetObjectGuid()); } void Unit::BuildMoveWaterWalkPacket(WorldPacket* data, bool apply, uint32 value) { - if (apply) - { - data->Initialize(SMSG_MOVE_WATER_WALK, 13); - data->WriteGuidMask<4, 7, 6, 0, 1, 3, 5, 2>(GetObjectGuid()); - data->WriteGuidBytes<0, 5, 2>(GetObjectGuid()); - *data << uint32(value); - data->WriteGuidBytes<7, 3, 4, 1, 6>(GetObjectGuid()); - } - else - { - data->Initialize(SMSG_MOVE_LAND_WALK, 13); - data->WriteGuidMask<5, 1, 6, 2, 3, 4, 0, 7>(GetObjectGuid()); - data->WriteGuidBytes<6, 1, 7, 5, 4, 0, 3, 2>(GetObjectGuid()); - *data << uint32(value); - } + if (apply) + { + data->Initialize(SMSG_MOVE_WATER_WALK, 13); + data->WriteGuidMask<4, 7, 6, 0, 1, 3, 5, 2>(GetObjectGuid()); + data->WriteGuidBytes<0, 5, 2>(GetObjectGuid()); + *data << uint32(value); + data->WriteGuidBytes<7, 3, 4, 1, 6>(GetObjectGuid()); + } + else + { + data->Initialize(SMSG_MOVE_LAND_WALK, 13); + data->WriteGuidMask<5, 1, 6, 2, 3, 4, 0, 7>(GetObjectGuid()); + data->WriteGuidBytes<6, 1, 7, 5, 4, 0, 3, 2>(GetObjectGuid()); + *data << uint32(value); + } } void Unit::BuildMoveFeatherFallPacket(WorldPacket* data, bool apply, uint32 value) { - ObjectGuid guid = GetObjectGuid(); - - if (apply) - { - data->Initialize(SMSG_MOVE_FEATHER_FALL, 1 + 4 + 8); - data->WriteGuidMask<3, 1, 7, 0, 4, 2, 5, 6>(guid); - data->WriteGuidBytes<5, 7, 2>(guid); - *data << uint32(value); - data->WriteGuidBytes<0, 3, 4, 1, 6>(guid); - } - else - { - data->Initialize(SMSG_MOVE_NORMAL_FALL, 1 + 4 + 8); - *data << uint32(value); - data->WriteGuidMask<3, 0, 1, 5, 7, 4, 6, 2>(guid); - data->WriteGuidBytes<2, 7, 1, 4, 5, 0, 3, 6>(guid); - } + ObjectGuid guid = GetObjectGuid(); + + if (apply) + { + data->Initialize(SMSG_MOVE_FEATHER_FALL, 1 + 4 + 8); + data->WriteGuidMask<3, 1, 7, 0, 4, 2, 5, 6>(guid); + data->WriteGuidBytes<5, 7, 2>(guid); + *data << uint32(value); + data->WriteGuidBytes<0, 3, 4, 1, 6>(guid); + } + else + { + data->Initialize(SMSG_MOVE_NORMAL_FALL, 1 + 4 + 8); + *data << uint32(value); + data->WriteGuidMask<3, 0, 1, 5, 7, 4, 6, 2>(guid); + data->WriteGuidBytes<2, 7, 1, 4, 5, 0, 3, 6>(guid); + } } void Unit::BuildMoveHoverPacket(WorldPacket* data, bool apply, uint32 value) { - ObjectGuid guid = GetObjectGuid(); + ObjectGuid guid = GetObjectGuid(); - if (apply) - { - data->Initialize(SMSG_MOVE_SET_HOVER, 8 + 4 + 1); - data->WriteGuidMask<1, 4, 2, 3, 0, 5, 6, 7>(guid); - data->WriteGuidBytes<5, 4, 1, 2, 3, 6, 0, 7>(guid); - *data << uint32(0); - } - else - { - data->Initialize(SMSG_MOVE_UNSET_HOVER, 8 + 4 + 1); - data->WriteGuidMask<4, 6, 3, 1, 2, 7, 5, 0>(guid); - data->WriteGuidBytes<4, 5, 3, 6, 7, 1, 2, 0>(guid); - *data << uint32(0); - } + if (apply) + { + data->Initialize(SMSG_MOVE_SET_HOVER, 8 + 4 + 1); + data->WriteGuidMask<1, 4, 2, 3, 0, 5, 6, 7>(guid); + data->WriteGuidBytes<5, 4, 1, 2, 3, 6, 0, 7>(guid); + *data << uint32(0); + } + else + { + data->Initialize(SMSG_MOVE_UNSET_HOVER, 8 + 4 + 1); + data->WriteGuidMask<4, 6, 3, 1, 2, 7, 5, 0>(guid); + data->WriteGuidBytes<4, 5, 3, 6, 7, 1, 2, 0>(guid); + *data << uint32(0); + } } void Unit::BuildMoveLevitatePacket(WorldPacket* data, bool apply, uint32 value) { - ObjectGuid guid = GetObjectGuid(); - - if (apply) - { - data->Initialize(SMSG_MOVE_GRAVITY_ENABLE); - data->WriteGuidMask<1, 4, 7, 5, 2, 0, 3, 6>(GetObjectGuid()); - data->WriteGuidBytes<3>(GetObjectGuid()); - *data << uint32(value); - data->WriteGuidBytes<7, 6, 4, 0, 1, 5, 2>(GetObjectGuid()); - } - else - { - data->Initialize(SMSG_MOVE_GRAVITY_DISABLE); - data->WriteGuidMask<0, 1, 5, 7, 6, 4, 3, 2>(GetObjectGuid()); - data->WriteGuidBytes<7, 2, 0>(GetObjectGuid()); - *data << uint32(value); - data->WriteGuidBytes<5, 1, 3, 4, 6>(GetObjectGuid()); - } + ObjectGuid guid = GetObjectGuid(); + + if (apply) + { + data->Initialize(SMSG_MOVE_GRAVITY_ENABLE); + data->WriteGuidMask<1, 4, 7, 5, 2, 0, 3, 6>(GetObjectGuid()); + data->WriteGuidBytes<3>(GetObjectGuid()); + *data << uint32(value); + data->WriteGuidBytes<7, 6, 4, 0, 1, 5, 2>(GetObjectGuid()); + } + else + { + data->Initialize(SMSG_MOVE_GRAVITY_DISABLE); + data->WriteGuidMask<0, 1, 5, 7, 6, 4, 3, 2>(GetObjectGuid()); + data->WriteGuidBytes<7, 2, 0>(GetObjectGuid()); + *data << uint32(value); + data->WriteGuidBytes<5, 1, 3, 4, 6>(GetObjectGuid()); + } } void Unit::SendCollisionHeightUpdate(float height) { - if (GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_MOVE_SET_COLLISION_HGT, GetPackGUID().size() + 4 + 4); - data.WriteGuidMask<6, 1, 4, 7, 5, 2, 0, 3>(GetObjectGuid()); - data.WriteGuidBytes<6, 0, 4, 3, 5>(GetObjectGuid()); - data << uint32(sWorld.GetGameTime()); // Packet counter - data.WriteGuidBytes<1, 2, 7>(GetObjectGuid()); - data << ((Player*)this)->GetCollisionHeight(true); - ((Player*)this)->GetSession()->SendPacket(&data); - } + if (GetTypeId() == TYPEID_PLAYER) + { + WorldPacket data(SMSG_MOVE_SET_COLLISION_HGT, GetPackGUID().size() + 4 + 4); + data.WriteGuidMask<6, 1, 4, 7, 5, 2, 0, 3>(GetObjectGuid()); + data.WriteGuidBytes<6, 0, 4, 3, 5>(GetObjectGuid()); + data << uint32(sWorld.GetGameTime()); // Packet counter + data.WriteGuidBytes<1, 2, 7>(GetObjectGuid()); + data << ((Player*)this)->GetCollisionHeight(true); + ((Player*)this)->GetSession()->SendPacket(&data); + } } // This will create a new creature and set the current unit as the controller of that new creature Unit* Unit::TakePossessOf(SpellEntry const* spellEntry, SummonPropertiesEntry const* summonProp, SpellEffectEntry const* spellEffect, float x, float y, float z, float ang) { - int32 const& creatureEntry = spellEffect->EffectMiscValue; - CreatureInfo const* cinfo = ObjectMgr::GetCreatureTemplate(creatureEntry); - if (!cinfo) - { - sLog.outErrorDb("WorldObject::SummonCreature: Creature (Entry: %u) not existed for summoner: %s. ", creatureEntry, GetGuidStr().c_str()); - return NULL; - } - - if (GetCharm()) - { - sLog.outError("Unit::TakePossessOf> There is already a charmed creature for %s its : %s. ", GetGuidStr().c_str(), GetCharm()->GetGuidStr().c_str()); - return NULL; - } - - TemporarySummon* pCreature = new TemporarySummon(GetObjectGuid()); - - CreatureCreatePos pos(GetMap(), x, y, z, ang, GetPhaseMask()); - - if (x == 0.0f && y == 0.0f && z == 0.0f) - pos = CreatureCreatePos(this, GetOrientation(), CONTACT_DISTANCE, ang); - - if (!pCreature->Create(GetMap()->GenerateLocalLowGuid(cinfo->GetHighGuid()), pos, cinfo)) - { - delete pCreature; - return NULL; - } - - Player* player = GetTypeId() == TYPEID_PLAYER ? static_cast(this): NULL; - - pCreature->setFaction(getFaction()); // set same faction than player - pCreature->SetRespawnCoord(pos); // set spawn coord - pCreature->SetCharmerGuid(GetObjectGuid()); // save guid of the charmer - pCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellEntry->Id); // set the spell id used to create this (may be used for removing corresponding aura - pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); // set flag for client that mean this unit is controlled by a player - pCreature->addUnitState(UNIT_STAT_CONTROLLED); // also set internal unit state flag - pCreature->SelectLevel(getLevel()); // set level to same level than summoner TODO:: not sure its always the case... - pCreature->SetLinkedToOwnerAura(TEMPSUMMON_LINKED_AURA_OWNER_CHECK | TEMPSUMMON_LINKED_AURA_REMOVE_OWNER); // set what to do if linked aura is removed or the creature is dead. - pCreature->SetWalk(IsWalking(), true); // sync the walking state with the summoner - - // important before adding to the map! - SetCharmGuid(pCreature->GetObjectGuid()); // save guid of charmed creature - - pCreature->SetSummonProperties(TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); // set 5s corpse decay - GetMap()->Add(static_cast(pCreature)); // create the creature in the client - - // Give the control to the player - if (player) - { - player->GetCamera().SetView(pCreature); // modify camera view to the creature view - player->SetClientControl(pCreature, 1); // transfer client control to the creature - player->SetMover(pCreature); // set mover so now we know that creature is "moved" by this unit - player->SendForcedObjectUpdate(); // we have to update client data here to avoid problem with the "release spirit" windows reappear. - } - - // initialize AI - pCreature->AIM_Initialize(); - - if (player) - { - // Initialize pet bar - if (CharmInfo* charmInfo = pCreature->InitCharmInfo(pCreature)) - charmInfo->InitPossessCreateSpells(); - player->PossessSpellInitialize(); - } - else - { - // fire just summoned hook - if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) - ((Creature*)this)->AI()->JustSummoned(pCreature); - } - - // Creature Linking, Initial load is handled like respawn - if (pCreature->IsLinkingEventTrigger()) - GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_RESPAWN, pCreature); - - // return the creature therewith the summoner has access to it - return pCreature; + int32 const& creatureEntry = spellEffect->EffectMiscValue; + CreatureInfo const* cinfo = ObjectMgr::GetCreatureTemplate(creatureEntry); + if (!cinfo) + { + sLog.outErrorDb("WorldObject::SummonCreature: Creature (Entry: %u) not existed for summoner: %s. ", creatureEntry, GetGuidStr().c_str()); + return NULL; + } + + if (GetCharm()) + { + sLog.outError("Unit::TakePossessOf> There is already a charmed creature for %s its : %s. ", GetGuidStr().c_str(), GetCharm()->GetGuidStr().c_str()); + return NULL; + } + + TemporarySummon* pCreature = new TemporarySummon(GetObjectGuid()); + + CreatureCreatePos pos(GetMap(), x, y, z, ang, GetPhaseMask()); + + if (x == 0.0f && y == 0.0f && z == 0.0f) + pos = CreatureCreatePos(this, GetOrientation(), CONTACT_DISTANCE, ang); + + if (!pCreature->Create(GetMap()->GenerateLocalLowGuid(cinfo->GetHighGuid()), pos, cinfo)) + { + delete pCreature; + return NULL; + } + + Player* player = GetTypeId() == TYPEID_PLAYER ? static_cast(this) : NULL; + + pCreature->setFaction(getFaction()); // set same faction than player + pCreature->SetRespawnCoord(pos); // set spawn coord + pCreature->SetCharmerGuid(GetObjectGuid()); // save guid of the charmer + pCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellEntry->Id); // set the spell id used to create this (may be used for removing corresponding aura + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); // set flag for client that mean this unit is controlled by a player + pCreature->addUnitState(UNIT_STAT_CONTROLLED); // also set internal unit state flag + pCreature->SelectLevel(getLevel()); // set level to same level than summoner TODO:: not sure its always the case... + pCreature->SetLinkedToOwnerAura(TEMPSUMMON_LINKED_AURA_OWNER_CHECK | TEMPSUMMON_LINKED_AURA_REMOVE_OWNER); // set what to do if linked aura is removed or the creature is dead. + pCreature->SetWalk(IsWalking(), true); // sync the walking state with the summoner + + // important before adding to the map! + SetCharmGuid(pCreature->GetObjectGuid()); // save guid of charmed creature + + pCreature->SetSummonProperties(TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); // set 5s corpse decay + GetMap()->Add(static_cast(pCreature)); // create the creature in the client + + // Give the control to the player + if (player) + { + player->GetCamera().SetView(pCreature); // modify camera view to the creature view + player->SetClientControl(pCreature, 1); // transfer client control to the creature + player->SetMover(pCreature); // set mover so now we know that creature is "moved" by this unit + player->SendForcedObjectUpdate(); // we have to update client data here to avoid problem with the "release spirit" windows reappear. + } + + // initialize AI + pCreature->AIM_Initialize(); + + if (player) + { + // Initialize pet bar + if (CharmInfo* charmInfo = pCreature->InitCharmInfo(pCreature)) + charmInfo->InitPossessCreateSpells(); + player->PossessSpellInitialize(); + } + else + { + // fire just summoned hook + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) + ((Creature*)this)->AI()->JustSummoned(pCreature); + } + + // Creature Linking, Initial load is handled like respawn + if (pCreature->IsLinkingEventTrigger()) + GetMap()->GetCreatureLinkingHolder()->DoCreatureLinkingEvent(LINKING_EVENT_RESPAWN, pCreature); + + // return the creature therewith the summoner has access to it + return pCreature; } bool Unit::TakePossessOf(Unit* possessed) { - Player* player = NULL; - if (GetTypeId() == TYPEID_PLAYER) - player = static_cast(this); - - possessed->addUnitState(UNIT_STAT_CONTROLLED); - possessed->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); - possessed->SetCharmerGuid(GetObjectGuid()); - possessed->setFaction(getFaction()); - - SetCharm(possessed); - - Creature* possessedCreature = NULL; - if (possessed->GetTypeId() == TYPEID_UNIT) - possessedCreature = static_cast(possessed); - - if (player) - { - player->GetCamera().SetView(possessed); - player->SetClientControl(possessed, 1); - player->SetMover(possessed); - player->SendForcedObjectUpdate(); - - if (possessedCreature && possessedCreature->IsPet() && possessedCreature->GetObjectGuid() == GetPetGuid()) - { - possessed->StopMoving(); - possessed->GetMotionMaster()->Clear(false); - possessed->GetMotionMaster()->MoveIdle(); - return true; - } - else if (CharmInfo* charmInfo = possessed->InitCharmInfo(possessed)) - { - charmInfo->InitPossessCreateSpells(); - charmInfo->SetReactState(REACT_PASSIVE); - charmInfo->SetCommandState(COMMAND_STAY); - } - player->PossessSpellInitialize(); - } - - possessed->CombatStop(true); - possessed->DeleteThreatList(); - possessed->GetHostileRefManager().deleteReferences(); - - if (possessedCreature) - { - possessedCreature->AIM_Initialize(); - } - else if (possessed->GetTypeId() == TYPEID_PLAYER) - { - static_cast(possessed)->SetClientControl(possessed, 0); - } - return true; + Player* player = NULL; + if (GetTypeId() == TYPEID_PLAYER) + player = static_cast(this); + + possessed->addUnitState(UNIT_STAT_CONTROLLED); + possessed->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); + possessed->SetCharmerGuid(GetObjectGuid()); + possessed->setFaction(getFaction()); + + SetCharm(possessed); + + Creature* possessedCreature = NULL; + if (possessed->GetTypeId() == TYPEID_UNIT) + possessedCreature = static_cast(possessed); + + if (player) + { + player->GetCamera().SetView(possessed); + player->SetClientControl(possessed, 1); + player->SetMover(possessed); + player->SendForcedObjectUpdate(); + + if (possessedCreature && possessedCreature->IsPet() && possessedCreature->GetObjectGuid() == GetPetGuid()) + { + possessed->StopMoving(); + possessed->GetMotionMaster()->Clear(false); + possessed->GetMotionMaster()->MoveIdle(); + return true; + } + else if (CharmInfo* charmInfo = possessed->InitCharmInfo(possessed)) + { + charmInfo->InitPossessCreateSpells(); + charmInfo->SetReactState(REACT_PASSIVE); + charmInfo->SetCommandState(COMMAND_STAY); + } + player->PossessSpellInitialize(); + } + + possessed->CombatStop(true); + possessed->DeleteThreatList(); + possessed->GetHostileRefManager().deleteReferences(); + + if (possessedCreature) + { + possessedCreature->AIM_Initialize(); + } + else if (possessed->GetTypeId() == TYPEID_PLAYER) + { + static_cast(possessed)->SetClientControl(possessed, 0); + } + return true; } void Unit::ResetControlState(bool attackCharmer /*= true*/) { - Player* player = NULL; - if (GetTypeId() == TYPEID_PLAYER) - player = static_cast(this); - - Unit* possessed = GetCharm(); - - if (!possessed) - { - if (player) - { - player->GetCamera().ResetView(); - player->SetClientControl(player, 1); - player->SetMover(NULL); - } - return; - } - - Creature* possessedCreature = static_cast(possessed); - - possessed->clearUnitState(UNIT_STAT_CONTROLLED); - possessed->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); - possessed->SetCharmerGuid(ObjectGuid()); - SetCharmGuid(ObjectGuid()); - - if (player) - { - player->SetClientControl(possessed, 0); - player->SetMover(NULL); - player->GetCamera().ResetView(); - - if (possessedCreature->IsPet() && possessedCreature->GetObjectGuid() == GetPetGuid()) - { - // out of range pet dismissed - if (!possessedCreature->IsWithinDistInMap(this, possessedCreature->GetMap()->GetVisibilityDistance())) - { - player->RemovePet(PET_SAVE_REAGENTS); - } - else - { - possessedCreature->GetMotionMaster()->MoveFollow(this, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - } - - return; - } - else - player->RemovePetActionBar(); - } - - possessed->CombatStop(true); - possessed->DeleteThreatList(); - possessed->GetHostileRefManager().deleteReferences(); - - if (possessed->GetTypeId() == TYPEID_PLAYER) - { - Player* possessedPlayer = static_cast(possessed); - possessedPlayer->setFactionForRace(possessedPlayer->getRace()); - possessedPlayer->SetClientControl(possessedPlayer, 1); - } - else if (possessedCreature) - { - if (possessedCreature->IsPet() && possessedCreature->GetObjectGuid() == GetPetGuid()) - { - // out of range pet dismissed - if (!possessedCreature->IsWithinDistInMap(this, possessedCreature->GetMap()->GetVisibilityDistance())) - { - player->RemovePet(PET_SAVE_REAGENTS); - } - else - { - possessedCreature->GetMotionMaster()->MoveFollow(this, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - } - } - else if (attackCharmer) - { - CreatureInfo const* cinfo = possessedCreature->GetCreatureInfo(); - possessedCreature->setFaction(cinfo->FactionAlliance); - possessedCreature->AIM_Initialize(); - possessedCreature->AttackedBy(this); - } - } + Player* player = NULL; + if (GetTypeId() == TYPEID_PLAYER) + player = static_cast(this); + + Unit* possessed = GetCharm(); + + if (!possessed) + { + if (player) + { + player->GetCamera().ResetView(); + player->SetClientControl(player, 1); + player->SetMover(NULL); + } + return; + } + + Creature* possessedCreature = static_cast(possessed); + + possessed->clearUnitState(UNIT_STAT_CONTROLLED); + possessed->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); + possessed->SetCharmerGuid(ObjectGuid()); + SetCharmGuid(ObjectGuid()); + + if (player) + { + player->SetClientControl(possessed, 0); + player->SetMover(NULL); + player->GetCamera().ResetView(); + + if (possessedCreature->IsPet() && possessedCreature->GetObjectGuid() == GetPetGuid()) + { + // out of range pet dismissed + if (!possessedCreature->IsWithinDistInMap(this, possessedCreature->GetMap()->GetVisibilityDistance())) + { + player->RemovePet(PET_SAVE_REAGENTS); + } + else + { + possessedCreature->GetMotionMaster()->MoveFollow(this, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + } + + return; + } + else + player->RemovePetActionBar(); + } + + possessed->CombatStop(true); + possessed->DeleteThreatList(); + possessed->GetHostileRefManager().deleteReferences(); + + if (possessed->GetTypeId() == TYPEID_PLAYER) + { + Player* possessedPlayer = static_cast(possessed); + possessedPlayer->setFactionForRace(possessedPlayer->getRace()); + possessedPlayer->SetClientControl(possessedPlayer, 1); + } + else if (possessedCreature) + { + if (possessedCreature->IsPet() && possessedCreature->GetObjectGuid() == GetPetGuid()) + { + // out of range pet dismissed + if (!possessedCreature->IsWithinDistInMap(this, possessedCreature->GetMap()->GetVisibilityDistance())) + { + player->RemovePet(PET_SAVE_REAGENTS); + } + else + { + possessedCreature->GetMotionMaster()->MoveFollow(this, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + } + } + else if (attackCharmer) + { + CreatureInfo const* cinfo = possessedCreature->GetCreatureInfo(); + possessedCreature->setFaction(cinfo->FactionAlliance); + possessedCreature->AIM_Initialize(); + possessedCreature->AttackedBy(this); + } + } } - diff --git a/src/game/Server/DBCStructure.h b/src/game/Server/DBCStructure.h index 44b53a09b..44da63479 100644 --- a/src/game/Server/DBCStructure.h +++ b/src/game/Server/DBCStructure.h @@ -37,9 +37,9 @@ #include "DB2Structure.h" -// Structures using to access raw DBC data and required packing to portability + // Structures using to access raw DBC data and required packing to portability -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform + // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform #if defined( __GNUC__ ) #pragma pack(1) #else @@ -50,1054 +50,1054 @@ typedef char const* const* DBCString; //char* DBCStrings[M struct AchievementEntry { - uint32 ID; // 0 m_ID - uint32 factionFlag; // 1 m_faction -1=all, 0=horde, 1=alliance - uint32 mapID; // 2 m_instance_id -1=none - uint32 parentAchievement; // 3 m_supercedes its Achievement parent (can`t start while parent uncomplete, use its Criteria if don`t have own, use its progress on begin) - DBCString name; // 4 m_title_lang - DBCString description; // 5 m_description_lang - uint32 categoryId; // 6 m_category - uint32 points; // 7 m_points - uint32 OrderInCategory; // 8 m_ui_order - uint32 flags; // 9 m_flags - uint32 icon; // 10 m_iconID - DBCString titleReward; // 11 m_reward_lang - uint32 count; // 12 m_minimum_criteria - need this count of completed criterias (own or referenced achievement criterias) - uint32 refAchievement; // 13 m_shares_criteria - referenced achievement (counting of all completed criterias) - // 14 5.x + uint32 ID; // 0 m_ID + uint32 factionFlag; // 1 m_faction -1=all, 0=horde, 1=alliance + uint32 mapID; // 2 m_instance_id -1=none + uint32 parentAchievement; // 3 m_supercedes its Achievement parent (can`t start while parent uncomplete, use its Criteria if don`t have own, use its progress on begin) + DBCString name; // 4 m_title_lang + DBCString description; // 5 m_description_lang + uint32 categoryId; // 6 m_category + uint32 points; // 7 m_points + uint32 OrderInCategory; // 8 m_ui_order + uint32 flags; // 9 m_flags + uint32 icon; // 10 m_iconID + DBCString titleReward; // 11 m_reward_lang + uint32 count; // 12 m_minimum_criteria - need this count of completed criterias (own or referenced achievement criterias) + uint32 refAchievement; // 13 m_shares_criteria - referenced achievement (counting of all completed criterias) + // 14 5.x }; struct AchievementCategoryEntry { - uint32 ID; // 0 m_ID - uint32 parentCategory; // 1 m_parent -1 for main category - DBCString name; // 2 m_name_lang - uint32 sortOrder; // 3 m_ui_order + uint32 ID; // 0 m_ID + uint32 parentCategory; // 1 m_parent -1 for main category + DBCString name; // 2 m_name_lang + uint32 sortOrder; // 3 m_ui_order }; struct AchievementCriteriaEntry { - uint32 ID; // 0 m_ID - uint32 referredAchievement; // 1 m_achievement_id - uint32 requiredType; // 2 m_type - union - { - // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0 - // TODO: also used for player deaths.. - struct - { - uint32 creatureID; // 3 - uint32 creatureCount; // 4 - } kill_creature; - - // ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1 - struct - { - uint32 bgMapID; // 3 - uint32 winCount; // 4 - uint32 additionalRequirement1_type; // 5 - uint32 additionalRequirement1_value; // 6 - uint32 additionalRequirement2_type; // 7 - uint32 additionalRequirement2_value; // 8 - } win_bg; - - // ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5 - struct - { - uint32 unused; // 3 - uint32 level; // 4 - } reach_level; - - // ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7 - struct - { - uint32 skillID; // 3 - uint32 skillLevel; // 4 - } reach_skill_level; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8 - struct - { - uint32 linkedAchievement; // 3 - } complete_achievement; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9 - struct - { - uint32 unused; // 3 - uint32 totalQuestCount; // 4 - } complete_quest_count; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10 - struct - { - uint32 unused; // 3 - uint32 numberOfDays; // 4 - } complete_daily_quest_daily; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11 - struct - { - uint32 zoneID; // 3 - uint32 questCount; // 4 - } complete_quests_in_zone; - - // ACHIEVEMENT_CRITERIA_TYPE_CURRENCY_EARNED = 12 - struct - { - uint32 currencyId; // 3 - uint32 count; // 4 - } currencyEarned; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14 - struct - { - uint32 unused; // 3 - uint32 questCount; // 4 - } complete_daily_quest; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15 - struct - { - uint32 mapID; // 3 - } complete_battleground; - - // ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16 - struct - { - uint32 mapID; // 3 - } death_at_map; - - // ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18 - struct - { - uint32 manLimit; // 3 - } death_in_dungeon; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19 - struct - { - uint32 groupSize; // 3 can be 5, 10 or 25 - } complete_raid; - - // ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20 - struct - { - uint32 creatureEntry; // 3 - } killed_by_creature; - - // ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24 - struct - { - uint32 unused; // 3 - uint32 fallHeight; // 4 - } fall_without_dying; - - // ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26 - struct - { - uint32 type; // 3, see enum EnviromentalDamage - } death_from; - - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27 - struct - { - uint32 questID; // 3 - uint32 questCount; // 4 - } complete_quest; - - // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28 - // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69 - struct - { - uint32 spellID; // 3 - uint32 spellCount; // 4 - } be_spell_target; - - // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29 - // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110 - struct - { - uint32 spellID; // 3 - uint32 castCount; // 4 - } cast_spell; - - // ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE = 30 - struct - { - uint32 captureID; // 3 - uint32 captureCount; // 4 - } objective_capture; - - // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31 - struct - { - uint32 areaID; // 3 Reference to AreaTable.dbc - uint32 killCount; // 4 - } honorable_kill_at_area; - - // ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32 - struct - { - uint32 mapID; // 3 Reference to Map.dbc - uint32 count; // 4 - } win_arena; - - // ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33 - struct - { - uint32 mapID; // 3 Reference to Map.dbc - } play_arena; - - // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34 - struct - { - uint32 spellID; // 3 Reference to Map.dbc - } learn_spell; - - // ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36 - struct - { - uint32 itemID; // 3 - uint32 itemCount; // 4 - } own_item; - - // ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37 - struct - { - uint32 unused; // 3 - uint32 count; // 4 - uint32 flag; // 5 4=in a row - } win_rated_arena; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38 - struct - { - uint32 teamtype; // 3 {2,3,5} - } highest_team_rating; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING= 39 - struct - { - uint32 teamtype; // 3 {2,3,5} - uint32 teamrating; // 4 - } highest_personal_rating; - - // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40 - struct - { - uint32 skillID; // 3 - uint32 skillLevel; // 4 apprentice=1, journeyman=2, expert=3, artisan=4, master=5, grand master=6 - } learn_skill_level; - - // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41 - struct - { - uint32 itemID; // 3 - uint32 itemCount; // 4 - } use_item; - - // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42 - struct - { - uint32 itemID; // 3 - uint32 itemCount; // 4 - } loot_item; - - // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43 - struct - { - // TODO: This rank is _NOT_ the index from AreaTable.dbc - uint32 areaReference; // 3 - } explore_area; - - // ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44 - struct - { - // TODO: This rank is _NOT_ the index from CharTitles.dbc - uint32 rank; // 3 - } own_rank; - - // ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45 - struct - { - uint32 unused; // 3 - uint32 numberOfSlots; // 4 - } buy_bank_slot; - - // ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46 - struct - { - uint32 factionID; // 3 - uint32 reputationAmount; // 4 Total reputation amount, so 42000 = exalted - } gain_reputation; - - // ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION= 47 - struct - { - uint32 unused; // 3 - uint32 numberOfExaltedFactions; // 4 - } gain_exalted_reputation; - - // ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48 - struct - { - uint32 unused; // 3 - uint32 numberOfVisits; // 4 - } visit_barber; - - // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49 - // TODO: where is the required itemlevel stored? - struct - { - uint32 itemSlot; // 3 - uint32 count; // 4 - } equip_epic_item; - - // ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50 - struct - { - uint32 rollValue; // 3 - uint32 count; // 4 - } roll_need_on_loot; - // ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51 - struct - { - uint32 rollValue; // 3 - uint32 count; // 4 - } roll_greed_on_loot; - - // ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52 - struct - { - uint32 classID; // 3 - uint32 count; // 4 - } hk_class; - - // ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53 - struct - { - uint32 raceID; // 3 - uint32 count; // 4 - } hk_race; - - // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54 - // TODO: where is the information about the target stored? - struct - { - uint32 emoteID; // 3 enum TextEmotes - uint32 count; // 4 count of emotes, always required special target or requirements - } do_emote; - // ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13 - // ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55 - // ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56 - struct - { - uint32 unused; // 3 - uint32 count; // 4 - uint32 flag; // 5 =3 for battleground healing - uint32 mapid; // 6 - } healing_done; - - // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57 - struct - { - uint32 itemID; // 3 - uint32 count; // 4 - } equip_item; - - // ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD= 62 - struct - { - uint32 unused; // 3 - uint32 goldInCopper; // 4 - } quest_reward_money; - - // ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67 - struct - { - uint32 unused; // 3 - uint32 goldInCopper; // 4 - } loot_money; - - // ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68 - struct - { - uint32 goEntry; // 3 - uint32 useCount; // 4 - } use_gameobject; - - // ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70 - // TODO: are those special criteria stored in the dbc or do we have to add another sql table? - struct - { - uint32 unused; // 3 - uint32 killCount; // 4 - } special_pvp_kill; - - // ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72 - struct - { - uint32 goEntry; // 3 - uint32 lootCount; // 4 - } fish_in_gameobject; - - // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75 - struct - { - uint32 skillLine; // 3 - uint32 spellCount; // 4 - } learn_skillline_spell; - - // ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76 - struct - { - uint32 unused; // 3 - uint32 duelCount; // 4 - } win_duel; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96 - struct - { - uint32 powerType; // 3 mana=0, 1=rage, 3=energy, 6=runic power - } highest_power; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97 - struct - { - uint32 statType; // 3 4=spirit, 3=int, 2=stamina, 1=agi, 0=strength - } highest_stat; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98 - struct - { - uint32 spellSchool; // 3 - } highest_spellpower; - - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING = 100 - struct - { - uint32 ratingType; // 3 - } highest_rating; - - // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109 - struct - { - uint32 lootType; // 3 3=fishing, 2=pickpocket, 4=disentchant - uint32 lootTypeCount; // 4 - } loot_type; - - // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112 - struct - { - uint32 skillLine; // 3 - uint32 spellCount; // 4 - } learn_skill_line; - - // ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113 - struct - { - uint32 unused; // 3 - uint32 killCount; // 4 - } honorable_kill; - - struct - { - uint32 value; // 3 m_asset_id - uint32 count; // 4 m_quantity - uint32 additionalRequirement1_type; // 5 m_start_event - uint32 additionalRequirement1_value; // 6 m_start_asset - uint32 additionalRequirement2_type; // 7 m_fail_event - uint32 additionalRequirement2_value; // 8 m_fail_asset - } raw; - }; - //uint32 unk1; // 9 - DBCString name; // 10 m_description_lang - uint32 completionFlag; // 11 m_flags - uint32 timedCriteriaStartType; // 12 m_timer_start_event Only appears with timed achievements, seems to be the type of starting a timed Achievement, only type 1 and some of type 6 need manual starting - // 1: ByEventId(?) (serverside IDs), 2: ByQuestId, 5: ByCastSpellId(?) - // 6: BySpellIdTarget(some of these are unknown spells, some not, some maybe spells) - // 7: ByKillNpcId, 9: ByUseItemId - uint32 timedCriteriaMiscId; // 13 m_timer_asset_id Alway appears with timed events, used internally to start the achievement, store - uint32 timeLimit; // 14 m_timer_time time limit in seconds - uint32 showOrder; // 15 m_ui_order also used in achievement shift-links as index in state bitmask - //uint32 unk2; // 16 - //uint32 moreRequirement[3]; // 17-19 - //uint32 moreRequirementValue[3]; // 20-22 - - // helpers - bool IsExplicitlyStartedTimedCriteria() const - { - if (!timeLimit) - { - return false; - } - - // in case raw.value == timedCriteriaMiscId in timedCriteriaMiscId stored spellid/itemids for cast/use, so repeating aura start at first cast/use until fails - return requiredType == ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST || raw.value != timedCriteriaMiscId; - } + uint32 ID; // 0 m_ID + uint32 referredAchievement; // 1 m_achievement_id + uint32 requiredType; // 2 m_type + union + { + // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0 + // TODO: also used for player deaths.. + struct + { + uint32 creatureID; // 3 + uint32 creatureCount; // 4 + } kill_creature; + + // ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1 + struct + { + uint32 bgMapID; // 3 + uint32 winCount; // 4 + uint32 additionalRequirement1_type; // 5 + uint32 additionalRequirement1_value; // 6 + uint32 additionalRequirement2_type; // 7 + uint32 additionalRequirement2_value; // 8 + } win_bg; + + // ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5 + struct + { + uint32 unused; // 3 + uint32 level; // 4 + } reach_level; + + // ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7 + struct + { + uint32 skillID; // 3 + uint32 skillLevel; // 4 + } reach_skill_level; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8 + struct + { + uint32 linkedAchievement; // 3 + } complete_achievement; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9 + struct + { + uint32 unused; // 3 + uint32 totalQuestCount; // 4 + } complete_quest_count; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10 + struct + { + uint32 unused; // 3 + uint32 numberOfDays; // 4 + } complete_daily_quest_daily; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11 + struct + { + uint32 zoneID; // 3 + uint32 questCount; // 4 + } complete_quests_in_zone; + + // ACHIEVEMENT_CRITERIA_TYPE_CURRENCY_EARNED = 12 + struct + { + uint32 currencyId; // 3 + uint32 count; // 4 + } currencyEarned; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14 + struct + { + uint32 unused; // 3 + uint32 questCount; // 4 + } complete_daily_quest; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15 + struct + { + uint32 mapID; // 3 + } complete_battleground; + + // ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16 + struct + { + uint32 mapID; // 3 + } death_at_map; + + // ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18 + struct + { + uint32 manLimit; // 3 + } death_in_dungeon; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19 + struct + { + uint32 groupSize; // 3 can be 5, 10 or 25 + } complete_raid; + + // ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20 + struct + { + uint32 creatureEntry; // 3 + } killed_by_creature; + + // ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24 + struct + { + uint32 unused; // 3 + uint32 fallHeight; // 4 + } fall_without_dying; + + // ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26 + struct + { + uint32 type; // 3, see enum EnviromentalDamage + } death_from; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27 + struct + { + uint32 questID; // 3 + uint32 questCount; // 4 + } complete_quest; + + // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28 + // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69 + struct + { + uint32 spellID; // 3 + uint32 spellCount; // 4 + } be_spell_target; + + // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29 + // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110 + struct + { + uint32 spellID; // 3 + uint32 castCount; // 4 + } cast_spell; + + // ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE = 30 + struct + { + uint32 captureID; // 3 + uint32 captureCount; // 4 + } objective_capture; + + // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31 + struct + { + uint32 areaID; // 3 Reference to AreaTable.dbc + uint32 killCount; // 4 + } honorable_kill_at_area; + + // ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32 + struct + { + uint32 mapID; // 3 Reference to Map.dbc + uint32 count; // 4 + } win_arena; + + // ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33 + struct + { + uint32 mapID; // 3 Reference to Map.dbc + } play_arena; + + // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34 + struct + { + uint32 spellID; // 3 Reference to Map.dbc + } learn_spell; + + // ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36 + struct + { + uint32 itemID; // 3 + uint32 itemCount; // 4 + } own_item; + + // ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37 + struct + { + uint32 unused; // 3 + uint32 count; // 4 + uint32 flag; // 5 4=in a row + } win_rated_arena; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38 + struct + { + uint32 teamtype; // 3 {2,3,5} + } highest_team_rating; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING= 39 + struct + { + uint32 teamtype; // 3 {2,3,5} + uint32 teamrating; // 4 + } highest_personal_rating; + + // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40 + struct + { + uint32 skillID; // 3 + uint32 skillLevel; // 4 apprentice=1, journeyman=2, expert=3, artisan=4, master=5, grand master=6 + } learn_skill_level; + + // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41 + struct + { + uint32 itemID; // 3 + uint32 itemCount; // 4 + } use_item; + + // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42 + struct + { + uint32 itemID; // 3 + uint32 itemCount; // 4 + } loot_item; + + // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43 + struct + { + // TODO: This rank is _NOT_ the index from AreaTable.dbc + uint32 areaReference; // 3 + } explore_area; + + // ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44 + struct + { + // TODO: This rank is _NOT_ the index from CharTitles.dbc + uint32 rank; // 3 + } own_rank; + + // ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45 + struct + { + uint32 unused; // 3 + uint32 numberOfSlots; // 4 + } buy_bank_slot; + + // ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46 + struct + { + uint32 factionID; // 3 + uint32 reputationAmount; // 4 Total reputation amount, so 42000 = exalted + } gain_reputation; + + // ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION= 47 + struct + { + uint32 unused; // 3 + uint32 numberOfExaltedFactions; // 4 + } gain_exalted_reputation; + + // ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48 + struct + { + uint32 unused; // 3 + uint32 numberOfVisits; // 4 + } visit_barber; + + // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49 + // TODO: where is the required itemlevel stored? + struct + { + uint32 itemSlot; // 3 + uint32 count; // 4 + } equip_epic_item; + + // ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50 + struct + { + uint32 rollValue; // 3 + uint32 count; // 4 + } roll_need_on_loot; + // ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51 + struct + { + uint32 rollValue; // 3 + uint32 count; // 4 + } roll_greed_on_loot; + + // ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52 + struct + { + uint32 classID; // 3 + uint32 count; // 4 + } hk_class; + + // ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53 + struct + { + uint32 raceID; // 3 + uint32 count; // 4 + } hk_race; + + // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54 + // TODO: where is the information about the target stored? + struct + { + uint32 emoteID; // 3 enum TextEmotes + uint32 count; // 4 count of emotes, always required special target or requirements + } do_emote; + // ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13 + // ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55 + // ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56 + struct + { + uint32 unused; // 3 + uint32 count; // 4 + uint32 flag; // 5 =3 for battleground healing + uint32 mapid; // 6 + } healing_done; + + // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57 + struct + { + uint32 itemID; // 3 + uint32 count; // 4 + } equip_item; + + // ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD= 62 + struct + { + uint32 unused; // 3 + uint32 goldInCopper; // 4 + } quest_reward_money; + + // ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67 + struct + { + uint32 unused; // 3 + uint32 goldInCopper; // 4 + } loot_money; + + // ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68 + struct + { + uint32 goEntry; // 3 + uint32 useCount; // 4 + } use_gameobject; + + // ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70 + // TODO: are those special criteria stored in the dbc or do we have to add another sql table? + struct + { + uint32 unused; // 3 + uint32 killCount; // 4 + } special_pvp_kill; + + // ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72 + struct + { + uint32 goEntry; // 3 + uint32 lootCount; // 4 + } fish_in_gameobject; + + // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75 + struct + { + uint32 skillLine; // 3 + uint32 spellCount; // 4 + } learn_skillline_spell; + + // ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76 + struct + { + uint32 unused; // 3 + uint32 duelCount; // 4 + } win_duel; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96 + struct + { + uint32 powerType; // 3 mana=0, 1=rage, 3=energy, 6=runic power + } highest_power; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97 + struct + { + uint32 statType; // 3 4=spirit, 3=int, 2=stamina, 1=agi, 0=strength + } highest_stat; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98 + struct + { + uint32 spellSchool; // 3 + } highest_spellpower; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING = 100 + struct + { + uint32 ratingType; // 3 + } highest_rating; + + // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109 + struct + { + uint32 lootType; // 3 3=fishing, 2=pickpocket, 4=disentchant + uint32 lootTypeCount; // 4 + } loot_type; + + // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112 + struct + { + uint32 skillLine; // 3 + uint32 spellCount; // 4 + } learn_skill_line; + + // ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113 + struct + { + uint32 unused; // 3 + uint32 killCount; // 4 + } honorable_kill; + + struct + { + uint32 value; // 3 m_asset_id + uint32 count; // 4 m_quantity + uint32 additionalRequirement1_type; // 5 m_start_event + uint32 additionalRequirement1_value; // 6 m_start_asset + uint32 additionalRequirement2_type; // 7 m_fail_event + uint32 additionalRequirement2_value; // 8 m_fail_asset + } raw; + }; + //uint32 unk1; // 9 + DBCString name; // 10 m_description_lang + uint32 completionFlag; // 11 m_flags + uint32 timedCriteriaStartType; // 12 m_timer_start_event Only appears with timed achievements, seems to be the type of starting a timed Achievement, only type 1 and some of type 6 need manual starting + // 1: ByEventId(?) (serverside IDs), 2: ByQuestId, 5: ByCastSpellId(?) + // 6: BySpellIdTarget(some of these are unknown spells, some not, some maybe spells) + // 7: ByKillNpcId, 9: ByUseItemId + uint32 timedCriteriaMiscId; // 13 m_timer_asset_id Alway appears with timed events, used internally to start the achievement, store + uint32 timeLimit; // 14 m_timer_time time limit in seconds + uint32 showOrder; // 15 m_ui_order also used in achievement shift-links as index in state bitmask + //uint32 unk2; // 16 + //uint32 moreRequirement[3]; // 17-19 + //uint32 moreRequirementValue[3]; // 20-22 + + // helpers + bool IsExplicitlyStartedTimedCriteria() const + { + if (!timeLimit) + { + return false; + } + + // in case raw.value == timedCriteriaMiscId in timedCriteriaMiscId stored spellid/itemids for cast/use, so repeating aura start at first cast/use until fails + return requiredType == ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST || raw.value != timedCriteriaMiscId; + } }; struct AreaTableEntry { - uint32 ID; // 0 m_ID - uint32 mapid; // 1 m_ContinentID - uint32 zone; // 2 m_ParentAreaID - uint32 exploreFlag; // 3 m_AreaBit - uint32 flags; // 4 m_flags - // 5 5.x - // 6 m_SoundProviderPref - // 7 m_SoundProviderPrefUnderwater - // 8 m_AmbienceID - // 9 m_ZoneMusic - // 10 5.x - // 11 m_IntroSound - int32 area_level; // 12 m_ExplorationLevel - DBCString area_name; // 13 m_AreaName_lang - uint32 team; // 14 m_factionGroupMask - uint32 LiquidTypeOverride[4]; // 15-18 m_liquidTypeID[4] - // 19 m_minElevation - // 20 m_ambient_multiplier - // 21 m_lightid - //uint32 unk20; // 22 4.0.0 - //uint32 unk21; // 23 4.0.0 - //uint32 unk22; // 24 4.0.0 - //uint32 unk23; // 25 4.0.0 - //uint32 unk24; // 26 4.0.1, may be worldStateId - // 27 5.x - // 28 5.x - // 29 5.x + uint32 ID; // 0 m_ID + uint32 mapid; // 1 m_ContinentID + uint32 zone; // 2 m_ParentAreaID + uint32 exploreFlag; // 3 m_AreaBit + uint32 flags; // 4 m_flags + // 5 5.x + // 6 m_SoundProviderPref + // 7 m_SoundProviderPrefUnderwater + // 8 m_AmbienceID + // 9 m_ZoneMusic + // 10 5.x + // 11 m_IntroSound + int32 area_level; // 12 m_ExplorationLevel + DBCString area_name; // 13 m_AreaName_lang + uint32 team; // 14 m_factionGroupMask + uint32 LiquidTypeOverride[4]; // 15-18 m_liquidTypeID[4] + // 19 m_minElevation + // 20 m_ambient_multiplier + // 21 m_lightid + //uint32 unk20; // 22 4.0.0 + //uint32 unk21; // 23 4.0.0 + //uint32 unk22; // 24 4.0.0 + //uint32 unk23; // 25 4.0.0 + //uint32 unk24; // 26 4.0.1, may be worldStateId + // 27 5.x + // 28 5.x + // 29 5.x }; struct AreaGroupEntry { - uint32 AreaGroupId; // 0 m_ID - uint32 AreaId[6]; // 1-6 m_areaID - uint32 nextGroup; // 7 m_nextAreaID + uint32 AreaGroupId; // 0 m_ID + uint32 AreaId[6]; // 1-6 m_areaID + uint32 nextGroup; // 7 m_nextAreaID }; struct AreaTriggerEntry { - uint32 id; // 0 m_ID - uint32 mapid; // 1 m_ContinentID - float x; // 2 m_x - float y; // 3 m_y - float z; // 4 m_z - //uint32 // 5 - //uint32 // 6 - //uint32 // 7 - float radius; // 8 m_radius - float box_x; // 9 m_box_length - float box_y; // 10 m_box_width - float box_z; // 11 m_box_heigh - float box_orientation; // 12 m_box_yaw - // 13 5.x - // 14 5.x - // 15 5.x + uint32 id; // 0 m_ID + uint32 mapid; // 1 m_ContinentID + float x; // 2 m_x + float y; // 3 m_y + float z; // 4 m_z + //uint32 // 5 + //uint32 // 6 + //uint32 // 7 + float radius; // 8 m_radius + float box_x; // 9 m_box_length + float box_y; // 10 m_box_width + float box_z; // 11 m_box_heigh + float box_orientation; // 12 m_box_yaw + // 13 5.x + // 14 5.x + // 15 5.x }; struct ArmorLocationEntry { - uint32 InventoryType; // 0 - float Value[5]; // 1-5 multiplier for armor types (cloth...plate, no armor?) + uint32 InventoryType; // 0 + float Value[5]; // 1-5 multiplier for armor types (cloth...plate, no armor?) }; struct AuctionHouseEntry { - uint32 houseId; // 0 m_ID - uint32 faction; // 1 m_factionID - uint32 depositPercent; // 2 m_depositRate - uint32 cutPercent; // 3 m_consignmentRate - //char* name; // 4 m_name_lang + uint32 houseId; // 0 m_ID + uint32 faction; // 1 m_factionID + uint32 depositPercent; // 2 m_depositRate + uint32 cutPercent; // 3 m_consignmentRate + //char* name; // 4 m_name_lang }; struct BankBagSlotPricesEntry { - uint32 ID; // 0 m_ID - uint32 price; // 1 m_Cost + uint32 ID; // 0 m_ID + uint32 price; // 1 m_Cost }; struct BarberShopStyleEntry { - uint32 Id; // 0 m_ID - uint32 type; // 1 m_type - //char* name; // 2 m_DisplayName_lang - //uint32 unk_name; // 3 m_Description_lang - //float CostMultiplier; // 4 m_Cost_Modifier - uint32 race; // 5 m_race - uint32 gender; // 6 m_sex - uint32 hair_id; // 7 m_data (real ID to hair/facial hair) + uint32 Id; // 0 m_ID + uint32 type; // 1 m_type + //char* name; // 2 m_DisplayName_lang + //uint32 unk_name; // 3 m_Description_lang + //float CostMultiplier; // 4 m_Cost_Modifier + uint32 race; // 5 m_race + uint32 gender; // 6 m_sex + uint32 hair_id; // 7 m_data (real ID to hair/facial hair) }; struct BattlemasterListEntry { - uint32 id; // 0 m_ID - int32 mapid[16]; // 1-16 m_mapID[16] - uint32 type; // 17 m_instanceType - //uint32 unkName; // 18 - DBCString name; // 19 m_name_lang - uint32 maxGroupSize; // 20 m_maxGroupSize - uint32 HolidayWorldStateId; // 21 m_holidayWorldState - uint32 minLevel; // 22 m_minlevel (sync with PvPDifficulty.dbc content) - uint32 maxLevel; // 23 m_maxlevel (sync with PvPDifficulty.dbc content) - uint32 maxGroupSizeRated; // 24 4.0.1 - uint32 minPlayers; // 25 4.0.6.13596 - uint32 maxPlayers; // 26 4.0.1 - uint32 rated; // 27 4.0.3, value 2 for Rated Battlegrounds - //uint32 // 28 5.4.x - //uint32 // 29 5.4.x + uint32 id; // 0 m_ID + int32 mapid[16]; // 1-16 m_mapID[16] + uint32 type; // 17 m_instanceType + //uint32 unkName; // 18 + DBCString name; // 19 m_name_lang + uint32 maxGroupSize; // 20 m_maxGroupSize + uint32 HolidayWorldStateId; // 21 m_holidayWorldState + uint32 minLevel; // 22 m_minlevel (sync with PvPDifficulty.dbc content) + uint32 maxLevel; // 23 m_maxlevel (sync with PvPDifficulty.dbc content) + uint32 maxGroupSizeRated; // 24 4.0.1 + uint32 minPlayers; // 25 4.0.6.13596 + uint32 maxPlayers; // 26 4.0.1 + uint32 rated; // 27 4.0.3, value 2 for Rated Battlegrounds + //uint32 unk1; // 28 5.4.x + //DBCString typeName; // 29 5.4.x }; /*struct Cfg_CategoriesEntry { - uint32 Index; // m_ID categoryId (sent in RealmList packet) - uint32 Unk1; // m_localeMask - uint32 Unk2; // m_charsetMask - uint32 IsTournamentRealm; // m_flags - char *categoryName; // m_name_lang + uint32 Index; // m_ID categoryId (sent in RealmList packet) + uint32 Unk1; // m_localeMask + uint32 Unk2; // m_charsetMask + uint32 IsTournamentRealm; // m_flags + char *categoryName; // m_name_lang }*/ /*struct Cfg_ConfigsEntry { - uint32 Id; // m_ID - uint32 Type; // m_realmType (sent in RealmList packet) - uint32 IsPvp; // m_playerKillingAllowed - uint32 IsRp; // m_roleplaying + uint32 Id; // m_ID + uint32 Type; // m_realmType (sent in RealmList packet) + uint32 IsPvp; // m_playerKillingAllowed + uint32 IsRp; // m_roleplaying };*/ #define MAX_OUTFIT_ITEMS 24 struct CharStartOutfitEntry { - // uint32 Id; // 0 m_ID - uint32 RaceClassGender; // 1 m_raceID m_classID m_sexID m_outfitID (UNIT_FIELD_BYTES_0 & 0x00FFFFFF) comparable (0 byte = race, 1 byte = class, 2 byte = gender) - int32 ItemId[MAX_OUTFIT_ITEMS]; // 2-25 m_ItemID - // int32 ItemDisplayId[MAX_OUTFIT_ITEMS]; // 26-29 m_DisplayItemID not required at server side - // int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 50-73 m_InventoryType not required at server side - // uint32 Unknown1; // 74 unique values (index-like with gaps ordered in other way as ids) - // uint32 Unknown2; // 75 - // uint32 Unknown3; // 76 - //uint32 Unknown4; // 77 - //uint32 Unknown5; // 78 + // uint32 Id; // 0 m_ID + uint32 RaceClassGender; // 1 m_raceID m_classID m_sexID m_outfitID (UNIT_FIELD_BYTES_0 & 0x00FFFFFF) comparable (0 byte = race, 1 byte = class, 2 byte = gender) + int32 ItemId[MAX_OUTFIT_ITEMS]; // 2-25 m_ItemID + // int32 ItemDisplayId[MAX_OUTFIT_ITEMS]; // 26-29 m_DisplayItemID not required at server side + // int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 50-73 m_InventoryType not required at server side + // uint32 Unknown1; // 74 unique values (index-like with gaps ordered in other way as ids) + // uint32 Unknown2; // 75 + // uint32 Unknown3; // 76 + //uint32 Unknown4; // 77 + //uint32 Unknown5; // 78 }; struct CharTitlesEntry { - uint32 ID; // 0, m_ID - // uint32 unk1; // 1 m_Condition_ID - DBCString name; // 2 m_name_lang - //char* name2; // 3 m_name1_lang - uint32 bit_index; // 4 m_mask_ID used in PLAYER_CHOSEN_TITLE and 1< CreatureDisplayInfoExtraEntry::DisplayExtraId - float Scale; // 4 m_creatureModelScale - // 5 m_creatureModelAlpha - // 6-8 m_textureVariation[3] - // 9 m_portraitTextureName - // 10 m_sizeClass - // 11 m_bloodID - // 12 m_NPCSoundID - // 13 m_particleColorID - // 14 m_creatureGeosetData - // 15 m_objectEffectPackageID - // 16 all 0 - // 17 5.x - // 18 5.x - // 19 5.4.1 + uint32 Displayid; // 0 m_ID + uint32 ModelId; // 1 m_modelID + // 2 m_soundID + uint32 ExtendedDisplayInfoID; // 3 m_extendedDisplayInfoID -> CreatureDisplayInfoExtraEntry::DisplayExtraId + float Scale; // 4 m_creatureModelScale + // 5 m_creatureModelAlpha + // 6-8 m_textureVariation[3] + // 9 m_portraitTextureName + // 10 m_sizeClass + // 11 m_bloodID + // 12 m_NPCSoundID + // 13 m_particleColorID + // 14 m_creatureGeosetData + // 15 m_objectEffectPackageID + // 16 all 0 + // 17 5.x + // 18 5.x + // 19 5.4.1 }; struct CreatureDisplayInfoExtraEntry { - uint32 DisplayExtraId; // 0 m_ID CreatureDisplayInfoEntry::m_extendedDisplayInfoID - uint32 Race; // 1 m_DisplayRaceID - // uint32 Gender; // 2 m_DisplaySexID - // uint32 SkinColor; // 3 m_SkinID - // uint32 FaceType; // 4 m_FaceID - // uint32 HairType; // 5 m_HairStyleID - // uint32 HairStyle; // 6 m_HairColorID - // uint32 BeardStyle; // 7 m_FacialHairID - // uint32 Equipment[11]; // 8-18 m_NPCItemDisplay equipped static items EQUIPMENT_SLOT_HEAD..EQUIPMENT_SLOT_HANDS, client show its by self - // uint32 CanEquip; // 19 m_flags 0..1 Can equip additional things when used for players - // char* // 20 m_BakeName CreatureDisplayExtra-*.blp + uint32 DisplayExtraId; // 0 m_ID CreatureDisplayInfoEntry::m_extendedDisplayInfoID + uint32 Race; // 1 m_DisplayRaceID + // uint32 Gender; // 2 m_DisplaySexID + // uint32 SkinColor; // 3 m_SkinID + // uint32 FaceType; // 4 m_FaceID + // uint32 HairType; // 5 m_HairStyleID + // uint32 HairStyle; // 6 m_HairColorID + // uint32 BeardStyle; // 7 m_FacialHairID + // uint32 Equipment[11]; // 8-18 m_NPCItemDisplay equipped static items EQUIPMENT_SLOT_HEAD..EQUIPMENT_SLOT_HANDS, client show its by self + // uint32 CanEquip; // 19 m_flags 0..1 Can equip additional things when used for players + // char* // 20 m_BakeName CreatureDisplayExtra-*.blp }; struct CreatureFamilyEntry { - uint32 ID; // 0 m_ID - float minScale; // 1 m_minScale - uint32 minScaleLevel; // 2 m_minScaleLevel - float maxScale; // 3 m_maxScale - uint32 maxScaleLevel; // 4 m_maxScaleLevel - uint32 skillLine[2]; // 5-6 m_skillLine - uint32 petFoodMask; // 7 m_petFoodMask - int32 petTalentType; // 8 m_petTalentType - // 9 m_categoryEnumID - DBCString Name; // 10 m_name_lang - // 11 m_iconFile + uint32 ID; // 0 m_ID + float minScale; // 1 m_minScale + uint32 minScaleLevel; // 2 m_minScaleLevel + float maxScale; // 3 m_maxScale + uint32 maxScaleLevel; // 4 m_maxScaleLevel + uint32 skillLine[2]; // 5-6 m_skillLine + uint32 petFoodMask; // 7 m_petFoodMask + int32 petTalentType; // 8 m_petTalentType + // 9 m_categoryEnumID + DBCString Name; // 10 m_name_lang + // 11 m_iconFile }; struct CreatureModelDataEntry { - uint32 Id; // 0 - //uint32 Flags; // 1 - //char* ModelPath // 2 - //uint32 InhabitType; // 3 model inhabit type - //float Scale; // 4 Used in calculation of unit collision data - //int32 Unk2 // 5 - //int32 Unk3 // 6 - //uint32 Unk4 // 7 - //uint32 Unk5 // 8 - //float Unk6 // 9 - //uint32 Unk7 // 10 - //float Unk8 // 11 - //uint32 Unk9 // 12 - //uint32 Unk10 // 13 - //float CollisionWidth; // 14 - float CollisionHeight; // 15 - float MountHeight; // 16 Used in calculation of unit collision data when mounted - //float Unks[14] // 17-30 + uint32 Id; // 0 + //uint32 Flags; // 1 + //char* ModelPath // 2 + //uint32 InhabitType; // 3 model inhabit type + //float Scale; // 4 Used in calculation of unit collision data + //int32 Unk2 // 5 + //int32 Unk3 // 6 + //uint32 Unk4 // 7 + //uint32 Unk5 // 8 + //float Unk6 // 9 + //uint32 Unk7 // 10 + //float Unk8 // 11 + //uint32 Unk9 // 12 + //uint32 Unk10 // 13 + //float CollisionWidth; // 14 + float CollisionHeight; // 15 + float MountHeight; // 16 Used in calculation of unit collision data when mounted + //float Unks[14] // 17-30 }; #define MAX_CREATURE_SPELL_DATA_SLOT 4 struct CreatureSpellDataEntry { - uint32 ID; // 0 m_ID - uint32 spellId[MAX_CREATURE_SPELL_DATA_SLOT]; // 1-4 m_spells[4] - // uint32 availability[MAX_CREATURE_SPELL_DATA_SLOT];// 4-7 m_availability[4] + uint32 ID; // 0 m_ID + uint32 spellId[MAX_CREATURE_SPELL_DATA_SLOT]; // 1-4 m_spells[4] + // uint32 availability[MAX_CREATURE_SPELL_DATA_SLOT];// 4-7 m_availability[4] }; struct CreatureTypeEntry { - uint32 ID; // 0 m_ID - //char* Name; // 1 m_name_lang - //uint32 no_expirience; // 2 m_flags no exp? critters, non-combat pets, gas cloud. + uint32 ID; // 0 m_ID + //char* Name; // 1 m_name_lang + //uint32 no_expirience; // 2 m_flags no exp? critters, non-combat pets, gas cloud. }; /*struct CurrencyCategoryEntry { - uint32 ID; // 0 m_ID - uint32 Unk1; // 1 m_flags 0 for known categories and 3 for unknown one (3.0.9) - char* Name; // 2 m_name_lang + uint32 ID; // 0 m_ID + uint32 Unk1; // 1 m_flags 0 for known categories and 3 for unknown one (3.0.9) + char* Name; // 2 m_name_lang };*/ struct CurrencyTypesEntry { - uint32 ID; // 0 - uint32 Category; // 1 - DBCString name; // 2 - //char* iconName; // 3 - //char* iconName2; // 4 - //uint32 unk5; // 5 - //uint32 unk6; // 6 - uint32 TotalCap; // 7 - uint32 WeekCap; // 8 - uint32 Flags; // 9 - //uint32 // 10 5.4.1 - //DBCString description; // 11 + uint32 ID; // 0 + uint32 Category; // 1 + DBCString name; // 2 + //char* iconName; // 3 + //char* iconName2; // 4 + //uint32 unk5; // 5 + //uint32 unk6; // 6 + uint32 TotalCap; // 7 + uint32 WeekCap; // 8 + uint32 Flags; // 9 + //uint32 // 10 5.4.1 + //DBCString description; // 11 - bool HasPrecision() const { return Flags & CURRENCY_FLAG_HAS_PRECISION; } - bool HasSeasonCount() const { return Flags & CURRENCY_FLAG_HAS_SEASON_COUNT; } - float GetPrecision() const { return HasPrecision() ? CURRENCY_PRECISION : 1.0f; } + bool HasPrecision() const { return Flags & CURRENCY_FLAG_HAS_PRECISION; } + bool HasSeasonCount() const { return Flags & CURRENCY_FLAG_HAS_SEASON_COUNT; } + float GetPrecision() const { return HasPrecision() ? CURRENCY_PRECISION : 1.0f; } }; struct DestructibleModelDataEntry { - uint32 m_ID; // 0 m_ID - uint32 intactDisplayId; // 1 - // uint32 unk2; // 2 - // uint32 unk3; // 3 - // uint32 unk4; // 4 - uint32 damagedDisplayId; // 5 - // uint32 unk6; // 6 - // uint32 unk7; // 7 - // uint32 unk8; // 8 - // uint32 unk9; // 9 - uint32 destroyedDisplayId; // 10 - // uint32 unk11; // 11 - // uint32 unk12; // 12 - // uint32 unk13; // 13 - // uint32 unk14; // 14 - uint32 rebuildingDisplayId; // 15 - // uint32 unk16; // 16 - // uint32 unk17; // 17 - // uint32 unk18; // 18 - // uint32 unk19; // 19 - uint32 smokeDisplayId; // 20 - // uint32 unk21; // 21 - // uint32 unk22; // 22 - // uint32 unk23; // 23 + uint32 m_ID; // 0 m_ID + uint32 intactDisplayId; // 1 + // uint32 unk2; // 2 + // uint32 unk3; // 3 + // uint32 unk4; // 4 + uint32 damagedDisplayId; // 5 + // uint32 unk6; // 6 + // uint32 unk7; // 7 + // uint32 unk8; // 8 + // uint32 unk9; // 9 + uint32 destroyedDisplayId; // 10 + // uint32 unk11; // 11 + // uint32 unk12; // 12 + // uint32 unk13; // 13 + // uint32 unk14; // 14 + uint32 rebuildingDisplayId; // 15 + // uint32 unk16; // 16 + // uint32 unk17; // 17 + // uint32 unk18; // 18 + // uint32 unk19; // 19 + uint32 smokeDisplayId; // 20 + // uint32 unk21; // 21 + // uint32 unk22; // 22 + // uint32 unk23; // 23 }; struct DungeonEncounterEntry { - uint32 Id; // 0 m_ID - uint32 mapId; // 1 m_mapID - uint32 Difficulty; // 2 m_difficulty - uint32 encounterData; // 3 m_orderIndex - uint32 encounterIndex; // 4 m_Bit - DBCString encounterName; // 5 - encounter name - //uint32 nameLangFlags; // 6 m_name_lang_flags - //uint32 spellIconID; // 7 m_spellIconID - //uint32 // 8 5.4.1 + uint32 Id; // 0 m_ID + uint32 mapId; // 1 m_mapID + uint32 Difficulty; // 2 m_difficulty + uint32 encounterData; // 3 m_orderIndex + uint32 encounterIndex; // 4 m_Bit + DBCString encounterName; // 5 - encounter name + //uint32 nameLangFlags; // 6 m_name_lang_flags + //uint32 spellIconID; // 7 m_spellIconID + //uint32 // 8 5.4.1 }; struct DurabilityCostsEntry { - uint32 Itemlvl; // 0 m_ID - uint32 multiplier[29]; // 1-29 m_weaponSubClassCost m_armorSubClassCost + uint32 Itemlvl; // 0 m_ID + uint32 multiplier[29]; // 1-29 m_weaponSubClassCost m_armorSubClassCost }; struct DurabilityQualityEntry { - uint32 Id; // 0 m_ID - float quality_mod; // 1 m_data + uint32 Id; // 0 m_ID + float quality_mod; // 1 m_data }; struct EmotesEntry { - uint32 Id; // 0 m_ID - //char* Name; // 1 m_EmoteSlashCommand - //uint32 AnimationId; // 2 m_AnimID - uint32 Flags; // 3 m_EmoteFlags - uint32 EmoteType; // 4 m_EmoteSpecProc (determine how emote are shown) - uint32 UnitStandState; // 5 m_EmoteSpecProcParam - //uint32 SoundId; // 6 m_EventSoundID - //uint32 unk; // 7 - 4.2.0 + uint32 Id; // 0 m_ID + //char* Name; // 1 m_EmoteSlashCommand + //uint32 AnimationId; // 2 m_AnimID + uint32 Flags; // 3 m_EmoteFlags + uint32 EmoteType; // 4 m_EmoteSpecProc (determine how emote are shown) + uint32 UnitStandState; // 5 m_EmoteSpecProcParam + //uint32 SoundId; // 6 m_EventSoundID + //uint32 unk; // 7 - 4.2.0 }; struct EmotesTextEntry { - uint32 Id; // m_ID - // m_name - uint32 textid; // m_emoteID - // m_emoteText + uint32 Id; // m_ID + // m_name + uint32 textid; // m_emoteID + // m_emoteText }; struct FactionEntry { - uint32 ID; // 0 m_ID - int32 reputationListID; // 1 m_reputationIndex - uint32 BaseRepRaceMask[4]; // 2-5 m_reputationRaceMask - uint32 BaseRepClassMask[4]; // 6-9 m_reputationClassMask - int32 BaseRepValue[4]; // 10-13 m_reputationBase - uint32 ReputationFlags[4]; // 14-17 m_reputationFlags - uint32 team; // 18 m_parentFactionID - float spilloverRateIn; // 19 m_parentFactionMod[2] Faction gains incoming rep * spilloverRateIn - float spilloverRateOut; // 20 Faction outputs rep * spilloverRateOut as spillover reputation - uint32 spilloverMaxRankIn; // 21 m_parentFactionCap[2] The highest rank the faction will profit from incoming spillover - //uint32 spilloverRank_unk; // 22 It does not seem to be the max standing at which a faction outputs spillover ...so no idea - DBCString name; // 23 m_name_lang - //char* description; // 24 m_description_lang - //uint32 // 25 - //uint32 // 26 5.4.1 - //uint32 // 27 5.4.1 - - // helpers - - int GetIndexFitTo(uint32 raceMask, uint32 classMask) const - { - for (int i = 0; i < 4; ++i) - { - if ((BaseRepRaceMask[i] == 0 || (BaseRepRaceMask[i] & raceMask)) && - (BaseRepClassMask[i] == 0 || (BaseRepClassMask[i] & classMask))) - return i; - } - - return -1; - } + uint32 ID; // 0 m_ID + int32 reputationListID; // 1 m_reputationIndex + uint32 BaseRepRaceMask[4]; // 2-5 m_reputationRaceMask + uint32 BaseRepClassMask[4]; // 6-9 m_reputationClassMask + int32 BaseRepValue[4]; // 10-13 m_reputationBase + uint32 ReputationFlags[4]; // 14-17 m_reputationFlags + uint32 team; // 18 m_parentFactionID + float spilloverRateIn; // 19 m_parentFactionMod[2] Faction gains incoming rep * spilloverRateIn + float spilloverRateOut; // 20 Faction outputs rep * spilloverRateOut as spillover reputation + uint32 spilloverMaxRankIn; // 21 m_parentFactionCap[2] The highest rank the faction will profit from incoming spillover + //uint32 spilloverRank_unk; // 22 It does not seem to be the max standing at which a faction outputs spillover ...so no idea + DBCString name; // 23 m_name_lang + //char* description; // 24 m_description_lang + //uint32 // 25 + //uint32 // 26 5.4.1 + //uint32 // 27 5.4.1 + + // helpers + + int GetIndexFitTo(uint32 raceMask, uint32 classMask) const + { + for (int i = 0; i < 4; ++i) + { + if ((BaseRepRaceMask[i] == 0 || (BaseRepRaceMask[i] & raceMask)) && + (BaseRepClassMask[i] == 0 || (BaseRepClassMask[i] & classMask))) + return i; + } + + return -1; + } }; struct FactionTemplateEntry { - uint32 ID; // 0 m_ID - uint32 faction; // 1 m_faction - uint32 factionFlags; // 2 m_flags - uint32 ourMask; // 3 m_factionGroup - uint32 friendlyMask; // 4 m_friendGroup - uint32 hostileMask; // 5 m_enemyGroup - uint32 enemyFaction[4]; // 6 m_enemies[4] - uint32 friendFaction[4]; // 10 m_friend[4] - //------------------------------------------------------- end structure - - // helpers - bool IsFriendlyTo(FactionTemplateEntry const& entry) const - { - if (entry.faction) - { - for (int i = 0; i < 4; ++i) - if (enemyFaction[i] == entry.faction) - { - return false; - } - for (int i = 0; i < 4; ++i) - if (friendFaction[i] == entry.faction) - { - return true; - } - } - return (friendlyMask & entry.ourMask) || (ourMask & entry.friendlyMask); - } - bool IsHostileTo(FactionTemplateEntry const& entry) const - { - if (entry.faction) - { - for (int i = 0; i < 4; ++i) - if (enemyFaction[i] == entry.faction) - { - return true; - } - for (int i = 0; i < 4; ++i) - if (friendFaction[i] == entry.faction) - { - return false; - } - } - return (hostileMask & entry.ourMask) != 0; - } - bool IsHostileToPlayers() const { return (hostileMask & FACTION_MASK_PLAYER) != 0; } - bool IsNeutralToAll() const - { - for (int i = 0; i < 4; ++i) - if (enemyFaction[i] != 0) - { - return false; - } - return hostileMask == 0 && friendlyMask == 0; - } - bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD) != 0; } + uint32 ID; // 0 m_ID + uint32 faction; // 1 m_faction + uint32 factionFlags; // 2 m_flags + uint32 ourMask; // 3 m_factionGroup + uint32 friendlyMask; // 4 m_friendGroup + uint32 hostileMask; // 5 m_enemyGroup + uint32 enemyFaction[4]; // 6 m_enemies[4] + uint32 friendFaction[4]; // 10 m_friend[4] + //------------------------------------------------------- end structure + + // helpers + bool IsFriendlyTo(FactionTemplateEntry const& entry) const + { + if (entry.faction) + { + for (int i = 0; i < 4; ++i) + if (enemyFaction[i] == entry.faction) + { + return false; + } + for (int i = 0; i < 4; ++i) + if (friendFaction[i] == entry.faction) + { + return true; + } + } + return (friendlyMask & entry.ourMask) || (ourMask & entry.friendlyMask); + } + bool IsHostileTo(FactionTemplateEntry const& entry) const + { + if (entry.faction) + { + for (int i = 0; i < 4; ++i) + if (enemyFaction[i] == entry.faction) + { + return true; + } + for (int i = 0; i < 4; ++i) + if (friendFaction[i] == entry.faction) + { + return false; + } + } + return (hostileMask & entry.ourMask) != 0; + } + bool IsHostileToPlayers() const { return (hostileMask & FACTION_MASK_PLAYER) != 0; } + bool IsNeutralToAll() const + { + for (int i = 0; i < 4; ++i) + if (enemyFaction[i] != 0) + { + return false; + } + return hostileMask == 0 && friendlyMask == 0; + } + bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD) != 0; } }; struct GameObjectDisplayInfoEntry { - uint32 Displayid; // 0 m_ID - char* filename; // 1 m_modelName - // uint32 unknown2[10]; // 2-11 m_Sound - float geoBoxMinX; // 12 m_geoBoxMinX (use first value as interact dist, mostly in hacks way) - float geoBoxMinY; // 13 m_geoBoxMinY - float geoBoxMinZ; // 14 m_geoBoxMinZ - float geoBoxMaxX; // 15 m_geoBoxMaxX - float geoBoxMaxY; // 16 m_geoBoxMaxY - float geoBoxMaxZ; // 17 m_geoBoxMaxZ - //uint32 transport; // 18 - //uint32 unk; // 19 - //uint32 unk1; // 20 + uint32 Displayid; // 0 m_ID + char* filename; // 1 m_modelName + // uint32 unknown2[10]; // 2-11 m_Sound + float geoBoxMinX; // 12 m_geoBoxMinX (use first value as interact dist, mostly in hacks way) + float geoBoxMinY; // 13 m_geoBoxMinY + float geoBoxMinZ; // 14 m_geoBoxMinZ + float geoBoxMaxX; // 15 m_geoBoxMaxX + float geoBoxMaxY; // 16 m_geoBoxMaxY + float geoBoxMaxZ; // 17 m_geoBoxMaxZ + //uint32 transport; // 18 + //uint32 unk; // 19 + //uint32 unk1; // 20 }; struct GemPropertiesEntry { - uint32 ID; // 0 m_id - uint32 spellitemenchantement; // 1 m_enchant_id - // 2 m_maxcount_inv - // 3 m_maxcount_item - uint32 color; // 4 m_type - //uint32 // 5 + uint32 ID; // 0 m_id + uint32 spellitemenchantement; // 1 m_enchant_id + // 2 m_maxcount_inv + // 3 m_maxcount_item + uint32 color; // 4 m_type + //uint32 // 5 }; struct GlyphPropertiesEntry { - uint32 Id; // m_id - uint32 SpellId; // m_spellID - uint32 TypeFlags; // m_glyphSlotFlags - uint32 Unk1; // m_spellIconID + uint32 Id; // m_id + uint32 SpellId; // m_spellID + uint32 TypeFlags; // m_glyphSlotFlags + uint32 Unk1; // m_spellIconID }; struct GlyphSlotEntry { - uint32 Id; // m_id - uint32 TypeFlags; // m_type - uint32 Order; // m_tooltip + uint32 Id; // m_id + uint32 TypeFlags; // m_type + uint32 Order; // m_tooltip }; // All Gt* DBC store data for 100 levels, some by 100 per class/race @@ -1107,152 +1107,152 @@ struct GlyphSlotEntry struct GtBarberShopCostBaseEntry { - //uint32 level; - float cost; + //uint32 level; + float cost; }; struct GtCombatRatingsEntry { - //uint32 level; - float ratio; + //uint32 level; + float ratio; }; struct GtChanceToMeleeCritBaseEntry { - //uint32 level; - float base; + //uint32 level; + float base; }; struct GtChanceToMeleeCritEntry { - //uint32 level; - float ratio; + //uint32 level; + float ratio; }; struct GtChanceToSpellCritBaseEntry { - //uint32 level; - float base; + //uint32 level; + float base; }; struct GtChanceToSpellCritEntry { - //uint32 level; - float ratio; + //uint32 level; + float ratio; }; struct GtOCTClassCombatRatingScalarEntry { - float ratio; + float ratio; }; struct GtOCTHpPerStaminaEntry { - //uint32 level; - float ratio; + //uint32 level; + float ratio; }; struct GtRegenMPPerSptEntry { - //uint32 level; - float ratio; + //uint32 level; + float ratio; }; struct GtSpellScalingEntry { - //uint32 id; - float value; + //uint32 id; + float value; }; struct GtOCTBaseHPByClassEntry { - float ratio; + float ratio; }; struct GtOCTBaseMPByClassEntry { - float ratio; + float ratio; }; /*struct HolidayDescriptionsEntry { - uint32 ID; // 0 m_ID this is NOT holiday id - //char* name; // 1 m_name_lang + uint32 ID; // 0 m_ID this is NOT holiday id + //char* name; // 1 m_name_lang };*/ /*struct HolidayNamesEntry { - uint32 ID; // 0, m_ID this is NOT holiday id - //char* name; // 1 m_name_lang + uint32 ID; // 0, m_ID this is NOT holiday id + //char* name; // 1 m_name_lang };*/ struct HolidaysEntry { - uint32 ID; // 0 m_ID - // uint32 duration[10]; // 1-10 m_duration - // uint32 date[26]; // 11-36 m_date (dates in unix time starting at January, 1, 2000) - // uint32 region; // 37 m_region (wow region) - // uint32 looping; // 38 m_looping - // uint32 calendarFlags[10]; // 39-48 m_calendarFlags - // uint32 holidayNameId; // 49 m_holidayNameID (HolidayNames.dbc) - // uint32 holidayDescriptionId; // 50 m_holidayDescriptionID (HolidayDescriptions.dbc) - // char *textureFilename; // 51 m_textureFilename - // uint32 priority; // 52 m_priority - // uint32 calendarFilterType; // 53 m_calendarFilterType (-1,0,1 or 2) - // uint32 flags; // 54 m_flags + uint32 ID; // 0 m_ID + // uint32 duration[10]; // 1-10 m_duration + // uint32 date[26]; // 11-36 m_date (dates in unix time starting at January, 1, 2000) + // uint32 region; // 37 m_region (wow region) + // uint32 looping; // 38 m_looping + // uint32 calendarFlags[10]; // 39-48 m_calendarFlags + // uint32 holidayNameId; // 49 m_holidayNameID (HolidayNames.dbc) + // uint32 holidayDescriptionId; // 50 m_holidayDescriptionID (HolidayDescriptions.dbc) + // char *textureFilename; // 51 m_textureFilename + // uint32 priority; // 52 m_priority + // uint32 calendarFilterType; // 53 m_calendarFilterType (-1,0,1 or 2) + // uint32 flags; // 54 m_flags }; struct ItemArmorQualityEntry { - uint32 Id; // 0 item level - float Value[7]; // 1-7 multiplier for item quality - uint32 Id2; // 8 item level + uint32 Id; // 0 item level + float Value[7]; // 1-7 multiplier for item quality + uint32 Id2; // 8 item level }; struct ItemArmorShieldEntry { - uint32 Id; // 0 item level - uint32 Id2; // 1 item level - float Value[7]; // 2-8 multiplier for item quality + uint32 Id; // 0 item level + uint32 Id2; // 1 item level + float Value[7]; // 2-8 multiplier for item quality }; struct ItemArmorTotalEntry { - uint32 Id; // 0 item level - uint32 Id2; // 1 item level - float Value[4]; // 2-5 multiplier for armor types (cloth...plate) + uint32 Id; // 0 item level + uint32 Id2; // 1 item level + float Value[4]; // 2-5 multiplier for armor types (cloth...plate) }; struct ItemBagFamilyEntry { - uint32 ID; // 0 m_ID - //char* name; // 1 m_name_lang + uint32 ID; // 0 m_ID + //char* name; // 1 m_name_lang }; struct ItemClassEntry { - uint32 ID; // 0 m_ID - uint32 Class; // 1 - //uint32 unk2; // 2 looks like second class - //uint32 unk3; // 3 1 for weapons - float PriceFactor; // 4 - DBCString name; // 5 m_name_lang + uint32 ID; // 0 m_ID + uint32 Class; // 1 + //uint32 unk2; // 2 looks like second class + //uint32 unk3; // 3 1 for weapons + float PriceFactor; // 4 + DBCString name; // 5 m_name_lang }; struct ItemDisplayInfoEntry { - uint32 ID; // 0 m_ID - // 1 m_modelName[2] - // 2 m_modelTexture[2] - // 3 m_inventoryIcon - // 4 m_geosetGroup[3] - // 5 m_flags - // 6 m_spellVisualID - // 7 m_groupSoundIndex - // 8 m_helmetGeosetVis[2] - // 9 m_texture[2] - // 10 m_itemVisual[8] - // 11 m_particleColorID + uint32 ID; // 0 m_ID + // 1 m_modelName[2] + // 2 m_modelTexture[2] + // 3 m_inventoryIcon + // 4 m_geosetGroup[3] + // 5 m_flags + // 6 m_spellVisualID + // 7 m_groupSoundIndex + // 8 m_helmetGeosetVis[2] + // 9 m_texture[2] + // 10 m_itemVisual[8] + // 11 m_particleColorID }; // common struct for: @@ -1266,532 +1266,532 @@ struct ItemDisplayInfoEntry // ItemDamageWand.dbc struct ItemDamageEntry { - uint32 Id; // 0 item level - float Value[7]; // 1-7 multiplier for item quality - uint32 Id2; // 8 item level + uint32 Id; // 0 item level + float Value[7]; // 1-7 multiplier for item quality + uint32 Id2; // 8 item level }; struct ItemLimitCategoryEntry { - uint32 ID; // 0 Id m_ID - //char* name; // 1 m_name_lang - uint32 maxCount; // 2, m_quantity max allowed equipped as item or in gem slot - uint32 mode; // 3, m_flags 0 = have, 1 = equip (enum ItemLimitCategoryMode) + uint32 ID; // 0 Id m_ID + //char* name; // 1 m_name_lang + uint32 maxCount; // 2, m_quantity max allowed equipped as item or in gem slot + uint32 mode; // 3, m_flags 0 = have, 1 = equip (enum ItemLimitCategoryMode) }; struct ItemRandomPropertiesEntry { - uint32 ID; // 0 m_ID - //char* internalName // 1 m_Name - uint32 enchant_id[5]; // 2-6 m_Enchantment - char* nameSuffix; // 7 m_name_lang + uint32 ID; // 0 m_ID + //char* internalName // 1 m_Name + uint32 enchant_id[5]; // 2-6 m_Enchantment + char* nameSuffix; // 7 m_name_lang }; struct ItemRandomSuffixEntry { - uint32 ID; // 0 m_ID - char* nameSuffix; // 1 m_name_lang - // 2 m_internalName - uint32 enchant_id[5]; // 3-7 m_enchantment - uint32 prefix[5]; // 8-12 m_allocationPct + uint32 ID; // 0 m_ID + char* nameSuffix; // 1 m_name_lang + // 2 m_internalName + uint32 enchant_id[5]; // 3-7 m_enchantment + uint32 prefix[5]; // 8-12 m_allocationPct }; struct ItemReforgeEntry { - uint32 Id; // 0 - uint32 SourceStat; // 1 - float SourceMultiplier; // 2 - uint32 FinalStat; // 3 - float FinalMultiplier; // 4 + uint32 Id; // 0 + uint32 SourceStat; // 1 + float SourceMultiplier; // 2 + uint32 FinalStat; // 3 + float FinalMultiplier; // 4 }; struct ItemSetEntry { - //uint32 id // 0 m_ID - DBCString name; // 1 m_name_lang - //uint32 itemId[17]; // 2-18 m_itemID - uint32 spells[8]; // 19-26 m_setSpellID - uint32 items_to_triggerspell[8]; // 27-34 m_setThreshold - uint32 required_skill_id; // 35 m_requiredSkill - uint32 required_skill_value; // 36 m_requiredSkillRank + //uint32 id // 0 m_ID + DBCString name; // 1 m_name_lang + //uint32 itemId[17]; // 2-18 m_itemID + uint32 spells[8]; // 19-26 m_setSpellID + uint32 items_to_triggerspell[8]; // 27-34 m_setThreshold + uint32 required_skill_id; // 35 m_requiredSkill + uint32 required_skill_value; // 36 m_requiredSkillRank }; struct LfgDungeonsEntry { - uint32 ID; - DBCString Name; - uint32 minLevel; - uint32 maxLevel; - uint32 target_level; - uint32 target_level_min; - uint32 target_level_max; - float mapID; - uint32 difficulty; - uint32 flags; - uint32 typeID; - float faction; - DBCString textureFilename; - uint32 expansionLevel; - DBCString order_index; - uint32 group_id; - DBCString description_lang; - uint32 col17; - uint32 col18; - uint32 col19; - uint32 col20; - - uint32 Entry() const { return ID + ((uint8)typeID << 24); } + uint32 ID; + DBCString Name; + uint32 minLevel; + uint32 maxLevel; + uint32 target_level; + uint32 target_level_min; + uint32 target_level_max; + float mapID; + uint32 difficulty; + uint32 flags; + uint32 typeID; + float faction; + DBCString textureFilename; + uint32 expansionLevel; + DBCString order_index; + uint32 group_id; + DBCString description_lang; + uint32 col17; + uint32 col18; + uint32 col19; + uint32 col20; + + uint32 Entry() const { return ID + ((uint8)typeID << 24); } }; /*struct LfgDungeonGroupEntry { - m_ID - m_name_lang - m_order_index - m_parent_group_id - m_typeid + m_ID + m_name_lang + m_order_index + m_parent_group_id + m_typeid };*/ /*struct LfgDungeonExpansionEntry { - m_ID - m_lfg_id - m_expansion_level - m_random_id - m_hard_level_min - m_hard_level_max - m_target_level_min - m_target_level_max + m_ID + m_lfg_id + m_expansion_level + m_random_id + m_hard_level_min + m_hard_level_max + m_target_level_min + m_target_level_max };*/ struct LiquidTypeEntry { - uint32 Id; // 0 - //char* Name; // 1 - //uint32 Flags; // 2 Water: 1|2|4|8, Magma: 8|16|32|64, Slime: 2|64|256, WMO Ocean: 1|2|4|8|512 - uint32 Type; // 3 0: Water, 1: Ocean, 2: Magma, 3: Slime - //uint32 SoundId; // 4 Reference to SoundEntries.dbc - uint32 SpellId; // 5 Reference to Spell.dbc - //float MaxDarkenDepth; // 6 Only oceans got values here! - //float FogDarkenIntensity; // 7 Only oceans got values here! - //float AmbDarkenIntensity; // 8 Only oceans got values here! - //float DirDarkenIntensity; // 9 Only oceans got values here! - //uint32 LightID; // 10 Only Slime (6) and Magma (7) - //float ParticleScale; // 11 0: Slime, 1: Water/Ocean, 4: Magma - //uint32 ParticleMovement; // 12 - //uint32 ParticleTexSlots; // 13 - //uint32 LiquidMaterialID; // 14 - //char* Texture[6]; // 15-20 - //uint32 Color[2]; // 21-22 - //float Unk1[18]; // 23-40 Most likely these are attributes for the shaders. Water: (23, TextureTilesPerBlock),(24, Rotation) Magma: (23, AnimationX),(24, AnimationY) - //uint32 Unk2[4]; // 41-44 + uint32 Id; // 0 + //char* Name; // 1 + //uint32 Flags; // 2 Water: 1|2|4|8, Magma: 8|16|32|64, Slime: 2|64|256, WMO Ocean: 1|2|4|8|512 + uint32 Type; // 3 0: Water, 1: Ocean, 2: Magma, 3: Slime + //uint32 SoundId; // 4 Reference to SoundEntries.dbc + uint32 SpellId; // 5 Reference to Spell.dbc + //float MaxDarkenDepth; // 6 Only oceans got values here! + //float FogDarkenIntensity; // 7 Only oceans got values here! + //float AmbDarkenIntensity; // 8 Only oceans got values here! + //float DirDarkenIntensity; // 9 Only oceans got values here! + //uint32 LightID; // 10 Only Slime (6) and Magma (7) + //float ParticleScale; // 11 0: Slime, 1: Water/Ocean, 4: Magma + //uint32 ParticleMovement; // 12 + //uint32 ParticleTexSlots; // 13 + //uint32 LiquidMaterialID; // 14 + //char* Texture[6]; // 15-20 + //uint32 Color[2]; // 21-22 + //float Unk1[18]; // 23-40 Most likely these are attributes for the shaders. Water: (23, TextureTilesPerBlock),(24, Rotation) Magma: (23, AnimationX),(24, AnimationY) + //uint32 Unk2[4]; // 41-44 }; #define MAX_LOCK_CASE 8 struct LockEntry { - uint32 ID; // 0 m_ID - uint32 Type[MAX_LOCK_CASE]; // 1-8 m_Type - uint32 Index[MAX_LOCK_CASE]; // 9-16 m_Index - uint32 Skill[MAX_LOCK_CASE]; // 17-24 m_Skill - //uint32 Action[MAX_LOCK_CASE]; // 25-32 m_Action + uint32 ID; // 0 m_ID + uint32 Type[MAX_LOCK_CASE]; // 1-8 m_Type + uint32 Index[MAX_LOCK_CASE]; // 9-16 m_Index + uint32 Skill[MAX_LOCK_CASE]; // 17-24 m_Skill + //uint32 Action[MAX_LOCK_CASE]; // 25-32 m_Action }; struct MailTemplateEntry { - uint32 ID; // 0 m_ID - //char* subject; // 1 m_subject_lang - DBCString content; // 2 m_body_lang + uint32 ID; // 0 m_ID + //char* subject; // 1 m_subject_lang + DBCString content; // 2 m_body_lang }; struct MapEntry { - uint32 MapID; // 0 m_ID - DBCString internalname; // 1 unused - uint32 map_type; // 2 m_InstanceType - uint32 mapFlags; // 3 m_Flags (0x100 - CAN_CHANGE_PLAYER_DIFFICULTY) - uint32 isPvP; // 4 m_PVP 0 or 1 for battlegrounds (not arenas) - DBCString name; // 5 m_MapName_lang - uint32 linked_zone; // 6 m_areaTableID - DBCString hordeIntro; // 7 m_MapDescription0_lang - DBCString allianceIntro; // 8 m_MapDescription1_lang - uint32 multimap_id; // 9 m_LoadingScreenID (LoadingScreens.dbc) - float BattlefieldMapIconScale; // 10 m_minimapIconScale - int32 ghost_entrance_map; // 11 m_corpseMapID map_id of entrance map in ghost mode (continent always and in most cases = normal entrance) - float ghost_entrance_x; // 12 m_corpseX entrance x coordinate in ghost mode (in most cases = normal entrance) - float ghost_entrance_y; // 13 m_corpseY entrance y coordinate in ghost mode (in most cases = normal entrance) - uint32 timeOfDayOverride; // 14 m_timeOfDayOverride - uint32 addon; // 15 m_expansionID - uint32 unkTime; // 16 m_raidOffset - uint32 maxPlayers; // 17 m_maxPlayers - int32 rootPhaseMap; // 18 map with base phasing - - // Helpers - uint32 Expansion() const { return addon; } - - bool IsDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID || map_type == MAP_SCENARIO; } - bool IsNonRaidDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_SCENARIO; } - bool Instanceable() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID || map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA || map_type == MAP_SCENARIO; } - bool IsScenario() const { return map_type == MAP_SCENARIO; } - bool IsRaid() const { return map_type == MAP_RAID; } - bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; } - bool IsBattleArena() const { return map_type == MAP_ARENA; } - bool IsBattleGroundOrArena() const { return map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; } - - bool IsMountAllowed() const - { - return !IsDungeon() || - MapID == 209 || MapID == 269 || MapID == 309 || // TanarisInstance, CavernsOfTime, Zul'gurub - MapID == 509 || MapID == 534 || MapID == 560 || // AhnQiraj, HyjalPast, HillsbradPast - MapID == 568 || MapID == 580 || MapID == 595 || // ZulAman, Sunwell Plateau, Culling of Stratholme - MapID == 603 || MapID == 615 || MapID == 616 || // Ulduar, The Obsidian Sanctum, The Eye Of Eternity - MapID == 631 || // Icecrown Citadel, - MapID == 654 || MapID == 655 || MapID == 656 || // Gilneas, Gilneas Phase 1, Gilneas Phase 2 - MapID == 658 || MapID == 720 || MapID == 724 || // Pit of Saron, Firelands, Ruby Sanctum - MapID == 644 || MapID == 721 || MapID == 734 || // Halls of Origination, Firelands, ????????? - MapID == 754 || MapID == 755 || MapID == 859 || // Throne of Four Winds, Lost City of Tol'Vir, Zul'Gurub - MapID == 861 || MapID == 938 || MapID == 939 || // Firelands Dailies, End Time, Well of Eternity - MapID == 940 || MapID == 962 || MapID == 967 || // Hour of Twilight, Gate of Setting Sun, Dragon Soul - MapID == 996 || MapID == 1007 || MapID == 1011; // Endless Spring, New Scholomance, Niuzao Temple - } - - bool IsContinent() const - { - return MapID == 0 || MapID == 1 || MapID == 530 || MapID == 571 || MapID == 860 || MapID == 870; - } - - bool IsTransport() const - { - if (IsContinent()) - return false; - return map_type == MAP_COMMON && mapFlags == MAP_FLAG_INSTANCEABLE; - } + uint32 MapID; // 0 m_ID + DBCString internalname; // 1 unused + uint32 map_type; // 2 m_InstanceType + uint32 mapFlags; // 3 m_Flags (0x100 - CAN_CHANGE_PLAYER_DIFFICULTY) + uint32 isPvP; // 4 m_PVP 0 or 1 for battlegrounds (not arenas) + DBCString name; // 5 m_MapName_lang + uint32 linked_zone; // 6 m_areaTableID + DBCString hordeIntro; // 7 m_MapDescription0_lang + DBCString allianceIntro; // 8 m_MapDescription1_lang + uint32 multimap_id; // 9 m_LoadingScreenID (LoadingScreens.dbc) + float BattlefieldMapIconScale; // 10 m_minimapIconScale + int32 ghost_entrance_map; // 11 m_corpseMapID map_id of entrance map in ghost mode (continent always and in most cases = normal entrance) + float ghost_entrance_x; // 12 m_corpseX entrance x coordinate in ghost mode (in most cases = normal entrance) + float ghost_entrance_y; // 13 m_corpseY entrance y coordinate in ghost mode (in most cases = normal entrance) + uint32 timeOfDayOverride; // 14 m_timeOfDayOverride + uint32 addon; // 15 m_expansionID + uint32 unkTime; // 16 m_raidOffset + uint32 maxPlayers; // 17 m_maxPlayers + int32 rootPhaseMap; // 18 map with base phasing + + // Helpers + uint32 Expansion() const { return addon; } + + bool IsDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID || map_type == MAP_SCENARIO; } + bool IsNonRaidDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_SCENARIO; } + bool Instanceable() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID || map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA || map_type == MAP_SCENARIO; } + bool IsScenario() const { return map_type == MAP_SCENARIO; } + bool IsRaid() const { return map_type == MAP_RAID; } + bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; } + bool IsBattleArena() const { return map_type == MAP_ARENA; } + bool IsBattleGroundOrArena() const { return map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; } + + bool IsMountAllowed() const + { + return !IsDungeon() || + MapID == 209 || MapID == 269 || MapID == 309 || // TanarisInstance, CavernsOfTime, Zul'gurub + MapID == 509 || MapID == 534 || MapID == 560 || // AhnQiraj, HyjalPast, HillsbradPast + MapID == 568 || MapID == 580 || MapID == 595 || // ZulAman, Sunwell Plateau, Culling of Stratholme + MapID == 603 || MapID == 615 || MapID == 616 || // Ulduar, The Obsidian Sanctum, The Eye Of Eternity + MapID == 631 || // Icecrown Citadel, + MapID == 654 || MapID == 655 || MapID == 656 || // Gilneas, Gilneas Phase 1, Gilneas Phase 2 + MapID == 658 || MapID == 720 || MapID == 724 || // Pit of Saron, Firelands, Ruby Sanctum + MapID == 644 || MapID == 721 || MapID == 734 || // Halls of Origination, Firelands, ????????? + MapID == 754 || MapID == 755 || MapID == 859 || // Throne of Four Winds, Lost City of Tol'Vir, Zul'Gurub + MapID == 861 || MapID == 938 || MapID == 939 || // Firelands Dailies, End Time, Well of Eternity + MapID == 940 || MapID == 962 || MapID == 967 || // Hour of Twilight, Gate of Setting Sun, Dragon Soul + MapID == 996 || MapID == 1007 || MapID == 1011; // Endless Spring, New Scholomance, Niuzao Temple + } + + bool IsContinent() const + { + return MapID == 0 || MapID == 1 || MapID == 530 || MapID == 571 || MapID == 860 || MapID == 870; + } + + bool IsTransport() const + { + if (IsContinent()) + return false; + return map_type == MAP_COMMON && mapFlags == MAP_FLAG_INSTANCEABLE; + } }; struct MapDifficultyEntry { - uint32 Id; // 0 m_ID - uint32 MapId; // 1 m_mapID - uint32 Difficulty; // 2 m_difficulty (for arenas: arena slot) - DBCString areaTriggerText; // 3 m_message_lang (text showed when transfer to map failed) - uint32 resetTime; // 4, m_raidDuration in secs, 0 if no fixed reset time - uint32 maxPlayers; // 5, m_maxPlayers some heroic versions have 0 when expected same amount as in normal version - DBCString difficultyString; // 6 m_difficultystring + uint32 Id; // 0 m_ID + uint32 MapId; // 1 m_mapID + uint32 Difficulty; // 2 m_difficulty (for arenas: arena slot) + DBCString areaTriggerText; // 3 m_message_lang (text showed when transfer to map failed) + uint32 resetTime; // 4, m_raidDuration in secs, 0 if no fixed reset time + uint32 maxPlayers; // 5, m_maxPlayers some heroic versions have 0 when expected same amount as in normal version + DBCString difficultyString; // 6 m_difficultystring }; struct MovieEntry { - uint32 Id; // 0 m_ID - //uint32 unk1; // 1 m_volume - //uint32 unk2; // 2 5.x - //uint32 unk3; // 3 4.0.0 - //uint32 unk4; // 4 5.x + uint32 Id; // 0 m_ID + //uint32 unk1; // 1 m_volume + //uint32 unk2; // 2 5.x + //uint32 unk3; // 3 4.0.0 + //uint32 unk4; // 4 5.x }; struct MountCapabilityEntry { - uint32 Id; - uint32 Flags; - uint32 RequiredRidingSkill; - uint32 RequiredArea; - uint32 RequiredAura; - uint32 RequiredSpell; - uint32 SpeedModSpell; - int32 RequiredMap; + uint32 Id; + uint32 Flags; + uint32 RequiredRidingSkill; + uint32 RequiredArea; + uint32 RequiredAura; + uint32 RequiredSpell; + uint32 SpeedModSpell; + int32 RequiredMap; }; #define MAX_MOUNT_CAPABILITIES 24 struct MountTypeEntry { - uint32 Id; - uint32 MountCapability[MAX_MOUNT_CAPABILITIES]; + uint32 Id; + uint32 MountCapability[MAX_MOUNT_CAPABILITIES]; }; struct NumTalentsAtLevelEntry { - //uint32 Level; // 0 index - float Talents; // 1 talent count + //uint32 Level; // 0 index + float Talents; // 1 talent count }; #define MAX_OVERRIDE_SPELLS 10 struct OverrideSpellDataEntry { - uint32 Id; // 0 m_ID - uint32 Spells[MAX_OVERRIDE_SPELLS]; // 1-10 m_spells - // uint32 unk2; // 11 m_flags - //uint32 unk3; // 12 possibly flag + uint32 Id; // 0 m_ID + uint32 Spells[MAX_OVERRIDE_SPELLS]; // 1-10 m_spells + // uint32 unk2; // 11 m_flags + //uint32 unk3; // 12 possibly flag }; struct PhaseEntry { - uint32 Id; // 0 - uint32 PhaseShift; // 1 - uint32 Flags; // 2 - 0x0, 0x4, 0x8 + uint32 Id; // 0 + uint32 PhaseShift; // 1 + uint32 Flags; // 2 - 0x0, 0x4, 0x8 }; struct PowerDisplayEntry { - uint32 id; // 0 m_ID - uint32 power; // 1 m_power - // uint32 unk1 // 2 - // float unk2 // 3 - // float unk3 // 4 - // float unk4 // 5 + uint32 id; // 0 m_ID + uint32 power; // 1 m_power + // uint32 unk1 // 2 + // float unk2 // 3 + // float unk3 // 4 + // float unk4 // 5 }; struct PvPDifficultyEntry { - //uint32 id; // 0 m_ID - uint32 mapId; // 1 m_mapID - uint32 bracketId; // 2 m_rangeIndex - uint32 minLevel; // 3 m_minLevel - uint32 maxLevel; // 4 m_maxLevel - uint32 difficulty; // 5 m_difficulty + //uint32 id; // 0 m_ID + uint32 mapId; // 1 m_mapID + uint32 bracketId; // 2 m_rangeIndex + uint32 minLevel; // 3 m_minLevel + uint32 maxLevel; // 4 m_maxLevel + uint32 difficulty; // 5 m_difficulty - // helpers - BattleGroundBracketId GetBracketId() const { return BattleGroundBracketId(bracketId); } + // helpers + BattleGroundBracketId GetBracketId() const { return BattleGroundBracketId(bracketId); } }; struct QuestFactionRewardEntry { - uint32 id; // 0 m_ID - int32 rewardValue[10]; // 1-10 m_Difficulty + uint32 id; // 0 m_ID + int32 rewardValue[10]; // 1-10 m_Difficulty }; struct QuestSortEntry { - uint32 id; // 0 m_ID - //char* name; // 1 m_SortName_lang + uint32 id; // 0 m_ID + //char* name; // 1 m_SortName_lang }; struct QuestXPLevel { - uint32 questLevel; // 0 m_ID - uint32 xpIndex[10]; // 1-10 m_difficulty[10] + uint32 questLevel; // 0 m_ID + uint32 xpIndex[10]; // 1-10 m_difficulty[10] }; struct RandomPropertiesPointsEntry { - uint32 itemLevel; // 0 m_ItemLevel - uint32 EpicPropertiesPoints[5]; // 1-5 m_Epic - uint32 RarePropertiesPoints[5]; // 6-10 m_Superior - uint32 UncommonPropertiesPoints[5]; // 11-15 m_Good + uint32 itemLevel; // 0 m_ItemLevel + uint32 EpicPropertiesPoints[5]; // 1-5 m_Epic + uint32 RarePropertiesPoints[5]; // 6-10 m_Superior + uint32 UncommonPropertiesPoints[5]; // 11-15 m_Good }; struct ScalingStatDistributionEntry { - uint32 Id; // 0 m_ID - int32 StatMod[10]; // 1-10 m_statID - uint32 Modifier[10]; // 11-20 m_bonus - //uint32 unk1; // 21 - uint32 MaxLevel; // 22 m_maxlevel + uint32 Id; // 0 m_ID + int32 StatMod[10]; // 1-10 m_statID + uint32 Modifier[10]; // 11-20 m_bonus + //uint32 unk1; // 21 + uint32 MaxLevel; // 22 m_maxlevel }; struct ScalingStatValuesEntry { - uint32 Id; // 0 m_ID - uint32 Level; // 1 m_charlevel - uint32 dpsMod[6]; // 2-7 DPS mod for level - // 8 5.x unk bonus - uint32 spellBonus; // 9 spell power for level - uint32 ssdMultiplier[5]; // 10-14 Multiplier for ScalingStatDistribution - uint32 armorMod[4]; // 15-18 Armor for level - uint32 armorMod2[4]; // 19-22 Armor for level - //uint32 trash[24]; // 23-47 - //uint32 unk2; // 48 unk, probably also Armor for level (flag 0x80000?) - - /*struct ScalingStatValuesEntry - { - m_ID - m_charlevel - m_shoulderBudget - m_trinketBudget - m_weaponBudget1H - m_rangedBudget - m_clothShoulderArmor - m_leatherShoulderArmor - m_mailShoulderArmor - m_plateShoulderArmor - m_weaponDPS1H - m_weaponDPS2H - m_spellcasterDPS1H - m_spellcasterDPS2H - m_rangedDPS - m_wandDPS - m_spellPower - m_primaryBudget - m_tertiaryBudget - m_clothCloakArmor - m_clothChestArmor - m_leatherChestArmor - m_mailChestArmor - m_plateChestArmor - };*/ - uint32 getssdMultiplier(uint32 mask) const - { - if (mask & 0x4001F) - { - if(mask & 0x00000001) return ssdMultiplier[1]; - if(mask & 0x00000002) return ssdMultiplier[2]; // 0 and 1 were duplicated - if(mask & 0x00000004) return ssdMultiplier[3]; - if(mask & 0x00000008) return ssdMultiplier[0]; - if(mask & 0x00000010) return ssdMultiplier[4]; - if(mask & 0x00040000) return ssdMultiplier[2]; // 4.0.0 - } - return 0; - } - - uint32 getArmorMod(uint32 mask) const - { - if (mask & 0x00F001E0) - { - if (mask & 0x00000020) return armorMod[0]; - if (mask & 0x00000040) return armorMod[1]; - if (mask & 0x00000080) return armorMod[2]; - if (mask & 0x00000100) return armorMod[3]; - - if (mask & 0x00100000) return armorMod2[0]; // cloth - if (mask & 0x00200000) return armorMod2[1]; // leather - if (mask & 0x00400000) return armorMod2[2]; // mail - if (mask & 0x00800000) return armorMod2[3]; // plate - } - return 0; - } - - uint32 getDPSMod(uint32 mask) const - { - if (mask & 0x7E00) - { - if (mask & 0x00000200) return dpsMod[0]; - if (mask & 0x00000400) return dpsMod[1]; - if (mask & 0x00000800) return dpsMod[2]; - if (mask & 0x00001000) return dpsMod[3]; - if (mask & 0x00002000) return dpsMod[4]; - if (mask & 0x00004000) return dpsMod[5]; // not used? - } - return 0; - } - - uint32 getSpellBonus(uint32 mask) const - { - if (mask & 0x00008000) - { - return spellBonus; - } - return 0; - } + uint32 Id; // 0 m_ID + uint32 Level; // 1 m_charlevel + uint32 dpsMod[6]; // 2-7 DPS mod for level + // 8 5.x unk bonus + uint32 spellBonus; // 9 spell power for level + uint32 ssdMultiplier[5]; // 10-14 Multiplier for ScalingStatDistribution + uint32 armorMod[4]; // 15-18 Armor for level + uint32 armorMod2[4]; // 19-22 Armor for level + //uint32 trash[24]; // 23-47 + //uint32 unk2; // 48 unk, probably also Armor for level (flag 0x80000?) + + /*struct ScalingStatValuesEntry + { + m_ID + m_charlevel + m_shoulderBudget + m_trinketBudget + m_weaponBudget1H + m_rangedBudget + m_clothShoulderArmor + m_leatherShoulderArmor + m_mailShoulderArmor + m_plateShoulderArmor + m_weaponDPS1H + m_weaponDPS2H + m_spellcasterDPS1H + m_spellcasterDPS2H + m_rangedDPS + m_wandDPS + m_spellPower + m_primaryBudget + m_tertiaryBudget + m_clothCloakArmor + m_clothChestArmor + m_leatherChestArmor + m_mailChestArmor + m_plateChestArmor + };*/ + uint32 getssdMultiplier(uint32 mask) const + { + if (mask & 0x4001F) + { + if (mask & 0x00000001) return ssdMultiplier[1]; + if (mask & 0x00000002) return ssdMultiplier[2]; // 0 and 1 were duplicated + if (mask & 0x00000004) return ssdMultiplier[3]; + if (mask & 0x00000008) return ssdMultiplier[0]; + if (mask & 0x00000010) return ssdMultiplier[4]; + if (mask & 0x00040000) return ssdMultiplier[2]; // 4.0.0 + } + return 0; + } + + uint32 getArmorMod(uint32 mask) const + { + if (mask & 0x00F001E0) + { + if (mask & 0x00000020) return armorMod[0]; + if (mask & 0x00000040) return armorMod[1]; + if (mask & 0x00000080) return armorMod[2]; + if (mask & 0x00000100) return armorMod[3]; + + if (mask & 0x00100000) return armorMod2[0]; // cloth + if (mask & 0x00200000) return armorMod2[1]; // leather + if (mask & 0x00400000) return armorMod2[2]; // mail + if (mask & 0x00800000) return armorMod2[3]; // plate + } + return 0; + } + + uint32 getDPSMod(uint32 mask) const + { + if (mask & 0x7E00) + { + if (mask & 0x00000200) return dpsMod[0]; + if (mask & 0x00000400) return dpsMod[1]; + if (mask & 0x00000800) return dpsMod[2]; + if (mask & 0x00001000) return dpsMod[3]; + if (mask & 0x00002000) return dpsMod[4]; + if (mask & 0x00004000) return dpsMod[5]; // not used? + } + return 0; + } + + uint32 getSpellBonus(uint32 mask) const + { + if (mask & 0x00008000) + { + return spellBonus; + } + return 0; + } }; /*struct SkillLineCategoryEntry{ - uint32 id; // 0 m_ID - char* name; // 1 m_name_lang - uint32 displayOrder; // 2 m_sortIndex + uint32 id; // 0 m_ID + char* name; // 1 m_name_lang + uint32 displayOrder; // 2 m_sortIndex };*/ struct SkillRaceClassInfoEntry { - //uint32 id; // 0 m_ID - uint32 skillId; // 1 m_skillID - uint32 raceMask; // 2 m_raceMask - uint32 classMask; // 3 m_classMask - uint32 flags; // 4 m_flags - uint32 reqLevel; // 5 m_minLevel - //uint32 skillTierId; // 6 m_skillTierID - //uint32 skillCostID; // 7 m_skillCostIndex - //uint32 Unk; // 8 + //uint32 id; // 0 m_ID + uint32 skillId; // 1 m_skillID + uint32 raceMask; // 2 m_raceMask + uint32 classMask; // 3 m_classMask + uint32 flags; // 4 m_flags + uint32 reqLevel; // 5 m_minLevel + //uint32 skillTierId; // 6 m_skillTierID + //uint32 skillCostID; // 7 m_skillCostIndex + //uint32 Unk; // 8 }; /*struct SkillTiersEntry{ - uint32 id; // 0 m_ID - uint32 skillValue[16]; // 1-17 m_cost - uint32 maxSkillValue[16]; // 18-3 m_valueMax + uint32 id; // 0 m_ID + uint32 skillValue[16]; // 1-17 m_cost + uint32 maxSkillValue[16]; // 18-3 m_valueMax };*/ struct SkillLineEntry { - uint32 id; // 0 m_ID - int32 categoryId; // 1 m_categoryID - DBCString name; // 2 m_displayName_lang - //DBCString description; // 3 m_description_lang - uint32 spellIcon; // 4 m_spellIconID - //DBCString alternateVerb; // 5 m_alternateVerb_lang - uint32 canLink; // 6 m_canLink (prof. with recipes) + uint32 id; // 0 m_ID + int32 categoryId; // 1 m_categoryID + DBCString name; // 2 m_displayName_lang + //DBCString description; // 3 m_description_lang + uint32 spellIcon; // 4 m_spellIconID + //DBCString alternateVerb; // 5 m_alternateVerb_lang + uint32 canLink; // 6 m_canLink (prof. with recipes) }; struct SkillLineAbilityEntry { - uint32 id; // 0 m_ID - uint32 skillId; // 1 m_skillLine - uint32 spellId; // 2 m_spell - uint32 racemask; // 3 m_raceMask - uint32 classmask; // 4 m_classMask - //uint32 racemaskNot; // 5 m_excludeRace - //uint32 classmaskNot; // 6 m_excludeClass - uint32 req_skill_value; // 7 m_minSkillLineRank - uint32 forward_spellid; // 8 m_supercededBySpell - uint32 learnOnGetSkill; // 9 m_acquireMethod - uint32 max_value; // 10 m_trivialSkillLineRankHigh - uint32 min_value; // 11 m_trivialSkillLineRankLow - uint32 characterPoints; // 12 4.0.0 - //uint32 // 13 4.0.0 + uint32 id; // 0 m_ID + uint32 skillId; // 1 m_skillLine + uint32 spellId; // 2 m_spell + uint32 racemask; // 3 m_raceMask + uint32 classmask; // 4 m_classMask + //uint32 racemaskNot; // 5 m_excludeRace + //uint32 classmaskNot; // 6 m_excludeClass + uint32 req_skill_value; // 7 m_minSkillLineRank + uint32 forward_spellid; // 8 m_supercededBySpell + uint32 learnOnGetSkill; // 9 m_acquireMethod + uint32 max_value; // 10 m_trivialSkillLineRankHigh + uint32 min_value; // 11 m_trivialSkillLineRankLow + uint32 characterPoints; // 12 4.0.0 + //uint32 // 13 4.0.0 }; struct SoundEntriesEntry { - uint32 Id; // 0 m_ID - uint32 Type; // 1 m_soundType - DBCString InternalName; // 2 m_name - ///uint32 unk[10]; // 3-12 unk[10] - //uint32 unk2[10]; // 13-22 unk[10] - // 23 m_volumeFloat - // 24 m_flags - // 25 m_minDistance - // 26 m_distanceCutoff - // 27 m_EAXDef - // 28 m_soundEntriesAdvancedID, new in 3.1 - // 29 4.0.0 - // 30 4.0.0 - // 31 4.0.0 - // 32 4.0.0 - // 33 4.3.0 - // 34 5.x + uint32 Id; // 0 m_ID + uint32 Type; // 1 m_soundType + DBCString InternalName; // 2 m_name + ///uint32 unk[10]; // 3-12 unk[10] + //uint32 unk2[10]; // 13-22 unk[10] + // 23 m_volumeFloat + // 24 m_flags + // 25 m_minDistance + // 26 m_distanceCutoff + // 27 m_EAXDef + // 28 m_soundEntriesAdvancedID, new in 3.1 + // 29 4.0.0 + // 30 4.0.0 + // 31 4.0.0 + // 32 4.0.0 + // 33 4.3.0 + // 34 5.x }; struct ClassFamilyMask { - uint64 Flags; - uint32 Flags2; + uint64 Flags; + uint32 Flags2; - ClassFamilyMask() : Flags(0), Flags2(0) {} - explicit ClassFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) : Flags(familyFlags), Flags2(familyFlags2) {} + ClassFamilyMask() : Flags(0), Flags2(0) {} + explicit ClassFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) : Flags(familyFlags), Flags2(familyFlags2) {} - bool Empty() const { return Flags == 0 && Flags2 == 0; } - bool operator! () const { return Empty(); } - operator void const* () const { return Empty() ? NULL : this; }// for allow normal use in if(mask) + bool Empty() const { return Flags == 0 && Flags2 == 0; } + bool operator! () const { return Empty(); } + operator void const* () const { return Empty() ? NULL : this; }// for allow normal use in if(mask) - bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const - { - return (Flags & familyFlags) || (Flags2 & familyFlags2); - } + bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const + { + return (Flags & familyFlags) || (Flags2 & familyFlags2); + } - bool IsFitToFamilyMask(ClassFamilyMask const& mask) const - { - return (Flags & mask.Flags) || (Flags2 & mask.Flags2); - } + bool IsFitToFamilyMask(ClassFamilyMask const& mask) const + { + return (Flags & mask.Flags) || (Flags2 & mask.Flags2); + } - uint64 operator& (uint64 mask) const // possible will removed at finish convertion code use IsFitToFamilyMask - { - return Flags & mask; - } + uint64 operator& (uint64 mask) const // possible will removed at finish convertion code use IsFitToFamilyMask + { + return Flags & mask; + } - ClassFamilyMask& operator|= (ClassFamilyMask const& mask) - { - Flags |= mask.Flags; - Flags2 |= mask.Flags2; - return *this; - } + ClassFamilyMask& operator|= (ClassFamilyMask const& mask) + { + Flags |= mask.Flags; + Flags2 |= mask.Flags2; + return *this; + } }; #define MAX_SPELL_REAGENTS 8 @@ -1801,232 +1801,229 @@ struct ClassFamilyMask // SpellAuraOptions.dbc struct SpellAuraOptionsEntry { - //uint32 Id; // 0 m_ID - // 1 5.x - // 2 5.x - uint32 StackAmount; // 3 m_cumulativeAura - uint32 procChance; // 4 m_procChance - uint32 procCharges; // 5 m_procCharges - uint32 procFlags; // 6 m_procTypeMask - //uint32 // 7 5.4.1 - //uint32 // 8 5.4.1 + //uint32 Id; // 0 m_ID + // 1 5.x + // 2 5.x + uint32 StackAmount; // 3 m_cumulativeAura + uint32 procChance; // 4 m_procChance + uint32 procCharges; // 5 m_procCharges + uint32 procFlags; // 6 m_procTypeMask + //uint32 // 7 5.4.1 + //uint32 // 8 5.4.1 }; // SpellAuraRestrictions.dbc struct SpellAuraRestrictionsEntry { - //uint32 Id; // 0 m_ID - // 1 5.x - // 2 5.x - uint32 CasterAuraState; // 21 m_casterAuraState - uint32 TargetAuraState; // 22 m_targetAuraState - uint32 CasterAuraStateNot; // 23 m_excludeCasterAuraState - uint32 TargetAuraStateNot; // 24 m_excludeTargetAuraState - uint32 casterAuraSpell; // 25 m_casterAuraSpell - uint32 targetAuraSpell; // 26 m_targetAuraSpell - uint32 excludeCasterAuraSpell; // 27 m_excludeCasterAuraSpell - uint32 excludeTargetAuraSpell; // 28 m_excludeTargetAuraSpell + //uint32 Id; // 0 m_ID + // 1 5.x + // 2 5.x + uint32 CasterAuraState; // 21 m_casterAuraState + uint32 TargetAuraState; // 22 m_targetAuraState + uint32 CasterAuraStateNot; // 23 m_excludeCasterAuraState + uint32 TargetAuraStateNot; // 24 m_excludeTargetAuraState + uint32 casterAuraSpell; // 25 m_casterAuraSpell + uint32 targetAuraSpell; // 26 m_targetAuraSpell + uint32 excludeCasterAuraSpell; // 27 m_excludeCasterAuraSpell + uint32 excludeTargetAuraSpell; // 28 m_excludeTargetAuraSpell }; // SpellCastingRequirements.dbc struct SpellCastingRequirementsEntry { - //uint32 Id; // 0 m_ID - uint32 FacingCasterFlags; // 20 m_facingCasterFlags - //uint32 MinFactionId; // 159 m_minFactionID not used - //uint32 MinReputation; // 160 m_minReputation not used - int32 AreaGroupId; // 164 m_requiredAreaGroupId - //uint32 RequiredAuraVision; // 161 m_requiredAuraVision not used - uint32 RequiresSpellFocus; // 19 m_requiresSpellFocus + //uint32 Id; // 0 m_ID + uint32 FacingCasterFlags; // 20 m_facingCasterFlags + //uint32 MinFactionId; // 159 m_minFactionID not used + //uint32 MinReputation; // 160 m_minReputation not used + int32 AreaGroupId; // 164 m_requiredAreaGroupId + //uint32 RequiredAuraVision; // 161 m_requiredAuraVision not used + uint32 RequiresSpellFocus; // 19 m_requiresSpellFocus }; // SpellCategories.dbc struct SpellCategoriesEntry { - //uint32 Id; // 0 m_ID - // 1 5.x - // 2 5.x - uint32 Category; // 3 m_category - uint32 DmgClass; // 4 m_defenseType - uint32 Dispel; // 5 m_dispelType - uint32 Mechanic; // 6 m_mechanic - uint32 PreventionType; // 7 m_preventionType - uint32 StartRecoveryCategory; // 8 m_startRecoveryCategory - // 9 5.x + //uint32 Id; // 0 m_ID + // 1 5.x + // 2 5.x + uint32 Category; // 3 m_category + uint32 DmgClass; // 4 m_defenseType + uint32 Dispel; // 5 m_dispelType + uint32 Mechanic; // 6 m_mechanic + uint32 PreventionType; // 7 m_preventionType + uint32 StartRecoveryCategory; // 8 m_startRecoveryCategory + // 9 5.x }; // SpellClassOptions.dbc struct SpellClassOptionsEntry { - //uint32 Id; // 0 m_ID - //uint32 modalNextSpell; // 50 m_modalNextSpell not used - ClassFamilyMask SpellFamilyFlags; // 149-151 m_spellClassMask NOTE: size is 12 bytes!!! - uint32 SpellFamilyName; // 148 m_spellClassSet - //char* Description; // 6 4.0.0 - // helpers + //uint32 Id; // 0 m_ID + //uint32 modalNextSpell; // 50 m_modalNextSpell not used + ClassFamilyMask SpellFamilyFlags; // 149-151 m_spellClassMask NOTE: size is 12 bytes!!! + uint32 SpellFamilyName; // 148 m_spellClassSet + //char* Description; // 6 4.0.0 + // helpers - bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const - { - return SpellFamilyFlags.IsFitToFamilyMask(familyFlags, familyFlags2); - } + bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const + { + return SpellFamilyFlags.IsFitToFamilyMask(familyFlags, familyFlags2); + } - bool IsFitToFamily(SpellFamily family, uint64 familyFlags, uint32 familyFlags2 = 0) const - { - return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(familyFlags, familyFlags2); - } + bool IsFitToFamily(SpellFamily family, uint64 familyFlags, uint32 familyFlags2 = 0) const + { + return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(familyFlags, familyFlags2); + } - bool IsFitToFamilyMask(ClassFamilyMask const& mask) const - { - return SpellFamilyFlags.IsFitToFamilyMask(mask); - } + bool IsFitToFamilyMask(ClassFamilyMask const& mask) const + { + return SpellFamilyFlags.IsFitToFamilyMask(mask); + } - bool IsFitToFamily(SpellFamily family, ClassFamilyMask const& mask) const - { - return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(mask); - } + bool IsFitToFamily(SpellFamily family, ClassFamilyMask const& mask) const + { + return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(mask); + } - private: - // catch wrong uses - template - bool IsFitToFamilyMask(SpellFamily family, T t) const; +private: + // catch wrong uses + template + bool IsFitToFamilyMask(SpellFamily family, T t) const; }; // SpellCooldowns.dbc struct SpellCooldownsEntry { - //uint32 Id; // 0 m_ID - // 1 5.x - // 2 5.x - uint32 CategoryRecoveryTime; // 3 m_categoryRecoveryTime - uint32 RecoveryTime; // 4 m_recoveryTime - uint32 StartRecoveryTime; // 5 m_startRecoveryTime + //uint32 Id; // 0 m_ID + // 1 5.x + // 2 5.x + uint32 CategoryRecoveryTime; // 3 m_categoryRecoveryTime + uint32 RecoveryTime; // 4 m_recoveryTime + uint32 StartRecoveryTime; // 5 m_startRecoveryTime }; // SpellEffect.dbc struct SpellEffectEntry { - //uint32 Id; // 0 m_ID - uint32 Difficulty; // 1 m_difficulty - uint32 Effect; // 2 m_effect - float EffectMultipleValue; // 3 m_effectAmplitude - uint32 EffectApplyAuraName; // 4 m_effectAura - uint32 EffectAmplitude; // 5 m_effectAuraPeriod - int32 EffectBasePoints; // 6 m_effectBasePoints (don't must be used in spell/auras explicitly, must be used cached Spell::m_currentBasePoints) - //float unk_320_4; // 7 3.2.0 - float DmgMultiplier; // 8 m_effectChainAmplitude - uint32 EffectChainTarget; // 9 m_effectChainTargets - int32 EffectDieSides; // 10 m_effectDieSides - uint32 EffectItemType; // 11 m_effectItemType - uint32 EffectMechanic; // 12 m_effectMechanic - int32 EffectMiscValue; // 13 m_effectMiscValue - int32 EffectMiscValueB; // 14 m_effectMiscValueB - float EffectPointsPerComboPoint; // 15 m_effectPointsPerCombo - uint32 EffectRadiusIndex; // 16 m_effectRadiusIndex - spellradius.dbc - uint32 EffectRadiusMaxIndex; // 17 4.0.0 - float EffectRealPointsPerLevel; // 18 m_effectRealPointsPerLevel - ClassFamilyMask EffectSpellClassMask; // 19-21 m_effectSpellClassMask - uint32 EffectSpellClassMask4; // 22 5.x FIXME - uint32 EffectTriggerSpell; // 23 m_effectTriggerSpell - uint32 EffectImplicitTargetA; // 24 m_implicitTargetA - uint32 EffectImplicitTargetB; // 25 m_implicitTargetB - uint32 EffectSpellId; // 26 new 4.0.0 - uint32 EffectIndex; // 27 new 4.0.0 - //uint32 unk; // 28 4.2.0 - - // helpers - - int32 CalculateSimpleValue() const { return EffectBasePoints; } - - uint32 GetRadiusIndex() const - { - if (EffectRadiusIndex != 0) - { - return EffectRadiusIndex; - } - - return EffectRadiusMaxIndex; - } + //uint32 Id; // 0 m_ID + uint32 Difficulty; // 1 m_difficulty + uint32 Effect; // 2 m_effect + float EffectMultipleValue; // 3 m_effectAmplitude + uint32 EffectApplyAuraName; // 4 m_effectAura + uint32 EffectAmplitude; // 5 m_effectAuraPeriod + int32 EffectBasePoints; // 6 m_effectBasePoints (don't must be used in spell/auras explicitly, must be used cached Spell::m_currentBasePoints) + //float unk_320_4; // 7 3.2.0 + float DmgMultiplier; // 8 m_effectChainAmplitude + uint32 EffectChainTarget; // 9 m_effectChainTargets + int32 EffectDieSides; // 10 m_effectDieSides + uint32 EffectItemType; // 11 m_effectItemType + uint32 EffectMechanic; // 12 m_effectMechanic + int32 EffectMiscValue; // 13 m_effectMiscValue + int32 EffectMiscValueB; // 14 m_effectMiscValueB + float EffectPointsPerComboPoint; // 15 m_effectPointsPerCombo + uint32 EffectRadiusIndex; // 16 m_effectRadiusIndex - spellradius.dbc + uint32 EffectRadiusMaxIndex; // 17 4.0.0 + float EffectRealPointsPerLevel; // 18 m_effectRealPointsPerLevel + ClassFamilyMask EffectSpellClassMask; // 19-21 m_effectSpellClassMask + uint32 EffectSpellClassMask4; // 22 5.x FIXME + uint32 EffectTriggerSpell; // 23 m_effectTriggerSpell + uint32 EffectImplicitTargetA; // 24 m_implicitTargetA + uint32 EffectImplicitTargetB; // 25 m_implicitTargetB + uint32 EffectSpellId; // 26 new 4.0.0 + uint32 EffectIndex; // 27 new 4.0.0 + //uint32 unk; // 28 4.2.0 + + // helpers + + int32 CalculateSimpleValue() const { return EffectBasePoints; } + + uint32 GetRadiusIndex() const + { + if (EffectRadiusIndex != 0) + { + return EffectRadiusIndex; + } + + return EffectRadiusMaxIndex; + } }; // SpellEquippedItems.dbc struct SpellEquippedItemsEntry { - //uint32 Id; // 0 m_ID - // 1 unk 5.1.0 - // 2 unk 5.1.0 - int32 EquippedItemClass; // 3 m_equippedItemClass (value) - int32 EquippedItemInventoryTypeMask; // 4 m_equippedItemInvTypes (mask) - int32 EquippedItemSubClassMask; // 5 m_equippedItemSubclass (mask) + //uint32 Id; // 0 m_ID + // 1 unk 5.1.0 + // 2 unk 5.1.0 + int32 EquippedItemClass; // 3 m_equippedItemClass (value) + int32 EquippedItemInventoryTypeMask; // 4 m_equippedItemInvTypes (mask) + int32 EquippedItemSubClassMask; // 5 m_equippedItemSubclass (mask) }; // SpellInterrupts.dbc struct SpellInterruptsEntry { - //uint32 Id; // 0 m_ID - // 1 unk 5.1.0 - // 2 unk 5.1.0 - uint32 AuraInterruptFlags; // 3 m_auraInterruptFlags - //uint32 // 4 4.0.0 - uint32 ChannelInterruptFlags; // 5 m_channelInterruptFlags - //uint32 // 6 4.0.0 - uint32 InterruptFlags; // 7 m_interruptFlags + //uint32 Id; // 0 m_ID + // 1 unk 5.1.0 + // 2 unk 5.1.0 + uint32 AuraInterruptFlags; // 3 m_auraInterruptFlags + //uint32 // 4 4.0.0 + uint32 ChannelInterruptFlags; // 5 m_channelInterruptFlags + //uint32 // 6 4.0.0 + uint32 InterruptFlags; // 7 m_interruptFlags }; // SpellLevels.dbc struct SpellLevelsEntry { - //uint32 Id; // 0 m_ID - // 1 unk 5.1.0 - // 2 unk 5.1.0 - uint32 baseLevel; // 3 m_baseLevel - uint32 maxLevel; // 4 m_maxLevel - uint32 spellLevel; // 5 m_spellLevel + //uint32 Id; // 0 m_ID + // 1 unk 5.1.0 + // 2 unk 5.1.0 + uint32 baseLevel; // 3 m_baseLevel + uint32 maxLevel; // 4 m_maxLevel + uint32 spellLevel; // 5 m_spellLevel }; // SpellPower.dbc struct SpellPowerEntry { - //uint32 Id; // 0 - m_ID - uint32 SpellId; // 1 5.x - // 2 5.x - uint32 powerType; // 3 m_powerType - uint32 manaCost; // 4 m_manaCost - uint32 manaCostPerlevel; // 5 m_manaCostPerLevel - uint32 ManaCostPercentage; // 6 m_manaCostPct - uint32 manaPerSecond; // 7 m_manaPerSecond - //uint32 PowerDisplayId; // 8 m_powerDisplayID - id from PowerDisplay.dbc, new in 3.1 - //uint32 unk1; // 9 4.0.0 - //unk // 10 4.3.0 - // 11 5.x - // 12 5.x + //uint32 Id; // 0 - m_ID + uint32 SpellId; // 1 5.x + // 2 5.x + uint32 powerType; // 3 m_powerType + uint32 manaCost; // 4 m_manaCost + uint32 manaCostPerlevel; // 5 m_manaCostPerLevel + uint32 ManaCostPercentage; // 6 m_manaCostPct + uint32 manaPerSecond; // 7 m_manaPerSecond + //uint32 PowerDisplayId; // 8 m_powerDisplayID - id from PowerDisplay.dbc, new in 3.1 + //uint32 unk1; // 9 4.0.0 + //unk // 10 4.3.0 + // 11 5.x + // 12 5.x }; // SpellScaling.dbc struct SpellScalingEntry { - //uint32 Id; // 0 m_ID - int32 castTimeMin; // 1 - int32 castTimeMax; // 2 - int32 castScalingMaxLevel; // 3 - int32 playerClass; // 4 (index * 100) + charLevel => gtSpellScaling.dbc - float coeff1; // 5-7 - float coeff2; // 8-10 - float coeff3; // 11-13 - //float coefBase; // 14 some coefficient, mostly 1.0f - int32 coefLevelBase; // 15 some level - -// bool IsScalableEffect(SpellEffectIndex i) const { return coeff1[i] != 0.0f; }; + uint32 Id; // 0 m_ID + int32 castTimeMin; // 1 + int32 castTimeMax; // 2 + int32 castScalingMaxLevel; // 3 + int32 playerClass; // 4 (index * 100) + charLevel => gtSpellScaling.dbc + float coeff1; // 5 + float coeff2; // 6 + float coeff3; // 7 + int32 coefLevelBase; // 8 }; // SpellShapeshift.dbc struct SpellShapeshiftEntry { - //uint32 Id; // 0 m_ID - uint32 StancesNot; // 13 m_shapeshiftMask - // uint32 unk_320_2; // 14 3.2.0 - uint32 Stances; // 15 m_shapeshiftExclude - // uint32 unk_320_3; // 16 3.2.0 - // uint32 StanceBarOrder; // 155 m_stanceBarOrder not used + //uint32 Id; // 0 m_ID + uint32 StancesNot; // 13 m_shapeshiftMask + // uint32 unk_320_2; // 14 3.2.0 + uint32 Stances; // 15 m_shapeshiftExclude + // uint32 unk_320_3; // 16 3.2.0 + // uint32 StanceBarOrder; // 155 m_stanceBarOrder not used }; //// SpellShapeshiftForm.dbc @@ -2051,53 +2048,53 @@ struct SpellShapeshiftEntry // SpellTargetRestrictions.dbc struct SpellTargetRestrictionsEntry { - //uint32 Id; // 0 m_ID - // 1 unk 5.1.0 - // 2 unk 5.1.0 - float MaxTargetRadius; // 3 m_maxTargetRadius - //float // 4 unk 5.1.0 - uint32 MaxAffectedTargets; // 5 m_maxTargets - uint32 MaxTargetLevel; // 6 m_maxTargetLevel - uint32 TargetCreatureType; // 7 m_targetCreatureType - uint32 Targets; // 8 m_targets + //uint32 Id; // 0 m_ID + // 1 unk 5.1.0 + // 2 unk 5.1.0 + float MaxTargetRadius; // 3 m_maxTargetRadius + //float // 4 unk 5.1.0 + uint32 MaxAffectedTargets; // 5 m_maxTargets + uint32 MaxTargetLevel; // 6 m_maxTargetLevel + uint32 TargetCreatureType; // 7 m_targetCreatureType + uint32 Targets; // 8 m_targets }; // SpellTotems.dbc struct SpellTotemsEntry { - //uint32 Id; // 0 m_ID - uint32 TotemCategory[MAX_SPELL_TOTEM_CATEGORIES]; // 162-163 m_requiredTotemCategoryID - uint32 Totem[MAX_SPELL_TOTEMS]; // 52-53 m_totem + //uint32 Id; // 0 m_ID + uint32 TotemCategory[MAX_SPELL_TOTEM_CATEGORIES]; // 162-163 m_requiredTotemCategoryID + uint32 Totem[MAX_SPELL_TOTEMS]; // 52-53 m_totem }; // SpellMisc.dbc struct SpellMiscEntry { - //uint32 Id; // 0 - //uint32 SpellId; // 1 - //uint32 // 2 unk - uint32 Attributes; // 3 - uint32 AttributesEx; // 4 - uint32 AttributesEx2; // 5 - uint32 AttributesEx3; // 6 - uint32 AttributesEx4; // 7 - uint32 AttributesEx5; // 8 - uint32 AttributesEx6; // 9 - uint32 AttributesEx7; // 10 - uint32 AttributesEx8; // 11 - uint32 AttributesEx9; // 12 - uint32 AttributesEx10; // 13 - uint32 AttributesEx11; // 14 - uint32 AttributesEx12; // 15 - uint32 AttributesEx13; // 16 - uint32 CastingTimeIndex; // 17 m_castingTimeIndex - uint32 DurationIndex; // 18 m_durationIndex - uint32 rangeIndex; // 19 m_rangeIndex - float speed; // 20 m_speed - uint32 SpellVisual[2]; // 21-22 m_spellVisualID - uint32 SpellIconID; // 23 m_spellIconID - uint32 activeIconID; // 24 m_activeIconID - uint32 SchoolMask; // 25 m_schoolMask + //uint32 Id; // 0 + //uint32 SpellId; // 1 + //uint32 // 2 unk + uint32 Attributes; // 3 + uint32 AttributesEx; // 4 + uint32 AttributesEx2; // 5 + uint32 AttributesEx3; // 6 + uint32 AttributesEx4; // 7 + uint32 AttributesEx5; // 8 + uint32 AttributesEx6; // 9 + uint32 AttributesEx7; // 10 + uint32 AttributesEx8; // 11 + uint32 AttributesEx9; // 12 + uint32 AttributesEx10; // 13 + uint32 AttributesEx11; // 14 + uint32 AttributesEx12; // 15 + uint32 AttributesEx13; // 16 + uint32 CastingTimeIndex; // 17 m_castingTimeIndex + uint32 DurationIndex; // 18 m_durationIndex + uint32 rangeIndex; // 19 m_rangeIndex + float speed; // 20 m_speed + uint32 SpellVisual[2]; // 21-22 m_spellVisualID + uint32 SpellIconID; // 23 m_spellIconID + uint32 activeIconID; // 24 m_activeIconID + uint32 SchoolMask; // 25 m_schoolMask }; struct SpellReagentsEntry; @@ -2105,165 +2102,165 @@ struct SpellReagentsEntry; // Spell.dbc struct SpellEntry { - uint32 Id; // 0 m_ID - DBCString SpellName; // 1 m_name_lang - DBCString Rank; // 2 m_nameSubtext_lang - //DBCString Description; // 3 m_description_lang not used - //DBCString ToolTip; // 4 m_auraDescription_lang not used - uint32 runeCostID; // 5 m_runeCostID - //uint32 spellMissileID; // 6 m_spellMissileID not used - //uint32 spellDescriptionVariableID; // 7 m_spellDescriptionVariableID, 3.2.0 - //float unk_f1; // 8 - uint32 SpellScalingId; // 9 SpellScaling.dbc - uint32 SpellAuraOptionsId; // 10 SpellAuraOptions.dbc - uint32 SpellAuraRestrictionsId; // 11 SpellAuraRestrictions.dbc - uint32 SpellCastingRequirementsId; // 12 SpellCastingRequirements.dbc - uint32 SpellCategoriesId; // 13 SpellCategories.dbc - uint32 SpellClassOptionsId; // 14 SpellClassOptions.dbc - uint32 SpellCooldownsId; // 15 SpellCooldowns.dbc - uint32 SpellEquippedItemsId; // 16 SpellEquippedItems.dbc - uint32 SpellInterruptsId; // 17 SpellInterrupts.dbc - uint32 SpellLevelsId; // 18 SpellLevels.dbc - uint32 SpellReagentsId; // 19 SpellReagents.dbc - uint32 SpellShapeshiftId; // 20 SpellShapeshift.dbc - uint32 SpellTargetRestrictionsId; // 21 SpellTargetRestrictions.dbc - uint32 SpellTotemsId; // 22 SpellTotems.dbc - //uint32 ResearchProject; // 23 ResearchProject.dbc - uint32 SpellMiscId; // 24 SpellMisc.dbc - - // helpers - int32 CalculateSimpleValue(SpellEffectIndex eff) const; - ClassFamilyMask const& GetEffectSpellClassMask(SpellEffectIndex eff) const; - - // struct access functions - SpellAuraOptionsEntry const* GetSpellAuraOptions() const; - SpellAuraRestrictionsEntry const* GetSpellAuraRestrictions() const; - SpellCastingRequirementsEntry const* GetSpellCastingRequirements() const; - SpellCategoriesEntry const* GetSpellCategories() const; - SpellClassOptionsEntry const* GetSpellClassOptions() const; - SpellCooldownsEntry const* GetSpellCooldowns() const; - SpellEffectEntry const* GetSpellEffect(SpellEffectIndex eff) const; - SpellEquippedItemsEntry const* GetSpellEquippedItems() const; - SpellInterruptsEntry const* GetSpellInterrupts() const; - SpellLevelsEntry const* GetSpellLevels() const; - SpellPowerEntry const* GetSpellPower() const; - SpellReagentsEntry const* GetSpellReagents() const; - SpellScalingEntry const* GetSpellScaling() const; - SpellShapeshiftEntry const* GetSpellShapeshift() const; - SpellTargetRestrictionsEntry const* GetSpellTargetRestrictions() const; - SpellTotemsEntry const* GetSpellTotems() const; - SpellMiscEntry const* GetSpellMisc() const; - - // single fields - uint32 GetManaCost() const; - uint32 GetPreventionType() const; - uint32 GetCategory() const; - uint32 GetStartRecoveryTime() const; - uint32 GetMechanic() const; - uint32 GetRecoveryTime() const; - uint32 GetCategoryRecoveryTime() const; - uint32 GetStartRecoveryCategory() const; - uint32 GetSpellLevel() const; - int32 GetEquippedItemClass() const; - SpellFamily GetSpellFamilyName() const; - uint32 GetDmgClass() const; - uint32 GetDispel() const; - uint32 GetMaxAffectedTargets() const; - uint32 GetStackAmount() const; - uint32 GetManaCostPercentage() const; - uint32 GetProcCharges() const; - uint32 GetProcChance() const; - uint32 GetMaxLevel() const; - uint32 GetTargetAuraState() const; - uint32 GetManaPerSecond() const; - uint32 GetRequiresSpellFocus() const; - uint32 GetSpellEffectIdByIndex(SpellEffectIndex index) const; - uint32 GetAuraInterruptFlags() const; - uint32 GetEffectImplicitTargetAByIndex(SpellEffectIndex index) const; - int32 GetAreaGroupId() const; - uint32 GetFacingCasterFlags() const; - uint32 GetBaseLevel() const; - uint32 GetInterruptFlags() const; - uint32 GetTargetCreatureType() const; - int32 GetEffectMiscValue(SpellEffectIndex index) const; - uint32 GetStances() const; - uint32 GetStancesNot() const; - uint32 GetProcFlags() const; - uint32 GetChannelInterruptFlags() const; - uint32 GetManaCostPerLevel() const; - uint32 GetCasterAuraState() const; - uint32 GetTargets() const; - uint32 GetEffectApplyAuraNameByIndex(SpellEffectIndex index) const; - uint32 GetCastingTimeIndex() const; - uint32 GetDurationIndex() const; - uint32 GetRangeIndex() const; - float GetSpeed() const; - uint32 GetSpellVisual(int idx = 0) const; - uint32 GetSpellIconID() const; - uint32 GetActiveIconID() const; - uint32 GetSchoolMask() const; - uint32 GetPowerType() const; - - bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const - { - SpellClassOptionsEntry const* classOpt = GetSpellClassOptions(); - return classOpt && classOpt->IsFitToFamilyMask(familyFlags, familyFlags2); - } - - bool IsFitToFamily(SpellFamily family, uint64 familyFlags, uint32 familyFlags2 = 0) const - { - SpellClassOptionsEntry const* classOpt = GetSpellClassOptions(); - return classOpt && classOpt->IsFitToFamily(family, familyFlags, familyFlags2); - } - - bool IsFitToFamilyMask(ClassFamilyMask const& mask) const - { - SpellClassOptionsEntry const* classOpt = GetSpellClassOptions(); - return classOpt && classOpt->IsFitToFamilyMask(mask); - } - - bool IsFitToFamily(SpellFamily family, ClassFamilyMask const& mask) const - { - SpellClassOptionsEntry const* classOpt = GetSpellClassOptions(); - return classOpt && classOpt->IsFitToFamily(family, mask); - } - - uint32 GetAttributes() const; - uint32 GetAttributesEx() const; - uint32 GetAttributesEx2() const; - uint32 GetAttributesEx3() const; - uint32 GetAttributesEx4() const; - uint32 GetAttributesEx5() const; - uint32 GetAttributesEx6() const; - uint32 GetAttributesEx7() const; - uint32 GetAttributesEx8() const; - uint32 GetAttributesEx9() const; - uint32 GetAttributesEx10() const; - uint32 GetAttributesEx11() const; - uint32 GetAttributesEx12() const; - uint32 GetAttributesEx13() const; - inline bool HasAttribute(SpellAttributes attribute) const { return GetAttributes() & attribute; } - inline bool HasAttribute(SpellAttributesEx attribute) const { return GetAttributesEx() & attribute; } - inline bool HasAttribute(SpellAttributesEx2 attribute) const { return GetAttributesEx2() & attribute; } - inline bool HasAttribute(SpellAttributesEx3 attribute) const { return GetAttributesEx3() & attribute; } - inline bool HasAttribute(SpellAttributesEx4 attribute) const { return GetAttributesEx4() & attribute; } - inline bool HasAttribute(SpellAttributesEx5 attribute) const { return GetAttributesEx5() & attribute; } - inline bool HasAttribute(SpellAttributesEx6 attribute) const { return GetAttributesEx6() & attribute; } - inline bool HasAttribute(SpellAttributesEx7 attribute) const { return GetAttributesEx7() & attribute; } - inline bool HasAttribute(SpellAttributesEx8 attribute) const { return GetAttributesEx8() & attribute; } - inline bool HasAttribute(SpellAttributesEx9 attribute) const { return GetAttributesEx9() & attribute; } - inline bool HasAttribute(SpellAttributesEx10 attribute) const { return GetAttributesEx10() & attribute; } - inline bool HasAttribute(SpellAttributesEx11 attribute) const { return GetAttributesEx11() & attribute; } - inline bool HasAttribute(SpellAttributesEx12 attribute) const { return GetAttributesEx12() & attribute; } - inline bool HasAttribute(SpellAttributesEx13 attribute) const { return GetAttributesEx13() & attribute; } - - private: - // prevent creating custom entries (copy data from original in fact) - SpellEntry(SpellEntry const&); // DON'T must have implementation - - // catch wrong uses - template - bool IsFitToFamilyMask(SpellFamily family, T t) const; + uint32 Id; // 0 m_ID + DBCString SpellName; // 1 m_name_lang + DBCString Rank; // 2 m_nameSubtext_lang + //DBCString Description; // 3 m_description_lang not used + //DBCString ToolTip; // 4 m_auraDescription_lang not used + uint32 runeCostID; // 5 m_runeCostID + //uint32 spellMissileID; // 6 m_spellMissileID not used + //uint32 spellDescriptionVariableID; // 7 m_spellDescriptionVariableID, 3.2.0 + //float unk_f1; // 8 + uint32 SpellScalingId; // 9 SpellScaling.dbc + uint32 SpellAuraOptionsId; // 10 SpellAuraOptions.dbc + uint32 SpellAuraRestrictionsId; // 11 SpellAuraRestrictions.dbc + uint32 SpellCastingRequirementsId; // 12 SpellCastingRequirements.dbc + uint32 SpellCategoriesId; // 13 SpellCategories.dbc + uint32 SpellClassOptionsId; // 14 SpellClassOptions.dbc + uint32 SpellCooldownsId; // 15 SpellCooldowns.dbc + uint32 SpellEquippedItemsId; // 16 SpellEquippedItems.dbc + uint32 SpellInterruptsId; // 17 SpellInterrupts.dbc + uint32 SpellLevelsId; // 18 SpellLevels.dbc + uint32 SpellReagentsId; // 19 SpellReagents.dbc + uint32 SpellShapeshiftId; // 20 SpellShapeshift.dbc + uint32 SpellTargetRestrictionsId; // 21 SpellTargetRestrictions.dbc + uint32 SpellTotemsId; // 22 SpellTotems.dbc + //uint32 ResearchProject; // 23 ResearchProject.dbc + uint32 SpellMiscId; // 24 SpellMisc.dbc + + // helpers + int32 CalculateSimpleValue(SpellEffectIndex eff) const; + ClassFamilyMask const& GetEffectSpellClassMask(SpellEffectIndex eff) const; + + // struct access functions + SpellAuraOptionsEntry const* GetSpellAuraOptions() const; + SpellAuraRestrictionsEntry const* GetSpellAuraRestrictions() const; + SpellCastingRequirementsEntry const* GetSpellCastingRequirements() const; + SpellCategoriesEntry const* GetSpellCategories() const; + SpellClassOptionsEntry const* GetSpellClassOptions() const; + SpellCooldownsEntry const* GetSpellCooldowns() const; + SpellEffectEntry const* GetSpellEffect(SpellEffectIndex eff) const; + SpellEquippedItemsEntry const* GetSpellEquippedItems() const; + SpellInterruptsEntry const* GetSpellInterrupts() const; + SpellLevelsEntry const* GetSpellLevels() const; + SpellPowerEntry const* GetSpellPower() const; + SpellReagentsEntry const* GetSpellReagents() const; + SpellScalingEntry const* GetSpellScaling() const; + SpellShapeshiftEntry const* GetSpellShapeshift() const; + SpellTargetRestrictionsEntry const* GetSpellTargetRestrictions() const; + SpellTotemsEntry const* GetSpellTotems() const; + SpellMiscEntry const* GetSpellMisc() const; + + // single fields + uint32 GetManaCost() const; + uint32 GetPreventionType() const; + uint32 GetCategory() const; + uint32 GetStartRecoveryTime() const; + uint32 GetMechanic() const; + uint32 GetRecoveryTime() const; + uint32 GetCategoryRecoveryTime() const; + uint32 GetStartRecoveryCategory() const; + uint32 GetSpellLevel() const; + int32 GetEquippedItemClass() const; + SpellFamily GetSpellFamilyName() const; + uint32 GetDmgClass() const; + uint32 GetDispel() const; + uint32 GetMaxAffectedTargets() const; + uint32 GetStackAmount() const; + uint32 GetManaCostPercentage() const; + uint32 GetProcCharges() const; + uint32 GetProcChance() const; + uint32 GetMaxLevel() const; + uint32 GetTargetAuraState() const; + uint32 GetManaPerSecond() const; + uint32 GetRequiresSpellFocus() const; + uint32 GetSpellEffectIdByIndex(SpellEffectIndex index) const; + uint32 GetAuraInterruptFlags() const; + uint32 GetEffectImplicitTargetAByIndex(SpellEffectIndex index) const; + int32 GetAreaGroupId() const; + uint32 GetFacingCasterFlags() const; + uint32 GetBaseLevel() const; + uint32 GetInterruptFlags() const; + uint32 GetTargetCreatureType() const; + int32 GetEffectMiscValue(SpellEffectIndex index) const; + uint32 GetStances() const; + uint32 GetStancesNot() const; + uint32 GetProcFlags() const; + uint32 GetChannelInterruptFlags() const; + uint32 GetManaCostPerLevel() const; + uint32 GetCasterAuraState() const; + uint32 GetTargets() const; + uint32 GetEffectApplyAuraNameByIndex(SpellEffectIndex index) const; + uint32 GetCastingTimeIndex() const; + uint32 GetDurationIndex() const; + uint32 GetRangeIndex() const; + float GetSpeed() const; + uint32 GetSpellVisual(int idx = 0) const; + uint32 GetSpellIconID() const; + uint32 GetActiveIconID() const; + uint32 GetSchoolMask() const; + uint32 GetPowerType() const; + + bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const + { + SpellClassOptionsEntry const* classOpt = GetSpellClassOptions(); + return classOpt && classOpt->IsFitToFamilyMask(familyFlags, familyFlags2); + } + + bool IsFitToFamily(SpellFamily family, uint64 familyFlags, uint32 familyFlags2 = 0) const + { + SpellClassOptionsEntry const* classOpt = GetSpellClassOptions(); + return classOpt && classOpt->IsFitToFamily(family, familyFlags, familyFlags2); + } + + bool IsFitToFamilyMask(ClassFamilyMask const& mask) const + { + SpellClassOptionsEntry const* classOpt = GetSpellClassOptions(); + return classOpt && classOpt->IsFitToFamilyMask(mask); + } + + bool IsFitToFamily(SpellFamily family, ClassFamilyMask const& mask) const + { + SpellClassOptionsEntry const* classOpt = GetSpellClassOptions(); + return classOpt && classOpt->IsFitToFamily(family, mask); + } + + uint32 GetAttributes() const; + uint32 GetAttributesEx() const; + uint32 GetAttributesEx2() const; + uint32 GetAttributesEx3() const; + uint32 GetAttributesEx4() const; + uint32 GetAttributesEx5() const; + uint32 GetAttributesEx6() const; + uint32 GetAttributesEx7() const; + uint32 GetAttributesEx8() const; + uint32 GetAttributesEx9() const; + uint32 GetAttributesEx10() const; + uint32 GetAttributesEx11() const; + uint32 GetAttributesEx12() const; + uint32 GetAttributesEx13() const; + inline bool HasAttribute(SpellAttributes attribute) const { return GetAttributes() & attribute; } + inline bool HasAttribute(SpellAttributesEx attribute) const { return GetAttributesEx() & attribute; } + inline bool HasAttribute(SpellAttributesEx2 attribute) const { return GetAttributesEx2() & attribute; } + inline bool HasAttribute(SpellAttributesEx3 attribute) const { return GetAttributesEx3() & attribute; } + inline bool HasAttribute(SpellAttributesEx4 attribute) const { return GetAttributesEx4() & attribute; } + inline bool HasAttribute(SpellAttributesEx5 attribute) const { return GetAttributesEx5() & attribute; } + inline bool HasAttribute(SpellAttributesEx6 attribute) const { return GetAttributesEx6() & attribute; } + inline bool HasAttribute(SpellAttributesEx7 attribute) const { return GetAttributesEx7() & attribute; } + inline bool HasAttribute(SpellAttributesEx8 attribute) const { return GetAttributesEx8() & attribute; } + inline bool HasAttribute(SpellAttributesEx9 attribute) const { return GetAttributesEx9() & attribute; } + inline bool HasAttribute(SpellAttributesEx10 attribute) const { return GetAttributesEx10() & attribute; } + inline bool HasAttribute(SpellAttributesEx11 attribute) const { return GetAttributesEx11() & attribute; } + inline bool HasAttribute(SpellAttributesEx12 attribute) const { return GetAttributesEx12() & attribute; } + inline bool HasAttribute(SpellAttributesEx13 attribute) const { return GetAttributesEx13() & attribute; } + +private: + // prevent creating custom entries (copy data from original in fact) + SpellEntry(SpellEntry const&); // DON'T must have implementation + + // catch wrong uses + template + bool IsFitToFamilyMask(SpellFamily family, T t) const; }; // A few fields which are required for automated convertion @@ -2273,125 +2270,125 @@ struct SpellEntry struct SpellCastTimesEntry { - uint32 ID; // 0 m_ID - int32 CastTime; // 1 m_base - float CastTimePerLevel; // 2 m_perLevel - int32 MinCastTime; // 3 m_minimum + uint32 ID; // 0 m_ID + int32 CastTime; // 1 m_base + float CastTimePerLevel; // 2 m_perLevel + int32 MinCastTime; // 3 m_minimum }; struct SpellFocusObjectEntry { - uint32 ID; // 0 m_ID - //char* Name; // 1 m_name_lang + uint32 ID; // 0 m_ID + //char* Name; // 1 m_name_lang }; struct SpellRadiusEntry { - uint32 ID; // 0 m_ID - float Radius; // 1 m_radius - // 2 m_radiusPerLevel - //float // 3 5.x - //float RadiusMax; // 4 m_radiusMax + uint32 ID; // 0 m_ID + float Radius; // 1 m_radius + // 2 m_radiusPerLevel + //float // 3 5.x + //float RadiusMax; // 4 m_radiusMax }; struct SpellRangeEntry { - uint32 ID; // 0 m_ID - float minRange; // 1 m_rangeMin[2] - float minRangeFriendly; // 2 - float maxRange; // 3 m_rangeMax[2] - float maxRangeFriendly; // 4 - //uint32 Flags; // 5 m_flags - //char* Name; // 6-21 m_displayName_lang - //char* ShortName; // 23-38 m_displayNameShort_lang + uint32 ID; // 0 m_ID + float minRange; // 1 m_rangeMin[2] + float minRangeFriendly; // 2 + float maxRange; // 3 m_rangeMax[2] + float maxRangeFriendly; // 4 + //uint32 Flags; // 5 m_flags + //char* Name; // 6-21 m_displayName_lang + //char* ShortName; // 23-38 m_displayNameShort_lang }; struct SpellRuneCostEntry { - uint32 ID; // 0 m_ID - uint32 RuneCost[3]; // 1-3 m_blood m_unholy m_frost (0=blood, 1=frost, 2=unholy) - //uint32 // 4 5.x - uint32 runePowerGain; // 5 m_runicPower + uint32 ID; // 0 m_ID + uint32 RuneCost[3]; // 1-3 m_blood m_unholy m_frost (0=blood, 1=frost, 2=unholy) + //uint32 // 4 5.x + uint32 runePowerGain; // 5 m_runicPower - bool NoRuneCost() const { return RuneCost[0] == 0 && RuneCost[1] == 0 && RuneCost[2] == 0; } - bool NoRunicPowerGain() const { return runePowerGain == 0; } + bool NoRuneCost() const { return RuneCost[0] == 0 && RuneCost[1] == 0 && RuneCost[2] == 0; } + bool NoRunicPowerGain() const { return runePowerGain == 0; } }; struct SpellShapeshiftFormEntry { - uint32 ID; // 0 m_ID - //uint32 buttonPosition; // 1 m_bonusActionBar - //char* Name; // 2 m_name_lang - uint32 flags1; // 3 m_flags - int32 creatureType; // 4 m_creatureType <=0 humanoid, other normal creature types - //uint32 unk1; // 5 m_attackIconID - uint32 attackSpeed; // 6 m_combatRoundTime - uint32 modelID_A; // 7 m_creatureDisplayID[4] - uint32 modelID_H; // 8 - //uint32 unk3; // 9 unused always 0 - //uint32 unk4; // 10 unused always 0 - uint32 spellId[8]; // 11-18 m_presetSpellID[8] - //uint32 unk5; // 19 unused, !=0 for flight forms - //uint32 unk6; // 20 + uint32 ID; // 0 m_ID + //uint32 buttonPosition; // 1 m_bonusActionBar + //char* Name; // 2 m_name_lang + uint32 flags1; // 3 m_flags + int32 creatureType; // 4 m_creatureType <=0 humanoid, other normal creature types + //uint32 unk1; // 5 m_attackIconID + uint32 attackSpeed; // 6 m_combatRoundTime + uint32 modelID_A; // 7 m_creatureDisplayID[4] + uint32 modelID_H; // 8 + //uint32 unk3; // 9 unused always 0 + //uint32 unk4; // 10 unused always 0 + uint32 spellId[8]; // 11-18 m_presetSpellID[8] + //uint32 unk5; // 19 unused, !=0 for flight forms + //uint32 unk6; // 20 }; struct SpellDifficultyEntry { - uint32 ID; // 0 m_ID - uint32 spellId[MAX_DIFFICULTY]; // 1-4 m_difficultySpellID[4] + uint32 ID; // 0 m_ID + uint32 spellId[MAX_DIFFICULTY]; // 1-4 m_difficultySpellID[4] }; struct SpellDurationEntry { - uint32 ID; // m_ID - int32 Duration[3]; // m_duration, m_durationPerLevel, m_maxDuration + uint32 ID; // m_ID + int32 Duration[3]; // m_duration, m_durationPerLevel, m_maxDuration }; struct SpellItemEnchantmentEntry { - uint32 ID; // 0 m_ID - //uint32 charges; // 1 m_charges - uint32 type[3]; // 2-4 m_effect[3] - uint32 amount[3]; // 5-7 m_effectPointsMin[3] - uint32 spellid[3]; // 8-10 m_effectArg[3] - DBCString description; // 11 m_name_lang - uint32 aura_id; // 12 m_itemVisual - uint32 slot; // 13 m_flags - uint32 GemID; // 14 m_src_itemID - uint32 EnchantmentCondition; // 15 m_condition_id - //uint32 requiredSkill; // 16 m_requiredSkillID - //uint32 requiredSkillValue; // 17 m_requiredSkillRank - uint32 requiredLevel; // 18 new in 3.1 - //float // 19 5.x - //uint32 minItemLevel; // 20 new in 3.1 - //int32 // 21 5.x - //int32 // 22 5.4.1 - //float // 23 5.x - //uint32 // 24 5.x - //uint32 // 25 5.x + uint32 ID; // 0 m_ID + //uint32 charges; // 1 m_charges + uint32 type[3]; // 2-4 m_effect[3] + uint32 amount[3]; // 5-7 m_effectPointsMin[3] + uint32 spellid[3]; // 8-10 m_effectArg[3] + DBCString description; // 11 m_name_lang + uint32 aura_id; // 12 m_itemVisual + uint32 slot; // 13 m_flags + uint32 GemID; // 14 m_src_itemID + uint32 EnchantmentCondition; // 15 m_condition_id + //uint32 requiredSkill; // 16 m_requiredSkillID + //uint32 requiredSkillValue; // 17 m_requiredSkillRank + uint32 requiredLevel; // 18 new in 3.1 + //float // 19 5.x + //uint32 minItemLevel; // 20 new in 3.1 + //int32 // 21 5.x + //int32 // 22 5.4.1 + //float // 23 5.x + //uint32 // 24 5.x + //uint32 // 25 5.x }; struct SpellItemEnchantmentConditionEntry { - uint32 ID; // 0 m_ID - uint8 Color[5]; // 1-5 m_lt_operandType[5] - //uint32 LT_Operand[5]; // 6-10 m_lt_operand[5] - uint8 Comparator[5]; // 11-15 m_operator[5] - uint8 CompareColor[5]; // 15-20 m_rt_operandType[5] - uint32 Value[5]; // 21-25 m_rt_operand[5] - //uint8 Logic[5] // 25-30 m_logic[5] + uint32 ID; // 0 m_ID + uint8 Color[5]; // 1-5 m_lt_operandType[5] + //uint32 LT_Operand[5]; // 6-10 m_lt_operand[5] + uint8 Comparator[5]; // 11-15 m_operator[5] + uint8 CompareColor[5]; // 15-20 m_rt_operandType[5] + uint32 Value[5]; // 21-25 m_rt_operand[5] + //uint8 Logic[5] // 25-30 m_logic[5] }; struct SummonPropertiesEntry { - uint32 Id; // 0 m_id - uint32 Group; // 1 m_control (enum SummonPropGroup) - uint32 FactionId; // 2 m_faction - uint32 Title; // 3 m_title (enum UnitNameSummonTitle) - uint32 Slot; // 4 m_slot if title = UNITNAME_SUMMON_TITLE_TOTEM, its actual slot (0-6). - // if title = UNITNAME_SUMMON_TITLE_COMPANION, slot=6 -> defensive guardian, in other cases criter/minipet - // Slot may have other uses, selection of pet type in some cases? - uint32 Flags; // 5 m_flags (enum SummonPropFlags) + uint32 Id; // 0 m_id + uint32 Group; // 1 m_control (enum SummonPropGroup) + uint32 FactionId; // 2 m_faction + uint32 Title; // 3 m_title (enum UnitNameSummonTitle) + uint32 Slot; // 4 m_slot if title = UNITNAME_SUMMON_TITLE_TOTEM, its actual slot (0-6). + // if title = UNITNAME_SUMMON_TITLE_COMPANION, slot=6 -> defensive guardian, in other cases criter/minipet + // Slot may have other uses, selection of pet type in some cases? + uint32 Flags; // 5 m_flags (enum SummonPropFlags) }; #define MAX_TALENT_RANK 5 @@ -2400,287 +2397,289 @@ struct SummonPropertiesEntry struct TalentEntry { - uint32 TalentID; // 0 m_ID - uint32 TalentTab; // 1 m_tabID (TalentTab.dbc) - uint32 Row; // 2 m_tierID - uint32 Col; // 3 m_columnIndex - uint32 RankID[MAX_TALENT_RANK]; // 4-6 m_spellRank - uint32 DependsOn; // 9 m_prereqTalent (Talent.dbc) - // 10-11 part of prev field - uint32 DependsOnRank; // 12 m_prereqRank - // 13-14 part of prev field - //uint32 needAddInSpellBook; // 15 m_flags also need disable higest ranks on reset talent tree - //uint32 unk1; // 16 m_requiredSpellID - //uint64 allowForPet; // 17 m_categoryMask its a 64 bit mask for pet 1< PetFamilySpellsStore; // Structures not used for casting to loaded DBC data and not required then packing struct TalentSpellPos { - TalentSpellPos() : talent_id(0), rank(0) {} - TalentSpellPos(uint16 _talent_id, uint8 _rank) : talent_id(_talent_id), rank(_rank) {} + TalentSpellPos() : talent_id(0), rank(0) {} + TalentSpellPos(uint16 _talent_id, uint8 _rank) : talent_id(_talent_id), rank(_rank) {} - uint16 talent_id; - uint8 rank; + uint16 talent_id; + uint8 rank; }; typedef std::map TalentSpellPosMap; struct SpellEffect { - SpellEffect() - { - memset(effects, 0, sizeof(effects)); - } - SpellEffectEntry const* effects[MAX_EFFECT_INDEX]; + SpellEffect() + { + memset(effects, 0, sizeof(effects)); + } + SpellEffectEntry const* effects[MAX_EFFECT_INDEX]; }; typedef std::map SpellEffectMap; struct TaxiPathBySourceAndDestination { - TaxiPathBySourceAndDestination() : ID(0), price(0) {} - TaxiPathBySourceAndDestination(uint32 _id, uint32 _price) : ID(_id), price(_price) {} + TaxiPathBySourceAndDestination() : ID(0), price(0) {} + TaxiPathBySourceAndDestination(uint32 _id, uint32 _price) : ID(_id), price(_price) {} - uint32 ID; - uint32 price; + uint32 ID; + uint32 price; }; typedef std::map TaxiPathSetForSource; typedef std::map TaxiPathSetBySource; struct TaxiPathNodePtr { - TaxiPathNodePtr() : i_ptr(NULL) {} - TaxiPathNodePtr(TaxiPathNodeEntry const* ptr) : i_ptr(ptr) {} + TaxiPathNodePtr() : i_ptr(NULL) {} + TaxiPathNodePtr(TaxiPathNodeEntry const* ptr) : i_ptr(ptr) {} - TaxiPathNodeEntry const* i_ptr; + TaxiPathNodeEntry const* i_ptr; - operator TaxiPathNodeEntry const& () const { return *i_ptr; } + operator TaxiPathNodeEntry const& () const { return *i_ptr; } }; typedef Path TaxiPathNodeList; @@ -2747,4 +2746,4 @@ typedef UNORDERED_MAP TransportAnimationsByE #define TaxiMaskSize 114 typedef uint8 TaxiMask[TaxiMaskSize]; -#endif +#endif \ No newline at end of file diff --git a/src/game/Server/DBCfmt.h b/src/game/Server/DBCfmt.h index debf59d1d..b3daab269 100644 --- a/src/game/Server/DBCfmt.h +++ b/src/game/Server/DBCfmt.h @@ -27,14 +27,14 @@ const char Achievementfmt[]= "niiissiiiiisiix"; const char AchievementCriteriafmt[]="niiiiiiiixsiiiiixxxxxxx"; -const char AreaTableEntryfmt[] = "iiinixxxxxxxisiiiiixxxxxxxxxxx"; // TODO: NEED TO CONFIRM THIS +const char AreaTableEntryfmt[] = "iiinixxxxxxxisiiiiixxxxxxxxxxx"; // TODO: NEED TO CONFIRM THIs const char AreaGroupEntryfmt[] = "niiiiiii"; const char AreaTriggerEntryfmt[]="nifffxxxfffffxxx"; const char ArmorLocationfmt[]="nfffff"; const char AuctionHouseEntryfmt[]= "niiix"; const char BankBagSlotPricesEntryfmt[] = "ni"; const char BarberShopStyleEntryfmt[]= "nixxxiii"; -const char BattlemasterListEntryfmt[]="niiiiiiiiiiiiiiiiixsiiiiiiiixx"; // TODO: NEED TO CONFIRM THIS +const char BattlemasterListEntryfmt[]="niiiiiiiiiiiiiiiisxiiiiiiiiixx"; // TODO: NEED TO CONFIRM THIS const char CharStartOutfitEntryfmt[]= "diiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; const char CharTitlesEntryfmt[]="nxsxix"; const char ChatChannelsEntryfmt[]="iixsx"; @@ -107,9 +107,9 @@ const char Phasefmt[]="nii"; const char PvPDifficultyfmt[] = "diiiii"; const char RandomPropertiesPointsfmt[] = "niiiiiiiiiiiiiii"; const char ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiixi"; -const char ScalingStatValuesfmt[]="iniiiiiixiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxx"; // TODO: NEED TO CONFIRM THIS +const char ScalingStatValuesfmt[]="niiiiiiixiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxx"; // TODO: NEED TO CONFIRM THIS const char SkillLinefmt[]="nisxixixx"; // TODO: NEED TO CONFIRM THIS -const char SkillLineAbilityfmt[]="niiiixxiiiiii"; +const char SkillLineAbilityfmt[]="niiiiiiiiiixx"; const char SkillRaceClassInfofmt[]="diiiiixx"; const char SoundEntriesfmt[]="nisxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // TODO: NEED TO CONFIRM THIS const char SpellCastTimefmt[]="niii"; @@ -127,7 +127,7 @@ const char SpellEquippedItemsEntryfmt[]="dxxiii"; const char SpellInterruptsEntryfmt[]="dxxixixi"; const char SpellLevelsEntryfmt[]="dxxiii"; const char SpellPowerEntryfmt[]="xnxiiiiixxxxx"; -const char SpellScalingEntryfmt[]="diiiifffi"; // TODO: NEED TO CONFIRM THIS +const char SpellScalingEntryfmt[]="niiiifffi"; // TODO: NEED TO CONFIRM THIS const char SpellShapeshiftEntryfmt[]="dixixx"; const char SpellTargetRestrictionsEntryfmt[]="dxxfxiiii"; const char SpellTotemsEntryfmt[]="diiii";