Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-02-11 23:45:22 +08:00
54 changed files with 1943 additions and 1547 deletions
@@ -0,0 +1,5 @@
-- DB update 2024_02_05_04 -> 2024_02_06_00
--
UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_tainted_elemental' WHERE `entry` = 22009;
DELETE FROM `smart_scripts` WHERE `entryorguid` = 22009 AND `source_type` = 0;
@@ -0,0 +1,5 @@
-- DB update 2024_02_06_00 -> 2024_02_08_00
--
DELETE FROM `creature_template_movement` WHERE `CreatureId` = 24224;
INSERT INTO `creature_template_movement` (`CreatureId`, `Flight`, `Rooted`) VALUES
(24224, 1, 1);
@@ -0,0 +1,3 @@
-- DB update 2024_02_08_00 -> 2024_02_08_01
--
UPDATE `creature_template` SET `spell_school_immune_mask` = `spell_school_immune_mask`|4 WHERE `entry` IN (19514, 19551);
@@ -0,0 +1,4 @@
-- DB update 2024_02_08_01 -> 2024_02_08_02
DELETE FROM `gossip_menu_option` WHERE `MenuID`=21893;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(21893, 0, 0, 'Hand over the Southfury moonstone and I\'ll let you go.', 20723, 1, 1, 0, 0, 0, 0, '', 0, 0);
+5 -5
View File
@@ -12,10 +12,10 @@
if(WIN32) if(WIN32)
set(BOOST_DEBUG ON) set(BOOST_DEBUG ON)
if(DEFINED ENV{BOOST_ROOT}) if(DEFINED ENV{Boost_ROOT})
set(BOOST_ROOT $ENV{BOOST_ROOT}) set(Boost_ROOT $ENV{Boost_ROOT})
list(APPEND BOOST_LIBRARYDIR list(APPEND BOOST_LIBRARYDIR
${BOOST_ROOT}/lib${PLATFORM}-msvc-14.2) ${Boost_ROOT}/lib${PLATFORM}-msvc-14.2)
endif() endif()
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
@@ -35,8 +35,8 @@ endif()
find_package(Boost ${BOOST_REQUIRED_VERSION} REQUIRED system filesystem program_options iostreams regex thread) find_package(Boost ${BOOST_REQUIRED_VERSION} REQUIRED system filesystem program_options iostreams regex thread)
if(NOT Boost_FOUND) if(NOT Boost_FOUND)
if(NOT DEFINED ENV{BOOST_ROOT} AND NOT DEFINED Boost_DIR AND NOT DEFINED BOOST_ROOT AND NOT DEFINED BOOSTROOT) if(NOT DEFINED ENV{Boost_ROOT} AND NOT DEFINED Boost_DIR AND NOT DEFINED BOOST_ROOT AND NOT DEFINED BOOSTROOT)
message(FATAL_ERROR "No BOOST_ROOT environment variable could be found! Please make sure it is set and the points to your Boost installation.") message(FATAL_ERROR "No Boost_ROOT environment variable could be found! Please make sure it is set and the points to your Boost installation.")
endif() endif()
endif() endif()
+254 -103
View File
@@ -7,15 +7,29 @@ FindOpenSSL
Find the OpenSSL encryption library. Find the OpenSSL encryption library.
This module finds an installed OpenSSL library and determines its version.
.. versionadded:: 3.19
When a version is requested, it can be specified as a simple value or as a
range. For a detailed description of version range usage and capabilities,
refer to the :command:`find_package` command.
.. versionadded:: 3.18
Support for OpenSSL 3.0.
Optional COMPONENTS Optional COMPONENTS
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
.. versionadded:: 3.12
This module supports two optional COMPONENTS: ``Crypto`` and ``SSL``. Both This module supports two optional COMPONENTS: ``Crypto`` and ``SSL``. Both
components have associated imported targets, as described below. components have associated imported targets, as described below.
Imported Targets Imported Targets
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
.. versionadded:: 3.4
This module defines the following :prop_tgt:`IMPORTED` targets: This module defines the following :prop_tgt:`IMPORTED` targets:
``OpenSSL::SSL`` ``OpenSSL::SSL``
@@ -23,6 +37,8 @@ This module defines the following :prop_tgt:`IMPORTED` targets:
``OpenSSL::Crypto`` ``OpenSSL::Crypto``
The OpenSSL ``crypto`` library, if found. The OpenSSL ``crypto`` library, if found.
``OpenSSL::applink`` ``OpenSSL::applink``
.. versionadded:: 3.18
The OpenSSL ``applink`` components that might be need to be compiled into The OpenSSL ``applink`` components that might be need to be compiled into
projects under MSVC. This target is available only if found OpenSSL version projects under MSVC. This target is available only if found OpenSSL version
is not less than 0.9.8. By linking this target the above OpenSSL targets can is not less than 0.9.8. By linking this target the above OpenSSL targets can
@@ -74,36 +90,115 @@ This module will set the following variables in your project:
Hints Hints
^^^^^ ^^^^^
Set ``OPENSSL_ROOT_DIR`` to the root directory of an OpenSSL installation. The following variables may be set to control search behavior:
Set ``OPENSSL_USE_STATIC_LIBS`` to ``TRUE`` to look for static libraries.
Set ``OPENSSL_MSVC_STATIC_RT`` set ``TRUE`` to choose the MT version of the lib. ``OPENSSL_ROOT_DIR``
Set to the root directory of an OpenSSL installation.
``OPENSSL_USE_STATIC_LIBS``
.. versionadded:: 3.4
Set to ``TRUE`` to look for static libraries.
``OPENSSL_MSVC_STATIC_RT``
.. versionadded:: 3.5
Set to ``TRUE`` to choose the MT version of the lib.
``ENV{PKG_CONFIG_PATH}``
On UNIX-like systems, ``pkg-config`` is used to locate the system OpenSSL.
Set the ``PKG_CONFIG_PATH`` environment variable to look in alternate
locations. Useful on multi-lib systems.
#]=======================================================================] #]=======================================================================]
set(OPENSSL_EXPECTED_VERSION "1.0")
macro(_OpenSSL_test_and_find_dependencies ssl_library crypto_library) macro(_OpenSSL_test_and_find_dependencies ssl_library crypto_library)
if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND unset(_OpenSSL_extra_static_deps)
if(UNIX AND
(("${ssl_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$") OR (("${ssl_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$") OR
("${crypto_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$"))) ("${crypto_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$")))
set(_OpenSSL_has_dependencies TRUE) set(_OpenSSL_has_dependencies TRUE)
find_package(Threads) unset(_OpenSSL_has_dependency_zlib)
if(OPENSSL_USE_STATIC_LIBS)
set(_OpenSSL_libs "${_OPENSSL_STATIC_LIBRARIES}")
set(_OpenSSL_ldflags_other "${_OPENSSL_STATIC_LDFLAGS_OTHER}")
else()
set(_OpenSSL_libs "${_OPENSSL_LIBRARIES}")
set(_OpenSSL_ldflags_other "${_OPENSSL_LDFLAGS_OTHER}")
endif()
if(_OpenSSL_libs)
unset(_OpenSSL_has_dependency_dl)
foreach(_OPENSSL_DEP_LIB IN LISTS _OpenSSL_libs)
if (_OPENSSL_DEP_LIB STREQUAL "ssl" OR _OPENSSL_DEP_LIB STREQUAL "crypto")
# ignoring: these are the targets
elseif(_OPENSSL_DEP_LIB STREQUAL CMAKE_DL_LIBS)
set(_OpenSSL_has_dependency_dl TRUE)
elseif(_OPENSSL_DEP_LIB STREQUAL "z")
find_package(ZLIB)
set(_OpenSSL_has_dependency_zlib TRUE)
else()
list(APPEND _OpenSSL_extra_static_deps "${_OPENSSL_DEP_LIB}")
endif()
endforeach()
unset(_OPENSSL_DEP_LIB)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(_OpenSSL_has_dependency_dl TRUE)
endif()
if(_OpenSSL_ldflags_other)
unset(_OpenSSL_has_dependency_threads)
foreach(_OPENSSL_DEP_LDFLAG IN LISTS _OpenSSL_ldflags_other)
if (_OPENSSL_DEP_LDFLAG STREQUAL "-pthread")
set(_OpenSSL_has_dependency_threads TRUE)
find_package(Threads)
endif()
endforeach()
unset(_OPENSSL_DEP_LDFLAG)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(_OpenSSL_has_dependency_threads TRUE)
find_package(Threads)
endif()
unset(_OpenSSL_libs)
unset(_OpenSSL_ldflags_other)
else() else()
set(_OpenSSL_has_dependencies FALSE) set(_OpenSSL_has_dependencies FALSE)
endif() endif()
endmacro() endmacro()
function(_OpenSSL_add_dependencies libraries_var) function(_OpenSSL_add_dependencies libraries_var)
if(CMAKE_THREAD_LIBS_INIT) if(_OpenSSL_has_dependency_zlib)
list(APPEND ${libraries_var} ${ZLIB_LIBRARY})
endif()
if(_OpenSSL_has_dependency_threads)
list(APPEND ${libraries_var} ${CMAKE_THREAD_LIBS_INIT}) list(APPEND ${libraries_var} ${CMAKE_THREAD_LIBS_INIT})
endif() endif()
list(APPEND ${libraries_var} ${CMAKE_DL_LIBS}) if(_OpenSSL_has_dependency_dl)
list(APPEND ${libraries_var} ${CMAKE_DL_LIBS})
endif()
list(APPEND ${libraries_var} ${_OpenSSL_extra_static_deps})
set(${libraries_var} ${${libraries_var}} PARENT_SCOPE) set(${libraries_var} ${${libraries_var}} PARENT_SCOPE)
endfunction() endfunction()
function(_OpenSSL_target_add_dependencies target) function(_OpenSSL_target_add_dependencies target)
if(_OpenSSL_has_dependencies) if(_OpenSSL_has_dependencies)
set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES Threads::Threads ) if(_OpenSSL_has_dependency_zlib)
set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS} ) set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ZLIB::ZLIB )
endif()
if(_OpenSSL_has_dependency_threads)
set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES Threads::Threads)
endif()
if(_OpenSSL_has_dependency_dl)
set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS} )
endif()
if(_OpenSSL_extra_static_deps)
set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_OpenSSL_extra_static_deps})
endif()
endif()
if(WIN32 AND OPENSSL_USE_STATIC_LIBS)
if(WINCE)
set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2 )
else()
set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2_32 )
endif()
set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES crypt32 )
endif() endif()
endfunction() endfunction()
@@ -115,62 +210,87 @@ endif ()
# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
if(OPENSSL_USE_STATIC_LIBS) if(OPENSSL_USE_STATIC_LIBS)
set(_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
if(WIN32) if(MSVC)
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
else() else()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) set(CMAKE_FIND_LIBRARY_SUFFIXES .a )
endif() endif()
endif() endif()
if (WIN32) if(CMAKE_SYSTEM_NAME STREQUAL "QNX" AND
CMAKE_SYSTEM_VERSION VERSION_GREATER_EQUAL "7.0" AND CMAKE_SYSTEM_VERSION VERSION_LESS "7.1" AND
OpenSSL_FIND_VERSION VERSION_GREATER_EQUAL "1.1" AND OpenSSL_FIND_VERSION VERSION_LESS "1.2")
# QNX 7.0.x provides openssl 1.0.2 and 1.1.1 in parallel:
# * openssl 1.0.2: libcrypto.so.2 and libssl.so.2, headers under usr/include/openssl
# * openssl 1.1.1: libcrypto1_1.so.2.1 and libssl1_1.so.2.1, header under usr/include/openssl1_1
# See http://www.qnx.com/developers/articles/rel_6726_0.html
set(_OPENSSL_FIND_PATH_SUFFIX "openssl1_1")
set(_OPENSSL_NAME_POSTFIX "1_1")
else()
set(_OPENSSL_FIND_PATH_SUFFIX "include")
endif()
if (OPENSSL_ROOT_DIR OR NOT "$ENV{OPENSSL_ROOT_DIR}" STREQUAL "")
set(_OPENSSL_ROOT_HINTS HINTS ${OPENSSL_ROOT_DIR} ENV OPENSSL_ROOT_DIR)
set(_OPENSSL_ROOT_PATHS NO_DEFAULT_PATH)
elseif (MSVC)
# http://www.slproweb.com/products/Win32OpenSSL.html # http://www.slproweb.com/products/Win32OpenSSL.html
set(_OPENSSL_MSI_INSTALL_GUID "") set(_OPENSSL_MSI_INSTALL_GUIDS "")
if(PLATFORM EQUAL 64)
set(_OPENSSL_MSI_INSTALL_GUID "117551DB-A110-4BBD-BB05-CFE0BCB3ED31") if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
set(_OPENSSL_ROOT_HINTS if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]" set(_arch "Win64-ARM")
${OPENSSL_ROOT_DIR} set(_OPENSSL_MSI_INSTALL_GUIDS "99C28AFA-6419-40B1-B88D-32B810BB4234")
ENV OPENSSL_ROOT_DIR else()
) set(_arch "Win64")
set(_OPENSSL_MSI_INSTALL_GUIDS "117551DB-A110-4BBD-BB05-CFE0BCB3ED31" "50A9FBE2-0F8C-4D5D-97A4-A63A71C4EA1E")
endif()
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
set(_OPENSSL_ROOT_PATHS set(_OPENSSL_ROOT_HINTS HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]")
"${_programfiles}/OpenSSL"
"${_programfiles}/OpenSSL-Win64"
"C:/OpenSSL/"
"C:/OpenSSL-Win64/"
)
else() else()
set(_OPENSSL_MSI_INSTALL_GUID "A1EEC576-43B9-4E75-9E02-03DA542D2A38") set(_arch "Win32")
set(_OPENSSL_ROOT_HINTS set(_progfiles_x86 "ProgramFiles(x86)")
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]" if(NOT "$ENV{${_progfiles_x86}}" STREQUAL "")
${OPENSSL_ROOT_DIR} # under windows 64 bit machine
ENV OPENSSL_ROOT_DIR file(TO_CMAKE_PATH "$ENV{${_progfiles_x86}}" _programfiles)
) else()
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) # under windows 32 bit machine
set(_OPENSSL_ROOT_PATHS file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _programfiles)
"${_programfiles}/OpenSSL" endif()
"${_programfiles}/OpenSSL-Win32" set(_OPENSSL_ROOT_HINTS HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]")
"C:/OpenSSL/" set(_OPENSSL_MSI_INSTALL_GUIDS "A1EEC576-43B9-4E75-9E02-03DA542D2A38" "31D2408A-9CAE-4988-9EC3-F40FDE7D6AE5")
"C:/OpenSSL-Win32/"
)
endif() endif()
unset(_programfiles)
# If OpenSSL was installed using .msi package instead of .exe, Inno Setup registry values are not written to Uninstall\OpenSSL # If OpenSSL was installed using .msi package instead of .exe, Inno Setup registry values are not written to Uninstall\OpenSSL
# but because it is only a shim around Inno Setup it does write the location of uninstaller which we can use to determine path # but because it is only a shim around Inno Setup it does write the location of uninstaller which we can use to determine path
get_filename_component(_OPENSSL_MSI_INSTALL_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Inno Setup MSIs\\${_OPENSSL_MSI_INSTALL_GUID};]" DIRECTORY) foreach(_OPENSSL_MSI_INSTALL_GUID IN LISTS _OPENSSL_MSI_INSTALL_GUIDS)
if(NOT _OPENSSL_MSI_INSTALL_PATH STREQUAL "/") get_filename_component(_OPENSSL_MSI_INSTALL_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Inno Setup MSIs\\${_OPENSSL_MSI_INSTALL_GUID};]" DIRECTORY)
list(INSERT _OPENSSL_ROOT_HINTS 0 ${_OPENSSL_MSI_INSTALL_PATH}) if(NOT _OPENSSL_MSI_INSTALL_PATH STREQUAL "/")
endif() list(INSERT _OPENSSL_ROOT_HINTS 2 ${_OPENSSL_MSI_INSTALL_PATH})
else () endif()
set(_OPENSSL_ROOT_HINTS endforeach()
${OPENSSL_ROOT_DIR} unset(_OPENSSL_MSI_INSTALL_GUIDS)
ENV OPENSSL_ROOT_DIR
set(_OPENSSL_ROOT_PATHS
PATHS
"${_programfiles}/OpenSSL"
"${_programfiles}/OpenSSL-${_arch}"
"C:/OpenSSL/"
"C:/OpenSSL-${_arch}/"
) )
unset(_programfiles)
unset(_arch)
endif () endif ()
if(HOMEBREW_PREFIX)
list(APPEND _OPENSSL_ROOT_HINTS
"${HOMEBREW_PREFIX}/opt/openssl@1.1"
"${HOMEBREW_PREFIX}/opt/openssl@3")
endif()
set(_OPENSSL_ROOT_HINTS_AND_PATHS set(_OPENSSL_ROOT_HINTS_AND_PATHS
HINTS ${_OPENSSL_ROOT_HINTS} ${_OPENSSL_ROOT_HINTS}
PATHS ${_OPENSSL_ROOT_PATHS} ${_OPENSSL_ROOT_PATHS}
) )
find_path(OPENSSL_INCLUDE_DIR find_path(OPENSSL_INCLUDE_DIR
@@ -181,7 +301,7 @@ find_path(OPENSSL_INCLUDE_DIR
${_OPENSSL_INCLUDEDIR} ${_OPENSSL_INCLUDEDIR}
${_OPENSSL_INCLUDE_DIRS} ${_OPENSSL_INCLUDE_DIRS}
PATH_SUFFIXES PATH_SUFFIXES
include ${_OPENSSL_FIND_PATH_SUFFIX}
) )
if(WIN32 AND NOT CYGWIN) if(WIN32 AND NOT CYGWIN)
@@ -210,9 +330,15 @@ if(WIN32 AND NOT CYGWIN)
# Since OpenSSL 1.1, lib names are like libcrypto32MTd.lib and libssl32MTd.lib # Since OpenSSL 1.1, lib names are like libcrypto32MTd.lib and libssl32MTd.lib
if( "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8" ) if( "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8" )
set(_OPENSSL_MSVC_ARCH_SUFFIX "64") set(_OPENSSL_MSVC_ARCH_SUFFIX "64")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
set(_OPENSSL_MSVC_ARCH_DIRECTORY "arm64")
else()
set(_OPENSSL_MSVC_ARCH_DIRECTORY "x64")
endif()
else() else()
set(_OPENSSL_MSVC_ARCH_SUFFIX "32") set(_OPENSSL_MSVC_ARCH_SUFFIX "32")
set(_OPENSSL_MSVC_ARCH_DIRECTORY "x86")
endif() endif()
if(OPENSSL_USE_STATIC_LIBS) if(OPENSSL_USE_STATIC_LIBS)
@@ -237,29 +363,40 @@ if(WIN32 AND NOT CYGWIN)
find_library(LIB_EAY_DEBUG find_library(LIB_EAY_DEBUG
NAMES NAMES
# When OpenSSL is built with default options, the static library name is suffixed with "_static". libcrypto${_OPENSSL_STATIC_SUFFIX}
# Looking the "libcrypto_static.lib" with a higher priority than "libcrypto.lib" which is the
# import library of "libcrypto.dll".
libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libcrypto${_OPENSSL_STATIC_SUFFIX}d
libeay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libeay32${_OPENSSL_STATIC_SUFFIX}d
crypto${_OPENSSL_STATIC_SUFFIX}d
# When OpenSSL is built with the "-static" option, only the static build is produced,
# and it is not suffixed with "_static".
libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libcrypto${_OPENSSL_MSVC_RT_MODE}d
libcryptod
libeay32${_OPENSSL_MSVC_RT_MODE}d
libeay32d
cryptod
NAMES_PER_DIR NAMES_PER_DIR
${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES PATH_SUFFIXES
${_OPENSSL_PATH_SUFFIXES} "lib/VC/${_OPENSSL_MSVC_ARCH_DIRECTORY}/${_OPENSSL_MSVC_RT_MODE}d"
) )
if(NOT LIB_EAY_DEBUG)
find_library(LIB_EAY_DEBUG
NAMES
# When OpenSSL is built with default options, the static library name is suffixed with "_static".
# Looking the "libcrypto_static.lib" with a higher priority than "libcrypto.lib" which is the
# import library of "libcrypto.dll".
libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libcrypto${_OPENSSL_STATIC_SUFFIX}d
libeay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libeay32${_OPENSSL_STATIC_SUFFIX}d
crypto${_OPENSSL_STATIC_SUFFIX}d
# When OpenSSL is built with the "-static" option, only the static build is produced,
# and it is not suffixed with "_static".
libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libcrypto${_OPENSSL_MSVC_RT_MODE}d
libcryptod
libeay32${_OPENSSL_MSVC_RT_MODE}d
libeay32d
cryptod
NAMES_PER_DIR
${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
${_OPENSSL_PATH_SUFFIXES}
)
endif()
find_library(LIB_EAY_RELEASE find_library(LIB_EAY_RELEASE
NAMES NAMES
# When OpenSSL is built with default options, the static library name is suffixed with "_static". # When OpenSSL is built with default options, the static library name is suffixed with "_static".
@@ -283,33 +420,45 @@ if(WIN32 AND NOT CYGWIN)
${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES PATH_SUFFIXES
${_OPENSSL_PATH_SUFFIXES} ${_OPENSSL_PATH_SUFFIXES}
"lib/VC/${_OPENSSL_MSVC_ARCH_DIRECTORY}/${_OPENSSL_MSVC_RT_MODE}"
) )
find_library(SSL_EAY_DEBUG find_library(SSL_EAY_DEBUG
NAMES NAMES
# When OpenSSL is built with default options, the static library name is suffixed with "_static". libssl${_OPENSSL_STATIC_SUFFIX}
# Looking the "libssl_static.lib" with a higher priority than "libssl.lib" which is the
# import library of "libssl.dll".
libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libssl${_OPENSSL_STATIC_SUFFIX}d
ssleay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
ssleay32${_OPENSSL_STATIC_SUFFIX}d
ssl${_OPENSSL_STATIC_SUFFIX}d
# When OpenSSL is built with the "-static" option, only the static build is produced,
# and it is not suffixed with "_static".
libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libssl${_OPENSSL_MSVC_RT_MODE}d
libssld
ssleay32${_OPENSSL_MSVC_RT_MODE}d
ssleay32d
ssld
NAMES_PER_DIR NAMES_PER_DIR
${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES PATH_SUFFIXES
${_OPENSSL_PATH_SUFFIXES} "lib/VC/${_OPENSSL_MSVC_ARCH_DIRECTORY}/${_OPENSSL_MSVC_RT_MODE}d"
) )
if(NOT SSL_EAY_DEBUG)
find_library(SSL_EAY_DEBUG
NAMES
# When OpenSSL is built with default options, the static library name is suffixed with "_static".
# Looking the "libssl_static.lib" with a higher priority than "libssl.lib" which is the
# import library of "libssl.dll".
libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libssl${_OPENSSL_STATIC_SUFFIX}d
ssleay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
ssleay32${_OPENSSL_STATIC_SUFFIX}d
ssl${_OPENSSL_STATIC_SUFFIX}d
# When OpenSSL is built with the "-static" option, only the static build is produced,
# and it is not suffixed with "_static".
libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
libssl${_OPENSSL_MSVC_RT_MODE}d
libssld
ssleay32${_OPENSSL_MSVC_RT_MODE}d
ssleay32d
ssld
NAMES_PER_DIR
${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
${_OPENSSL_PATH_SUFFIXES}
)
endif()
find_library(SSL_EAY_RELEASE find_library(SSL_EAY_RELEASE
NAMES NAMES
# When OpenSSL is built with default options, the static library name is suffixed with "_static". # When OpenSSL is built with default options, the static library name is suffixed with "_static".
@@ -333,6 +482,7 @@ if(WIN32 AND NOT CYGWIN)
${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES PATH_SUFFIXES
${_OPENSSL_PATH_SUFFIXES} ${_OPENSSL_PATH_SUFFIXES}
"lib/VC/${_OPENSSL_MSVC_ARCH_DIRECTORY}/${_OPENSSL_MSVC_RT_MODE}"
) )
set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}") set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}")
@@ -360,6 +510,7 @@ if(WIN32 AND NOT CYGWIN)
PATH_SUFFIXES PATH_SUFFIXES
"lib/MinGW" "lib/MinGW"
"lib" "lib"
"lib64"
) )
find_library(SSL_EAY find_library(SSL_EAY
@@ -370,6 +521,7 @@ if(WIN32 AND NOT CYGWIN)
PATH_SUFFIXES PATH_SUFFIXES
"lib/MinGW" "lib/MinGW"
"lib" "lib"
"lib64"
) )
mark_as_advanced(SSL_EAY LIB_EAY) mark_as_advanced(SSL_EAY LIB_EAY)
@@ -411,7 +563,7 @@ else()
find_library(OPENSSL_SSL_LIBRARY find_library(OPENSSL_SSL_LIBRARY
NAMES NAMES
ssl ssl${_OPENSSL_NAME_POSTFIX}
ssleay32 ssleay32
ssleay32MD ssleay32MD
NAMES_PER_DIR NAMES_PER_DIR
@@ -420,19 +572,19 @@ else()
${_OPENSSL_LIBDIR} ${_OPENSSL_LIBDIR}
${_OPENSSL_LIBRARY_DIRS} ${_OPENSSL_LIBRARY_DIRS}
PATH_SUFFIXES PATH_SUFFIXES
lib lib lib64
) )
find_library(OPENSSL_CRYPTO_LIBRARY find_library(OPENSSL_CRYPTO_LIBRARY
NAMES NAMES
crypto crypto${_OPENSSL_NAME_POSTFIX}
NAMES_PER_DIR NAMES_PER_DIR
${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_ROOT_HINTS_AND_PATHS}
HINTS HINTS
${_OPENSSL_LIBDIR} ${_OPENSSL_LIBDIR}
${_OPENSSL_LIBRARY_DIRS} ${_OPENSSL_LIBRARY_DIRS}
PATH_SUFFIXES PATH_SUFFIXES
lib lib lib64
) )
mark_as_advanced(OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY) mark_as_advanced(OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY)
@@ -570,14 +722,6 @@ find_package_handle_standard_args(OpenSSL
mark_as_advanced(OPENSSL_INCLUDE_DIR) mark_as_advanced(OPENSSL_INCLUDE_DIR)
if(OPENSSL_FOUND) if(OPENSSL_FOUND)
message(STATUS "Found OpenSSL library: ${OPENSSL_LIBRARIES}")
message(STATUS "Found OpenSSL headers: ${OPENSSL_INCLUDE_DIR}")
include(EnsureVersion)
ENSURE_VERSION("${OPENSSL_EXPECTED_VERSION}" "${OPENSSL_VERSION}" OPENSSL_VERSION_OK)
if(NOT OPENSSL_VERSION_OK)
message(FATAL_ERROR "AzerothCore needs OpenSSL version ${OPENSSL_EXPECTED_VERSION} but found too new version ${OPENSSL_VERSION}. AzerothCore needs OpenSSL 1.0.x or 1.1.x to work properly. If you still have problems please install OpenSSL 1.0.x if you still have problems search on forum for TCE00022")
endif()
if(NOT TARGET OpenSSL::Crypto AND if(NOT TARGET OpenSSL::Crypto AND
(EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR
EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR
@@ -642,7 +786,7 @@ if(OPENSSL_FOUND)
_OpenSSL_target_add_dependencies(OpenSSL::SSL) _OpenSSL_target_add_dependencies(OpenSSL::SSL)
endif() endif()
if("${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_FIX}" VERSION_GREATER_EQUAL "0.9.8") if("${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}" VERSION_GREATER_EQUAL "0.9.8")
if(MSVC) if(MSVC)
if(EXISTS "${OPENSSL_INCLUDE_DIR}") if(EXISTS "${OPENSSL_INCLUDE_DIR}")
set(_OPENSSL_applink_paths PATHS ${OPENSSL_INCLUDE_DIR}) set(_OPENSSL_applink_paths PATHS ${OPENSSL_INCLUDE_DIR})
@@ -669,3 +813,10 @@ endif()
if(OPENSSL_USE_STATIC_LIBS) if(OPENSSL_USE_STATIC_LIBS)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES ${_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
endif() endif()
unset(_OPENSSL_FIND_PATH_SUFFIX)
unset(_OPENSSL_NAME_POSTFIX)
unset(_OpenSSL_extra_static_deps)
unset(_OpenSSL_has_dependency_dl)
unset(_OpenSSL_has_dependency_threads)
unset(_OpenSSL_has_dependency_zlib)
@@ -3069,9 +3069,9 @@ Rate.RepairCost = 1
# Description: Should the player leave their group when they log out? # Description: Should the player leave their group when they log out?
# (It does not affect raids or dungeon finder groups) # (It does not affect raids or dungeon finder groups)
# #
# Default: 1 - (Enabled) # Default: 0 - (Disabled)
LeaveGroupOnLogout.Enabled = 1 LeaveGroupOnLogout.Enabled = 0
# #
# Group.Raid.LevelRestriction # Group.Raid.LevelRestriction
@@ -227,7 +227,11 @@ bool MySQLConnection::Execute(PreparedStatementBase* stmt)
uint32 _s = getMSTime(); uint32 _s = getMSTime();
#if !defined(MARIADB_VERSION_ID) && (MYSQL_VERSION_ID >= 80300)
if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
#else
if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
#endif
{ {
uint32 lErrno = mysql_errno(m_Mysql); uint32 lErrno = mysql_errno(m_Mysql);
LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT)); LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
@@ -275,7 +279,11 @@ bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLPreparedStatement
uint32 _s = getMSTime(); uint32 _s = getMSTime();
#if !defined(MARIADB_VERSION_ID) && (MYSQL_VERSION_ID >= 80300)
if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
#else
if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
#endif
{ {
uint32 lErrno = mysql_errno(m_Mysql); uint32 lErrno = mysql_errno(m_Mysql);
LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT)); LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
@@ -42,7 +42,7 @@ bool ArenaSpectator::HandleSpectatorSpectateCommand(ChatHandler* handler, std::s
return true; return true;
} }
if (player->getClass() == CLASS_DEATH_KNIGHT && player->GetMapId() == 609) if (player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TELEPORT) && player->GetMapId() == 609)
{ {
handler->PSendSysMessage("Death Knights can't spectate before finishing questline."); handler->PSendSysMessage("Death Knights can't spectate before finishing questline.");
return true; return true;
+1 -1
View File
@@ -1055,7 +1055,7 @@ namespace lfg
baseAP = p->GetTotalAttackPowerValue(BASE_ATTACK); baseAP = p->GetTotalAttackPowerValue(BASE_ATTACK);
rangedAP = p->GetTotalAttackPowerValue(RANGED_ATTACK); rangedAP = p->GetTotalAttackPowerValue(RANGED_ATTACK);
maxPower = 0; maxPower = 0;
if (p->getClass() == CLASS_DRUID) if (p->IsClass(CLASS_DRUID))
maxPower = p->GetMaxPower(POWER_MANA); maxPower = p->GetMaxPower(POWER_MANA);
else else
maxPower = (p->getPowerType() == POWER_RAGE || p->getPowerType() == POWER_RUNIC_POWER) ? p->GetMaxPower(p->getPowerType()) / 10 : p->GetMaxPower(p->getPowerType()); maxPower = (p->getPowerType() == POWER_RAGE || p->getPowerType() == POWER_RUNIC_POWER) ? p->GetMaxPower(p->getPowerType()) / 10 : p->GetMaxPower(p->getPowerType());
@@ -1196,8 +1196,8 @@ bool Creature::isCanInteractWithBattleMaster(Player* player, bool msg) const
bool Creature::isCanTrainingAndResetTalentsOf(Player* player) const bool Creature::isCanTrainingAndResetTalentsOf(Player* player) const
{ {
return player->GetLevel() >= 10 return player->GetLevel() >= 10
&& GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS && GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS
&& player->getClass() == GetCreatureTemplate()->trainer_class; && player->IsClass((Classes)GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER);
} }
bool Creature::IsValidTrainerForPlayer(Player* player, uint32* npcFlags /*= nullptr*/) const bool Creature::IsValidTrainerForPlayer(Player* player, uint32* npcFlags /*= nullptr*/) const
@@ -1211,7 +1211,7 @@ bool Creature::IsValidTrainerForPlayer(Player* player, uint32* npcFlags /*= null
{ {
case TRAINER_TYPE_CLASS: case TRAINER_TYPE_CLASS:
case TRAINER_TYPE_PETS: case TRAINER_TYPE_PETS:
if (m_creatureInfo->trainer_class && m_creatureInfo->trainer_class != player->getClass()) if (m_creatureInfo->trainer_class && !player->IsClass((Classes)m_creatureInfo->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
{ {
if (npcFlags) if (npcFlags)
*npcFlags &= ~UNIT_NPC_FLAG_TRAINER_CLASS; *npcFlags &= ~UNIT_NPC_FLAG_TRAINER_CLASS;
+16 -19
View File
@@ -107,7 +107,7 @@ void Pet::AddToWorld()
{ {
if (Player* owner = GetOwner()) if (Player* owner = GetOwner())
{ {
if (getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK) if (getPetType() == SUMMON_PET && owner->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET))
{ {
owner->SetLastPetSpell(GetUInt32Value(UNIT_CREATED_BY_SPELL)); owner->SetLastPetSpell(GetUInt32Value(UNIT_CREATED_BY_SPELL));
} }
@@ -238,7 +238,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
bool forceLoadFromDB = false; bool forceLoadFromDB = false;
sScriptMgr->OnBeforeLoadPetFromDB(owner, petEntry, petnumber, current, forceLoadFromDB); sScriptMgr->OnBeforeLoadPetFromDB(owner, petEntry, petnumber, current, forceLoadFromDB);
if (!forceLoadFromDB && (owner->getClass() == CLASS_DEATH_KNIGHT && !owner->CanSeeDKPet())) // DK Pet exception if (!forceLoadFromDB && (owner->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_PET) && !owner->CanSeeDKPet())) // DK Pet exception
return false; return false;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(petInfo->CreatedBySpellId); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(petInfo->CreatedBySpellId);
@@ -1043,12 +1043,12 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
if (petType == MAX_PET_TYPE) if (petType == MAX_PET_TYPE)
{ {
// The petType was not overwritten by the hook, continue with default initialization // The petType was not overwritten by the hook, continue with default initialization
if (owner->getClass() == CLASS_WARLOCK || if (owner->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET) ||
owner->getClass() == CLASS_SHAMAN || // Fire Elemental owner->IsClass(CLASS_SHAMAN, CLASS_CONTEXT_PET) || // Fire Elemental
owner->getClass() == CLASS_DEATH_KNIGHT || // Risen Ghoul owner->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_PET) || // Risen Ghoul
owner->getClass() == CLASS_MAGE) // Water Elemental with glyph owner->IsClass(CLASS_MAGE, CLASS_CONTEXT_PET)) // Water Elemental with glyph
petType = SUMMON_PET; petType = SUMMON_PET;
else if (owner->getClass() == CLASS_HUNTER) else if (owner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
{ {
petType = HUNTER_PET; petType = HUNTER_PET;
} }
@@ -1080,7 +1080,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50)); SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
uint32 attackTime = BASE_ATTACK_TIME; uint32 attackTime = BASE_ATTACK_TIME;
if (owner->getClass() != CLASS_HUNTER && cinfo->BaseAttackTime >= 1000) if (!owner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET) && cinfo->BaseAttackTime >= 1000)
attackTime = cinfo->BaseAttackTime; attackTime = cinfo->BaseAttackTime;
SetAttackTime(BASE_ATTACK, attackTime); SetAttackTime(BASE_ATTACK, attackTime);
@@ -2299,17 +2299,14 @@ bool Pet::IsPermanentPetFor(Player* owner) const
switch (getPetType()) switch (getPetType())
{ {
case SUMMON_PET: case SUMMON_PET:
switch (owner->getClass()) if (owner->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET))
{ return GetCreatureTemplate()->type == CREATURE_TYPE_DEMON;
case CLASS_WARLOCK: else if (owner->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_PET))
return GetCreatureTemplate()->type == CREATURE_TYPE_DEMON; return GetCreatureTemplate()->type == CREATURE_TYPE_UNDEAD;
case CLASS_DEATH_KNIGHT: else if (owner->IsClass(CLASS_MAGE, CLASS_CONTEXT_PET))
return GetCreatureTemplate()->type == CREATURE_TYPE_UNDEAD; return GetEntry() == 37994;
case CLASS_MAGE: else
return GetEntry() == 37994; return false;
default:
return false;
}
case HUNTER_PET: case HUNTER_PET:
return true; return true;
default: default:
@@ -204,12 +204,13 @@ void KillRewarder::_RewardPlayer(Player* player, bool isDungeon)
if (_victim->GetTypeId() == TYPEID_PLAYER) if (_victim->GetTypeId() == TYPEID_PLAYER)
player->KilledPlayerCredit(); player->KilledPlayerCredit();
} }
// Give XP only in PvE or in battlegrounds. // Give XP only in PvE or in battlegrounds.
// Give reputation and kill credit only in PvE. // Give reputation and kill credit only in PvE.
if (!_isPvP || _isBattleGround) if (!_isPvP || _isBattleGround)
{ {
float xpRate = _group ? _groupRate * float(player->GetLevel()) / _aliveSumLevel : /*Personal rate is 100%.*/ 1.0f; // Group rate depends on the sum of levels. float xpRate = _group ? _groupRate * float(player->GetLevel()) / _aliveSumLevel : /*Personal rate is 100%.*/ 1.0f; // Group rate depends on the sum of levels.
sScriptMgr->OnRewardKillRewarder(player, isDungeon, xpRate); // Personal rate is 100%. sScriptMgr->OnRewardKillRewarder(player, this, isDungeon, xpRate); // Personal rate is 100%.
if (_xp) if (_xp)
{ {
@@ -290,3 +291,13 @@ void KillRewarder::Reward()
if (Map* map = _victim->FindMap()) if (Map* map = _victim->FindMap())
map->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, _victim->GetEntry(), _victim); map->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, _victim->GetEntry(), _victim);
} }
Unit* KillRewarder::GetVictim()
{
return _victim;
}
Player* KillRewarder::GetKiller()
{
return _killer;
}
@@ -30,6 +30,8 @@ public:
KillRewarder(Player* killer, Unit* victim, bool isBattleGround); KillRewarder(Player* killer, Unit* victim, bool isBattleGround);
void Reward(); void Reward();
Unit* GetVictim();
Player* GetKiller();
private: private:
void _InitXP(Player* player); void _InitXP(Player* player);
+55 -37
View File
@@ -553,7 +553,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
// set starting level // set starting level
uint32 start_level = getClass() != CLASS_DEATH_KNIGHT uint32 start_level = !IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT)
? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) ? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)
: sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL); : sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
@@ -568,7 +568,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
InitRunes(); InitRunes();
SetUInt32Value(PLAYER_FIELD_COINAGE, getClass() != CLASS_DEATH_KNIGHT SetUInt32Value(PLAYER_FIELD_COINAGE, !IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT)
? sWorld->getIntConfig(CONFIG_START_PLAYER_MONEY) ? sWorld->getIntConfig(CONFIG_START_PLAYER_MONEY)
: sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_MONEY)); : sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_MONEY));
SetHonorPoints(sWorld->getIntConfig(CONFIG_START_HONOR_POINTS)); SetHonorPoints(sWorld->getIntConfig(CONFIG_START_HONOR_POINTS));
@@ -587,13 +587,13 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
InitPrimaryProfessions(); // to max set before any spell added InitPrimaryProfessions(); // to max set before any spell added
// apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods() // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods()
if (getPowerType() == POWER_MANA) if (HasActivePowerType(POWER_MANA))
{ {
UpdateMaxPower(POWER_MANA); // Update max Mana (for add bonus from intellect) UpdateMaxPower(POWER_MANA); // Update max Mana (for add bonus from intellect)
SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
} }
if (getPowerType() == POWER_RUNIC_POWER) if (HasActivePowerType(POWER_RUNIC_POWER))
{ {
SetPower(POWER_RUNE, 8); SetPower(POWER_RUNE, 8);
SetMaxPower(POWER_RUNE, 8); SetMaxPower(POWER_RUNE, 8);
@@ -633,7 +633,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
switch (iProto->Spells[0].SpellCategory) switch (iProto->Spells[0].SpellCategory)
{ {
case SPELL_CATEGORY_FOOD: // food case SPELL_CATEGORY_FOOD: // food
count = getClass() == CLASS_DEATH_KNIGHT ? 10 : 4; count = IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT) ? 10 : 4;
break; break;
case SPELL_CATEGORY_DRINK: // drink case SPELL_CATEGORY_DRINK: // drink
count = 2; count = 2;
@@ -1269,6 +1269,15 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
return true; return true;
} }
bool Player::IsClass(Classes unitClass, ClassContext context) const
{
Optional<bool> scriptResult = sScriptMgr->OnPlayerIsClass(this, unitClass, context);
if (scriptResult != std::nullopt)
return *scriptResult;
else
return (getClass() == unitClass);
}
void Player::ToggleAFK() void Player::ToggleAFK()
{ {
ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK);
@@ -1460,7 +1469,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
} }
else else
{ {
if (getClass() == CLASS_DEATH_KNIGHT && GetMapId() == 609 && !IsGameMaster() && !HasSpell(50977)) if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TELEPORT) && GetMapId() == 609 && !IsGameMaster() && !HasSpell(50977))
{ {
SendTransferAborted(mapid, TRANSFER_ABORT_UNIQUE_MESSAGE, 1); SendTransferAborted(mapid, TRANSFER_ABORT_UNIQUE_MESSAGE, 1);
return false; return false;
@@ -1745,7 +1754,7 @@ void Player::RegenerateAll()
Regenerate(POWER_MANA); Regenerate(POWER_MANA);
// Runes act as cooldowns, and they don't need to send any data // Runes act as cooldowns, and they don't need to send any data
if (getClass() == CLASS_DEATH_KNIGHT) if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
for (uint8 i = 0; i < MAX_RUNES; ++i) for (uint8 i = 0; i < MAX_RUNES; ++i)
{ {
// xinef: implement grace // xinef: implement grace
@@ -1775,7 +1784,7 @@ void Player::RegenerateAll()
} }
Regenerate(POWER_RAGE); Regenerate(POWER_RAGE);
if (getClass() == CLASS_DEATH_KNIGHT) if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
Regenerate(POWER_RUNIC_POWER); Regenerate(POWER_RUNIC_POWER);
m_regenTimerCount -= 2000; m_regenTimerCount -= 2000;
@@ -2019,22 +2028,21 @@ void Player::RegenerateHealth()
void Player::ResetAllPowers() void Player::ResetAllPowers()
{ {
SetHealth(GetMaxHealth()); SetHealth(GetMaxHealth());
switch (getPowerType()) if (HasActivePowerType(POWER_MANA))
{ {
case POWER_MANA: SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); }
break; if (HasActivePowerType(POWER_RAGE))
case POWER_RAGE: {
SetPower(POWER_RAGE, 0); SetPower(POWER_RAGE, 0);
break; }
case POWER_ENERGY: if (HasActivePowerType(POWER_ENERGY))
SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); {
break; SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY));
case POWER_RUNIC_POWER: }
SetPower(POWER_RUNIC_POWER, 0); if (HasActivePowerType(POWER_RUNIC_POWER))
break; {
default: SetPower(POWER_RUNIC_POWER, 0);
break;
} }
} }
@@ -2107,7 +2115,7 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask)
// pussywizard: many npcs have missing conditions for class training and rogue trainer can for eg. train dual wield to a shaman :/ too many to change in sql and watch in the future // pussywizard: many npcs have missing conditions for class training and rogue trainer can for eg. train dual wield to a shaman :/ too many to change in sql and watch in the future
// pussywizard: this function is not used when talking, but when already taking action (buy spell, reset talents, show spell list) // pussywizard: this function is not used when talking, but when already taking action (buy spell, reset talents, show spell list)
if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS && getClass() != creature->GetCreatureTemplate()->trainer_class) if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS && !IsClass((Classes)creature->GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
return nullptr; return nullptr;
return creature; return creature;
@@ -2714,6 +2722,14 @@ void Player::InitStatsForLevel(bool reapplyMods)
pet->SynchronizeLevelWithOwner(); pet->SynchronizeLevelWithOwner();
} }
bool Player::HasActivePowerType(Powers power)
{
if (sScriptMgr->OnPlayerHasActivePowerType(this, power))
return true;
else
return (getPowerType() == power);
}
void Player::SendInitialSpells() void Player::SendInitialSpells()
{ {
uint32 curTime = GameTime::GetGameTimeMS().count(); uint32 curTime = GameTime::GetGameTimeMS().count();
@@ -6388,7 +6404,7 @@ void Player::DuelComplete(DuelCompleteType type)
opponent->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1); opponent->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
// Credit for quest Death's Challenge // Credit for quest Death's Challenge
if (getClass() == CLASS_DEATH_KNIGHT && opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE) if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_QUEST) && opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE)
{ {
opponent->CastSpell(opponent, 52994, true); opponent->CastSpell(opponent, 52994, true);
} }
@@ -6784,7 +6800,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
} }
// Druids get feral AP bonus from weapon dps (also use DPS from ScalingStatValue) // Druids get feral AP bonus from weapon dps (also use DPS from ScalingStatValue)
if (getClass() == CLASS_DRUID) if (IsClass(CLASS_DRUID, CLASS_CONTEXT_STATS))
{ {
int32 dpsMod = 0; int32 dpsMod = 0;
int32 feral_bonus = 0; int32 feral_bonus = 0;
@@ -9841,7 +9857,7 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
if (apply) if (apply)
{ {
m_spellMods[mod->op].push_back(mod); m_spellMods[mod->op].push_back(mod);
if (getClass() == CLASS_MAGE) if (IsClass(CLASS_MAGE, CLASS_CONTEXT_ABILITY))
m_spellMods[mod->op].sort(MageSpellModPred()); m_spellMods[mod->op].sort(MageSpellModPred());
else else
m_spellMods[mod->op].sort(SpellModPred()); m_spellMods[mod->op].sort(SpellModPred());
@@ -10275,7 +10291,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
// only one mount ID for both sides. Probably not good to use 315 in case DBC nodes // only one mount ID for both sides. Probably not good to use 315 in case DBC nodes
// change but I couldn't find a suitable alternative. OK to use class because only DK // change but I couldn't find a suitable alternative. OK to use class because only DK
// can use this taxi. // can use this taxi.
uint32 mount_display_id = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetTeamId(true), npc == nullptr || (sourcenode == 315 && getClass() == CLASS_DEATH_KNIGHT)); uint32 mount_display_id = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetTeamId(true), npc == nullptr || (sourcenode == 315 && IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TAXI)));
// in spell case allow 0 model // in spell case allow 0 model
if ((mount_display_id == 0 && spellid == 0) || sourcepath == 0) if ((mount_display_id == 0 && spellid == 0) || sourcepath == 0)
@@ -11324,7 +11340,7 @@ WorldLocation Player::GetStartPosition() const
{ {
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(true), getClass()); PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(true), getClass());
uint32 mapId = info->mapId; uint32 mapId = info->mapId;
if (getClass() == CLASS_DEATH_KNIGHT && HasSpell(50977)) if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT) && HasSpell(50977))
return WorldLocation(0, 2352.0f, -5709.0f, 154.5f, 0.0f); return WorldLocation(0, 2352.0f, -5709.0f, 154.5f, 0.0f);
return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0); return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0);
} }
@@ -11818,7 +11834,7 @@ void Player::LearnDefaultSkill(uint32 skillId, uint16 rank)
{ {
skillValue = maxValue; skillValue = maxValue;
} }
else if (getClass() == CLASS_DEATH_KNIGHT) else if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_SKILL))
{ {
skillValue = std::min(std::max<uint16>({ 1, uint16((GetLevel() - 1) * 5) }), maxValue); skillValue = std::min(std::max<uint16>({ 1, uint16((GetLevel() - 1) * 5) }), maxValue);
} }
@@ -11851,7 +11867,7 @@ void Player::LearnDefaultSkill(uint32 skillId, uint16 rank)
{ {
skillValue = maxValue; skillValue = maxValue;
} }
else if (getClass() == CLASS_DEATH_KNIGHT) else if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_SKILL))
{ {
skillValue = std::min(std::max<uint16>({ uint16(1), uint16((GetLevel() - 1) * 5) }), maxValue); skillValue = std::min(std::max<uint16>({ uint16(1), uint16((GetLevel() - 1) * 5) }), maxValue);
} }
@@ -13376,7 +13392,7 @@ static RuneType runeSlotTypes[MAX_RUNES] =
void Player::InitRunes() void Player::InitRunes()
{ {
if (getClass() != CLASS_DEATH_KNIGHT) if (!IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return; return;
m_runes = new Runes; m_runes = new Runes;
@@ -13542,7 +13558,7 @@ uint32 Player::CalculateTalentsPoints() const
uint32 base_talent = GetLevel() < 10 ? 0 : GetLevel() - 9; uint32 base_talent = GetLevel() < 10 ? 0 : GetLevel() - 9;
uint32 talentPointsForLevel = 0; uint32 talentPointsForLevel = 0;
if (getClass() != CLASS_DEATH_KNIGHT || GetMapId() != 609) if (!IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TALENT_POINT_CALC) || GetMapId() != 609)
{ {
talentPointsForLevel = base_talent; talentPointsForLevel = base_talent;
} }
@@ -14174,19 +14190,21 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
bool Player::CanResummonPet(uint32 spellid) bool Player::CanResummonPet(uint32 spellid)
{ {
if (getClass() == CLASS_DEATH_KNIGHT) if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_PET))
{ {
if (CanSeeDKPet()) if (CanSeeDKPet())
return true; return true;
else if (spellid == 52150) // Raise Dead else if (spellid == 52150) // Raise Dead
return false; return false;
} }
else if (getClass() == CLASS_MAGE)
if (IsClass(CLASS_MAGE, CLASS_CONTEXT_PET))
{ {
if (HasSpell(31687) && HasAura(70937)) //Has [Summon Water Elemental] spell and [Glyph of Eternal Water]. if (HasSpell(31687) && HasAura(70937)) //Has [Summon Water Elemental] spell and [Glyph of Eternal Water].
return true; return true;
} }
else if (getClass() == CLASS_HUNTER)
if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
{ {
return true; return true;
} }
@@ -15171,7 +15189,7 @@ void Player::ActivateSpec(uint8 spec)
AutoUnequipOffhandIfNeed(); AutoUnequipOffhandIfNeed();
// Xinef: Patch 3.2.0: Switching spec removes paladins spell Righteous Fury (25780) // Xinef: Patch 3.2.0: Switching spec removes paladins spell Righteous Fury (25780)
if (getClass() == CLASS_PALADIN) if (IsClass(CLASS_PALADIN, CLASS_CONTEXT_ABILITY))
RemoveAurasDueToSpell(25780); RemoveAurasDueToSpell(25780);
// Xinef: Remove talented single target auras at other targets // Xinef: Remove talented single target auras at other targets
+4
View File
@@ -1112,6 +1112,8 @@ public:
static bool BuildEnumData(PreparedQueryResult result, WorldPacket* data); static bool BuildEnumData(PreparedQueryResult result, WorldPacket* data);
[[nodiscard]] bool IsClass(Classes playerClass, ClassContext context = CLASS_CONTEXT_NONE) const override;
void SetInWater(bool apply); void SetInWater(bool apply);
[[nodiscard]] bool IsInWater() const override { return m_isInWater; } [[nodiscard]] bool IsInWater() const override { return m_isInWater; }
@@ -1170,6 +1172,8 @@ public:
void InitStatsForLevel(bool reapplyMods = false); void InitStatsForLevel(bool reapplyMods = false);
[[nodiscard]] bool HasActivePowerType(Powers power) override;
// .cheat command related // .cheat command related
[[nodiscard]] bool GetCommandStatus(uint32 command) const { return _activeCheats & command; } [[nodiscard]] bool GetCommandStatus(uint32 command) const { return _activeCheats & command; }
void SetCommandStatusOn(uint32 command) { _activeCheats |= command; } void SetCommandStatusOn(uint32 command) { _activeCheats |= command; }
@@ -109,7 +109,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
canTalk = false; canTalk = false;
break; break;
case GOSSIP_OPTION_STABLEPET: case GOSSIP_OPTION_STABLEPET:
if (getClass() != CLASS_HUNTER) if (!IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
canTalk = false; canTalk = false;
break; break;
case GOSSIP_OPTION_QUESTGIVER: case GOSSIP_OPTION_QUESTGIVER:
@@ -133,8 +133,6 @@ void Player::SetSheath(SheathState sheathed)
uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const
{ {
uint8 playerClass = getClass();
uint8 slots[4]; uint8 slots[4];
slots[0] = NULL_SLOT; slots[0] = NULL_SLOT;
slots[1] = NULL_SLOT; slots[1] = NULL_SLOT;
@@ -246,23 +244,23 @@ uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) c
switch (proto->SubClass) switch (proto->SubClass)
{ {
case ITEM_SUBCLASS_ARMOR_LIBRAM: case ITEM_SUBCLASS_ARMOR_LIBRAM:
if (playerClass == CLASS_PALADIN) if (IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED; slots[0] = EQUIPMENT_SLOT_RANGED;
break; break;
case ITEM_SUBCLASS_ARMOR_IDOL: case ITEM_SUBCLASS_ARMOR_IDOL:
if (playerClass == CLASS_DRUID) if (IsClass(CLASS_DRUID, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED; slots[0] = EQUIPMENT_SLOT_RANGED;
break; break;
case ITEM_SUBCLASS_ARMOR_TOTEM: case ITEM_SUBCLASS_ARMOR_TOTEM:
if (playerClass == CLASS_SHAMAN) if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED; slots[0] = EQUIPMENT_SLOT_RANGED;
break; break;
case ITEM_SUBCLASS_ARMOR_MISC: case ITEM_SUBCLASS_ARMOR_MISC:
if (playerClass == CLASS_WARLOCK) if (IsClass(CLASS_WARLOCK, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED; slots[0] = EQUIPMENT_SLOT_RANGED;
break; break;
case ITEM_SUBCLASS_ARMOR_SIGIL: case ITEM_SUBCLASS_ARMOR_SIGIL:
if (playerClass == CLASS_DEATH_KNIGHT) if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED; slots[0] = EQUIPMENT_SLOT_RANGED;
break; break;
} }
@@ -2270,16 +2268,13 @@ InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const
// In fact it's a visual bug, everything works properly... I need sniffs of operations with // In fact it's a visual bug, everything works properly... I need sniffs of operations with
// binded to account items from off server. // binded to account items from off server.
switch (getClass()) if (IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_ARMOR_CLASS) || IsClass(CLASS_WARRIOR, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
{ {
case CLASS_HUNTER: allowEquip = (itemSkill == SKILL_PLATE_MAIL);
case CLASS_SHAMAN: }
allowEquip = (itemSkill == SKILL_MAIL); else if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_EQUIP_ARMOR_CLASS) || IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
break; {
case CLASS_PALADIN: allowEquip = (itemSkill == SKILL_MAIL);
case CLASS_WARRIOR:
allowEquip = (itemSkill == SKILL_PLATE_MAIL);
break;
} }
} }
if (!allowEquip && GetSkillValue(itemSkill) == 0) if (!allowEquip && GetSkillValue(itemSkill) == 0)
@@ -2394,39 +2389,40 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje
return EQUIP_ERR_CANT_EQUIP_SKILL; return EQUIP_ERR_CANT_EQUIP_SKILL;
} }
uint8 _class = getClass();
if (proto->Class == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->SubClass]) == 0) if (proto->Class == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->SubClass]) == 0)
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
if (proto->Class == ITEM_CLASS_ARMOR) if (proto->Class == ITEM_CLASS_ARMOR)
{ {
// Check for shields // Check for shields
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_SHIELD && !(_class == CLASS_PALADIN || _class == CLASS_WARRIOR || _class == CLASS_SHAMAN)) if (proto->SubClass == ITEM_SUBCLASS_ARMOR_SHIELD && !(
IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_SHIELDS)
|| IsClass(CLASS_WARRIOR, CLASS_CONTEXT_EQUIP_SHIELDS)
|| IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_SHIELDS)))
{ {
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
} }
// Check for librams. // Check for librams.
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_LIBRAM && _class != CLASS_PALADIN) if (proto->SubClass == ITEM_SUBCLASS_ARMOR_LIBRAM && !IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_RELIC))
{ {
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
} }
// CHeck for idols. // CHeck for idols.
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_IDOL && _class != CLASS_DRUID) if (proto->SubClass == ITEM_SUBCLASS_ARMOR_IDOL && !IsClass(CLASS_DRUID, CLASS_CONTEXT_EQUIP_RELIC))
{ {
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
} }
// Check for totems. // Check for totems.
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_TOTEM && _class != CLASS_SHAMAN) if (proto->SubClass == ITEM_SUBCLASS_ARMOR_TOTEM && !IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_RELIC))
{ {
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
} }
// Check for sigils. // Check for sigils.
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_SIGIL && _class != CLASS_DEATH_KNIGHT) if (proto->SubClass == ITEM_SUBCLASS_ARMOR_SIGIL && !IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_EQUIP_RELIC))
{ {
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
} }
@@ -2436,33 +2432,33 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje
proto->InventoryType != INVTYPE_CLOAK) proto->InventoryType != INVTYPE_CLOAK)
{ {
uint32 subclassToCompare = ITEM_SUBCLASS_ARMOR_CLOTH; uint32 subclassToCompare = ITEM_SUBCLASS_ARMOR_CLOTH;
switch (_class) if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_EQUIP_ARMOR_CLASS) || IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
{ {
case CLASS_WARRIOR: subclassToCompare = ITEM_SUBCLASS_ARMOR_PLATE;
if (proto->HasStat(ITEM_MOD_SPELL_POWER) || proto->HasSpellPowerStat()) }
{ else if (IsClass(CLASS_WARRIOR, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
return EQUIP_ERR_CANT_DO_RIGHT_NOW; {
} if ((proto->HasStat(ITEM_MOD_SPELL_POWER) || proto->HasSpellPowerStat()))
[[fallthrough]]; {
case CLASS_DEATH_KNIGHT: return EQUIP_ERR_CANT_DO_RIGHT_NOW;
case CLASS_PALADIN: }
subclassToCompare = ITEM_SUBCLASS_ARMOR_PLATE; subclassToCompare = ITEM_SUBCLASS_ARMOR_PLATE;
break; }
case CLASS_HUNTER: else if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_EQUIP_ARMOR_CLASS) || IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
case CLASS_SHAMAN: {
subclassToCompare = ITEM_SUBCLASS_ARMOR_MAIL; subclassToCompare = ITEM_SUBCLASS_ARMOR_MAIL;
break; }
case CLASS_ROGUE: else if (IsClass(CLASS_DRUID, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
if (proto->HasStat(ITEM_MOD_SPELL_POWER) || proto->HasSpellPowerStat()) {
{ subclassToCompare = ITEM_SUBCLASS_ARMOR_LEATHER;
return EQUIP_ERR_CANT_DO_RIGHT_NOW; }
} else if (IsClass(CLASS_ROGUE, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
[[fallthrough]]; {
case CLASS_DRUID: if (proto->HasStat(ITEM_MOD_SPELL_POWER) || proto->HasSpellPowerStat())
subclassToCompare = ITEM_SUBCLASS_ARMOR_LEATHER; {
break; return EQUIP_ERR_CANT_DO_RIGHT_NOW;
default: }
break; subclassToCompare = ITEM_SUBCLASS_ARMOR_LEATHER;
} }
if (proto->SubClass > subclassToCompare) if (proto->SubClass > subclassToCompare)
@@ -2772,7 +2768,7 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
if (pProto && IsInCombat() && (pProto->Class == ITEM_CLASS_WEAPON || pProto->InventoryType == INVTYPE_RELIC) && m_weaponChangeTimer == 0) if (pProto && IsInCombat() && (pProto->Class == ITEM_CLASS_WEAPON || pProto->InventoryType == INVTYPE_RELIC) && m_weaponChangeTimer == 0)
{ {
uint32 cooldownSpell = getClass() == CLASS_ROGUE ? 6123 : 6119; uint32 cooldownSpell = IsClass(CLASS_ROGUE, CLASS_CONTEXT_WEAPON_SWAP) ? 6123 : 6119;
SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell); SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell);
if (!spellProto) if (!spellProto)
@@ -4645,7 +4641,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
} }
case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon
{ {
if (getClass() == CLASS_SHAMAN) if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_ABILITY))
{ {
float addValue = 0.0f; float addValue = 0.0f;
if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
+97 -104
View File
@@ -346,134 +346,127 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS; index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
switch (getClass()) if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS))
{ {
case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f;
val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; }
break; else if (IsClass(CLASS_ROGUE, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARRIOR, CLASS_CONTEXT_STATS))
case CLASS_ROGUE: {
case CLASS_WARRIOR: val2 = level + GetStat(STAT_AGILITY) - 10.0f;
val2 = level + GetStat(STAT_AGILITY) - 10.0f; }
break; else if (IsClass(CLASS_DRUID, CLASS_CONTEXT_STATS))
case CLASS_DRUID: {
switch (GetShapeshiftForm()) switch (GetShapeshiftForm())
{ {
case FORM_CAT: case FORM_CAT:
case FORM_BEAR: case FORM_BEAR:
case FORM_DIREBEAR: case FORM_DIREBEAR:
val2 = 0.0f; val2 = 0.0f;
break;
default:
val2 = GetStat(STAT_AGILITY) - 10.0f;
break;
}
break; break;
default: default:
val2 = GetStat(STAT_AGILITY) - 10.0f; val2 = GetStat(STAT_AGILITY) - 10.0f;
break; break;
}
}
else
{
val2 = GetStat(STAT_AGILITY) - 10.0f;
} }
} }
else else
{ {
switch (getClass()) if (IsClass(CLASS_PALADIN, CLASS_CONTEXT_STATS) || IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARRIOR, CLASS_CONTEXT_STATS))
{ {
case CLASS_PALADIN: val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
case CLASS_DEATH_KNIGHT: }
case CLASS_WARRIOR: else if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS) || IsClass(CLASS_SHAMAN, CLASS_CONTEXT_STATS) || IsClass(CLASS_ROGUE, CLASS_CONTEXT_STATS))
val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f; {
break; val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f;
case CLASS_HUNTER: }
case CLASS_SHAMAN: else if (IsClass(CLASS_DRUID, CLASS_CONTEXT_STATS))
case CLASS_ROGUE: {
val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; // Check if Predatory Strikes is skilled
break; float mLevelMult = 0.0f;
case CLASS_DRUID: float weapon_bonus = 0.0f;
if (IsInFeralForm())
{
Unit::AuraEffectList const& mDummy = GetAuraEffectsByType(SPELL_AURA_DUMMY);
for (Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
{ {
// Check if Predatory Strikes is skilled AuraEffect* aurEff = *itr;
float mLevelMult = 0.0f; if (aurEff->GetSpellInfo()->SpellIconID == 1563)
float weapon_bonus = 0.0f;
if (IsInFeralForm())
{ {
Unit::AuraEffectList const& mDummy = GetAuraEffectsByType(SPELL_AURA_DUMMY); switch (aurEff->GetEffIndex())
for (Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
{ {
AuraEffect* aurEff = *itr; case 0: // Predatory Strikes (effect 0)
if (aurEff->GetSpellInfo()->SpellIconID == 1563) mLevelMult = CalculatePct(1.0f, aurEff->GetAmount());
break;
case 1: // Predatory Strikes (effect 1)
if (Item* mainHand = m_items[EQUIPMENT_SLOT_MAINHAND])
{ {
switch (aurEff->GetEffIndex()) // also gains % attack power from equipped weapon
ItemTemplate const* proto = mainHand->GetTemplate();
if (!proto)
continue;
uint32 ap = proto->getFeralBonus();
// Get AP Bonuses from weapon
for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
{ {
case 0: // Predatory Strikes (effect 0) if (i >= proto->StatsCount)
mLevelMult = CalculatePct(1.0f, aurEff->GetAmount());
break; break;
case 1: // Predatory Strikes (effect 1)
if (Item* mainHand = m_items[EQUIPMENT_SLOT_MAINHAND])
{
// also gains % attack power from equipped weapon
ItemTemplate const* proto = mainHand->GetTemplate();
if (!proto)
continue;
uint32 ap = proto->getFeralBonus(); if (proto->ItemStat[i].ItemStatType == ITEM_MOD_ATTACK_POWER)
// Get AP Bonuses from weapon ap += proto->ItemStat[i].ItemStatValue;
for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
{
if (i >= proto->StatsCount)
break;
if (proto->ItemStat[i].ItemStatType == ITEM_MOD_ATTACK_POWER)
ap += proto->ItemStat[i].ItemStatValue;
}
// Get AP Bonuses from weapon spells
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
// no spell
if (!proto->Spells[i].SpellId || proto->Spells[i].SpellTrigger != ITEM_SPELLTRIGGER_ON_EQUIP)
continue;
// check if it is valid spell
SpellInfo const* spellproto = sSpellMgr->GetSpellInfo(proto->Spells[i].SpellId);
if (!spellproto)
continue;
for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
if (spellproto->Effects[j].ApplyAuraName == SPELL_AURA_MOD_ATTACK_POWER)
ap += spellproto->Effects[j].CalcValue();
}
weapon_bonus = CalculatePct(float(ap), aurEff->GetAmount());
}
break;
default:
break;
} }
}
}
}
switch (GetShapeshiftForm()) // Get AP Bonuses from weapon spells
{ for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
case FORM_CAT: {
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f + GetStat(STAT_AGILITY) - 20.0f + weapon_bonus + m_baseFeralAP; // no spell
break; if (!proto->Spells[i].SpellId || proto->Spells[i].SpellTrigger != ITEM_SPELLTRIGGER_ON_EQUIP)
case FORM_BEAR: continue;
case FORM_DIREBEAR:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + weapon_bonus + m_baseFeralAP; // check if it is valid spell
break; SpellInfo const* spellproto = sSpellMgr->GetSpellInfo(proto->Spells[i].SpellId);
case FORM_MOONKIN: if (!spellproto)
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + m_baseFeralAP; continue;
for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
if (spellproto->Effects[j].ApplyAuraName == SPELL_AURA_MOD_ATTACK_POWER)
ap += spellproto->Effects[j].CalcValue();
}
weapon_bonus = CalculatePct(float(ap), aurEff->GetAmount());
}
break; break;
default: default:
val2 = GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
break; break;
}
} }
break;
} }
case CLASS_MAGE: }
case CLASS_PRIEST:
case CLASS_WARLOCK: switch (GetShapeshiftForm())
val2 = GetStat(STAT_STRENGTH) - 10.0f; {
case FORM_CAT:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f + GetStat(STAT_AGILITY) - 20.0f + weapon_bonus + m_baseFeralAP;
break; break;
case FORM_BEAR:
case FORM_DIREBEAR:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + weapon_bonus + m_baseFeralAP;
break;
case FORM_MOONKIN:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + m_baseFeralAP;
break;
default:
val2 = GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
break;
}
}
else if (IsClass(CLASS_MAGE, CLASS_CONTEXT_STATS) || IsClass(CLASS_PRIEST, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARLOCK, CLASS_CONTEXT_STATS))
{
val2 = GetStat(STAT_STRENGTH) - 10.0f;
} }
} }
@@ -521,7 +514,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
UpdateDamagePhysical(BASE_ATTACK); UpdateDamagePhysical(BASE_ATTACK);
if (CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon if (CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
UpdateDamagePhysical(OFF_ATTACK); UpdateDamagePhysical(OFF_ATTACK);
if (getClass() == CLASS_SHAMAN || getClass() == CLASS_PALADIN) // mental quickness if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_STATS) || IsClass(CLASS_PALADIN, CLASS_CONTEXT_STATS)) // mental quickness
UpdateSpellDamageAndHealingBonus(); UpdateSpellDamageAndHealingBonus();
} }
} }
+21 -21
View File
@@ -929,7 +929,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
} }
// Rage from Damage made (only from direct weapon damage) // Rage from Damage made (only from direct weapon damage)
if (attacker && cleanDamage && damagetype == DIRECT_DAMAGE && attacker != victim && attacker->getPowerType() == POWER_RAGE) if (attacker && cleanDamage && damagetype == DIRECT_DAMAGE && attacker != victim && attacker->HasActivePowerType(POWER_RAGE))
{ {
uint32 weaponSpeedHitFactor; uint32 weaponSpeedHitFactor;
@@ -957,10 +957,10 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
// Rage from absorbed damage // Rage from absorbed damage
if (cleanDamage && cleanDamage->absorbed_damage) if (cleanDamage && cleanDamage->absorbed_damage)
{ {
if (victim->getPowerType() == POWER_RAGE) if (victim->HasActivePowerType(POWER_RAGE))
victim->RewardRage(cleanDamage->absorbed_damage, 0, false); victim->RewardRage(cleanDamage->absorbed_damage, 0, false);
if (attacker && attacker->getPowerType() == POWER_RAGE ) if (attacker && attacker->HasActivePowerType(POWER_RAGE))
attacker->RewardRage(cleanDamage->absorbed_damage, 0, true); attacker->RewardRage(cleanDamage->absorbed_damage, 0, true);
} }
@@ -1083,7 +1083,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
} }
// Rage from damage received // Rage from damage received
if (attacker != victim && victim->getPowerType() == POWER_RAGE) if (attacker != victim && victim->HasActivePowerType(POWER_RAGE))
{ {
uint32 rageDamage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0); uint32 rageDamage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
victim->RewardRage(rageDamage, 0, false); victim->RewardRage(rageDamage, 0, false);
@@ -6996,7 +6996,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
// Magic Absorption // Magic Absorption
if (dummySpell->SpellIconID == 459) // only this spell has SpellIconID == 459 and dummy aura if (dummySpell->SpellIconID == 459) // only this spell has SpellIconID == 459 and dummy aura
{ {
if (getPowerType() != POWER_MANA) if (!HasActivePowerType(POWER_MANA))
return false; return false;
// mana reward // mana reward
@@ -7775,7 +7775,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
// Judgement of Wisdom // Judgement of Wisdom
case 20186: case 20186:
{ {
if (!victim || !victim->IsAlive() || victim->getPowerType() != POWER_MANA || victim->HasSpellCooldown(20268)) if (!victim || !victim->IsAlive() || !victim->HasActivePowerType(POWER_MANA) || victim->HasSpellCooldown(20268))
return false; return false;
// 2% of base mana // 2% of base mana
@@ -8834,7 +8834,7 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp
// Convert recently used Blood Rune to Death Rune // Convert recently used Blood Rune to Death Rune
if (Player* player = ToPlayer()) if (Player* player = ToPlayer())
{ {
if (player->getClass() != CLASS_DEATH_KNIGHT) if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return false; return false;
// xinef: not true // xinef: not true
@@ -9565,7 +9565,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
// Item - Death Knight T10 Melee 4P Bonus // Item - Death Knight T10 Melee 4P Bonus
if (auraSpellInfo->Id == 70656) if (auraSpellInfo->Id == 70656)
{ {
if (GetTypeId() != TYPEID_PLAYER || getClass() != CLASS_DEATH_KNIGHT) if (GetTypeId() != TYPEID_PLAYER || !IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return false; return false;
for (uint8 i = 0; i < MAX_RUNES; ++i) for (uint8 i = 0; i < MAX_RUNES; ++i)
@@ -9576,7 +9576,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
else if (auraSpellInfo->SpellIconID == 85) else if (auraSpellInfo->SpellIconID == 85)
{ {
Player* plr = ToPlayer(); Player* plr = ToPlayer();
if (!plr || plr->getClass() != CLASS_DEATH_KNIGHT || !procSpell) if (!plr || !plr->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY) || !procSpell)
return false; return false;
if (!plr->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD)) if (!plr->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD))
@@ -13840,7 +13840,7 @@ void Unit::ClearInCombat()
else if (Player* player = ToPlayer()) else if (Player* player = ToPlayer())
{ {
player->UpdatePotionCooldown(); player->UpdatePotionCooldown();
if (player->getClass() == CLASS_DEATH_KNIGHT) if (player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
for (uint8 i = 0; i < MAX_RUNES; ++i) for (uint8 i = 0; i < MAX_RUNES; ++i)
player->SetGracePeriod(i, 0); player->SetGracePeriod(i, 0);
} }
@@ -16378,7 +16378,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
if (procExtra & PROC_EX_DODGE) if (procExtra & PROC_EX_DODGE)
{ {
// Update AURA_STATE on dodge // Update AURA_STATE on dodge
if (getClass() != CLASS_ROGUE) // skip Rogue Riposte if (!IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY_REACTIVE)) // skip Rogue Riposte
{ {
ModifyAuraState(AURA_STATE_DEFENSE, true); ModifyAuraState(AURA_STATE_DEFENSE, true);
StartReactiveTimer(REACTIVE_DEFENSE); StartReactiveTimer(REACTIVE_DEFENSE);
@@ -16388,7 +16388,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
if (procExtra & PROC_EX_PARRY) if (procExtra & PROC_EX_PARRY)
{ {
// For Hunters only Counterattack (skip Mongoose bite) // For Hunters only Counterattack (skip Mongoose bite)
if (getClass() == CLASS_HUNTER) if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_ABILITY_REACTIVE))
{ {
ModifyAuraState(AURA_STATE_HUNTER_PARRY, true); ModifyAuraState(AURA_STATE_HUNTER_PARRY, true);
StartReactiveTimer(REACTIVE_HUNTER_PARRY); StartReactiveTimer(REACTIVE_HUNTER_PARRY);
@@ -16411,7 +16411,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
// Overpower on victim dodge // Overpower on victim dodge
if (procExtra & PROC_EX_DODGE) if (procExtra & PROC_EX_DODGE)
{ {
if (getClass() == CLASS_WARRIOR) if (IsClass(CLASS_WARRIOR, CLASS_CONTEXT_ABILITY_REACTIVE))
{ {
AddComboPoints(target, 1); AddComboPoints(target, 1);
StartReactiveTimer(REACTIVE_OVERPOWER); StartReactiveTimer(REACTIVE_OVERPOWER);
@@ -17218,9 +17218,9 @@ void Unit::ClearAllReactives()
if (HasAuraState(AURA_STATE_DEFENSE)) if (HasAuraState(AURA_STATE_DEFENSE))
ModifyAuraState(AURA_STATE_DEFENSE, false); ModifyAuraState(AURA_STATE_DEFENSE, false);
if (getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY)) if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_ABILITY_REACTIVE) && HasAuraState(AURA_STATE_HUNTER_PARRY))
ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
if (getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) if (IsClass(CLASS_WARRIOR, CLASS_CONTEXT_ABILITY_REACTIVE) && GetTypeId() == TYPEID_PLAYER)
ClearComboPoints(); ClearComboPoints();
} }
@@ -17244,11 +17244,11 @@ void Unit::UpdateReactives(uint32 p_time)
ModifyAuraState(AURA_STATE_DEFENSE, false); ModifyAuraState(AURA_STATE_DEFENSE, false);
break; break;
case REACTIVE_HUNTER_PARRY: case REACTIVE_HUNTER_PARRY:
if (getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY)) if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_ABILITY_REACTIVE) && HasAuraState(AURA_STATE_HUNTER_PARRY))
ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
break; break;
case REACTIVE_OVERPOWER: case REACTIVE_OVERPOWER:
if (getClass() == CLASS_WARRIOR) if (IsClass(CLASS_WARRIOR, CLASS_CONTEXT_ABILITY_REACTIVE))
{ {
ClearComboPoints(); ClearComboPoints();
} }
@@ -18113,7 +18113,7 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
// Spirit of Redemption // Spirit of Redemption
// if talent known but not triggered (check priest class for speedup check) // if talent known but not triggered (check priest class for speedup check)
bool spiritOfRedemption = false; bool spiritOfRedemption = false;
if (victim->GetTypeId() == TYPEID_PLAYER && victim->getClass() == CLASS_PRIEST && !victim->ToPlayer()->HasPlayerFlag(PLAYER_FLAGS_IS_OUT_OF_BOUNDS)) if (victim->GetTypeId() == TYPEID_PLAYER && victim->IsClass(CLASS_PRIEST, CLASS_CONTEXT_ABILITY) && !victim->ToPlayer()->HasPlayerFlag(PLAYER_FLAGS_IS_OUT_OF_BOUNDS))
{ {
if (AuraEffect* aurEff = victim->GetAuraEffectDummy(20711)) if (AuraEffect* aurEff = victim->GetAuraEffectDummy(20711))
{ {
@@ -18723,7 +18723,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
GetMotionMaster()->MoveIdle(); GetMotionMaster()->MoveIdle();
StopMoving(); StopMoving();
if (charmer->GetTypeId() == TYPEID_PLAYER && charmer->getClass() == CLASS_WARLOCK && ToCreature()->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON) if (charmer->GetTypeId() == TYPEID_PLAYER && charmer->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET_CHARM) && ToCreature()->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON)
{ {
// Disable CreatureAI/SmartAI and switch to CharmAI when charmed by warlock // Disable CreatureAI/SmartAI and switch to CharmAI when charmed by warlock
Creature* charmed = ToCreature(); Creature* charmed = ToCreature();
@@ -18789,7 +18789,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
playerCharmer->PossessSpellInitialize(); playerCharmer->PossessSpellInitialize();
break; break;
case CHARM_TYPE_CHARM: case CHARM_TYPE_CHARM:
if (GetTypeId() == TYPEID_UNIT && charmer->getClass() == CLASS_WARLOCK) if (GetTypeId() == TYPEID_UNIT && charmer->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET_CHARM))
{ {
CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate(); CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate();
if (cinfo && cinfo->type == CREATURE_TYPE_DEMON) if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
@@ -18911,7 +18911,7 @@ void Unit::RemoveCharmedBy(Unit* charmer)
ClearUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); ClearUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
break; break;
case CHARM_TYPE_CHARM: case CHARM_TYPE_CHARM:
if (GetTypeId() == TYPEID_UNIT && charmer->getClass() == CLASS_WARLOCK) if (GetTypeId() == TYPEID_UNIT && charmer->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET_CHARM))
{ {
CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate(); CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate();
if (cinfo && cinfo->type == CREATURE_TYPE_DEMON) if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
+25
View File
@@ -440,6 +440,29 @@ enum DamageEffectType : uint8
SELF_DAMAGE = 5 SELF_DAMAGE = 5
}; };
// Used for IsClass hook
enum ClassContext : uint8
{
CLASS_CONTEXT_NONE = 0, // Default
CLASS_CONTEXT_INIT = 1,
CLASS_CONTEXT_TELEPORT = 2,
CLASS_CONTEXT_QUEST = 3,
CLASS_CONTEXT_STATS = 4,
CLASS_CONTEXT_TAXI = 5,
CLASS_CONTEXT_SKILL = 6,
CLASS_CONTEXT_TALENT_POINT_CALC = 7,
CLASS_CONTEXT_ABILITY = 8,
CLASS_CONTEXT_ABILITY_REACTIVE = 9,
CLASS_CONTEXT_PET = 10,
CLASS_CONTEXT_PET_CHARM = 11,
CLASS_CONTEXT_EQUIP_RELIC = 12,
CLASS_CONTEXT_EQUIP_SHIELDS = 13,
CLASS_CONTEXT_EQUIP_ARMOR_CLASS = 14,
CLASS_CONTEXT_WEAPON_SWAP = 15,
CLASS_CONTEXT_GRAVEYARD = 16,
CLASS_CONTEXT_CLASS_TRAINER = 17
};
// Value masks for UNIT_FIELD_FLAGS // Value masks for UNIT_FIELD_FLAGS
// EnumUtils: DESCRIBE THIS // EnumUtils: DESCRIBE THIS
enum UnitFlags : uint32 enum UnitFlags : uint32
@@ -1436,6 +1459,7 @@ public:
void setRace(uint8 race); void setRace(uint8 race);
[[nodiscard]] uint32 getRaceMask() const { return 1 << (getRace(true) - 1); } [[nodiscard]] uint32 getRaceMask() const { return 1 << (getRace(true) - 1); }
[[nodiscard]] uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, 1); } [[nodiscard]] uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, 1); }
[[nodiscard]] virtual bool IsClass(Classes unitClass, [[maybe_unused]] ClassContext context = CLASS_CONTEXT_NONE) const { return (getClass() == unitClass); }
[[nodiscard]] uint32 getClassMask() const { return 1 << (getClass() - 1); } [[nodiscard]] uint32 getClassMask() const { return 1 << (getClass() - 1); }
[[nodiscard]] uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, 2); } [[nodiscard]] uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, 2); }
[[nodiscard]] DisplayRace GetDisplayRaceFromModelId(uint32 modelId) const; [[nodiscard]] DisplayRace GetDisplayRaceFromModelId(uint32 modelId) const;
@@ -1472,6 +1496,7 @@ public:
[[nodiscard]] Powers getPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, 3)); } [[nodiscard]] Powers getPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, 3)); }
void setPowerType(Powers power); void setPowerType(Powers power);
[[nodiscard]] virtual bool HasActivePowerType(Powers power) { return getPowerType() == power; }
[[nodiscard]] uint32 GetPower(Powers power) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_POWER1) + power); } [[nodiscard]] uint32 GetPower(Powers power) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_POWER1) + power); }
[[nodiscard]] uint32 GetMaxPower(Powers power) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_MAXPOWER1) + power); } [[nodiscard]] uint32 GetMaxPower(Powers power) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_MAXPOWER1) + power); }
void SetPower(Powers power, uint32 val, bool withPowerUpdate = true, bool fromRegenerate = false); void SetPower(Powers power, uint32 val, bool withPowerUpdate = true, bool fromRegenerate = false);
+1 -1
View File
@@ -72,7 +72,7 @@ void Vehicle::Install()
{ {
if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(_vehicleInfo->m_powerDisplayId)) if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(_vehicleInfo->m_powerDisplayId))
_me->setPowerType(Powers(powerDisplay->PowerType)); _me->setPowerType(Powers(powerDisplay->PowerType));
else if (_me->getClass() == CLASS_ROGUE) else if (_me->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY))
_me->setPowerType(POWER_ENERGY); _me->setPowerType(POWER_ENERGY);
} }
+1 -1
View File
@@ -1983,7 +1983,7 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
return ERR_IN_NON_RANDOM_BG; return ERR_IN_NON_RANDOM_BG;
// don't let Death Knights join BG queues when they are not allowed to be teleported yet // don't let Death Knights join BG queues when they are not allowed to be teleported yet
if (member->getClass() == CLASS_DEATH_KNIGHT && member->GetMapId() == 609 && !member->IsGameMaster() && !member->HasSpell(50977)) if (member->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TELEPORT) && member->GetMapId() == 609 && !member->IsGameMaster() && !member->HasSpell(50977))
return ERR_GROUP_JOIN_BATTLEGROUND_FAIL; return ERR_GROUP_JOIN_BATTLEGROUND_FAIL;
if (!member->GetBGAccessByLevel(bgTemplate->GetBgTypeID())) if (!member->GetBGAccessByLevel(bgTemplate->GetBgTypeID()))
@@ -184,7 +184,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
err = ERR_BATTLEGROUND_QUEUED_FOR_RATED; err = ERR_BATTLEGROUND_QUEUED_FOR_RATED;
} }
// don't let Death Knights join BG queues when they are not allowed to be teleported yet // don't let Death Knights join BG queues when they are not allowed to be teleported yet
else if (_player->getClass() == CLASS_DEATH_KNIGHT && _player->GetMapId() == 609 && !_player->IsGameMaster() && !_player->HasSpell(50977)) else if (_player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TELEPORT) && _player->GetMapId() == 609 && !_player->IsGameMaster() && !_player->HasSpell(50977))
{ {
err = ERR_BATTLEGROUND_NONE; err = ERR_BATTLEGROUND_NONE;
} }
+3 -3
View File
@@ -83,7 +83,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
{ {
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); bool lootAllowed = creature && creature->IsAlive() == (player->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY) && creature->loot.loot_type == LOOT_PICKPOCKETING);
if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
{ {
player->SendLootError(lguid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL); player->SendLootError(lguid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL);
@@ -162,7 +162,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
case HighGuid::Vehicle: case HighGuid::Vehicle:
{ {
Creature* creature = player->GetMap()->GetCreature(guid); Creature* creature = player->GetMap()->GetCreature(guid);
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); bool lootAllowed = creature && creature->IsAlive() == (player->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY) && creature->loot.loot_type == LOOT_PICKPOCKETING);
if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE)) if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE))
{ {
loot = &creature->loot; loot = &creature->loot;
@@ -382,7 +382,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
{ {
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); bool lootAllowed = creature && creature->IsAlive() == (player->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY) && creature->loot.loot_type == LOOT_PICKPOCKETING);
if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
return; return;
@@ -1000,11 +1000,11 @@ void ScriptMgr::PetitionShowList(Player* player, Creature* creature, uint32& Cha
}); });
} }
void ScriptMgr::OnRewardKillRewarder(Player* player, bool isDungeon, float& rate) void ScriptMgr::OnRewardKillRewarder(Player* player, KillRewarder* rewarder, bool isDungeon, float& rate)
{ {
ExecuteScript<PlayerScript>([&](PlayerScript* script) ExecuteScript<PlayerScript>([&](PlayerScript* script)
{ {
script->OnRewardKillRewarder(player, isDungeon, rate); script->OnRewardKillRewarder(player, rewarder, isDungeon, rate);
}); });
} }
@@ -1046,6 +1046,19 @@ bool ScriptMgr::CanRepopAtGraveyard(Player* player)
return true; return true;
} }
Optional<bool> ScriptMgr::OnPlayerIsClass(Player const* player, Classes unitClass, ClassContext context)
{
if (ScriptRegistry<PlayerScript>::ScriptPointerList.empty())
return {};
for (auto const& [scriptID, script] : ScriptRegistry<PlayerScript>::ScriptPointerList)
{
Optional<bool> scriptResult = script->OnPlayerIsClass(player, unitClass, context);
if (scriptResult)
return scriptResult;
}
return {};
}
void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure) void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure)
{ {
ExecuteScript<PlayerScript>([&](PlayerScript* script) ExecuteScript<PlayerScript>([&](PlayerScript* script)
@@ -1054,6 +1067,21 @@ void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result,
}); });
} }
bool ScriptMgr::OnPlayerHasActivePowerType(Player const* player, Powers power)
{
auto ret = IsValidBoolScript<PlayerScript>([&](PlayerScript* script)
{
return script->OnPlayerHasActivePowerType(player, power);
});
if (ret && *ret)
{
return true;
}
return false;
}
void ScriptMgr::OnUpdateGatheringSkill(Player *player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32 &gain) { void ScriptMgr::OnUpdateGatheringSkill(Player *player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32 &gain) {
ExecuteScript<PlayerScript>([&](PlayerScript* script) ExecuteScript<PlayerScript>([&](PlayerScript* script)
{ {
@@ -22,6 +22,7 @@
// TODO to remove // TODO to remove
#include "AchievementMgr.h" #include "AchievementMgr.h"
#include "KillRewarder.h"
class PlayerScript : public ScriptObject class PlayerScript : public ScriptObject
{ {
@@ -315,7 +316,7 @@ public:
virtual void PetitionShowList(Player* /*player*/, Creature* /*creature*/, uint32& /*CharterEntry*/, uint32& /*CharterDispayID*/, uint32& /*CharterCost*/) { } virtual void PetitionShowList(Player* /*player*/, Creature* /*creature*/, uint32& /*CharterEntry*/, uint32& /*CharterDispayID*/, uint32& /*CharterCost*/) { }
virtual void OnRewardKillRewarder(Player* /*player*/, bool /*isDungeon*/, float& /*rate*/) { } virtual void OnRewardKillRewarder(Player* /*player*/, KillRewarder* /*rewarder*/, bool /*isDungeon*/, float& /*rate*/) { }
[[nodiscard]] virtual bool CanGiveMailRewardAtGiveLevel(Player* /*player*/, uint8 /*level*/) { return true; } [[nodiscard]] virtual bool CanGiveMailRewardAtGiveLevel(Player* /*player*/, uint8 /*level*/) { return true; }
@@ -323,8 +324,12 @@ public:
[[nodiscard]] virtual bool CanRepopAtGraveyard(Player* /*player*/) { return true; } [[nodiscard]] virtual bool CanRepopAtGraveyard(Player* /*player*/) { return true; }
[[nodiscard]] virtual Optional<bool> OnPlayerIsClass(Player const* /*player*/, Classes /*playerClass*/, ClassContext /*context*/) { return std::nullopt; }
virtual void OnGetMaxSkillValue(Player* /*player*/, uint32 /*skill*/, int32& /*result*/, bool /*IsPure*/) { } virtual void OnGetMaxSkillValue(Player* /*player*/, uint32 /*skill*/, int32& /*result*/, bool /*IsPure*/) { }
[[nodiscard]] virtual bool OnPlayerHasActivePowerType(Player const* /*player*/, Powers /*power*/) { return false; }
/** /**
* @brief This hook called before gathering skill gain is applied to the character. * @brief This hook called before gathering skill gain is applied to the character.
* *
+3 -1
View File
@@ -430,11 +430,13 @@ public: /* PlayerScript */
bool CanSendMail(Player* player, ObjectGuid receiverGuid, ObjectGuid mailbox, std::string& subject, std::string& body, uint32 money, uint32 COD, Item* item); bool CanSendMail(Player* player, ObjectGuid receiverGuid, ObjectGuid mailbox, std::string& subject, std::string& body, uint32 money, uint32 COD, Item* item);
void PetitionBuy(Player* player, Creature* creature, uint32& charterid, uint32& cost, uint32& type); void PetitionBuy(Player* player, Creature* creature, uint32& charterid, uint32& cost, uint32& type);
void PetitionShowList(Player* player, Creature* creature, uint32& CharterEntry, uint32& CharterDispayID, uint32& CharterCost); void PetitionShowList(Player* player, Creature* creature, uint32& CharterEntry, uint32& CharterDispayID, uint32& CharterCost);
void OnRewardKillRewarder(Player* player, bool isDungeon, float& rate); void OnRewardKillRewarder(Player* player, KillRewarder* rewarder, bool isDungeon, float& rate);
bool CanGiveMailRewardAtGiveLevel(Player* player, uint8 level); bool CanGiveMailRewardAtGiveLevel(Player* player, uint8 level);
void OnDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid); void OnDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid);
bool CanRepopAtGraveyard(Player* player); bool CanRepopAtGraveyard(Player* player);
std::optional<bool> OnPlayerIsClass(Player const* player, Classes playerClass, ClassContext context);
void OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure); void OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure);
bool OnPlayerHasActivePowerType(Player const* player, Powers power);
void OnUpdateGatheringSkill(Player* player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32& gain); void OnUpdateGatheringSkill(Player* player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32& gain);
void OnUpdateCraftingSkill(Player* player, SkillLineAbilityEntry const* skill, uint32 currentLevel, uint32& gain); void OnUpdateCraftingSkill(Player* player, SkillLineAbilityEntry const* skill, uint32 currentLevel, uint32& gain);
bool OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll); bool OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll);
@@ -79,6 +79,7 @@ class WorldSocket;
enum ArenaTeamInfoType : uint8; enum ArenaTeamInfoType : uint8;
enum AuraRemoveMode : uint8; enum AuraRemoveMode : uint8;
enum BattlegroundDesertionType : uint8; enum BattlegroundDesertionType : uint8;
enum ClassContext : uint8;
enum ContentLevels : uint8; enum ContentLevels : uint8;
enum DamageEffectType : uint8; enum DamageEffectType : uint8;
enum EnchantmentSlot : uint8; enum EnchantmentSlot : uint8;
@@ -2027,7 +2027,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
if (!target->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT)) if (!target->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT))
{ {
target->SetShapeshiftForm(FORM_NONE); target->SetShapeshiftForm(FORM_NONE);
if (target->getClass() == CLASS_DRUID) if (target->IsClass(CLASS_DRUID, CLASS_CONTEXT_ABILITY))
{ {
target->setPowerType(POWER_MANA); target->setPowerType(POWER_MANA);
// Remove movement impairing effects also when shifting out // Remove movement impairing effects also when shifting out
@@ -2106,7 +2106,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
if (target->GetTypeId() == TYPEID_PLAYER) if (target->GetTypeId() == TYPEID_PLAYER)
target->ToPlayer()->InitDataForForm(); target->ToPlayer()->InitDataForForm();
if (target->getClass() == CLASS_DRUID) if (target->IsClass(CLASS_DRUID, CLASS_CONTEXT_ABILITY))
{ {
// Dash // Dash
if (AuraEffect* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, 0, 0, 0x8)) if (AuraEffect* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, 0, 0, 0x8))
@@ -6038,7 +6038,7 @@ void AuraEffect::HandleAuraConvertRune(AuraApplication const* aurApp, uint8 mode
Player* player = target->ToPlayer(); Player* player = target->ToPlayer();
if (player->getClass() != CLASS_DEATH_KNIGHT) if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return; return;
uint32 runes = m_amount; uint32 runes = m_amount;
@@ -6244,7 +6244,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const
{ {
// Converts up to 10 rage per second into health for $d. Each point of rage is converted into ${$m2/10}.1% of max health. // Converts up to 10 rage per second into health for $d. Each point of rage is converted into ${$m2/10}.1% of max health.
// Should be manauser // Should be manauser
if (target->getPowerType() != POWER_RAGE) if (!target->HasActivePowerType(POWER_RAGE))
break; break;
uint32 rage = target->GetPower(POWER_RAGE); uint32 rage = target->GetPower(POWER_RAGE);
// Nothing todo // Nothing todo
@@ -6310,7 +6310,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const
{ {
if (target->GetTypeId() != TYPEID_PLAYER) if (target->GetTypeId() != TYPEID_PLAYER)
return; return;
if (target->ToPlayer()->getClass() != CLASS_DEATH_KNIGHT) if (!target->ToPlayer()->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return; return;
// timer expired - remove death runes // timer expired - remove death runes
@@ -7082,7 +7082,7 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con
{ {
Powers PowerType = Powers(GetMiscValue()); Powers PowerType = Powers(GetMiscValue());
if (!caster || !caster->IsAlive() || !target->IsAlive() || target->getPowerType() != PowerType) if (!caster || !caster->IsAlive() || !target->IsAlive() || !target->HasActivePowerType(PowerType))
return; return;
if (target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsImmunedToDamageOrSchool(GetSpellInfo())) if (target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsImmunedToDamageOrSchool(GetSpellInfo()))
@@ -7189,7 +7189,7 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons
{ {
Powers PowerType = Powers(GetMiscValue()); Powers PowerType = Powers(GetMiscValue());
if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() != PowerType && !m_spellInfo->HasAttribute(SPELL_ATTR7_ONLY_IN_SPELLBOOK_UNTIL_LEARNED)) if (target->GetTypeId() == TYPEID_PLAYER && !target->HasActivePowerType(PowerType) && !m_spellInfo->HasAttribute(SPELL_ATTR7_ONLY_IN_SPELLBOOK_UNTIL_LEARNED))
return; return;
if (!target->IsAlive() || !target->GetMaxPower(PowerType)) if (!target->IsAlive() || !target->GetMaxPower(PowerType))
@@ -7223,7 +7223,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
{ {
Powers PowerType = Powers(GetMiscValue()); Powers PowerType = Powers(GetMiscValue());
if (!caster || !target->IsAlive() || target->getPowerType() != PowerType) if (!caster || !target->IsAlive() || !target->HasActivePowerType(PowerType))
return; return;
if (target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsImmunedToDamageOrSchool(GetSpellInfo())) if (target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsImmunedToDamageOrSchool(GetSpellInfo()))
+1 -1
View File
@@ -1876,7 +1876,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
break; break;
if (target->GetTypeId() != TYPEID_PLAYER) if (target->GetTypeId() != TYPEID_PLAYER)
break; break;
if (target->ToPlayer()->getClass() != CLASS_DEATH_KNIGHT) if (!target->ToPlayer()->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
break; break;
// aura removed - remove death runes // aura removed - remove death runes
+6 -6
View File
@@ -4807,7 +4807,7 @@ void Spell::SendSpellGo()
} }
if ((m_caster->GetTypeId() == TYPEID_PLAYER) if ((m_caster->GetTypeId() == TYPEID_PLAYER)
&& (m_caster->getClass() == CLASS_DEATH_KNIGHT) && (m_caster->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
&& m_spellInfo->RuneCostID && m_spellInfo->RuneCostID
&& m_spellInfo->PowerType == POWER_RUNE) && m_spellInfo->PowerType == POWER_RUNE)
{ {
@@ -5396,7 +5396,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 RuneCostID)
return SPELL_CAST_OK; return SPELL_CAST_OK;
} }
if (player->getClass() != CLASS_DEATH_KNIGHT) if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return SPELL_CAST_OK; return SPELL_CAST_OK;
SpellRuneCostEntry const* src = sSpellRuneCostStore.LookupEntry(RuneCostID); SpellRuneCostEntry const* src = sSpellRuneCostStore.LookupEntry(RuneCostID);
@@ -5437,7 +5437,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 RuneCostID)
void Spell::TakeRunePower(bool didHit) void Spell::TakeRunePower(bool didHit)
{ {
if (m_caster->GetTypeId() != TYPEID_PLAYER || m_caster->getClass() != CLASS_DEATH_KNIGHT) if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_caster->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return; return;
SpellRuneCostEntry const* runeCostData = sSpellRuneCostStore.LookupEntry(m_spellInfo->RuneCostID); SpellRuneCostEntry const* runeCostData = sSpellRuneCostStore.LookupEntry(m_spellInfo->RuneCostID);
@@ -6173,7 +6173,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects) // Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects)
if (m_caster->GetTypeId() == TYPEID_PLAYER) if (m_caster->GetTypeId() == TYPEID_PLAYER)
if (Unit* target = m_targets.GetUnitTarget()) if (Unit* target = m_targets.GetUnitTarget())
if (target != m_caster && target->getPowerType() != Powers(m_spellInfo->Effects[i].MiscValue)) if (target != m_caster && !target->HasActivePowerType(Powers(m_spellInfo->Effects[i].MiscValue)))
return SPELL_FAILED_BAD_TARGETS; return SPELL_FAILED_BAD_TARGETS;
break; break;
} }
@@ -6408,7 +6408,7 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_ALREADY_HAVE_CHARM; return SPELL_FAILED_ALREADY_HAVE_CHARM;
} }
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARLOCK && strict) if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET) && strict)
if (Pet* pet = m_caster->ToPlayer()->GetPet()) if (Pet* pet = m_caster->ToPlayer()->GetPet())
pet->CastSpell(pet, 32752, true, nullptr, nullptr, pet->GetGUID()); //starting cast, trigger pet stun (cast by pet so it doesn't attack player) pet->CastSpell(pet, 32752, true, nullptr, nullptr, pet->GetGUID()); //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
@@ -6702,7 +6702,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (!m_targets.GetUnitTarget()) if (!m_targets.GetUnitTarget())
return SPELL_FAILED_BAD_IMPLICIT_TARGETS; return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
if (m_targets.GetUnitTarget()->getPowerType() != POWER_MANA) if (!m_targets.GetUnitTarget()->HasActivePowerType(POWER_MANA))
return SPELL_FAILED_BAD_TARGETS; return SPELL_FAILED_BAD_TARGETS;
break; break;
+8 -8
View File
@@ -1345,7 +1345,7 @@ void Spell::EffectPowerDrain(SpellEffIndex effIndex)
Powers PowerType = Powers(m_spellInfo->Effects[effIndex].MiscValue); Powers PowerType = Powers(m_spellInfo->Effects[effIndex].MiscValue);
if (!unitTarget || !unitTarget->IsAlive() || unitTarget->getPowerType() != PowerType || damage < 0) if (!unitTarget || !unitTarget->IsAlive() || !unitTarget->HasActivePowerType(PowerType) || damage < 0)
return; return;
// add spell damage bonus // add spell damage bonus
@@ -1424,7 +1424,7 @@ void Spell::EffectPowerBurn(SpellEffIndex effIndex)
Powers PowerType = Powers(m_spellInfo->Effects[effIndex].MiscValue); Powers PowerType = Powers(m_spellInfo->Effects[effIndex].MiscValue);
if (!unitTarget || !unitTarget->IsAlive() || unitTarget->getPowerType() != PowerType || damage < 0) if (!unitTarget || !unitTarget->IsAlive() || !unitTarget->HasActivePowerType(PowerType) || damage < 0)
return; return;
// burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn) // burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn)
@@ -1877,7 +1877,7 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && m_spellInfo->SpellFamilyName != SPELLFAMILY_POTION if (unitTarget->GetTypeId() == TYPEID_PLAYER && !unitTarget->HasActivePowerType(power) && m_spellInfo->SpellFamilyName != SPELLFAMILY_POTION
&& !m_spellInfo->HasAttribute(SPELL_ATTR7_ONLY_IN_SPELLBOOK_UNTIL_LEARNED)) && !m_spellInfo->HasAttribute(SPELL_ATTR7_ONLY_IN_SPELLBOOK_UNTIL_LEARNED))
return; return;
@@ -1982,7 +1982,7 @@ void Spell::EffectEnergizePct(SpellEffIndex effIndex)
Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !m_spellInfo->HasAttribute(SPELL_ATTR7_ONLY_IN_SPELLBOOK_UNTIL_LEARNED)) if (unitTarget->GetTypeId() == TYPEID_PLAYER && !unitTarget->HasActivePowerType(power) && !m_spellInfo->HasAttribute(SPELL_ATTR7_ONLY_IN_SPELLBOOK_UNTIL_LEARNED))
return; return;
uint32 maxPower = unitTarget->GetMaxPower(power); uint32 maxPower = unitTarget->GetMaxPower(power);
@@ -3077,7 +3077,7 @@ void Spell::EffectTameCreature(SpellEffIndex /*effIndex*/)
if (creatureTarget->IsPet()) if (creatureTarget->IsPet())
return; return;
if (m_caster->getClass() != CLASS_HUNTER) if (!m_caster->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
return; return;
// cast finish successfully // cast finish successfully
@@ -3209,7 +3209,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex)
pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
// Reset cooldowns // Reset cooldowns
if (owner->getClass() != CLASS_HUNTER) if (!owner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
{ {
pet->m_CreatureSpellCooldowns.clear(); pet->m_CreatureSpellCooldowns.clear();
owner->PetSpellInitialize(); owner->PetSpellInitialize();
@@ -5746,7 +5746,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
Player* player = m_caster->ToPlayer(); Player* player = m_caster->ToPlayer();
if (player->getClass() != CLASS_DEATH_KNIGHT) if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return; return;
// needed later // needed later
@@ -5814,7 +5814,7 @@ void Spell::EffectCreateTamedPet(SpellEffIndex effIndex)
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return; return;
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->GetPetGUID() || unitTarget->getClass() != CLASS_HUNTER) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->GetPetGUID() || !unitTarget->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
return; return;
uint32 creatureEntry = m_spellInfo->Effects[effIndex].MiscValue; uint32 creatureEntry = m_spellInfo->Effects[effIndex].MiscValue;
+1 -1
View File
@@ -140,7 +140,7 @@ public:
uint8 oldLevel = playerTarget->GetLevel(); uint8 oldLevel = playerTarget->GetLevel();
// set starting level // set starting level
uint32 startLevel = playerTarget->getClass() != CLASS_DEATH_KNIGHT uint32 startLevel = !playerTarget->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT)
? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) ? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)
: sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL); : sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
@@ -1029,7 +1029,7 @@ class spell_class_call_handler : public SpellScript
targets.remove_if([spellInfo](WorldObject const* target) -> bool targets.remove_if([spellInfo](WorldObject const* target) -> bool
{ {
Player const* player = target->ToPlayer(); Player const* player = target->ToPlayer();
if (!player || player->getClass() == CLASS_DEATH_KNIGHT) // ignore all death knights from whatever spell, for some reason the condition below is not working x.x if (!player || player->IsClass(CLASS_DEATH_KNIGHT)) // ignore all death knights from whatever spell, for some reason the condition below is not working x.x
{ {
return true; return true;
} }
@@ -37,9 +37,13 @@ enum Spells
SPELL_SHRED_ARMOR = 43243 // Used by Spirit Lynx SPELL_SHRED_ARMOR = 43243 // Used by Spirit Lynx
}; };
enum UniqueEvents
{
EVENT_BERSERK = 0
};
enum Hal_CreatureIds enum Hal_CreatureIds
{ {
NPC_SPIRIT_LYNX = 24143,
NPC_TOTEM = 24224 NPC_TOTEM = 24224
}; };
@@ -63,326 +67,274 @@ enum Yells
SAY_DEATH = 5 SAY_DEATH = 5
}; };
class boss_halazzi : public CreatureScript enum Groups
{ {
public: GROUP_LYNX = 0,
boss_halazzi() : CreatureScript("boss_halazzi") { } GROUP_HUMAN = 1,
GROUP_MERGE = 2
};
struct boss_halazziAI : public ScriptedAI struct boss_halazzi : public BossAI
{
boss_halazzi(Creature* creature) : BossAI(creature, DATA_HALAZZIEVENT)
{ {
boss_halazziAI(Creature* creature) : ScriptedAI(creature), summons(me) scheduler.SetValidator([this]
{ {
instance = creature->GetInstanceScript(); return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
BossAI::Reset();
_transformCount = 0;
_healthCheckPercentage = 0;
_phase = PHASE_NONE;
_lynxFormHealth = me->GetMaxHealth();
_healthPortion = _lynxFormHealth/4;
_humanFormHealth = (me->GetMaxHealth())/0.66666666;
EnterPhase(PHASE_LYNX);
DoCastSelf(SPELL_DUAL_WIELD, true);
}
void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
summon->Attack(me->GetVictim(), false);
summon->SetInCombatWithZone();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
ScheduleUniqueTimedEvent(10min, [&]
{
DoCastSelf(SPELL_BERSERK, true);
}, EVENT_BERSERK);
EnterPhase(PHASE_LYNX);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
if (damage >= me->GetHealth() && _phase != PHASE_ENRAGE)
{
damage = 0;
} }
else
InstanceScript* instance;
SummonList summons;
PhaseHalazzi Phase;
uint32 FrenzyTimer;
uint32 SaberlashTimer;
uint32 ShockTimer;
uint32 TotemTimer;
uint32 CheckTimer;
uint32 BerserkTimer;
uint32 TransformCount;
ObjectGuid LynxGUID;
void Reset() override
{ {
instance->SetData(DATA_HALAZZIEVENT, NOT_STARTED); if (_phase == PHASE_LYNX || _phase == PHASE_ENRAGE)
summons.DespawnAll();
LynxGUID.Clear();
TransformCount = 0;
BerserkTimer = 600000;
CheckTimer = 1000;
DoCast(me, SPELL_DUAL_WIELD, true);
Phase = PHASE_NONE;
EnterPhase(PHASE_LYNX);
}
void JustEngagedWith(Unit* /*who*/) override
{
instance->SetData(DATA_HALAZZIEVENT, IN_PROGRESS);
Talk(SAY_AGGRO);
EnterPhase(PHASE_LYNX);
}
void JustSummoned(Creature* summon) override
{
summon->AI()->AttackStart(me->GetVictim());
if (summon->GetEntry() == NPC_SPIRIT_LYNX)
LynxGUID = summon->GetGUID();
summons.Summon(summon);
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (damage >= me->GetHealth() && Phase != PHASE_ENRAGE)
damage = 0;
}
void SpellHit(Unit*, SpellInfo const* spell) override
{
if (spell->Id == SPELL_TRANSFORM_SPLIT2)
EnterPhase(PHASE_HUMAN);
}
void AttackStart(Unit* who) override
{
if (Phase != PHASE_MERGE)
ScriptedAI::AttackStart(who);
}
void EnterPhase(PhaseHalazzi NextPhase)
{
switch (NextPhase)
{ {
case PHASE_LYNX: _healthCheckPercentage = 25 * (3 - _transformCount);
case PHASE_ENRAGE: if (!HealthAbovePct(_healthCheckPercentage))
if (Phase == PHASE_MERGE) {
{ EnterPhase(PHASE_SPLIT);
DoCast(me, SPELL_TRANSFORM_MERGE, true); }
me->Attack(me->GetVictim(), true);
me->GetMotionMaster()->MoveChase(me->GetVictim());
}
if (Creature* Lynx = ObjectAccessor::GetCreature(*me, LynxGUID))
Lynx->DisappearAndDie();
me->SetMaxHealth(600000);
me->SetHealth(600000 - 150000 * TransformCount);
FrenzyTimer = 16000;
SaberlashTimer = 20000;
ShockTimer = 10000;
TotemTimer = 12000;
break;
case PHASE_SPLIT:
Talk(SAY_SPLIT);
DoCast(me, SPELL_TRANSFORM_SPLIT, true);
break;
case PHASE_HUMAN:
//DoCast(me, SPELL_SUMMON_LYNX, true);
DoSpawnCreature(NPC_SPIRIT_LYNX, 5, 5, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
me->SetMaxHealth(400000);
me->SetHealth(400000);
ShockTimer = 10000;
TotemTimer = 12000;
break;
case PHASE_MERGE:
if (Unit* pLynx = ObjectAccessor::GetUnit(*me, LynxGUID))
{
Talk(SAY_MERGE);
pLynx->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
pLynx->GetMotionMaster()->Clear();
pLynx->GetMotionMaster()->MoveFollow(me, 0, 0);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveFollow(pLynx, 0, 0);
++TransformCount;
}
break;
default:
break;
} }
Phase = NextPhase; else if (_phase == PHASE_HUMAN)
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (BerserkTimer <= diff)
{ {
DoCast(me, SPELL_BERSERK, true); if (Creature* lynx = instance->GetCreature(DATA_SPIRIT_LYNX))
BerserkTimer = 60000; {
if (!HealthAbovePct(20) || !lynx->HealthAbovePct(20))
{
EnterPhase(PHASE_MERGE);
}
}
else
{
//should not really happen
EnterEvadeMode();
}
} }
else BerserkTimer -= diff; }
}
if (Phase == PHASE_LYNX || Phase == PHASE_ENRAGE) void SpellHit(Unit*, SpellInfo const* spell) override
{ {
if (SaberlashTimer <= diff) if (spell->Id == SPELL_TRANSFORM_SPLIT2)
{
EnterPhase(PHASE_HUMAN);
}
}
void AttackStart(Unit* who) override
{
if (_phase != PHASE_MERGE)
{
BossAI::AttackStart(who);
}
}
void EnterPhase(PhaseHalazzi nextPhase)
{
switch (nextPhase)
{
case PHASE_LYNX:
case PHASE_ENRAGE:
if (_phase == PHASE_MERGE)
{
DoCastSelf(SPELL_TRANSFORM_MERGE, true);
me->RemoveAurasDueToSpell(SPELL_TRANSFORM_SPLIT2);
me->GetMotionMaster()->MoveChase(me->GetVictim());
}
summons.DespawnAll();
me->SetMaxHealth(_lynxFormHealth);
me->SetHealth(_lynxFormHealth - _healthPortion * _transformCount);
scheduler.CancelGroup(GROUP_MERGE);
scheduler.Schedule(16s, GROUP_LYNX, [this](TaskContext context)
{
DoCastSelf(SPELL_FRENZY);
context.Repeat(10s, 15s);
}).Schedule(20s, GROUP_LYNX, [this](TaskContext context)
{ {
Talk(SAY_SABER); Talk(SAY_SABER);
// A tank with more than 490 defense skills should receive no critical hit
//DoCast(me, 41296, true);
DoCastVictim(SPELL_SABER_LASH, true); DoCastVictim(SPELL_SABER_LASH, true);
//me->RemoveAurasDueToSpell(41296); context.Repeat(30s);
SaberlashTimer = 30000; });
} break;
else SaberlashTimer -= diff; case PHASE_SPLIT:
Talk(SAY_SPLIT);
if (FrenzyTimer <= diff) DoCastSelf(SPELL_TRANSFORM_SPLIT, true);
{ break;
DoCast(me, SPELL_FRENZY); case PHASE_HUMAN:
FrenzyTimer = urand(10000, 15000); scheduler.CancelGroup(GROUP_MERGE);
} DoCastSelf(SPELL_SUMMON_LYNX, true);
else FrenzyTimer -= diff; me->SetMaxHealth(_humanFormHealth);
me->SetHealth(_humanFormHealth);
if (Phase == PHASE_LYNX) scheduler.CancelGroup(GROUP_LYNX);
{ scheduler.Schedule(10s, GROUP_HUMAN, [this](TaskContext context)
if (CheckTimer <= diff)
{
if (HealthBelowPct(25 * (3 - TransformCount)))
EnterPhase(PHASE_SPLIT);
CheckTimer = 1000;
}
else CheckTimer -= diff;
}
}
if (Phase == PHASE_HUMAN || Phase == PHASE_ENRAGE)
{
if (TotemTimer <= diff)
{
DoCast(me, SPELL_SUMMON_TOTEM);
TotemTimer = 20000;
}
else TotemTimer -= diff;
if (ShockTimer <= diff)
{ {
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{ {
if (target->IsNonMeleeSpellCast(false)) if (target->IsNonMeleeSpellCast(false))
{
DoCast(target, SPELL_EARTHSHOCK); DoCast(target, SPELL_EARTHSHOCK);
}
else else
{
DoCast(target, SPELL_FLAMESHOCK); DoCast(target, SPELL_FLAMESHOCK);
ShockTimer = urand(10000, 15000);
}
}
else ShockTimer -= diff;
if (Phase == PHASE_HUMAN)
{
if (CheckTimer <= diff)
{
if (!HealthAbovePct(20) /*HealthBelowPct(10)*/)
EnterPhase(PHASE_MERGE);
else
{
Unit* Lynx = ObjectAccessor::GetUnit(*me, LynxGUID);
if (Lynx && !Lynx->HealthAbovePct(20) /*Lynx->HealthBelowPct(10)*/)
EnterPhase(PHASE_MERGE);
}
CheckTimer = 1000;
}
else CheckTimer -= diff;
}
}
if (Phase == PHASE_MERGE)
{
if (CheckTimer <= diff)
{
Unit* Lynx = ObjectAccessor::GetUnit(*me, LynxGUID);
if (Lynx)
{
Lynx->GetMotionMaster()->MoveFollow(me, 0, 0);
me->GetMotionMaster()->MoveFollow(Lynx, 0, 0);
if (me->IsWithinDistInMap(Lynx, 6.0f))
{
if (TransformCount < 3)
EnterPhase(PHASE_LYNX);
else
EnterPhase(PHASE_ENRAGE);
} }
} }
CheckTimer = 1000; context.Repeat(10s, 15s);
}).Schedule(12s, GROUP_HUMAN, [this](TaskContext context)
{
DoCastSelf(SPELL_SUMMON_TOTEM);
context.Repeat(20s);
});
break;
case PHASE_MERGE:
if (Creature* lynx = instance->GetCreature(DATA_SPIRIT_LYNX))
{
Talk(SAY_MERGE);
scheduler.CancelGroup(GROUP_HUMAN);
lynx->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
lynx->GetMotionMaster()->Clear();
lynx->GetMotionMaster()->MoveFollow(me, 0, 0);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveFollow(lynx, 0, 0);
++_transformCount;
scheduler.Schedule(2s, GROUP_MERGE, [this](TaskContext context)
{
if (Creature* lynx = instance->GetCreature(DATA_SPIRIT_LYNX))
{
if (me->IsWithinDistInMap(lynx, 6.0f))
{
if (_transformCount < 3)
{
EnterPhase(PHASE_LYNX);
}
else
{
EnterPhase(PHASE_ENRAGE);
}
}
}
context.Repeat(2s);
});
} }
else CheckTimer -= diff; break;
} default:
break;
DoMeleeAttackIfReady();
} }
_phase = nextPhase;
}
void KilledUnit(Unit* victim) override void KilledUnit(Unit* victim) override
{
BossAI::KilledUnit(victim);
if (victim->IsPlayer())
{ {
if (victim->GetTypeId() != TYPEID_PLAYER)
return;
Talk(SAY_KILL); Talk(SAY_KILL);
} }
void JustDied(Unit* /*killer*/) override
{
instance->SetData(DATA_HALAZZIEVENT, DONE);
Talk(SAY_DEATH);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulAmanAI<boss_halazziAI>(creature);
} }
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
private:
uint32 _lynxFormHealth;
uint32 _humanFormHealth;
uint32 _healthPortion;
uint8 _transformCount;
uint32 _healthCheckPercentage;
PhaseHalazzi _phase;
}; };
// Spirits Lynx AI // Spirits Lynx AI
class npc_halazzi_lynx : public CreatureScript struct npc_halazzi_lynx : public ScriptedAI
{ {
public: npc_halazzi_lynx(Creature* creature) : ScriptedAI(creature) { }
npc_halazzi_lynx() : CreatureScript("npc_halazzi_lynx") { }
struct npc_halazzi_lynxAI : public ScriptedAI void Reset() override
{ {
npc_halazzi_lynxAI(Creature* creature) : ScriptedAI(creature) { } scheduler.CancelAll();
}
uint32 FrenzyTimer; void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
uint32 shredder_timer;
void Reset() override
{
FrenzyTimer = urand(30000, 50000); //frenzy every 30-50 seconds
shredder_timer = 4000;
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (damage >= me->GetHealth())
damage = 0;
}
void AttackStart(Unit* who) override
{
if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
ScriptedAI::AttackStart(who);
}
void JustEngagedWith(Unit* /*who*/) override {/*DoZoneInCombat();*/ }
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (FrenzyTimer <= diff)
{
DoCast(me, SPELL_LYNX_FRENZY);
FrenzyTimer = urand(30000, 50000); //frenzy every 30-50 seconds
}
else FrenzyTimer -= diff;
if (shredder_timer <= diff)
{
DoCastVictim(SPELL_SHRED_ARMOR);
shredder_timer = 4000;
}
else shredder_timer -= diff;
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{ {
return GetZulAmanAI<npc_halazzi_lynxAI>(creature); if (damage >= me->GetHealth())
{
damage = 0;
}
}
void AttackStart(Unit* who) override
{
if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
{
ScriptedAI::AttackStart(who);
}
}
void JustEngagedWith(Unit* who) override
{
ScriptedAI::JustEngagedWith(who);
ScheduleTimedEvent(30s, 50s, [&]
{
DoCastSelf(SPELL_LYNX_FRENZY);
}, 30s, 50s);
ScheduleTimedEvent(4s, [&]{
DoCastVictim(SPELL_SHRED_ARMOR);
}, 4s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
scheduler.Update(diff);
DoMeleeAttackIfReady();
} }
}; };
void AddSC_boss_halazzi() void AddSC_boss_halazzi()
{ {
new boss_halazzi(); RegisterZulAmanCreatureAI(boss_halazzi);
new npc_halazzi_lynx(); RegisterZulAmanCreatureAI(npc_halazzi_lynx);
} }
@@ -447,9 +447,9 @@ public:
PlayerAbility_Timer = urand(8000, 10000); PlayerAbility_Timer = urand(8000, 10000);
PlayerClass = target->getClass() - 1; PlayerClass = target->getClass() - 1;
if (PlayerClass == CLASS_DRUID - 1) if (target->IsClass(CLASS_DRUID))
PlayerClass = CLASS_DRUID; PlayerClass = CLASS_DRUID;
else if (PlayerClass == CLASS_PRIEST - 1 && target->HasSpell(15473)) else if (target->IsClass(CLASS_PRIEST) && target->HasSpell(15473))
PlayerClass = CLASS_PRIEST; // shadow priest PlayerClass = CLASS_PRIEST; // shadow priest
SiphonSoul_Timer = 99999; // buff lasts 30 sec SiphonSoul_Timer = 99999; // buff lasts 30 sec
@@ -55,6 +55,17 @@ static SHostageInfo HostageInfo[] =
Position const HarrisonJonesLoc = {120.687f, 1674.0f, 42.0217f, 1.59044f}; Position const HarrisonJonesLoc = {120.687f, 1674.0f, 42.0217f, 1.59044f};
ObjectData const creatureData[] =
{
{ NPC_SPIRIT_LYNX, DATA_SPIRIT_LYNX },
{ 0, 0 }
};
ObjectData const gameObjectData[] =
{
{ 0, 0 }
};
class instance_zulaman : public InstanceMapScript class instance_zulaman : public InstanceMapScript
{ {
public: public:
@@ -92,6 +103,7 @@ public:
void Initialize() override void Initialize() override
{ {
SetHeaders(DataHeader); SetHeaders(DataHeader);
LoadObjectData(creatureData, gameObjectData);
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
QuestTimer = 0; QuestTimer = 0;
@@ -135,6 +147,7 @@ public:
default: default:
break; break;
} }
InstanceScript::OnCreatureCreate(creature);
} }
void OnGameObjectCreate(GameObject* go) override void OnGameObjectCreate(GameObject* go) override
@@ -32,9 +32,10 @@ enum DataTypes
DATA_HALAZZIEVENT = 4, DATA_HALAZZIEVENT = 4,
DATA_HEXLORDEVENT = 5, DATA_HEXLORDEVENT = 5,
DATA_ZULJINEVENT = 6, DATA_ZULJINEVENT = 6,
DATA_CHESTLOOTED = 7, DATA_SPIRIT_LYNX = 7,
TYPE_RAND_VENDOR_1 = 8, DATA_CHESTLOOTED = 8,
TYPE_RAND_VENDOR_2 = 9 TYPE_RAND_VENDOR_1 = 9,
TYPE_RAND_VENDOR_2 = 10
}; };
enum CreatureIds enum CreatureIds
@@ -44,7 +45,8 @@ enum CreatureIds
NPC_ZULJIN = 23863, NPC_ZULJIN = 23863,
NPC_HEXLORD = 24239, NPC_HEXLORD = 24239,
NPC_HALAZZI = 23577, NPC_HALAZZI = 23577,
NPC_NALORAKK = 23576 NPC_NALORAKK = 23576,
NPC_SPIRIT_LYNX = 24143
}; };
enum GameobjectIds enum GameobjectIds
@@ -68,4 +70,6 @@ inline AI* GetZulAmanAI(T* obj)
return GetInstanceAI<AI>(obj, ZulAmanScriptName); return GetInstanceAI<AI>(obj, ZulAmanScriptName);
} }
#define RegisterZulAmanCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetZulAmanAI)
#endif #endif
+4 -4
View File
@@ -53,10 +53,10 @@ enum RizzleSprysprocketData
SAY_RIZZLE_START = 0, SAY_RIZZLE_START = 0,
SAY_RIZZLE_GRENADE = 1, SAY_RIZZLE_GRENADE = 1,
SAY_RIZZLE_FINAL = 2, SAY_RIZZLE_FINAL = 2,
MSG_ESCAPE_NOTICE = 3 MSG_ESCAPE_NOTICE = 3,
}; GOSSIP_GET_MOONSTONE = 21893
#define GOSSIP_GET_MOONSTONE "Hand over the Southfury moonstone and I'll let you go." };
Position const WPs[58] = Position const WPs[58] =
{ {
@@ -295,7 +295,7 @@ public:
if (player->GetQuestStatus(QUEST_CHASING_THE_MOONSTONE) != QUEST_STATUS_INCOMPLETE) if (player->GetQuestStatus(QUEST_CHASING_THE_MOONSTONE) != QUEST_STATUS_INCOMPLETE)
return true; return true;
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_GET_MOONSTONE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); AddGossipItemFor(player, GOSSIP_GET_MOONSTONE, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, 10811, creature->GetGUID()); SendGossipMenuFor(player, 10811, creature->GetGUID());
return true; return true;
+50 -25
View File
@@ -65,7 +65,7 @@ public:
{ {
case GOSSIP_ACTION_INFO_DEF + 1: case GOSSIP_ACTION_INFO_DEF + 1:
CloseGossipMenuFor(player); CloseGossipMenuFor(player);
if (player->getClass() == CLASS_DRUID && player->GetTeamId() == TEAM_HORDE) if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_TAXI) && player->GetTeamId() == TEAM_HORDE)
player->ActivateTaxiPathTo(TAXI_PATH_ID_HORDE); player->ActivateTaxiPathTo(TAXI_PATH_ID_HORDE);
break; break;
case GOSSIP_ACTION_INFO_DEF + 2: case GOSSIP_ACTION_INFO_DEF + 2:
@@ -80,29 +80,42 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override bool OnGossipHello(Player* player, Creature* creature) override
{ {
if (player->getClass() != CLASS_DRUID) if (player->GetTeamId() != TEAM_HORDE)
{ {
SendGossipMenuFor(player, 4916, creature->GetGUID()); if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_QUEST) && player->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE)
}
else if (player->GetTeamId() != TEAM_HORDE)
{
if (player->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE)
{ {
AddGossipItemFor(player, 4042, 2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); AddGossipItemFor(player, 4042, 2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
} }
SendGossipMenuFor(player, 4917, creature->GetGUID()); if (player->IsClass(CLASS_DRUID))
{
SendGossipMenuFor(player, 4917, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 4916, creature->GetGUID());
}
} }
else if (player->getClass() == CLASS_DRUID && player->GetTeamId() == TEAM_HORDE) else if (player->GetTeamId() == TEAM_HORDE)
{ {
AddGossipItemFor(player, 4042, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_TAXI))
{
AddGossipItemFor(player, 4042, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
}
if (player->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE) if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_QUEST) && player->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE)
{ {
AddGossipItemFor(player, 4042, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); AddGossipItemFor(player, 4042, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
} }
SendGossipMenuFor(player, 4918, creature->GetGUID()); if (player->IsClass(CLASS_DRUID))
{
SendGossipMenuFor(player, 4918, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 4916, creature->GetGUID());
}
} }
return true; return true;
} }
@@ -176,7 +189,7 @@ public:
{ {
case GOSSIP_ACTION_INFO_DEF + 1: case GOSSIP_ACTION_INFO_DEF + 1:
CloseGossipMenuFor(player); CloseGossipMenuFor(player);
if (player->getClass() == CLASS_DRUID && player->GetTeamId() == TEAM_ALLIANCE) if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_TAXI) && player->GetTeamId() == TEAM_ALLIANCE)
player->ActivateTaxiPathTo(TAXI_PATH_ID_ALLY); player->ActivateTaxiPathTo(TAXI_PATH_ID_ALLY);
break; break;
case GOSSIP_ACTION_INFO_DEF + 2: case GOSSIP_ACTION_INFO_DEF + 2:
@@ -191,29 +204,41 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override bool OnGossipHello(Player* player, Creature* creature) override
{ {
if (player->getClass() != CLASS_DRUID) if (player->GetTeamId() != TEAM_ALLIANCE)
{ {
SendGossipMenuFor(player, 4913, creature->GetGUID()); if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_QUEST) && player->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE)
}
else if (player->GetTeamId() != TEAM_ALLIANCE)
{
if (player->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE)
{ {
AddGossipItemFor(player, 4041, 2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); AddGossipItemFor(player, 4041, 2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
} }
if (player->IsClass(CLASS_DRUID))
SendGossipMenuFor(player, 4915, creature->GetGUID()); {
SendGossipMenuFor(player, 4915, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 4913, creature->GetGUID());
}
} }
else if (player->getClass() == CLASS_DRUID && player->GetTeamId() == TEAM_ALLIANCE) else if (player->GetTeamId() == TEAM_ALLIANCE)
{ {
AddGossipItemFor(player, 4041, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_TAXI))
{
AddGossipItemFor(player, 4041, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
}
if (player->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE) if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_QUEST) && player->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE)
{ {
AddGossipItemFor(player, 4041, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); AddGossipItemFor(player, 4041, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
} }
SendGossipMenuFor(player, 4914, creature->GetGUID()); if (player->IsClass(CLASS_DRUID))
{
SendGossipMenuFor(player, 4914, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 4913, creature->GetGUID());
}
} }
return true; return true;
} }
@@ -853,12 +853,12 @@ public:
{ {
if (p->getPowerType() != POWER_MANA) if (p->getPowerType() != POWER_MANA)
return true; return true;
if (p->getClass() == CLASS_HUNTER) if (p->IsClass(CLASS_HUNTER))
return true; return true;
uint8 maxIndex = p->GetMostPointsTalentTree(); uint8 maxIndex = p->GetMostPointsTalentTree();
if ((p->getClass() == CLASS_PALADIN && maxIndex >= 1) || (p->getClass() == CLASS_SHAMAN && maxIndex == 1) || (p->getClass() == CLASS_DRUID && maxIndex == 1)) if ((p->IsClass(CLASS_PALADIN) && maxIndex >= 1) || (p->IsClass(CLASS_SHAMAN) && maxIndex == 1) || (p->IsClass(CLASS_DRUID) && maxIndex == 1))
return true; return true;
if (_removeHealers == ((p->getClass() == CLASS_DRUID && maxIndex == 2) || (p->getClass() == CLASS_PALADIN && maxIndex == 0) || (p->getClass() == CLASS_PRIEST && maxIndex <= 1) || (p->getClass() == CLASS_SHAMAN && maxIndex == 2))) if (_removeHealers == ((p->IsClass(CLASS_DRUID) && maxIndex == 2) || (p->IsClass(CLASS_PALADIN) && maxIndex == 0) || (p->IsClass(CLASS_PRIEST) && maxIndex <= 1) || (p->IsClass(CLASS_SHAMAN) && maxIndex == 2)))
return true; return true;
return false; return false;
@@ -2856,8 +2856,7 @@ public:
{ {
c->AI()->AttackStart(target); c->AI()->AttackStart(target);
DoZoneInCombat(c); DoZoneInCombat(c);
uint8 Class = target->getClass(); if (!target->IsClass(CLASS_DRUID))
if (Class != CLASS_DRUID)
if (Player* p = target->ToPlayer()) if (Player* p = target->ToPlayer())
{ {
if (Item* i = p->GetWeaponForAttack(BASE_ATTACK)) if (Item* i = p->GetWeaponForAttack(BASE_ATTACK))
@@ -2869,7 +2868,7 @@ public:
target->CastSpell(c, 60352, true); // Mirror Image, clone visual appearance target->CastSpell(c, 60352, true); // Mirror Image, clone visual appearance
} }
c->AI()->DoAction(Class); c->AI()->DoAction(target->getClass());
} }
} }
} }
@@ -57,7 +57,9 @@ enum Spells
SPELL_SUMMON_SPOREBAT2 = 38490, SPELL_SUMMON_SPOREBAT2 = 38490,
SPELL_SUMMON_SPOREBAT3 = 38492, SPELL_SUMMON_SPOREBAT3 = 38492,
SPELL_SUMMON_SPOREBAT4 = 38493, SPELL_SUMMON_SPOREBAT4 = 38493,
SPELL_TOXIC_SPORES = 38574 SPELL_TOXIC_SPORES = 38574,
SPELL_POISON_BOLT = 38253
}; };
enum Misc enum Misc
@@ -91,6 +93,8 @@ struct boss_lady_vashj : public BossAI
ScheduleHealthCheckEvent(70, [&]{ ScheduleHealthCheckEvent(70, [&]{
Talk(SAY_PHASE2); Talk(SAY_PHASE2);
scheduler.CancelAll();
me->CastStop();
me->SetReactState(REACT_PASSIVE); me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->MovePoint(POINT_HOME, me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY(), me->GetHomePosition().GetPositionZ(), true, true); me->GetMotionMaster()->MovePoint(POINT_HOME, me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY(), me->GetHomePosition().GetPositionZ(), true, true);
}); });
@@ -178,7 +182,6 @@ struct boss_lady_vashj : public BossAI
me->AddUnitState(UNIT_STATE_ROOT); me->AddUnitState(UNIT_STATE_ROOT);
me->SetFacingTo(me->GetHomePosition().GetOrientation()); me->SetFacingTo(me->GetHomePosition().GetOrientation());
instance->SetData(DATA_ACTIVATE_SHIELD, 0); instance->SetData(DATA_ACTIVATE_SHIELD, 0);
scheduler.CancelAll();
scheduler.Schedule(2400ms, [this](TaskContext context) scheduler.Schedule(2400ms, [this](TaskContext context)
{ {
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
@@ -271,6 +274,42 @@ private:
std::chrono::seconds _batTimer; std::chrono::seconds _batTimer;
}; };
struct npc_tainted_elemental : public ScriptedAI
{
npc_tainted_elemental(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
scheduler.CancelAll();
me->SetInCombatWithZone();
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
me->AddThreat(target, 1000.0f);
}
}
void JustEngagedWith(Unit* /*who*/) override
{
scheduler.Schedule(100ms, 500ms, [this](TaskContext context)
{
DoCastVictim(SPELL_POISON_BOLT);
context.Repeat(2350ms, 2650ms);
}).Schedule(15s, [this](TaskContext)
{
me->DespawnOrUnsummon();
});
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
}
};
class spell_lady_vashj_magic_barrier : public AuraScript class spell_lady_vashj_magic_barrier : public AuraScript
{ {
PrepareAuraScript(spell_lady_vashj_magic_barrier); PrepareAuraScript(spell_lady_vashj_magic_barrier);
@@ -410,6 +449,7 @@ class spell_lady_vashj_summons : public SpellScript
void AddSC_boss_lady_vashj() void AddSC_boss_lady_vashj()
{ {
RegisterSerpentShrineAI(boss_lady_vashj); RegisterSerpentShrineAI(boss_lady_vashj);
RegisterSerpentShrineAI(npc_tainted_elemental);
RegisterSpellScript(spell_lady_vashj_magic_barrier); RegisterSpellScript(spell_lady_vashj_magic_barrier);
RegisterSpellScript(spell_lady_vashj_remove_tainted_cores); RegisterSpellScript(spell_lady_vashj_remove_tainted_cores);
RegisterSpellScript(spell_lady_vashj_summon_sporebat); RegisterSpellScript(spell_lady_vashj_summon_sporebat);
@@ -28,6 +28,7 @@ enum Spells
SPELL_FLAME_QUILLS = 34229, SPELL_FLAME_QUILLS = 34229,
SPELL_QUILL_MISSILE_1 = 34269, // 21 SPELL_QUILL_MISSILE_1 = 34269, // 21
SPELL_QUILL_MISSILE_2 = 34314, // 3 SPELL_QUILL_MISSILE_2 = 34314, // 3
SPELL_CLEAR_ALL_DEBUFFS = 34098,
SPELL_FLAME_BUFFET = 34121, SPELL_FLAME_BUFFET = 34121,
SPELL_EMBER_BLAST = 34341, SPELL_EMBER_BLAST = 34341,
SPELL_REBIRTH_PHASE2 = 34342, SPELL_REBIRTH_PHASE2 = 34342,
@@ -38,15 +39,18 @@ enum Spells
SPELL_DIVE_BOMB = 35181 SPELL_DIVE_BOMB = 35181
}; };
const Position alarPoints[7] = // @todo: Alar doesnt seem to move to waypoints but instead to the triggers in p1
const Position alarPoints[9] =
{ {
{340.15f, 58.65f, 17.71f, 4.60f}, {335.638f, 59.4879f, 17.9319f, 4.60f}, //first platform
{388.09f, 31.54f, 20.18f, 1.61f}, {388.751007f, 31.731199f, 20.263599f, 1.61f},
{388.18f, -32.85f, 20.18f, 0.52f}, {388.790985f, -33.105900f, 20.263599f, 0.52f},
{340.29f, -60.19f, 17.72f, 5.71f}, {332.722992f, -61.159f, 17.979099f, 5.71f},
{332.0f, 0.01f, 43.0f, 0.0f}, {258.959015f, -38.687099f, 20.262899f, 5.21f},
{331.0f, 0.01f, -2.38f, 0.0f}, {259.2277997, 35.879002f, 20.263f, 4.81f}, //sixth platform
{332.0f, 0.01f, 43.0f, 0.0f} {332.0f, 0.01f, 43.0f, 0.0f}, //quill
{331.0f, 0.01f, -2.38f, 0.0f}, //middle (p2)
{332.0f, 0.01f, 43.0f, 0.0f} // dive
}; };
enum Misc enum Misc
@@ -56,26 +60,28 @@ enum Misc
NPC_FLAME_PATCH = 20602, NPC_FLAME_PATCH = 20602,
POINT_PLATFORM = 0, POINT_PLATFORM = 0,
POINT_QUILL = 4, POINT_QUILL = 6,
POINT_MIDDLE = 5, POINT_MIDDLE = 7,
POINT_DIVE = 6, POINT_DIVE = 8,
EVENT_SWITCH_PLATFORM = 1, EVENT_RELOCATE_MIDDLE = 1,
EVENT_START_QUILLS = 2, EVENT_REBIRTH = 2,
EVENT_RELOCATE_MIDDLE = 3, EVENT_SPELL_BERSERK = 3,
EVENT_REBIRTH = 4,
EVENT_SPELL_MELT_ARMOR = 5,
EVENT_SPELL_FLAME_PATCH = 6,
EVENT_SPELL_CHARGE = 7,
EVENT_SPELL_DIVE_BOMB = 8,
EVENT_START_DIVE = 9,
EVENT_CAST_DIVE_BOMB = 10,
EVENT_SUMMON_DIVE_PHOENIX = 11,
EVENT_REBIRTH_DIVE = 12,
EVENT_SPELL_BERSERK = 13,
EVENT_MOVE_TO_PHASE_2 = 20, EVENT_MOVE_TO_PHASE_2 = 4,
EVENT_FINISH_DIVE = 21 EVENT_FINISH_DIVE = 5
};
enum PlatformMoveDirections
{
DIRECTION_ANTI_CLOCKWISE = 0,
DIRECTION_CLOCKWISE = 1,
DIRECTION_ACROSS = 2
};
enum GroupAlar
{
GROUP_FLAME_BUFFET = 1
}; };
// Xinef: Ruse of the Ashtongue (10946) // Xinef: Ruse of the Ashtongue (10946)
@@ -85,279 +91,284 @@ enum qruseoftheAshtongue
QUEST_RUSE_OF_THE_ASHTONGUE = 10946, QUEST_RUSE_OF_THE_ASHTONGUE = 10946,
}; };
class boss_alar : public CreatureScript struct boss_alar : public BossAI
{ {
public:
boss_alar() : CreatureScript("boss_alar") { }
struct boss_alarAI : public BossAI boss_alar(Creature* creature) : BossAI(creature, DATA_ALAR)
{ {
boss_alarAI(Creature* creature) : BossAI(creature, DATA_ALAR) SetCombatMovement(false);
{
startPath = true;
SetCombatMovement(false);
}
uint8 platform;
uint8 noQuillTimes;
bool startPath;
void JustReachedHome() override
{
BossAI::JustReachedHome();
startPath = true;
}
void Reset() override
{
BossAI::Reset();
platform = 0;
noQuillTimes = 0;
me->SetModelVisible(true);
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FIRE, true);
me->SetReactState(REACT_AGGRESSIVE);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SWITCH_PLATFORM, 0);
}
void JustDied(Unit* killer) override
{
me->SetModelVisible(true);
BossAI::JustDied(killer);
// Xinef: Ruse of the Ashtongue (10946)
Map::PlayerList const& pl = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
{
Player* player = itr->GetSource();
if (player->GetQuestStatus(QUEST_RUSE_OF_THE_ASHTONGUE) == QUEST_STATUS_INCOMPLETE)
if (player->HasAura(SPELL_ASHTONGUE_RUSE))
player->AreaExploredOrEventHappens(QUEST_RUSE_OF_THE_ASHTONGUE);
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (summon->GetEntry() == NPC_EMBER_OF_ALAR)
summon->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FIRE, true);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (damage >= me->GetHealth() && platform < POINT_MIDDLE)
{
damage = 0;
if (events.GetNextEventTime(EVENT_REBIRTH) == 0)
{
me->InterruptNonMeleeSpells(false);
me->SetHealth(me->GetMaxHealth());
me->SetReactState(REACT_PASSIVE);
me->CastSpell(me, SPELL_EMBER_BLAST, true);
me->setAttackTimer(BASE_ATTACK, 16000);
events.Reset();
events.ScheduleEvent(EVENT_RELOCATE_MIDDLE, 8000);
events.ScheduleEvent(EVENT_MOVE_TO_PHASE_2, 12000);
events.ScheduleEvent(EVENT_REBIRTH, 16001);
}
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE)
{
if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized() && !me->IsInCombat())
startPath = true;
return;
}
if (id == POINT_PLATFORM)
me->setAttackTimer(BASE_ATTACK, 1000);
else if (id == POINT_QUILL)
events.ScheduleEvent(EVENT_START_QUILLS, 1000);
else if (id == POINT_DIVE)
{
events.ScheduleEvent(EVENT_START_DIVE, 1000);
events.ScheduleEvent(EVENT_CAST_DIVE_BOMB, 5000);
}
}
void UpdateAI(uint32 diff) override
{
if (startPath)
{
me->StopMoving();
startPath = false;
if (WaypointPath const* i_path = sWaypointMgr->GetPath(me->GetWaypointPath()))
{
Movement::PointsArray pathPoints;
pathPoints.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
for (uint8 i = 0; i < i_path->size(); ++i)
{
WaypointData const* node = i_path->at(i);
pathPoints.push_back(G3D::Vector3(node->x, node->y, node->z));
}
me->GetMotionMaster()->MoveSplinePath(&pathPoints);
}
}
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SWITCH_PLATFORM:
if (roll_chance_i(20 * noQuillTimes))
{
noQuillTimes = 0;
platform = RAND(0, 3);
me->GetMotionMaster()->MovePoint(POINT_QUILL, alarPoints[POINT_QUILL], false, true);
events.ScheduleEvent(EVENT_SWITCH_PLATFORM, 16000);
}
else
{
if (noQuillTimes++ > 0)
{
me->SetOrientation(alarPoints[platform].GetOrientation());
me->SummonCreature(NPC_EMBER_OF_ALAR, *me, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 6000);
}
me->GetMotionMaster()->MovePoint(POINT_PLATFORM, alarPoints[platform], false, true);
platform = (platform + 1) % 4;
events.ScheduleEvent(EVENT_SWITCH_PLATFORM, 30000);
}
me->setAttackTimer(BASE_ATTACK, 20000);
break;
case EVENT_START_QUILLS:
me->CastSpell(me, SPELL_FLAME_QUILLS, false);
break;
case EVENT_RELOCATE_MIDDLE:
me->SetPosition(alarPoints[POINT_MIDDLE]);
break;
case EVENT_MOVE_TO_PHASE_2:
me->RemoveAurasDueToSpell(SPELL_EMBER_BLAST);
me->CastSpell(me, SPELL_REBIRTH_PHASE2, false);
break;
case EVENT_REBIRTH:
me->SetReactState(REACT_AGGRESSIVE);
platform = POINT_MIDDLE;
me->GetMotionMaster()->MoveChase(me->GetVictim());
events.ScheduleEvent(EVENT_SPELL_MELT_ARMOR, 67000);
events.ScheduleEvent(EVENT_SPELL_CHARGE, 10000);
events.ScheduleEvent(EVENT_SPELL_FLAME_PATCH, 20000);
events.ScheduleEvent(EVENT_SPELL_DIVE_BOMB, 30000);
break;
case EVENT_SPELL_MELT_ARMOR:
me->CastSpell(me->GetVictim(), SPELL_MELT_ARMOR, false);
events.ScheduleEvent(EVENT_SPELL_MELT_ARMOR, 60000);
break;
case EVENT_SPELL_CHARGE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
me->CastSpell(target, SPELL_CHARGE, false);
events.ScheduleEvent(EVENT_SPELL_CHARGE, 30000);
break;
case EVENT_SPELL_FLAME_PATCH:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
me->SummonCreature(NPC_FLAME_PATCH, *target, TEMPSUMMON_TIMED_DESPAWN, 2 * MINUTE * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_SPELL_FLAME_PATCH, 30000);
break;
case EVENT_SPELL_DIVE_BOMB:
me->GetMotionMaster()->MovePoint(POINT_DIVE, alarPoints[POINT_DIVE], false, true);
events.ScheduleEvent(EVENT_SPELL_DIVE_BOMB, 30000);
events.DelayEvents(15000);
me->setAttackTimer(BASE_ATTACK, 20000);
break;
case EVENT_START_DIVE:
me->CastSpell(me, SPELL_DIVE_BOMB_VISUAL, false);
break;
case EVENT_CAST_DIVE_BOMB:
events.ScheduleEvent(EVENT_SUMMON_DIVE_PHOENIX, 2000);
events.ScheduleEvent(EVENT_REBIRTH_DIVE, 6000);
events.ScheduleEvent(EVENT_FINISH_DIVE, 10000);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 90.0f, true))
{
me->CastSpell(target, SPELL_DIVE_BOMB, false);
me->SetPosition(*target);
me->StopMovingOnCurrentPos();
}
me->RemoveAurasDueToSpell(SPELL_DIVE_BOMB_VISUAL);
break;
case EVENT_SUMMON_DIVE_PHOENIX:
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 10.0f, true);
me->SummonCreature(NPC_EMBER_OF_ALAR, target ? *target : *me, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 6000);
me->SummonCreature(NPC_EMBER_OF_ALAR, target ? *target : *me, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 6000);
break;
}
case EVENT_REBIRTH_DIVE:
me->SetModelVisible(true);
me->CastSpell(me, SPELL_REBIRTH_DIVE, false);
break;
case EVENT_FINISH_DIVE:
me->GetMotionMaster()->MoveChase(me->GetVictim());
break;
case EVENT_SPELL_BERSERK:
me->CastSpell(me, SPELL_BERSERK, true);
break;
}
if (me->isAttackReady())
{
if (me->IsWithinMeleeRange(me->GetVictim()))
{
me->AttackerStateUpdate(me->GetVictim());
me->resetAttackTimer();
}
else
{
me->resetAttackTimer();
ThreatContainer::StorageType const& threatList = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr)
if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
if (me->IsWithinMeleeRange(unit))
{
me->AttackerStateUpdate(unit);
return;
}
me->CastSpell(me, SPELL_FLAME_BUFFET, false);
}
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetTheEyeAI<boss_alarAI>(creature);
} }
void JustReachedHome() override
{
BossAI::JustReachedHome();
if (me->IsEngaged())
{
ConstructWaypointsAndMove();
}
}
void Reset() override
{
BossAI::Reset();
_canAttackCooldown = true;
_baseAttackOverride = false;
_spawnPhoenixes = false;
_platform = 0;
_platformRoll = 0;
_noQuillTimes = 0;
_platformMoveRepeatTimer = 16s;
me->SetModelVisible(true);
me->SetReactState(REACT_AGGRESSIVE);
ConstructWaypointsAndMove();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
ScheduleTimedEvent(0s, [&]
{
if (roll_chance_i(20 * _noQuillTimes))
{
_noQuillTimes = 0;
_platform = RAND(0, 5);
me->GetMotionMaster()->MovePoint(POINT_QUILL, alarPoints[POINT_QUILL], false, true);
_platformMoveRepeatTimer = 16s;
}
else
{
if (_noQuillTimes++ > 0)
{
me->SetOrientation(alarPoints[_platform].GetOrientation());
if (_spawnPhoenixes)
{
SpawnPhoenixes(3, me);
}
}
me->GetMotionMaster()->MovePoint(POINT_PLATFORM, alarPoints[_platform], false, true);
_platformRoll = RAND(0, 2);
switch(_platformRoll)
{
case DIRECTION_ANTI_CLOCKWISE:
_platform = (_platform+5)%6;
_spawnPhoenixes = false;
break;
case DIRECTION_CLOCKWISE:
_platform = (_platform+1)%6;
_spawnPhoenixes = false;
break;
case DIRECTION_ACROSS:
_platform = (_platform+3)%6;
_spawnPhoenixes = true;
break;
}
_platformMoveRepeatTimer = 30s;
}
}, _platformMoveRepeatTimer);
ScheduleMainSpellAttack(0s);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
me->SetModelVisible(true);
if (Map* map = me->GetMap())
{
map->DoForAllPlayers([&](Player* player)
{
if (player->GetQuestStatus(QUEST_RUSE_OF_THE_ASHTONGUE) == QUEST_STATUS_INCOMPLETE)
{
if (player->HasAura(SPELL_ASHTONGUE_RUSE))
{
player->AreaExploredOrEventHappens(QUEST_RUSE_OF_THE_ASHTONGUE);
}
}
});
}
}
void MoveInLineOfSight(Unit* /*who*/) override { }
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
if (damage >= me->GetHealth() && _platform < POINT_MIDDLE)
{
damage = 0;
me->InterruptNonMeleeSpells(false);
me->SetHealth(me->GetMaxHealth());
me->SetReactState(REACT_PASSIVE);
DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS);
DoCastSelf(SPELL_EMBER_BLAST, true);
scheduler.CancelAll();
ScheduleUniqueTimedEvent(8s, [&]{
me->SetPosition(alarPoints[POINT_MIDDLE]);
}, EVENT_RELOCATE_MIDDLE);
ScheduleUniqueTimedEvent(12s, [&]
{
me->RemoveAurasDueToSpell(SPELL_EMBER_BLAST);
DoCastSelf(SPELL_REBIRTH_PHASE2);
}, EVENT_MOVE_TO_PHASE_2);
ScheduleUniqueTimedEvent(16001ms, [&]{
me->SetReactState(REACT_AGGRESSIVE);
_platform = POINT_MIDDLE;
me->GetMotionMaster()->MoveChase(me->GetVictim());
ScheduleAbilities();
}, EVENT_REBIRTH);
}
}
void ScheduleAbilities()
{
ScheduleTimedEvent(57s, [&]
{
DoCastVictim(SPELL_MELT_ARMOR);
}, 60s);
ScheduleTimedEvent(10s, [&]
{
DoCastRandomTarget(SPELL_CHARGE, 0, 50.0f);
}, 30s);
ScheduleTimedEvent(20s, [&]
{
// find spell from sniffs?
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
{
me->SummonCreature(NPC_FLAME_PATCH, *target, TEMPSUMMON_TIMED_DESPAWN, 2 * MINUTE * IN_MILLISECONDS);
}
}, 30s);
ScheduleTimedEvent(30s, [&]
{
me->GetMotionMaster()->MovePoint(POINT_DIVE, alarPoints[POINT_DIVE], false, true);
scheduler.DelayAll(15s);
}, 30s);
ScheduleUniqueTimedEvent(10min, [&]
{
DoCastSelf(SPELL_BERSERK);
}, EVENT_SPELL_BERSERK);
ScheduleMainSpellAttack(0s);
}
void SpawnPhoenixes(uint8 count, Unit* targetToSpawnAt)
{
if (targetToSpawnAt)
{
for (uint8 i = 0; i < count; ++i)
{
me->SummonCreature(NPC_EMBER_OF_ALAR, *targetToSpawnAt, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 6000);
}
}
}
void DoDiveBomb()
{
scheduler.Schedule(2s, [this](TaskContext)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 10.0f, true))
{
SpawnPhoenixes(2, target);
}
}).Schedule(6s, [this](TaskContext)
{
me->SetModelVisible(true);
DoCastSelf(SPELL_REBIRTH_DIVE);
}).Schedule(10s, [this](TaskContext)
{
me->GetMotionMaster()->MoveChase(me->GetVictim());
});
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 90.0f, true))
{
DoCast(target, SPELL_DIVE_BOMB);
me->SetPosition(*target);
me->StopMovingOnCurrentPos();
}
me->RemoveAurasDueToSpell(SPELL_DIVE_BOMB_VISUAL);
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE)
{
if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized() && !me->IsInCombat())
{
ConstructWaypointsAndMove();
}
return;
}
switch(id)
{
case POINT_QUILL:
scheduler.CancelGroup(GROUP_FLAME_BUFFET);
scheduler.Schedule(1s, [this](TaskContext)
{
DoCastSelf(SPELL_FLAME_QUILLS);
});
ScheduleMainSpellAttack(13s);
break;
case POINT_DIVE:
scheduler.Schedule(1s, [this](TaskContext)
{
DoCastSelf(SPELL_DIVE_BOMB_VISUAL);
}).Schedule(5s, [this](TaskContext)
{
DoDiveBomb();
});
break;
default:
return;
}
}
void ScheduleMainSpellAttack(std::chrono::seconds timer)
{
scheduler.Schedule(timer, GROUP_FLAME_BUFFET, [this](TaskContext context)
{
if (!me->IsWithinMeleeRange(me->GetVictim()) && !me->isMoving())
{
DoCastVictim(SPELL_FLAME_BUFFET);
}
context.Repeat(2s);
});
}
void ConstructWaypointsAndMove()
{
me->StopMoving();
if (WaypointPath const* i_path = sWaypointMgr->GetPath(me->GetWaypointPath()))
{
Movement::PointsArray pathPoints;
pathPoints.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
for (uint8 i = 0; i < i_path->size(); ++i)
{
WaypointData const* node = i_path->at(i);
pathPoints.push_back(G3D::Vector3(node->x, node->y, node->z));
}
me->GetMotionMaster()->MoveSplinePath(&pathPoints);
}
}
private:
bool _canAttackCooldown;
bool _baseAttackOverride;
bool _spawnPhoenixes;
uint8 _platform;
uint8 _platformRoll;
uint8 _noQuillTimes;
std::chrono::seconds _platformMoveRepeatTimer;
}; };
class CastQuill : public BasicEvent class CastQuill : public BasicEvent
{ {
public: public:
CastQuill(Unit* caster, uint32 spellId) : _caster(caster), _spellId(spellId) CastQuill(Unit* caster, uint32 spellId) : _caster(caster), _spellId(spellId){ }
{
}
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
{ {
_caster->CastSpell(_caster, _spellId, true); _caster->CastSpell(_caster, _spellId, true);
return true; return true;
} }
private: private:
Unit* _caster; Unit* _caster;
uint32 _spellId; uint32 _spellId;
@@ -496,7 +507,7 @@ public:
void AddSC_boss_alar() void AddSC_boss_alar()
{ {
new boss_alar(); RegisterTheEyeAI(boss_alar);
new spell_alar_flame_quills(); new spell_alar_flame_quills();
new spell_alar_ember_blast(); new spell_alar_ember_blast();
new spell_alar_ember_blast_death(); new spell_alar_ember_blast_death();
@@ -68,6 +68,7 @@ struct boss_high_astromancer_solarian : public BossAI
ScheduleHealthCheckEvent(20, [&]{ ScheduleHealthCheckEvent(20, [&]{
scheduler.CancelAll(); scheduler.CancelAll();
me->ResumeChasingVictim();
scheduler.Schedule(3s, [this](TaskContext context) scheduler.Schedule(3s, [this](TaskContext context)
{ {
DoCastVictim(SPELL_VOID_BOLT); DoCastVictim(SPELL_VOID_BOLT);
@@ -109,10 +110,21 @@ struct boss_high_astromancer_solarian : public BossAI
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who); BossAI::JustEngagedWith(who);
me->CallForHelp(105.0f); me->CallForHelp(105.0f);
me->GetMotionMaster()->Clear();
scheduler.Schedule(3650ms, [this](TaskContext context) scheduler.Schedule(3650ms, [this](TaskContext context)
{ {
DoCastRandomTarget(SPELL_ARCANE_MISSILES, 0, 40.0f); me->GetMotionMaster()->Clear();
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
{
DoCast(target, SPELL_ARCANE_MISSILES);
}
else
{
//no targets in required range
me->GetMotionMaster()->MoveChase(me->GetVictim(), 30.0f);
me->CastStop();
}
context.Repeat(800ms, 7300ms); context.Repeat(800ms, 7300ms);
}).Schedule(21800ms, [this](TaskContext context) }).Schedule(21800ms, [this](TaskContext context)
{ {
File diff suppressed because it is too large Load Diff
@@ -20,6 +20,21 @@
#include "SpellScriptLoader.h" #include "SpellScriptLoader.h"
#include "the_eye.h" #include "the_eye.h"
ObjectData const creatureData[] =
{
{ NPC_KAELTHAS, DATA_KAELTHAS },
{ NPC_THALADRED, DATA_THALADRED },
{ NPC_LORD_SANGUINAR, DATA_LORD_SANGUINAR },
{ NPC_CAPERNIAN, DATA_CAPERNIAN },
{ NPC_TELONICUS, DATA_TELONICUS },
{ 0, 0 }
};
ObjectData const gameObjectData[] =
{
{ 0, 0 }
};
class instance_the_eye : public InstanceMapScript class instance_the_eye : public InstanceMapScript
{ {
public: public:
@@ -30,6 +45,7 @@ public:
instance_the_eye_InstanceMapScript(Map* map) : InstanceScript(map) instance_the_eye_InstanceMapScript(Map* map) : InstanceScript(map)
{ {
SetHeaders(DataHeader); SetHeaders(DataHeader);
LoadObjectData(creatureData, gameObjectData);
SetBossNumber(MAX_ENCOUNTER); SetBossNumber(MAX_ENCOUNTER);
} }
@@ -66,6 +82,7 @@ public:
LordSanguinarGUID = creature->GetGUID(); LordSanguinarGUID = creature->GetGUID();
break; break;
} }
InstanceScript::OnCreatureCreate(creature);
} }
void OnGameObjectCreate(GameObject* gobject) override void OnGameObjectCreate(GameObject* gobject) override
@@ -98,14 +115,6 @@ public:
return AlarGUID; return AlarGUID;
case NPC_KAELTHAS: case NPC_KAELTHAS:
return KaelthasGUID; return KaelthasGUID;
case DATA_KAEL_ADVISOR1:
return ThaladredTheDarkenerGUID;
case DATA_KAEL_ADVISOR2:
return LordSanguinarGUID;
case DATA_KAEL_ADVISOR3:
return GrandAstromancerCapernianGUID;
case DATA_KAEL_ADVISOR4:
return MasterEngineerTelonicusGUID;
} }
return ObjectGuid::Empty; return ObjectGuid::Empty;
@@ -36,10 +36,10 @@ enum EyeData
DATA_KAELTHAS = 3, DATA_KAELTHAS = 3,
MAX_ENCOUNTER = 4, MAX_ENCOUNTER = 4,
DATA_KAEL_ADVISOR1 = 10, DATA_THALADRED = 10,
DATA_KAEL_ADVISOR2 = 11, DATA_LORD_SANGUINAR = 11,
DATA_KAEL_ADVISOR3 = 12, DATA_CAPERNIAN = 12,
DATA_KAEL_ADVISOR4 = 13 DATA_TELONICUS = 13
}; };
enum EyeNPCs enum EyeNPCs
+2 -2
View File
@@ -1014,7 +1014,7 @@ class spell_dk_blood_boil : public SpellScript
bool Load() override bool Load() override
{ {
_executed = false; _executed = false;
return GetCaster()->GetTypeId() == TYPEID_PLAYER && GetCaster()->getClass() == CLASS_DEATH_KNIGHT; return GetCaster()->GetTypeId() == TYPEID_PLAYER && GetCaster()->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY);
} }
void HandleAfterHit() void HandleAfterHit()
@@ -1258,7 +1258,7 @@ class spell_dk_death_gate : public SpellScript
SpellCastResult CheckClass() SpellCastResult CheckClass()
{ {
if (GetCaster()->getClass() != CLASS_DEATH_KNIGHT) if (!GetCaster()->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
{ {
SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_MUST_BE_DEATH_KNIGHT); SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_MUST_BE_DEATH_KNIGHT);
return SPELL_FAILED_CUSTOM_ERROR; return SPELL_FAILED_CUSTOM_ERROR;
+7 -7
View File
@@ -446,7 +446,7 @@ class spell_pet_hit_expertise_scalling : public AuraScript
{ {
if (Player* modOwner = GetUnitOwner()->GetSpellModOwner()) if (Player* modOwner = GetUnitOwner()->GetSpellModOwner())
{ {
if (modOwner->getClass() == CLASS_HUNTER) if (modOwner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS))
amount = CalculatePercent(modOwner->m_modRangedHitChance, 8.0f, 8.0f); amount = CalculatePercent(modOwner->m_modRangedHitChance, 8.0f, 8.0f);
else if (modOwner->getPowerType() == POWER_MANA) else if (modOwner->getPowerType() == POWER_MANA)
amount = CalculatePercent(modOwner->m_modSpellHitChance, 17.0f, 8.0f); amount = CalculatePercent(modOwner->m_modSpellHitChance, 17.0f, 8.0f);
@@ -459,7 +459,7 @@ class spell_pet_hit_expertise_scalling : public AuraScript
{ {
if (Player* modOwner = GetUnitOwner()->GetSpellModOwner()) if (Player* modOwner = GetUnitOwner()->GetSpellModOwner())
{ {
if (modOwner->getClass() == CLASS_HUNTER) if (modOwner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS))
amount = CalculatePercent(modOwner->m_modRangedHitChance, 8.0f, 17.0f); amount = CalculatePercent(modOwner->m_modRangedHitChance, 8.0f, 17.0f);
else if (modOwner->getPowerType() == POWER_MANA) else if (modOwner->getPowerType() == POWER_MANA)
amount = CalculatePercent(modOwner->m_modSpellHitChance, 17.0f, 17.0f); amount = CalculatePercent(modOwner->m_modSpellHitChance, 17.0f, 17.0f);
@@ -472,7 +472,7 @@ class spell_pet_hit_expertise_scalling : public AuraScript
{ {
if (Player* modOwner = GetUnitOwner()->GetSpellModOwner()) if (Player* modOwner = GetUnitOwner()->GetSpellModOwner())
{ {
if (modOwner->getClass() == CLASS_HUNTER) if (modOwner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS))
amount = CalculatePercent(modOwner->m_modRangedHitChance, 8.0f, 26.0f); amount = CalculatePercent(modOwner->m_modRangedHitChance, 8.0f, 26.0f);
else if (modOwner->getPowerType() == POWER_MANA) else if (modOwner->getPowerType() == POWER_MANA)
amount = CalculatePercent(modOwner->m_modSpellHitChance, 17.0f, 26.0f); amount = CalculatePercent(modOwner->m_modSpellHitChance, 17.0f, 26.0f);
@@ -1673,7 +1673,7 @@ class spell_gen_pet_summoned : public SpellScript
Player* player = GetCaster()->ToPlayer(); Player* player = GetCaster()->ToPlayer();
if (player->GetLastPetNumber() && player->CanResummonPet(player->GetLastPetSpell())) if (player->GetLastPetNumber() && player->CanResummonPet(player->GetLastPetSpell()))
{ {
PetType newPetType = (player->getClass() == CLASS_HUNTER) ? HUNTER_PET : SUMMON_PET; PetType newPetType = (player->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET)) ? HUNTER_PET : SUMMON_PET;
Pet* newPet = new Pet(player, newPetType); Pet* newPet = new Pet(player, newPetType);
if (newPet->LoadPetFromDB(player, 0, player->GetLastPetNumber(), true, 100)) if (newPet->LoadPetFromDB(player, 0, player->GetLastPetNumber(), true, 100))
{ {
@@ -3545,11 +3545,11 @@ class spell_gen_on_tournament_mount : public AuraScript
case NPC_ARGENT_WARHORSE: case NPC_ARGENT_WARHORSE:
{ {
if (player->HasAchieved(ACHIEVEMENT_CHAMPION_ALLIANCE) || player->HasAchieved(ACHIEVEMENT_CHAMPION_HORDE)) if (player->HasAchieved(ACHIEVEMENT_CHAMPION_ALLIANCE) || player->HasAchieved(ACHIEVEMENT_CHAMPION_HORDE))
return player->getClass() == CLASS_DEATH_KNIGHT ? SPELL_PENNANT_EBON_BLADE_CHAMPION : SPELL_PENNANT_ARGENT_CRUSADE_CHAMPION; return player->IsClass(CLASS_DEATH_KNIGHT) ? SPELL_PENNANT_EBON_BLADE_CHAMPION : SPELL_PENNANT_ARGENT_CRUSADE_CHAMPION;
else if (player->HasAchieved(ACHIEVEMENT_ARGENT_VALOR)) else if (player->HasAchieved(ACHIEVEMENT_ARGENT_VALOR))
return player->getClass() == CLASS_DEATH_KNIGHT ? SPELL_PENNANT_EBON_BLADE_VALIANT : SPELL_PENNANT_ARGENT_CRUSADE_VALIANT; return player->IsClass(CLASS_DEATH_KNIGHT) ? SPELL_PENNANT_EBON_BLADE_VALIANT : SPELL_PENNANT_ARGENT_CRUSADE_VALIANT;
else else
return player->getClass() == CLASS_DEATH_KNIGHT ? SPELL_PENNANT_EBON_BLADE_ASPIRANT : SPELL_PENNANT_ARGENT_CRUSADE_ASPIRANT; return player->IsClass(CLASS_DEATH_KNIGHT) ? SPELL_PENNANT_EBON_BLADE_ASPIRANT : SPELL_PENNANT_ARGENT_CRUSADE_ASPIRANT;
} }
default: default:
return 0; return 0;
+2 -2
View File
@@ -576,7 +576,7 @@ class spell_item_skull_of_impeding_doom : public AuraScript
void CalculateManaLeechAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) void CalculateManaLeechAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{ {
if (!GetCaster() || GetCaster()->getPowerType() != POWER_MANA) if (!GetCaster() || !GetCaster()->HasActivePowerType(POWER_MANA))
return; return;
amount = GetCaster()->GetMaxPower(POWER_MANA) * 0.12f; // 5 ticks which reduce health by 60% amount = GetCaster()->GetMaxPower(POWER_MANA) * 0.12f; // 5 ticks which reduce health by 60%
@@ -3469,7 +3469,7 @@ class spell_item_refocus : public SpellScript
{ {
Player* caster = GetCaster()->ToPlayer(); Player* caster = GetCaster()->ToPlayer();
if (!caster || caster->getClass() != CLASS_HUNTER) if (!caster || !caster->IsClass(CLASS_HUNTER, CLASS_CONTEXT_ABILITY))
return; return;
caster->RemoveCategoryCooldown(SPELL_CATEGORY_AIMED_MULTI); caster->RemoveCategoryCooldown(SPELL_CATEGORY_AIMED_MULTI);
+2 -2
View File
@@ -483,7 +483,7 @@ class spell_pal_blessing_of_sanctuary : public AuraScript
bool CheckProc(ProcEventInfo& /*eventInfo*/) bool CheckProc(ProcEventInfo& /*eventInfo*/)
{ {
return GetTarget()->getPowerType() == POWER_MANA; return GetTarget()->HasActivePowerType(POWER_MANA);
} }
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
@@ -969,7 +969,7 @@ class spell_pal_lay_on_hands : public SpellScript
// Xinef: Glyph of Divinity // Xinef: Glyph of Divinity
if (Unit* target = GetExplTargetUnit()) if (Unit* target = GetExplTargetUnit())
if (target->getPowerType() == POWER_MANA) if (target->HasActivePowerType(POWER_MANA))
_manaAmount = target->GetPower(POWER_MANA); _manaAmount = target->GetPower(POWER_MANA);
return SPELL_CAST_OK; return SPELL_CAST_OK;
+2 -2
View File
@@ -992,7 +992,7 @@ class spell_sha_mana_spring_totem : public SpellScript
int32 damage = GetEffectValue(); int32 damage = GetEffectValue();
if (Unit* target = GetHitUnit()) if (Unit* target = GetHitUnit())
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
if (target->getPowerType() == POWER_MANA) if (target->HasActivePowerType(POWER_MANA))
caster->CastCustomSpell(target, SPELL_SHAMAN_MANA_SPRING_TOTEM_ENERGIZE, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID()); caster->CastCustomSpell(target, SPELL_SHAMAN_MANA_SPRING_TOTEM_ENERGIZE, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID());
} }
@@ -1017,7 +1017,7 @@ class spell_sha_mana_tide_totem : public SpellScript
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
if (Unit* unitTarget = GetHitUnit()) if (Unit* unitTarget = GetHitUnit())
{ {
if (unitTarget->getPowerType() == POWER_MANA) if (unitTarget->HasActivePowerType(POWER_MANA))
{ {
int32 effValue = GetEffectValue(); int32 effValue = GetEffectValue();
// Glyph of Mana Tide // Glyph of Mana Tide