diff options
938 files changed, 26441 insertions, 7040 deletions
diff --git a/.travis.yml b/.travis.yml index 23c378a1169..80e237e4d12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,22 +6,24 @@ git: depth: 1 before_install: - - echo "yes" | sudo add-apt-repository ppa:kalakris/cmake + - echo "yes" | sudo add-apt-repository ppa:george-edison55/precise-backports - echo "yes" | sudo add-apt-repository ppa:boost-latest/ppa - echo "yes" | sudo add-apt-repository ppa:ubuntu-toolchain-r/test - echo "yes" | sudo add-apt-repository 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.5 main' - wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add - - sudo apt-get -qq update - - sudo apt-get -qq install build-essential libtool gcc-4.8 g++-4.8 make cmake openssl clang-3.5 + - sudo apt-get -qq install build-essential libtool gcc-4.8 g++-4.8 make cmake cmake-data openssl clang-3.5 - sudo apt-get -qq install libssl-dev libmysqlclient-dev libmysql++-dev libreadline6-dev zlib1g-dev libbz2-dev - sudo apt-get -qq install libboost1.55-dev libboost-thread1.55-dev libboost-filesystem1.55-dev libboost-system1.55-dev libboost-program-options1.55-dev libboost-iostreams1.55-dev - export CC=clang-3.5 CXX=clang++-3.5 + - git config user.email "travis@build.bot" && git config user.name "Travis CI" + - git tag -a -m "Travis build" init install: - mysql -uroot -e 'create database test_mysql;' - mkdir bin - cd bin - - cmake ../ -DWITH_WARNINGS=1 -DWITH_COREDEBUG=0 -DUSE_COREPCH=1 -DUSE_SCRIPTPCH=1 -DTOOLS=1 -DSCRIPTS=1 -DSERVERS=1 -DNOJEM=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror" + - cmake ../ -DWITH_WARNINGS=1 -DWITH_COREDEBUG=0 -DUSE_COREPCH=1 -DUSE_SCRIPTPCH=1 -DTOOLS=1 -DSCRIPTS="dynamic" -DSERVERS=1 -DNOJEM=1 -DWITH_DYNAMIC_LINKING=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror" -DCMAKE_INSTALL_PREFIX=check_install - cd .. - sudo chmod +x contrib/check_updates.sh @@ -36,4 +38,7 @@ script: - cat sql/updates/world/*.sql | mysql -utrinity -ptrinity world - mysql -uroot < sql/create/drop_mysql.sql - cd bin - - make -j 10 -k + - make -j 8 -k && make install + - cd check_install/bin + - ./authserver --version + - ./worldserver --version diff --git a/CMakeLists.txt b/CMakeLists.txt index 5eeb5911ca9..de08fe3181f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,15 +8,21 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# We require CMake >= 3.0 +cmake_minimum_required(VERSION 3.0) + # Set projectname (must be done AFTER setting configurationtypes) project(TrinityCore) # CMake policies (can not be handled elsewhere) -cmake_minimum_required(VERSION 2.8.9) cmake_policy(SET CMP0005 OLD) if(POLICY CMP0043) cmake_policy(SET CMP0043 OLD) # Disable 'Ignore COMPILE_DEFINITIONS_<Config> properties' -endif(POLICY CMP0043) +endif() + +if(POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) # Only interpret if() arguments as variables or keywords when unquoted - prevents intepreting if (SOME_STRING_VARIABLE MATCHES "MSVC") as if (SOME_STRING_VARIABLE MATCHES "1") +endif() # add this options before PROJECT keyword set(CMAKE_DISABLE_SOURCE_CHANGES ON) @@ -38,6 +44,7 @@ endif() include(CheckCXXSourceRuns) include(CheckIncludeFiles) +include(ConfigureScripts) # set default buildoptions and print them include(cmake/options.cmake) @@ -51,23 +58,11 @@ endif() include(CheckPlatform) include(GroupSources) - -# basic packagesearching and setup (further support will be needed, this is a preliminary release!) -set(OPENSSL_EXPECTED_VERSION 1.0.0) +include(AutoCollect) find_package(PCHSupport) -find_package(OpenSSL REQUIRED) -find_package(Threads REQUIRED) find_package(MySQL) -include(ConfigureBoost) - -if( UNIX ) - find_package(Readline) - find_package(ZLIB) - find_package(BZip2) -endif() - if(NOT WITHOUT_GIT) find_package(Git) endif() diff --git a/cmake/compiler/clang/settings.cmake b/cmake/compiler/clang/settings.cmake index 261a55b285f..1cd95bbf703 100644 --- a/cmake/compiler/clang/settings.cmake +++ b/cmake/compiler/clang/settings.cmake @@ -18,3 +18,16 @@ endif() # -Wno-deprecated-register is needed to suppress 185 gsoap warnings on Unix systems. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-narrowing -Wno-deprecated-register") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG=1") + +if (BUILD_SHARED_LIBS) + # -fPIC is needed to allow static linking in shared libs. + # -fvisibility=hidden sets the default visibility to hidden to prevent exporting of all symbols. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fvisibility=hidden") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -fvisibility=hidden") + + # --no-undefined to throw errors when there are undefined symbols + # (caused through missing TRINITY_*_API macros). + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --no-undefined") + + message(STATUS "Clang: Disallow undefined symbols") +endif() diff --git a/cmake/compiler/gcc/settings.cmake b/cmake/compiler/gcc/settings.cmake index acd71e82fd9..c4f97f4ffd4 100644 --- a/cmake/compiler/gcc/settings.cmake +++ b/cmake/compiler/gcc/settings.cmake @@ -34,3 +34,15 @@ if( WITH_COREDEBUG ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") message(STATUS "GCC: Debug-flags set (-g3)") endif() + +if (BUILD_SHARED_LIBS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fvisibility=hidden -Wno-attributes") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -fvisibility=hidden -Wno-attributes") + + # Should break the build when there are TRINITY_*_API macros missing + # but it complains about missing references in precompiled headers. + # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--no-undefined") + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--no-undefined") + + message(STATUS "GCC: Enabled shared linking") +endif() diff --git a/cmake/compiler/msvc/settings.cmake b/cmake/compiler/msvc/settings.cmake index be8028da024..afde70b0f79 100644 --- a/cmake/compiler/msvc/settings.cmake +++ b/cmake/compiler/msvc/settings.cmake @@ -18,11 +18,6 @@ if(PLATFORM EQUAL 64) add_definitions("-D_WIN64") message(STATUS "MSVC: 64-bit platform, enforced -D_WIN64 parameter") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.23026.0) - #Enable extended object support for debug compiles on X64 (not required on X86) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") - message(STATUS "MSVC: Enabled increased number of sections in object files") - endif() else() # mark 32 bit executables large address aware so they can use > 2GB address space set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE") @@ -36,20 +31,31 @@ else() endif() # Set build-directive (used in core to tell which buildtype we used) -add_definitions(-D_BUILD_DIRECTIVE=\\"$(ConfigurationName)\\") +# msbuild/devenv don't set CMAKE_MAKE_PROGRAM, you can choose build type from a dropdown after generating projects +if("${CMAKE_MAKE_PROGRAM}" MATCHES "MSBuild") + add_definitions(-D_BUILD_DIRECTIVE=\\"$(ConfigurationName)\\") +else() + # while all make-like generators do (nmake, ninja) + add_definitions(-D_BUILD_DIRECTIVE=\\"${CMAKE_BUILD_TYPE}\\") +endif() # multithreaded compiling on VS set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") +if((PLATFORM EQUAL 64) OR (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.23026.0) OR BUILD_SHARED_LIBS) + # Enable extended object support + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") + message(STATUS "MSVC: Enabled increased number of sections in object files") +endif() + # /Zc:throwingNew. # When you specify Zc:throwingNew on the command line, it instructs the compiler to assume # that the program will eventually be linked with a conforming operator new implementation, # and can omit all of these extra null checks from your program. # http://blogs.msdn.com/b/vcblog/archive/2015/08/06/new-in-vs-2015-zc-throwingnew.aspx if(NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.23026.0)) - # also enable /bigobj for ALL builds under visual studio 2015, increased number of templates in standard library # makes this flag a requirement to build TC at all - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew /bigobj") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew") endif() # Define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES - eliminates the warning by changing the strcpy call to strcpy_s, which prevents buffer overruns @@ -74,6 +80,13 @@ if(NOT WITH_WARNINGS) message(STATUS "MSVC: Disabled generic compiletime warnings") endif() +if (BUILD_SHARED_LIBS) + # C4251: needs to have dll-interface to be used by clients of class '...' + # C4275: non dll-interface class ...' used as base for dll-interface class '...' + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251 /wd4275") + message(STATUS "MSVC: Enabled shared linking") +endif() + # Specify the maximum PreCompiled Header memory allocation limit # Fixes a compiler-problem when using PCH - the /Ym flag is adjusted by the compiler in MSVC2012, hence we need to set an upper limit with /Zm to avoid discrepancies) # (And yes, this is a verified , unresolved bug with MSVC... *sigh*) @@ -84,3 +97,15 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zm500") # 'function' : member function does not override any base class virtual member function # 'virtual_function' : no override available for virtual member function from base 'class'; function is hidden set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /we4263 /we4264") + +# Disable incremental linking in debug builds. +# To prevent linking getting stuck (which might be fixed in a later VS version). +macro(DisableIncrementalLinking variable) + string(REGEX REPLACE "/INCREMENTAL *" "" ${variable} "${${variable}}") + set(${variable} "${${variable}} /INCREMENTAL:NO") +endmacro() + +DisableIncrementalLinking(CMAKE_EXE_LINKER_FLAGS_DEBUG) +DisableIncrementalLinking(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO) +DisableIncrementalLinking(CMAKE_SHARED_LINKER_FLAGS_DEBUG) +DisableIncrementalLinking(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO) diff --git a/cmake/genrev.cmake b/cmake/genrev.cmake index 5c013756f09..d123153e975 100644 --- a/cmake/genrev.cmake +++ b/cmake/genrev.cmake @@ -24,7 +24,7 @@ else() if(GIT_EXECUTABLE) # Create a revision-string that we can use execute_process( - COMMAND "${GIT_EXECUTABLE}" describe --match init --dirty=+ --abbrev=12 + COMMAND "${GIT_EXECUTABLE}" describe --long --match init --dirty=+ --abbrev=12 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE rev_info OUTPUT_STRIP_TRAILING_WHITESPACE diff --git a/cmake/macros/AutoCollect.cmake b/cmake/macros/AutoCollect.cmake new file mode 100644 index 00000000000..cddd3a20290 --- /dev/null +++ b/cmake/macros/AutoCollect.cmake @@ -0,0 +1,71 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# Collects all source files into the given variable, +# which is useful to include all sources in subdirectories. +# Ignores full qualified directories listed in the variadic arguments. +# +# Use it like: +# CollectSourceFiles( +# ${CMAKE_CURRENT_SOURCE_DIR} +# COMMON_PRIVATE_SOURCES +# # Exclude +# ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders +# ${CMAKE_CURRENT_SOURCE_DIR}/Platform) +# +function(CollectSourceFiles current_dir variable) + list(FIND ARGN "${current_dir}" IS_EXCLUDED) + if(IS_EXCLUDED EQUAL -1) + file(GLOB COLLECTED_SOURCES + ${current_dir}/*.c + ${current_dir}/*.cc + ${current_dir}/*.cpp + ${current_dir}/*.inl + ${current_dir}/*.def + ${current_dir}/*.h + ${current_dir}/*.hh + ${current_dir}/*.hpp) + list(APPEND ${variable} ${COLLECTED_SOURCES}) + + file(GLOB SUB_DIRECTORIES ${current_dir}/*) + foreach(SUB_DIRECTORY ${SUB_DIRECTORIES}) + if (IS_DIRECTORY ${SUB_DIRECTORY}) + CollectSourceFiles("${SUB_DIRECTORY}" "${variable}" "${ARGN}") + endif() + endforeach() + set(${variable} ${${variable}} PARENT_SCOPE) + endif() +endfunction() + +# Collects all subdirectoroies into the given variable, +# which is useful to include all subdirectories. +# Ignores full qualified directories listed in the variadic arguments. +# +# Use it like: +# CollectIncludeDirectories( +# ${CMAKE_CURRENT_SOURCE_DIR} +# COMMON_PUBLIC_INCLUDES +# # Exclude +# ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders +# ${CMAKE_CURRENT_SOURCE_DIR}/Platform) +# +function(CollectIncludeDirectories current_dir variable) + list(FIND ARGN "${current_dir}" IS_EXCLUDED) + if(IS_EXCLUDED EQUAL -1) + list(APPEND ${variable} ${current_dir}) + file(GLOB SUB_DIRECTORIES ${current_dir}/*) + foreach(SUB_DIRECTORY ${SUB_DIRECTORIES}) + if (IS_DIRECTORY ${SUB_DIRECTORY}) + CollectIncludeDirectories("${SUB_DIRECTORY}" "${variable}" "${ARGN}") + endif() + endforeach() + set(${variable} ${${variable}} PARENT_SCOPE) + endif() +endfunction() diff --git a/cmake/macros/ConfigureScripts.cmake b/cmake/macros/ConfigureScripts.cmake new file mode 100644 index 00000000000..5260d3a1afe --- /dev/null +++ b/cmake/macros/ConfigureScripts.cmake @@ -0,0 +1,104 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# Returns the base path to the script directory in the source directory +function(WarnAboutSpacesInBuildPath) + # Only check win32 since unix doesn't allow spaces in paths + if (WIN32) + string(FIND "${CMAKE_BINARY_DIR}" " " SPACE_INDEX_POS) + + if (SPACE_INDEX_POS GREATER -1) + message("") + message(WARNING " *** WARNING!\n" + " *** Your selected build directory contains spaces!\n" + " *** Please note that this will cause issues!") + endif() + endif() +endfunction() + +# Returns the base path to the script directory in the source directory +function(GetScriptsBasePath variable) + set(${variable} "${CMAKE_SOURCE_DIR}/src/server/scripts" PARENT_SCOPE) +endfunction() + +# Stores the absolut path of the given module in the variable +function(GetPathToScriptModule module variable) + GetScriptsBasePath(SCRIPTS_BASE_PATH) + set(${variable} "${SCRIPTS_BASE_PATH}/${module}" PARENT_SCOPE) +endfunction() + +# Stores the project name of the given module in the variable +function(GetProjectNameOfScriptModule module variable) + string(TOLOWER "scripts_${SCRIPT_MODULE}" GENERATED_NAME) + set(${variable} "${GENERATED_NAME}" PARENT_SCOPE) +endfunction() + +# Creates a list of all script modules +# and stores it in the given variable. +function(GetScriptModuleList variable) + GetScriptsBasePath(BASE_PATH) + file(GLOB LOCALE_SCRIPT_MODULE_LIST RELATIVE + ${BASE_PATH} + ${BASE_PATH}/*) + + set(${variable}) + foreach(SCRIPT_MODULE ${LOCALE_SCRIPT_MODULE_LIST}) + GetPathToScriptModule(${SCRIPT_MODULE} SCRIPT_MODULE_PATH) + if (IS_DIRECTORY ${SCRIPT_MODULE_PATH}) + list(APPEND ${variable} ${SCRIPT_MODULE}) + endif() + endforeach() + set(${variable} ${${variable}} PARENT_SCOPE) +endfunction() + +# Converts the given script module name into it's +# variable name which holds the linkage type. +function(ScriptModuleNameToVariable module variable) + string(TOUPPER ${module} ${variable}) + set(${variable} "SCRIPTS_${${variable}}") + set(${variable} ${${variable}} PARENT_SCOPE) +endfunction() + +# Stores in the given variable whether dynamic linking is required +function(IsDynamicLinkingRequired variable) + if(SCRIPTS MATCHES "dynamic") + set(IS_DEFAULT_VALUE_DYNAMIC ON) + endif() + + GetScriptModuleList(SCRIPT_MODULE_LIST) + set(IS_REQUIRED OFF) + foreach(SCRIPT_MODULE ${SCRIPT_MODULE_LIST}) + ScriptModuleNameToVariable(${SCRIPT_MODULE} SCRIPT_MODULE_VARIABLE) + if ((${SCRIPT_MODULE_VARIABLE} STREQUAL "dynamic") OR + (${SCRIPT_MODULE_VARIABLE} STREQUAL "default" AND IS_DEFAULT_VALUE_DYNAMIC)) + set(IS_REQUIRED ON) + break() + endif() + endforeach() + set(${variable} ${IS_REQUIRED} PARENT_SCOPE) +endfunction() + +# Stores the native variable name +function(GetNativeSharedLibraryName module variable) + if(WIN32) + set(${variable} "${module}.dll" PARENT_SCOPE) + else() + set(${variable} "lib${module}.so" PARENT_SCOPE) + endif() +endfunction() + +# Stores the native install path in the variable +function(GetInstallOffset variable) + if(WIN32) + set(${variable} "${CMAKE_INSTALL_PREFIX}/scripts" PARENT_SCOPE) + else() + set(${variable} "${CMAKE_INSTALL_PREFIX}/bin/scripts" PARENT_SCOPE) + endif() +endfunction() diff --git a/cmake/macros/FindPCHSupport.cmake b/cmake/macros/FindPCHSupport.cmake index 49d4be904d1..9cc39a13b04 100644 --- a/cmake/macros/FindPCHSupport.cmake +++ b/cmake/macros/FindPCHSupport.cmake @@ -1,17 +1,49 @@ -FUNCTION(GET_COMMON_PCH_PARAMS PCH_HEADER PCH_FE INCLUDE_PREFIX) +FUNCTION(GET_COMMON_PCH_PARAMS TARGET_NAME_LIST PCH_HEADER PCH_FE INCLUDE_PREFIX) GET_FILENAME_COMPONENT(PCH_HEADER_N ${PCH_HEADER} NAME) GET_DIRECTORY_PROPERTY(TARGET_INCLUDES INCLUDE_DIRECTORIES) + # Stores the inherited dependency definitions and include directories + # from the given target into the given variables + MACRO(CollectIncludes target inherited_includes inherited_definitions) + # Append the includes and definitions of the current target to the list + get_property(included TARGET ${target} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + LIST(APPEND "${inherited_includes}" ${included}) + get_property(definitions TARGET ${target} PROPERTY INTERFACE_COMPILE_DEFINITIONS) + FOREACH(def ${definitions}) + LIST(APPEND "${inherited_definitions}" "-D${def}") + ENDFOREACH() + # Add all inherited link targets which weren't included already + get_property(links TARGET ${target} PROPERTY INTERFACE_LINK_LIBRARIES) + # TODO Maybe catch circular dependencies? + FOREACH(target_link ${links}) + IF(TARGET ${target_link}) + CollectIncludes(${target_link} "${inherited_includes}" "${inherited_definitions}") + ENDIF() + ENDFOREACH() + ENDMACRO() + + FOREACH(TARGET_NAME ${TARGET_NAME_LIST}) + CollectIncludes(${TARGET_NAME} TARGET_INCLUDES TARGET_DEFINITIONS) + ENDFOREACH() + + LIST(REMOVE_DUPLICATES TARGET_INCLUDES) + LIST(REMOVE_DUPLICATES TARGET_DEFINITIONS) + FOREACH(ITEM ${TARGET_INCLUDES}) LIST(APPEND INCLUDE_FLAGS_LIST "${INCLUDE_PREFIX}\"${ITEM}\" ") ENDFOREACH(ITEM) + SET(PCH_INCLUDES ${TARGET_INCLUDES} PARENT_SCOPE) + SET(PCH_DEFINITIONS ${TARGET_DEFINITIONS} PARENT_SCOPE) SET(PCH_HEADER_NAME ${PCH_HEADER_N} PARENT_SCOPE) SET(PCH_HEADER_OUT ${CMAKE_CURRENT_BINARY_DIR}/${PCH_HEADER_N}.${PCH_FE} PARENT_SCOPE) SET(INCLUDE_FLAGS ${INCLUDE_FLAGS_LIST} PARENT_SCOPE) ENDFUNCTION(GET_COMMON_PCH_PARAMS) FUNCTION(GENERATE_CXX_PCH_COMMAND TARGET_NAME_LIST INCLUDE_FLAGS IN PCH_SRC OUT) + include_directories(${PCH_INCLUDES}) + add_definitions(${PCH_DEFINITIONS}) + IF (CMAKE_BUILD_TYPE) STRING(TOUPPER _${CMAKE_BUILD_TYPE} CURRENT_BUILD_TYPE) ENDIF () @@ -62,7 +94,7 @@ FUNCTION(GENERATE_CXX_PCH_COMMAND TARGET_NAME_LIST INCLUDE_FLAGS IN PCH_SRC OUT) ENDFUNCTION(GENERATE_CXX_PCH_COMMAND) FUNCTION(ADD_CXX_PCH_GCC TARGET_NAME_LIST PCH_HEADER PCH_SOURCE) - GET_COMMON_PCH_PARAMS(${PCH_HEADER} "gch" "-I") + GET_COMMON_PCH_PARAMS("${TARGET_NAME_LIST}" ${PCH_HEADER} "gch" "-I") GENERATE_CXX_PCH_COMMAND("${TARGET_NAME_LIST}" "${INCLUDE_FLAGS}" ${PCH_HEADER} ${PCH_SOURCE} ${PCH_HEADER_OUT}) FOREACH(TARGET_NAME ${TARGET_NAME_LIST}) @@ -74,7 +106,7 @@ FUNCTION(ADD_CXX_PCH_GCC TARGET_NAME_LIST PCH_HEADER PCH_SOURCE) ENDFUNCTION(ADD_CXX_PCH_GCC) FUNCTION(ADD_CXX_PCH_CLANG TARGET_NAME_LIST PCH_HEADER PCH_SOURCE) - GET_COMMON_PCH_PARAMS(${PCH_HEADER} "pch" "-I") + GET_COMMON_PCH_PARAMS("${TARGET_NAME_LIST}" ${PCH_HEADER} "pch" "-I") GENERATE_CXX_PCH_COMMAND("${TARGET_NAME_LIST}" "${INCLUDE_FLAGS}" ${PCH_HEADER} ${PCH_SOURCE} ${PCH_HEADER_OUT}) FOREACH(TARGET_NAME ${TARGET_NAME_LIST}) @@ -86,7 +118,7 @@ FUNCTION(ADD_CXX_PCH_CLANG TARGET_NAME_LIST PCH_HEADER PCH_SOURCE) ENDFUNCTION(ADD_CXX_PCH_CLANG) FUNCTION(ADD_CXX_PCH_MSVC TARGET_NAME_LIST PCH_HEADER PCH_SOURCE) - GET_COMMON_PCH_PARAMS(${PCH_HEADER} "pch" "/I") + GET_COMMON_PCH_PARAMS("${TARGET_NAME_LIST}" ${PCH_HEADER} "pch" "/I") FOREACH(TARGET_NAME ${TARGET_NAME_LIST}) SET_TARGET_PROPERTIES( @@ -111,7 +143,7 @@ FUNCTION(ADD_CXX_PCH_XCODE TARGET_NAME_LIST PCH_HEADER PCH_SOURCE) ENDFUNCTION(ADD_CXX_PCH_XCODE) FUNCTION(ADD_CXX_PCH TARGET_NAME_LIST PCH_HEADER PCH_SOURCE) - IF (MSVC) + IF (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") ADD_CXX_PCH_MSVC("${TARGET_NAME_LIST}" ${PCH_HEADER} ${PCH_SOURCE}) ELSEIF ("${CMAKE_GENERATOR}" MATCHES "Xcode") ADD_CXX_PCH_XCODE("${TARGET_NAME_LIST}" ${PCH_HEADER} ${PCH_SOURCE}) diff --git a/cmake/macros/FindReadline.cmake b/cmake/macros/FindReadline.cmake deleted file mode 100644 index 34af35204b5..00000000000 --- a/cmake/macros/FindReadline.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# find Readline (terminal input library) includes and library -# -# READLINE_INCLUDE_DIR - where the directory containing the READLINE headers can be found -# READLINE_LIBRARY - full path to the READLINE library -# READLINE_FOUND - TRUE if READLINE was found - -FIND_PATH(READLINE_INCLUDE_DIR readline/readline.h) -FIND_LIBRARY(READLINE_LIBRARY NAMES readline) - -IF (READLINE_INCLUDE_DIR AND READLINE_LIBRARY) - SET(READLINE_FOUND TRUE) - MESSAGE(STATUS "Found Readline library: ${READLINE_LIBRARY}") - MESSAGE(STATUS "Include dir is: ${READLINE_INCLUDE_DIR}") - INCLUDE_DIRECTORIES(${READLINE_INCLUDE_DIR}) -ELSE (READLINE_INCLUDE_DIR AND READLINE_LIBRARY) - SET(READLINE_FOUND FALSE) - MESSAGE(FATAL_ERROR "** Readline library not found!\n** Your distro may provide a binary for Readline e.g. for ubuntu try apt-get install libreadline5-dev") -ENDIF (READLINE_INCLUDE_DIR AND READLINE_LIBRARY) diff --git a/cmake/macros/GroupSources.cmake b/cmake/macros/GroupSources.cmake index 198d8c3e187..f8e252fe41a 100644 --- a/cmake/macros/GroupSources.cmake +++ b/cmake/macros/GroupSources.cmake @@ -10,7 +10,7 @@ macro(GroupSources dir) # Skip this if WITH_SOURCE_TREE is not set (empty string). - if (NOT ${_WITH_SOURCE_TREE} STREQUAL "") + if (NOT ${WITH_SOURCE_TREE} STREQUAL "") # Include all header and c files file(GLOB_RECURSE elements RELATIVE ${dir} *.h *.hpp *.c *.cpp *.cc) @@ -21,7 +21,7 @@ macro(GroupSources dir) if (NOT ${element_dir} STREQUAL "") # If the file is in a subdirectory use it as source group. - if (${_WITH_SOURCE_TREE} STREQUAL "flat") + if (${WITH_SOURCE_TREE} STREQUAL "flat") # Build flat structure by using only the first subdirectory. string(FIND ${element_dir} "/" delemiter_pos) if (NOT ${delemiter_pos} EQUAL -1) @@ -44,3 +44,8 @@ macro(GroupSources dir) endforeach() endif() endmacro() + +if (WITH_SOURCE_TREE STREQUAL "hierarchical-folders") + # Use folders + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +endif() diff --git a/cmake/options.cmake b/cmake/options.cmake index 19615001307..085a45fa03f 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -9,12 +9,32 @@ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. option(SERVERS "Build worldserver and authserver" 1) -option(SCRIPTS "Build core with scripts included" 1) +set(SCRIPTS "static" CACHE STRING "Build core with scripts") +set_property(CACHE SCRIPTS PROPERTY STRINGS none static dynamic minimal-static minimal-dynamic) + +# Build a list of all script modules when -DSCRIPT="custom" is selected +GetScriptModuleList(SCRIPT_MODULE_LIST) +foreach(SCRIPT_MODULE ${SCRIPT_MODULE_LIST}) + ScriptModuleNameToVariable(${SCRIPT_MODULE} SCRIPT_MODULE_VARIABLE) + set(${SCRIPT_MODULE_VARIABLE} "default" CACHE STRING "Build type of the ${SCRIPT_MODULE} module.") + set_property(CACHE ${SCRIPT_MODULE_VARIABLE} PROPERTY STRINGS default disabled static dynamic) +endforeach() + option(TOOLS "Build map/vmap/mmap extraction/assembler tools" 0) option(USE_SCRIPTPCH "Use precompiled headers when compiling scripts" 1) option(USE_COREPCH "Use precompiled headers when compiling servers" 1) +option(WITH_DYNAMIC_LINKING "Enable dynamic library linking." 0) +IsDynamicLinkingRequired(WITH_DYNAMIC_LINKING_FORCED) +if (WITH_DYNAMIC_LINKING AND WITH_DYNAMIC_LINKING_FORCED) + set(WITH_DYNAMIC_LINKING_FORCED OFF) +endif() +if (WITH_DYNAMIC_LINKING OR WITH_DYNAMIC_LINKING_FORCED) + set(BUILD_SHARED_LIBS ON) +else() + set(BUILD_SHARED_LIBS OFF) +endif() option(WITH_WARNINGS "Show all warnings during compile" 0) option(WITH_COREDEBUG "Include additional debug-code in core" 0) -set(WITH_SOURCE_TREE "no" CACHE STRING "Build the source tree for IDE's.") -set_property(CACHE WITH_SOURCE_TREE PROPERTY STRINGS no flat hierarchical) +set(WITH_SOURCE_TREE "hierarchical" CACHE STRING "Build the source tree for IDE's.") +set_property(CACHE WITH_SOURCE_TREE PROPERTY STRINGS no flat hierarchical hierarchical-folders) option(WITHOUT_GIT "Disable the GIT testing routines" 0) diff --git a/cmake/platform/unix/settings.cmake b/cmake/platform/unix/settings.cmake index 754ff450fcc..79b426d7e03 100644 --- a/cmake/platform/unix/settings.cmake +++ b/cmake/platform/unix/settings.cmake @@ -1,12 +1,3 @@ -# Package overloads - Linux -if(CMAKE_SYSTEM_NAME MATCHES "Linux") - if (NOT NOJEM) - set(JEMALLOC_LIBRARY "jemalloc") - add_definitions(-DNO_BUFFERPOOL) - message(STATUS "UNIX: Using jemalloc") - endif() -endif() - # set default configuration directory if( NOT CONF_DIR ) set(CONF_DIR ${CMAKE_INSTALL_PREFIX}/etc) @@ -38,7 +29,7 @@ if(CMAKE_C_COMPILER MATCHES "gcc" OR CMAKE_C_COMPILER_ID STREQUAL "GNU") include(${CMAKE_SOURCE_DIR}/cmake/compiler/gcc/settings.cmake) elseif(CMAKE_C_COMPILER MATCHES "icc") include(${CMAKE_SOURCE_DIR}/cmake/compiler/icc/settings.cmake) -elseif(CMAKE_C_COMPILER MATCHES "clang" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") +elseif(CMAKE_C_COMPILER MATCHES "clang" OR CMAKE_C_COMPILER_ID MATCHES "Clang") include(${CMAKE_SOURCE_DIR}/cmake/compiler/clang/settings.cmake) else() add_definitions(-D_BUILD_DIRECTIVE='"${CMAKE_BUILD_TYPE}"') diff --git a/cmake/platform/win/settings.cmake b/cmake/platform/win/settings.cmake index c68d7bc51cc..0c1a103304a 100644 --- a/cmake/platform/win/settings.cmake +++ b/cmake/platform/win/settings.cmake @@ -1,20 +1,9 @@ -# Package overloads -set(BZIP2_LIBRARIES "bzip2") -set(ZLIB_LIBRARIES "zlib") +add_definitions(-D_WIN32_WINNT=0x0601) -# check the CMake preload parameters (commented out by default) - -# overload CMAKE_INSTALL_PREFIX if not being set properly -#if( WIN32 ) -# if( NOT CYGWIN ) -# if( NOT CMAKE_INSTALL_PREFIX ) -# set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/bin") -# endif() -# endif() -#endif() - -if ( MSVC ) +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") include(${CMAKE_SOURCE_DIR}/cmake/compiler/msvc/settings.cmake) -elseif ( MINGW ) +elseif (CMAKE_CXX_PLATFORM_ID MATCHES "MinGW") include(${CMAKE_SOURCE_DIR}/cmake/compiler/mingw/settings.cmake) +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + include(${CMAKE_SOURCE_DIR}/cmake/compiler/clang/settings.cmake) endif() diff --git a/cmake/showoptions.cmake b/cmake/showoptions.cmake index 110b2f01a64..9229590381a 100644 --- a/cmake/showoptions.cmake +++ b/cmake/showoptions.cmake @@ -23,9 +23,8 @@ else() message("* Build world/authserver : No") endif() -if( SCRIPTS ) - message("* Build with scripts : Yes (default)") - add_definitions(-DSCRIPTS) +if(SCRIPTS AND (NOT SCRIPTS STREQUAL "none")) + message("* Build with scripts : Yes (${SCRIPTS})") else() message("* Build with scripts : No") endif() @@ -69,27 +68,10 @@ else() message("* Use coreside debug : No (default)") endif() -if( WITH_SOURCE_TREE STREQUAL "flat" OR WITH_SOURCE_TREE STREQUAL "hierarchical" ) - # TODO: Remove this after Debian 8 is released and set general required version to 2.8.12 - # Debian 7 is shipped with CMake 2.8.9 . But DIRECTORY flag of get_filename_component requires 2.8.12 . - if (NOT CMAKE_VERSION VERSION_LESS 2.8.12) - message("* Show source tree : Yes - ${WITH_SOURCE_TREE}") - set(_WITH_SOURCE_TREE ${WITH_SOURCE_TREE} CACHE INTERNAL "WITH_SOURCE_TREE support enabled.") - else() - message("* Show source tree : No (default)") - - message("") - message(" *** WITH_SOURCE_TREE - WARNING!") - message(" *** This functionality is ONLY supported on CMake 2.8.12 or higher.") - message(" *** You are running ${CMAKE_VERSION}, which does not have the functions needed") - message(" *** to create a sourcetree - this option is thus forced to disabled!") - message("") - - set(_WITH_SOURCE_TREE "" CACHE INTERNAL "WITH_SOURCE_TREE support disabled.") - endif() +if( NOT WITH_SOURCE_TREE STREQUAL "no" ) + message("* Show source tree : Yes (${WITH_SOURCE_TREE})") else() - message("* Show source tree : No (default)") - set(_WITH_SOURCE_TREE "" CACHE INTERNAL "WITH_SOURCE_TREE support disabled.") + message("* Show source tree : No") endif() if ( WITHOUT_GIT ) @@ -104,7 +86,7 @@ if ( WITHOUT_GIT ) message(" *** version of git for the revision-hash to work, and be allowede to ask for") message(" *** support if needed.") else() - message("* Use GIT revision hash : Yes") + message("* Use GIT revision hash : Yes (default)") endif() if ( NOJEM ) @@ -130,5 +112,18 @@ if ( HELGRIND ) add_definitions(-DHELGRIND) endif() -message("") +if (BUILD_SHARED_LIBS) + message("") + message(" *** WITH_DYNAMIC_LINKING - INFO!") + message(" *** Will link against shared libraries!") + message(" *** Please note that this is an experimental feature!") + if (WITH_DYNAMIC_LINKING_FORCED) + message("") + message(" *** Dynamic linking was enforced through a dynamic script module!") + endif() + add_definitions(-DTRINITY_API_USE_DYNAMIC_LINKING) + WarnAboutSpacesInBuildPath() +endif() + +message("") diff --git a/contrib/extractor.bat b/contrib/extractor.bat new file mode 100644 index 00000000000..eb7c99e5c0b --- /dev/null +++ b/contrib/extractor.bat @@ -0,0 +1,51 @@ +@ECHO OFF +CLS +:MENU +ECHO. +ECHO ............................................... +ECHO Trinitycore dbc/db2, maps, vmaps, mmaps extractor +ECHO ............................................... +ECHO PRESS 1, 2, 3 OR 4 to select your task, or 5 to EXIT. +ECHO ............................................... +ECHO. +ECHO 1 - Extract dbc/db2 and maps +ECHO 2 - Extract vmaps (needs maps to be extracted before you run this) +ECHO 3 - Extract mmaps (needs vmaps to be extracted before you run this, may take hours) +ECHO 4 - Extract all (may take hours) +ECHO 5 - EXIT +ECHO. +SET /P M=Type 1, 2, 3, 4 or 5 then press ENTER: +IF %M%==1 GOTO MAPS +IF %M%==2 GOTO VMAPS +IF %M%==3 GOTO MMAPS +IF %M%==4 GOTO ALL +IF %M%==5 GOTO EOF +:MAPS +start mapextractor.exe +pause +GOTO MENU +:VMAPS +start vmap4extractor.exe +md vmaps +start vmap4assembler.exe Buildings vmaps +pause +GOTO MENU +:MMAPS +md mmaps +start mmaps_generator.exe +pause +GOTO MENU +:ALL +start mapextractor.exe +ECHO wait before mapextractor.exe closes before continue +pause +start vmap4extractor.exe +md vmaps +start vmap4assembler.exe Buildings vmaps +rmdir Buildings /s /q +ECHO wait before vmap4assembler.exe closes before continue +pause +md mmaps +start mmaps_generator.exe +pause +GOTO MENU diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt index 7f4f1cd884c..48be56bc9ef 100644 --- a/dep/CMakeLists.txt +++ b/dep/CMakeLists.txt @@ -8,37 +8,38 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -if( MSVC ) +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + string(REGEX REPLACE "/W[0-4] " "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REGEX REPLACE "/W[0-4] " "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") add_definitions(/W0) else() add_definitions(-w) endif() -if(CMAKE_SYSTEM_NAME MATCHES "Linux") - if(SERVERS AND NOT NOJEM) - add_subdirectory(jemalloc) - endif() -endif() - -if(CMAKE_SYSTEM_NAME MATCHES "Windows") - if(TOOLS) - add_subdirectory(bzip2) - endif() - if(SERVERS OR TOOLS) - add_subdirectory(zlib) - endif() -endif() +add_subdirectory(threads) if(SERVERS OR TOOLS) + add_subdirectory(boost) + add_subdirectory(process) + add_subdirectory(zlib) add_subdirectory(g3dlite) add_subdirectory(recastnavigation) add_subdirectory(cppformat) + add_subdirectory(SFMT) + add_subdirectory(utf8cpp) + add_subdirectory(valgrind) + add_subdirectory(openssl) + add_subdirectory(jemalloc) endif() if(SERVERS) + add_subdirectory(mysql) + add_subdirectory(readline) add_subdirectory(gsoap) + add_subdirectory(efsw) endif() if(TOOLS) + add_subdirectory(bzip2) add_subdirectory(libmpq) endif() diff --git a/dep/PackageList.txt b/dep/PackageList.txt index e84fef8d3b2..66421127162 100644 --- a/dep/PackageList.txt +++ b/dep/PackageList.txt @@ -1,6 +1,6 @@ TrinityCore uses (parts of or in whole) the following opensource software : -Boost +Boost (external) http://www.boost.org Version: 1.55 @@ -14,7 +14,11 @@ bzip2 (a freely available, patent free, high-quality data compressor) cppformat (type safe format library) https://github.com/cppformat/cppformat - Version: 5c76d107cbaf5e851bd66b6c563e4fc7c90be7ad + Version: 5174b8ca281426af604b85fdf53be8a748b33f56 + +efws (Entropia File System Watcher - crossplatform file system watcher) + https://bitbucket.org/SpartanJ/efsw + ff0b69daeca1edf7785a8a580518e462be5a6f3d G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License) http://g3d.sourceforge.net/ @@ -23,11 +27,19 @@ G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License) jemalloc (a general-purpose scalable concurrent malloc-implementation) http://www.canonware.com/jemalloc/ Version: 3.6.0 - + libMPQ (a library for reading MPQ files) https://github.com/mbroemme/libmpq/ Version: d59b4cf1d107b5f6a0f67d6bc545c6c6ebef3d74 +libreadline (command line editing library) + https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html + Version: external + +OpenSSL (general-purpose cryptography library) + https://www.openssl.org/ + Version: external + SFMT (SIMD-oriented Fast Mersenne Twister) Based on http://agner.org/random/ Version: 2010-Aug-03 diff --git a/dep/SFMT/CMakeLists.txt b/dep/SFMT/CMakeLists.txt new file mode 100644 index 00000000000..5cf1b9bf972 --- /dev/null +++ b/dep/SFMT/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +add_library(sfmt INTERFACE) + +target_include_directories(sfmt + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/cmake/macros/ConfigureBoost.cmake b/dep/boost/CMakeLists.txt index b3a71b8a682..6cda5fbec4e 100644 --- a/cmake/macros/ConfigureBoost.cmake +++ b/dep/boost/CMakeLists.txt @@ -1,3 +1,13 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + if(WIN32) set(BOOST_DEBUG ON) if(DEFINED ENV{BOOST_ROOT}) @@ -14,14 +24,9 @@ if(WIN32) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) - - add_definitions(-D_WIN32_WINNT=0x0601) endif() -find_package(Boost 1.49 REQUIRED system filesystem thread program_options iostreams regex) -add_definitions(-DBOOST_DATE_TIME_NO_LIB) -add_definitions(-DBOOST_REGEX_NO_LIB) -add_definitions(-DBOOST_CHRONO_NO_LIB) +find_package(Boost 1.51 REQUIRED system filesystem thread program_options iostreams regex) # Find if Boost was compiled in C++03 mode because it requires -DBOOST_NO_CXX11_SCOPED_ENUMS @@ -30,24 +35,36 @@ include (CheckCXXSourceCompiles) set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_IOSTREAMS_LIBRARY}) set(CMAKE_REQUIRED_FLAGS "-std=c++11") -unset(boost_filesystem_copy_links_without_NO_SCOPED_ENUM CACHE) check_cxx_source_compiles(" #include <boost/filesystem/path.hpp> #include <boost/filesystem/operations.hpp> int main() { boost::filesystem::copy_file(boost::filesystem::path(), boost::filesystem::path()); }" boost_filesystem_copy_links_without_NO_SCOPED_ENUM) -unset(CMAKE_REQUIRED_INCLUDES CACHE) -unset(CMAKE_REQUIRED_LIBRARIES CACHE) -unset(CMAKE_REQUIRED_FLAGS CACHE) +unset(CMAKE_REQUIRED_INCLUDES) +unset(CMAKE_REQUIRED_LIBRARIES) +unset(CMAKE_REQUIRED_FLAGS) -if (NOT boost_filesystem_copy_links_without_NO_SCOPED_ENUM) - if (Boost_VERSION LESS 105100) # 1.51 - add_definitions(-DBOOST_NO_SCOPED_ENUMS) - else() - add_definitions(-DBOOST_NO_CXX11_SCOPED_ENUMS) - endif() -endif() +add_library(boost INTERFACE) + +target_link_libraries(boost + INTERFACE + ${Boost_LIBRARIES}) + +target_include_directories(boost + INTERFACE + ${Boost_INCLUDE_DIRS}) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) +if (boost_filesystem_copy_links_without_NO_SCOPED_ENUM) + target_compile_definitions(boost + INTERFACE + -DBOOST_DATE_TIME_NO_LIB + -DBOOST_REGEX_NO_LIB + -DBOOST_CHRONO_NO_LIB) +else() + target_compile_definitions(boost + INTERFACE + -DBOOST_DATE_TIME_NO_LIB + -DBOOST_REGEX_NO_LIB + -DBOOST_CHRONO_NO_LIB + -DBOOST_NO_CXX11_SCOPED_ENUMS) endif() diff --git a/dep/bzip2/CMakeLists.txt b/dep/bzip2/CMakeLists.txt index d3aadbe002e..d5a7414f383 100644 --- a/dep/bzip2/CMakeLists.txt +++ b/dep/bzip2/CMakeLists.txt @@ -8,15 +8,30 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -file(GLOB sources *.c) +if(UNIX) + # Look for an installed bzip2 on unix + find_package(BZip2 REQUIRED) -set(bzip2_STAT_SRCS - ${sources} -) + add_library(bzip2 SHARED IMPORTED GLOBAL) -include_directories( - ${CMAKE_SOURCE_DIR}/dep/zlib - ${CMAKE_CURRENT_SOURCE_DIR} -) + set_target_properties(bzip2 + PROPERTIES + IMPORTED_LOCATION + "${BZIP2_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES + "${BZIP2_INCLUDE_DIRS}") +else() + # Use the bundled source on windows + file(GLOB sources *.c) + add_library(bzip2 STATIC + ${sources}) -add_library(bzip2 STATIC ${bzip2_STAT_SRCS}) + target_include_directories(bzip2 + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}) + + set_target_properties(bzip2 + PROPERTIES + FOLDER + "dep") +endif() diff --git a/dep/cppformat/CMakeLists.txt b/dep/cppformat/CMakeLists.txt index 3be3e5f6dbb..1cbff49b871 100644 --- a/dep/cppformat/CMakeLists.txt +++ b/dep/cppformat/CMakeLists.txt @@ -1,31 +1,37 @@ -include(CheckCXXCompilerFlag) -include(CheckSymbolExists) - -set(FMT_SOURCES format.cc format.h) - -# Use variadic templates -add_definitions(-DFMT_VARIADIC_TEMPLATES=1) - -# Use deleted functions -add_definitions(-DFMT_USE_DELETED_FUNCTIONS=1) - -# Use static assert -add_definitions(-DFMT_USE_STATIC_ASSERT=1) +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +include(CheckSymbolExists) if (WIN32) check_symbol_exists(open io.h HAVE_OPEN) else () check_symbol_exists(open fcntl.h HAVE_OPEN) endif () +set(FMT_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/format.h + ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/format.cc) + if (HAVE_OPEN) - add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1) - set(FMT_SOURCES ${FMT_SOURCES} posix.cc posix.h) -endif () + set(FMT_SOURCES ${FMT_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/posix.h + ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/posix.cc) +endif() -add_library(format STATIC ${FMT_SOURCES}) +add_library(cppformat STATIC ${FMT_SOURCES}) -if (CMAKE_COMPILER_IS_GNUCXX) - set_target_properties(format PROPERTIES COMPILE_FLAGS - "-Wall -Wextra -Wshadow -pedantic") -endif () +target_include_directories(cppformat + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}) + +set_target_properties(cppformat + PROPERTIES + FOLDER + "dep") diff --git a/dep/cppformat/README.rst b/dep/cppformat/README.rst index fb4399f0af4..e859f909466 100644 --- a/dep/cppformat/README.rst +++ b/dep/cppformat/README.rst @@ -28,9 +28,9 @@ Features * Format API with `format string syntax <http://cppformat.github.io/latest/syntax.html>`_ similar to the one used by `str.format - <http://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python. + <https://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python. * Safe `printf implementation - <http://cppformat.github.io/latest/reference.html#printf-formatting-functions>`_ + <http://cppformat.github.io/latest/api.html#printf-formatting-functions>`_ including the POSIX extension for positional arguments. * Support for user-defined types. * High speed: performance of the format API is close to that of @@ -103,10 +103,10 @@ An object of any user-defined type for which there is an overloaded // s == "The date is 2012-12-9" You can use the `FMT_VARIADIC -<http://cppformat.github.io/latest/reference.html#utilities>`_ +<http://cppformat.github.io/latest/api.html#utilities>`_ macro to create your own functions similar to `format -<http://cppformat.github.io/latest/reference.html#format>`_ and -`print <http://cppformat.github.io/latest/reference.html#print>`_ +<http://cppformat.github.io/latest/api.html#format>`_ and +`print <http://cppformat.github.io/latest/api.html#print>`_ which take arbitrary arguments: .. code:: c++ @@ -132,13 +132,17 @@ Projects using this library * `AMPL/MP <https://github.com/ampl/mp>`_: An open-source library for mathematical programming -* `HarpyWar/pvpgn <https://github.com/HarpyWar/pvpgn>`_: +* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_: Player vs Player Gaming Network with tweaks -* `KBEngine <http://www.kbengine.org/>`_: An open-source MMOG server engine +* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine + +* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows * `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game +* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets + * `PenUltima Online (POL) <http://www.polserver.com/>`_: An MMO server, compatible with most Ultima Online clients @@ -148,7 +152,7 @@ Projects using this library * `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster proxy -* `Saddy <https://code.google.com/p/saddy/>`_: +* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_: Small crossplatform 2D graphic engine * `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_: @@ -188,7 +192,7 @@ doesn't support user-defined types. Printf also has safety issues although they are mostly solved with `__attribute__ ((format (printf, ...)) <http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC. There is a POSIX extension that adds positional arguments required for -`i18n <http://en.wikipedia.org/wiki/Internationalization_and_localization>`_ +`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_ to printf but it is not a part of C99 and may not be available on some platforms. @@ -376,18 +380,13 @@ C++ Format is distributed under the BSD `license The `Format String Syntax <http://cppformat.github.io/latest/syntax.html>`_ section in the documentation is based on the one from Python `string module -documentation <http://docs.python.org/3/library/string.html#module-string>`_ +documentation <https://docs.python.org/3/library/string.html#module-string>`_ adapted for the current library. For this reason the documentation is distributed under the Python Software Foundation license available in `doc/python-license.txt <https://raw.github.com/cppformat/cppformat/master/doc/python-license.txt>`_. It only applies if you distribute the documentation of C++ Format. -Links ------ - -`API changes/compatibility report <http://upstream-tracker.org/versions/cppformat.html>`_ - Acknowledgments --------------- diff --git a/dep/cppformat/format.cc b/dep/cppformat/cppformat/format.cc index 1970d53c500..daccd68f1da 100644 --- a/dep/cppformat/format.cc +++ b/dep/cppformat/cppformat/format.cc @@ -207,10 +207,15 @@ void format_error_code(fmt::Writer &out, int error_code, out.clear(); static const char SEP[] = ": "; static const char ERROR_STR[] = "error "; - fmt::internal::IntTraits<int>::MainType ec_value = error_code; // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - error_code_size += fmt::internal::count_digits(ec_value); + typedef fmt::internal::IntTraits<int>::MainType MainType; + MainType abs_value = static_cast<MainType>(error_code); + if (internal::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += fmt::internal::count_digits(abs_value); if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) out << message << SEP; out << ERROR_STR << error_code; @@ -252,7 +257,7 @@ class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> { template <typename T> unsigned visit_any_int(T value) { typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType; - UnsignedType width = value; + UnsignedType width = static_cast<UnsignedType>(value); if (fmt::internal::is_negative(value)) { spec_.align_ = fmt::ALIGN_LEFT; width = 0 - width; @@ -278,8 +283,21 @@ class PrecisionHandler : } }; -// Converts an integer argument to an integral type T for printf. +template <typename T, typename U> +struct is_same { + enum { value = 0 }; +}; + template <typename T> +struct is_same<T, T> { + enum { value = 1 }; +}; + +// An argument visitor that converts an integer argument to T for printf, +// if T is an integral type. If T is void, the argument is converted to +// corresponding signed or unsigned type depending on the type specifier: +// 'd' and 'i' - signed, other - unsigned) +template <typename T = void> class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> { private: fmt::internal::Arg &arg_; @@ -300,21 +318,25 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> { void visit_any_int(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; using fmt::internal::Arg; - if (sizeof(T) <= sizeof(int)) { + typedef typename fmt::internal::Conditional< + is_same<T, void>::value, U, T>::type TargetType; + if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { arg_.type = Arg::INT; - arg_.int_value = static_cast<int>(static_cast<T>(value)); + arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); } else { arg_.type = Arg::UINT; - arg_.uint_value = static_cast<unsigned>( - static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value)); + typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned; + arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); } } else { if (is_signed) { arg_.type = Arg::LONG_LONG; - arg_.long_long_value = - static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value); + // glibc's printf doesn't sign extend arguments of smaller types: + // std::printf("%lld", -42); // prints "4294967254" + // but we don't have to do the same because it's a UB. + arg_.long_long_value = static_cast<fmt::LongLong>(value); } else { arg_.type = Arg::ULONG_LONG; arg_.ulong_long_value = @@ -340,6 +362,21 @@ class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> { arg_.int_value = static_cast<char>(value); } }; + +// Write the content of w to os. +void write(std::ostream &os, fmt::Writer &w) { + const char *data = w.data(); + typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize; + UnsignedStreamSize size = w.size(); + UnsignedStreamSize max_size = + internal::to_unsigned((std::numeric_limits<std::streamsize>::max)()); + do { + UnsignedStreamSize n = size <= max_size ? size : max_size; + os.write(data, static_cast<std::streamsize>(n)); + data += n; + size -= n; + } while (size != 0); +} } // namespace namespace internal { @@ -551,27 +588,25 @@ FMT_FUNC void fmt::WindowsError::init( FMT_FUNC void fmt::internal::format_windows_error( fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT { - class String { - private: - LPWSTR str_; - - public: - String() : str_() {} - ~String() { LocalFree(str_); } - LPWSTR *ptr() { return &str_; } - LPCWSTR c_str() const { return str_; } - }; FMT_TRY { - String system_message; - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, - error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) { - UTF16ToUTF8 utf8_message; - if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; - return; + MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer; + buffer.resize(INLINE_BUFFER_SIZE); + for (;;) { + wchar_t *system_message = &buffer[0]; + int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + system_message, static_cast<uint32_t>(buffer.size()), 0); + if (result != 0) { + UTF16ToUTF8 utf8_message; + if (utf8_message.convert(system_message) == ERROR_SUCCESS) { + out << message << ": " << utf8_message; + return; + } + break; } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); } } FMT_CATCH(...) {} fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. @@ -616,7 +651,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) { return; case internal::Arg::NAMED_ARG: named_arg = static_cast<const NamedArg*>(args.values_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); + map_.push_back(Pair(named_arg->name, *named_arg)); break; default: /*nothing*/; @@ -628,7 +663,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) { internal::Arg::Type arg_type = args.type(i); if (arg_type == internal::Arg::NAMED_ARG) { named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); + map_.push_back(Pair(named_arg->name, *named_arg)); } } for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { @@ -637,7 +672,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) { return; case internal::Arg::NAMED_ARG: named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); + map_.push_back(Pair(named_arg->name, *named_arg)); break; default: /*nothing*/; @@ -659,6 +694,7 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( break; case Arg::NAMED_ARG: arg = *static_cast<const internal::Arg*>(arg.pointer); + break; default: /*nothing*/; } @@ -763,7 +799,7 @@ void fmt::internal::PrintfFormatter<Char>::format( if (*s == '.') { ++s; if ('0' <= *s && *s <= '9') { - spec.precision_ = parse_nonnegative_int(s); + spec.precision_ = static_cast<int>(parse_nonnegative_int(s)); } else if (*s == '*') { ++s; spec.precision_ = PrecisionHandler().visit(get_arg(s)); @@ -772,7 +808,7 @@ void fmt::internal::PrintfFormatter<Char>::format( Arg arg = get_arg(s, arg_index); if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) - spec.flags_ &= ~HASH_FLAG; + spec.flags_ &= ~to_unsigned<int>(HASH_FLAG); if (spec.fill_ == '0') { if (arg.type <= Arg::LAST_NUMERIC_TYPE) spec.align_ = ALIGN_NUMERIC; @@ -809,7 +845,7 @@ void fmt::internal::PrintfFormatter<Char>::format( break; default: --s; - ArgConverter<int>(arg, *s).visit(arg); + ArgConverter<void>(arg, *s).visit(arg); } // Parse type. @@ -861,10 +897,11 @@ FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) { print(stdout, format_str, args); } -FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) { +FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, + ArgList args) { MemoryWriter w; w.write(format_str, args); - os.write(w.data(), w.size()); + write(os, w); } FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { @@ -882,6 +919,13 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); } +FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + write(os, w); + return static_cast<int>(w.size()); +} + #ifndef FMT_HEADER_ONLY template struct fmt::internal::BasicData<void>; diff --git a/dep/cppformat/format.h b/dep/cppformat/cppformat/format.h index a98a166091b..08bb9b5d9e8 100644 --- a/dep/cppformat/format.h +++ b/dep/cppformat/cppformat/format.h @@ -28,14 +28,6 @@ #ifndef FMT_FORMAT_H_ #define FMT_FORMAT_H_ -#if defined _MSC_VER && _MSC_VER <= 1500 -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; -typedef long long intmax_t; -#else -#include <stdint.h> -#endif - #include <cassert> #include <cmath> #include <cstdio> @@ -44,7 +36,8 @@ typedef long long intmax_t; #include <memory> #include <stdexcept> #include <string> -#include <map> +#include <vector> +#include <utility> #ifndef FMT_USE_IOSTREAMS # define FMT_USE_IOSTREAMS 1 @@ -64,40 +57,23 @@ typedef long long intmax_t; # include <iterator> #endif -#ifdef _MSC_VER -# include <intrin.h> // _BitScanReverse, _BitScanReverse64 - -namespace fmt { -namespace internal { -# pragma intrinsic(_BitScanReverse) -inline uint32_t clz(uint32_t x) { - unsigned long r = 0; - _BitScanReverse(&r, x); - return 31 - r; -} -# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) - -# ifdef _WIN64 -# pragma intrinsic(_BitScanReverse64) -# endif - -inline uint32_t clzll(uint64_t x) { - unsigned long r = 0; -# ifdef _WIN64 - _BitScanReverse64(&r, x); -# else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) - return 63 - (r + 32); +#if defined(_MSC_VER) && _MSC_VER <= 1500 +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int64 intmax_t; +#else +#include <stdint.h> +#endif - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast<uint32_t>(x)); +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# ifdef FMT_EXPORT +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) # endif - return 63 - r; -} -# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) -} -} +#endif +#ifndef FMT_API +# define FMT_API #endif #ifdef __GNUC__ @@ -174,21 +150,6 @@ inline uint32_t clzll(uint64_t x) { # include <utility> // for std::move #endif -// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). -#ifndef FMT_USE_NOEXCEPT -# define FMT_USE_NOEXCEPT 0 -#endif - -#ifndef FMT_NOEXCEPT -# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - _MSC_VER >= 1900 -# define FMT_NOEXCEPT noexcept -# else -# define FMT_NOEXCEPT throw() -# endif -#endif - // Check if exceptions are disabled. #if defined(__GNUC__) && !defined(__EXCEPTIONS) # define FMT_EXCEPTIONS 0 @@ -208,6 +169,25 @@ inline uint32_t clzll(uint64_t x) { # endif #endif +// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). +#ifndef FMT_USE_NOEXCEPT +# define FMT_USE_NOEXCEPT 0 +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS +# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ + _MSC_VER >= 1900 +# define FMT_NOEXCEPT noexcept +# else +# define FMT_NOEXCEPT throw() +# endif +# else +# define FMT_NOEXCEPT +# endif +#endif + // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #ifndef FMT_USE_DELETED_FUNCTIONS @@ -241,6 +221,67 @@ inline uint32_t clzll(uint64_t x) { # define FMT_ASSERT(condition, message) assert((condition) && message) #endif + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +#endif + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +#endif + +// Some compilers masquerade as both MSVC and GCC-likes or +// otherwise support __builtin_clz and __builtin_clzll, so +// only define FMT_BUILTIN_CLZ using the MSVC intrinsics +// if the clz and clzll builtins are not available. +#if defined(_MSC_VER) && !defined(FMT_BUILTIN_CLZLL) +# include <intrin.h> // _BitScanReverse, _BitScanReverse64 + +namespace fmt { +namespace internal { +# pragma intrinsic(_BitScanReverse) +inline uint32_t clz(uint32_t x) { + unsigned long r = 0; + _BitScanReverse(&r, x); + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 31 - r; +} +# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) + +# ifdef _WIN64 +# pragma intrinsic(_BitScanReverse64) +# endif + +inline uint32_t clzll(uint64_t x) { + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast<uint32_t>(x)); +# endif + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 63 - r; +} +# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) +} +} +#endif + namespace fmt { namespace internal { struct DummyInt { @@ -396,7 +437,7 @@ class BasicStringRef { return std::basic_string<Char>(data_, size_); } - /** Returns the pointer to a C string. */ + /** Returns a pointer to the string data. */ const Char *data() const { return data_; } /** Returns the string size. */ @@ -492,6 +533,29 @@ class FormatError : public std::runtime_error { }; namespace internal { + +// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T. +template <typename T> +struct MakeUnsigned { typedef T Type; }; + +#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ + template <> \ + struct MakeUnsigned<T> { typedef U Type; } + +FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); +FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); +FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); +FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); +FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); +FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); + +// Casts nonnegative integer to unsigned. +template <typename Int> +inline typename MakeUnsigned<Int>::Type to_unsigned(Int value) { + FMT_ASSERT(value >= 0, "negative value"); + return static_cast<typename MakeUnsigned<Int>::Type>(value); +} + // The number of characters to store in the MemoryBuffer object itself // to avoid dynamic memory allocation. enum { INLINE_BUFFER_SIZE = 500 }; @@ -581,8 +645,7 @@ class Buffer { template <typename T> template <typename U> void Buffer<T>::append(const U *begin, const U *end) { - assert(begin <= end); - std::size_t new_size = size_ + (end - begin); + std::size_t new_size = size_ + internal::to_unsigned(end - begin); if (new_size > capacity_) grow(new_size); std::uninitialized_copy(begin, end, @@ -592,8 +655,8 @@ void Buffer<T>::append(const U *begin, const U *end) { namespace internal { -// A memory buffer for POD types with the first SIZE elements stored in -// the object itself. +// A memory buffer for trivially copyable/constructible types with the first SIZE +// elements stored in the object itself. template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> > class MemoryBuffer : private Allocator, public Buffer<T> { private: @@ -676,7 +739,7 @@ class FixedBuffer : public fmt::Buffer<Char> { FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {} protected: - void grow(std::size_t size); + FMT_API void grow(std::size_t size); }; template <typename Char> @@ -704,7 +767,7 @@ class CharTraits<char> : public BasicCharTraits<char> { // Formats a floating-point number. template <typename T> - static int format_float(char *buffer, std::size_t size, + FMT_API static int format_float(char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value); }; @@ -715,7 +778,7 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> { static wchar_t convert(wchar_t value) { return value; } template <typename T> - static int format_float(wchar_t *buffer, std::size_t size, + FMT_API static int format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value); }; @@ -754,27 +817,12 @@ struct IntTraits { TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType; }; -// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T. -template <typename T> -struct MakeUnsigned { typedef T Type; }; - -#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ - template <> \ - struct MakeUnsigned<T> { typedef U Type; } - -FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); -FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); -FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); -FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); - -void report_unknown_type(char code, const char *type); +FMT_API void report_unknown_type(char code, const char *type); // Static data is placed in this class template to allow header-only // configuration. template <typename T = void> -struct BasicData { +struct FMT_API BasicData { static const uint32_t POWERS_OF_10_32[]; static const uint64_t POWERS_OF_10_64[]; static const char DIGITS[]; @@ -782,22 +830,14 @@ struct BasicData { typedef BasicData<> Data; -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -#endif - -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -#endif - #ifdef FMT_BUILTIN_CLZLL // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1. inline unsigned count_digits(uint64_t n) { // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. - unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; - return t - (n < Data::POWERS_OF_10_64[t]) + 1; + int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1; } #else // Fallback version of count_digits used when __builtin_clz is not available. @@ -820,8 +860,8 @@ inline unsigned count_digits(uint64_t n) { #ifdef FMT_BUILTIN_CLZ // Optional version of count_digits for better performance on 32-bit platforms. inline unsigned count_digits(uint32_t n) { - uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; - return t - (n < Data::POWERS_OF_10_32[t]) + 1; + int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1; } #endif @@ -863,7 +903,7 @@ class UTF8ToUTF16 { MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_; public: - explicit UTF8ToUTF16(StringRef s); + FMT_API explicit UTF8ToUTF16(StringRef s); operator WStringRef() const { return WStringRef(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const wchar_t *c_str() const { return &buffer_[0]; } @@ -878,7 +918,7 @@ class UTF16ToUTF8 { public: UTF16ToUTF8() {} - explicit UTF16ToUTF8(WStringRef s); + FMT_API explicit UTF16ToUTF8(WStringRef s); operator StringRef() const { return StringRef(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const char *c_str() const { return &buffer_[0]; } @@ -887,15 +927,15 @@ class UTF16ToUTF8 { // Performs conversion returning a system error code instead of // throwing exception on conversion error. This method may still throw // in case of memory allocation error. - int convert(WStringRef s); + FMT_API int convert(WStringRef s); }; -void format_windows_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; +FMT_API void format_windows_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; #endif -void format_system_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; +FMT_API void format_system_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; // A formatting argument value. struct Value { @@ -938,8 +978,8 @@ struct Value { }; }; -// A formatting argument. It is a POD type to allow storage in -// internal::MemoryBuffer. +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in internal::MemoryBuffer. struct Arg : Value { Type type; }; @@ -976,6 +1016,7 @@ template <typename T> T &get(); struct DummyStream : std::ostream { + DummyStream(); // Suppress a bogus warning in MSVC. // Hide all operator<< overloads from std::ostream. void operator<<(Null<>); }; @@ -1199,17 +1240,27 @@ class MakeValue : public Arg { static uint64_t type(const NamedArg<Char_> &) { return Arg::NAMED_ARG; } }; +template <typename Formatter> +class MakeArg : public Arg { +public: + MakeArg() { + type = Arg::NONE; + } + + template <typename T> + MakeArg(const T &value) + : Arg(MakeValue<Formatter>(value)) { + type = static_cast<Arg::Type>(MakeValue<Formatter>::type(value)); + } +}; + template <typename Char> struct NamedArg : Arg { BasicStringRef<Char> name; - typedef internal::MakeValue< BasicFormatter<Char> > MakeValue; - template <typename T> NamedArg(BasicStringRef<Char> argname, const T &value) - : Arg(MakeValue(value)), name(argname) { - type = static_cast<Arg::Type>(MakeValue::type(value)); - } + : Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {} }; #define FMT_DISPATCH(call) static_cast<Impl*>(this)->call @@ -1631,17 +1682,22 @@ namespace internal { template <typename Char> class ArgMap { private: - typedef std::map<fmt::BasicStringRef<Char>, internal::Arg> MapType; + typedef std::vector<std::pair<fmt::BasicStringRef<Char>, internal::Arg> > MapType; typedef typename MapType::value_type Pair; MapType map_; public: - void init(const ArgList &args); + FMT_API void init(const ArgList &args); const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const { - typename MapType::const_iterator it = map_.find(name); - return it != map_.end() ? &it->second : 0; + // The list is unsorted, so just return the first matching name. + for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); + it != end; ++it) { + if (it->first == name) + return &it->second; + } + return 0; } }; @@ -1767,7 +1823,7 @@ class FormatterBase { int next_arg_index_; // Returns the argument with specified index. - Arg do_get_arg(unsigned arg_index, const char *&error); + FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); protected: const ArgList &args() const { return args_; } @@ -1780,7 +1836,7 @@ class FormatterBase { // Returns the next argument. Arg next_arg(const char *&error) { if (next_arg_index_ >= 0) - return do_get_arg(next_arg_index_++, error); + return do_get_arg(internal::to_unsigned(next_arg_index_++), error); error = "cannot switch from manual to automatic argument indexing"; return Arg(); } @@ -1803,7 +1859,7 @@ class FormatterBase { template <typename Char> void write(BasicWriter<Char> &w, const Char *start, const Char *end) { if (start != end) - w << BasicStringRef<Char>(start, end - start); + w << BasicStringRef<Char>(start, internal::to_unsigned(end - start)); } }; @@ -1823,14 +1879,16 @@ class PrintfFormatter : private FormatterBase { public: explicit PrintfFormatter(const ArgList &args) : FormatterBase(args) {} - void format(BasicWriter<Char> &writer, BasicCStringRef<Char> format_str); + FMT_API void format(BasicWriter<Char> &writer, + BasicCStringRef<Char> format_str); }; } // namespace internal -// A formatter. +/** This template formats data and writes the output to a writer. */ template <typename CharType> class BasicFormatter : private internal::FormatterBase { public: + /** The character type for the output. */ typedef CharType Char; private: @@ -1852,13 +1910,23 @@ class BasicFormatter : private internal::FormatterBase { internal::Arg parse_arg_name(const Char *&s); public: + /** + \rst + Constructs a ``BasicFormatter`` object. References to the arguments and + the writer are stored in the formatter object so make sure they have + appropriate lifetimes. + \endrst + */ BasicFormatter(const ArgList &args, BasicWriter<Char> &w) : internal::FormatterBase(args), writer_(w) {} + /** Returns a reference to the writer associated with this formatter. */ BasicWriter<Char> &writer() { return writer_; } + /** Formats stored arguments and writes the output to the writer. */ void format(BasicCStringRef<Char> format_str); + // Formats a single argument and advances format_str, a format string pointer. const Char *format(const Char *&format_str, const internal::Arg &arg); }; @@ -1889,16 +1957,29 @@ inline uint64_t make_type(const T &arg) { return MakeValue< BasicFormatter<char> >::type(arg); } +template <unsigned N, bool/*IsPacked*/= (N < ArgList::MAX_PACKED_ARGS)> +struct ArgArray; + +template <unsigned N> +struct ArgArray<N, true/*IsPacked*/> { + typedef Value Type[N > 0 ? N : 1]; + + template <typename Formatter, typename T> + static Value make(const T &value) { + Value result = MakeValue<Formatter>(value); + // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: + // https://github.com/cppformat/cppformat/issues/276 + (void)result.custom.format; + return result; + } +}; + template <unsigned N> -struct ArgArray { - // Computes the argument array size by adding 1 to N, which is the number of - // arguments, if N is zero, because array of zero size is invalid, or if N - // is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra - // argument that marks the end of the list. - enum { SIZE = N + (N == 0 || N >= ArgList::MAX_PACKED_ARGS ? 1 : 0) }; - - typedef typename Conditional< - (N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE]; +struct ArgArray<N, false/*IsPacked*/> { + typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE + + template <typename Formatter, typename T> + static Arg make(const T &value) { return MakeArg<Formatter>(value); } }; #if FMT_USE_VARIADIC_TEMPLATES @@ -1907,47 +1988,6 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) { return make_type(first) | (make_type(tail...) << 4); } -inline void do_set_types(Arg *) {} - -template <typename T, typename... Args> -inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) { - args->type = static_cast<Arg::Type>( - MakeValue< BasicFormatter<char> >::type(arg)); - do_set_types(args + 1, tail...); -} - -template <typename... Args> -inline void set_types(Arg *array, const Args & ... args) { - if (check(sizeof...(Args) > ArgList::MAX_PACKED_ARGS)) - do_set_types(array, args...); - array[sizeof...(Args)].type = Arg::NONE; -} - -template <typename... Args> -inline void set_types(Value *, const Args & ...) { - // Do nothing as types are passed separately from values. -} - -template <typename Formatter, typename Value> -inline void store_args(Value *) {} - -template <typename Formatter, typename Arg, typename T, typename... Args> -inline void store_args(Arg *args, const T &arg, const Args & ... tail) { - // Assign only the Value subobject of Arg and don't overwrite type (if any) - // that is assigned by set_types. - Value &value = *args; - value = MakeValue<Formatter>(arg); - store_args<Formatter>(args + 1, tail...); -} - -template <typename Formatter, typename... Args> -ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array, - const Args & ... args) { - if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS)) - set_types(array, args...); - store_args<Formatter>(array, args...); - return ArgList(make_type(args...), array); -} #else struct ArgType { @@ -1985,7 +2025,7 @@ class FormatBuf : public std::basic_streambuf<Char> { int_type overflow(int_type ch = traits_type::eof()) { if (!traits_type::eq_int_type(ch, traits_type::eof())) { - size_t size = this->pptr() - start_; + size_t size = this->size(); buffer_.resize(size); buffer_.reserve(size * 2); @@ -1997,7 +2037,7 @@ class FormatBuf : public std::basic_streambuf<Char> { } size_t size() const { - return this->pptr() - start_; + return to_unsigned(this->pptr() - start_); } }; } // namespace internal @@ -2015,18 +2055,20 @@ class FormatBuf : public std::basic_streambuf<Char> { # define FMT_VARIADIC_VOID(func, arg_type) \ template <typename... Args> \ void func(arg_type arg0, const Args & ... args) { \ - typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \ - func(arg0, fmt::internal::make_arg_list< \ - fmt::BasicFormatter<Char> >(array, args...)); \ + typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ + typename ArgArray::Type array{ \ + ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ + func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \ } // Defines a variadic constructor. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ template <typename... Args> \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \ - func(arg0, arg1, fmt::internal::make_arg_list< \ - fmt::BasicFormatter<Char> >(array, args...)); \ + typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ + typename ArgArray::Type array{ \ + ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ + func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ } #else @@ -2207,7 +2249,8 @@ class BasicWriter { // Writes a decimal integer. template <typename Int> void write_decimal(Int value) { - typename internal::IntTraits<Int>::MainType abs_value = value; + typedef typename internal::IntTraits<Int>::MainType MainType; + MainType abs_value = static_cast<MainType>(value); if (internal::is_negative(value)) { abs_value = 0 - abs_value; *write_unsigned_decimal(abs_value, 1) = '-'; @@ -2474,9 +2517,9 @@ void BasicWriter<Char>::write_str( return; } } - std::size_t precision = spec.precision_; + std::size_t precision = static_cast<std::size_t>(spec.precision_); if (spec.precision_ >= 0 && precision < str_size) - str_size = spec.precision_; + str_size = precision; write_str(str_value, str_size, spec); } @@ -2510,7 +2553,8 @@ typename BasicWriter<Char>::CharPtr // is specified. if (prefix_size > 0 && prefix[prefix_size - 1] == '0') --prefix_size; - unsigned number_size = prefix_size + spec.precision(); + unsigned number_size = + prefix_size + internal::to_unsigned(spec.precision()); AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); if (number_size >= width) return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); @@ -2564,7 +2608,7 @@ template <typename T, typename Spec> void BasicWriter<Char>::write_int(T value, Spec spec) { unsigned prefix_size = 0; typedef typename internal::IntTraits<T>::MainType UnsignedType; - UnsignedType abs_value = value; + UnsignedType abs_value = static_cast<UnsignedType>(value); char prefix[4] = ""; if (internal::is_negative(value)) { prefix[0] = '-'; @@ -2643,8 +2687,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) { template <typename Char> template <typename T> -void BasicWriter<Char>::write_double( - T value, const FormatSpec &spec) { +void BasicWriter<Char>::write_double(T value, const FormatSpec &spec) { // Check type. char type = spec.type(); bool upper = false; @@ -2744,6 +2787,8 @@ void BasicWriter<Char>::write_double( // Format using snprintf. Char fill = internal::CharTraits<Char>::cast(spec.fill()); + unsigned n = 0; + Char *start = 0; for (;;) { std::size_t buffer_size = buffer_.capacity() - offset; #ifdef _MSC_VER @@ -2755,41 +2800,44 @@ void BasicWriter<Char>::write_double( buffer_size = buffer_.capacity() - offset; } #endif - Char *start = &buffer_[offset]; - int n = internal::CharTraits<Char>::format_float( + start = &buffer_[offset]; + int result = internal::CharTraits<Char>::format_float( start, buffer_size, format, width_for_sprintf, spec.precision(), value); - if (n >= 0 && offset + n < buffer_.capacity()) { - if (sign) { - if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || - *start != ' ') { - *(start - 1) = sign; - sign = 0; - } else { - *(start - 1) = fill; - } - ++n; - } - if (spec.align() == ALIGN_CENTER && - spec.width() > static_cast<unsigned>(n)) { - width = spec.width(); - CharPtr p = grow_buffer(width); - std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); - fill_padding(p, spec.width(), n, fill); - return; - } - if (spec.fill() != ' ' || sign) { - while (*start == ' ') - *start++ = fill; - if (sign) - *(start - 1) = sign; - } - grow_buffer(n); - return; + if (result >= 0) { + n = internal::to_unsigned(result); + if (offset + n < buffer_.capacity()) + break; // The buffer is large enough - continue with formatting. + buffer_.reserve(offset + n + 1); + } else { + // If result is negative we ask to increase the capacity by at least 1, + // but as std::vector, the buffer grows exponentially. + buffer_.reserve(buffer_.capacity() + 1); } - // If n is negative we ask to increase the capacity by at least 1, - // but as std::vector, the buffer grows exponentially. - buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1); } + if (sign) { + if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || + *start != ' ') { + *(start - 1) = sign; + sign = 0; + } else { + *(start - 1) = fill; + } + ++n; + } + if (spec.align() == ALIGN_CENTER && spec.width() > n) { + width = spec.width(); + CharPtr p = grow_buffer(width); + std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); + fill_padding(p, spec.width(), n, fill); + return; + } + if (spec.fill() != ' ' || sign) { + while (*start == ' ') + *start++ = fill; + if (sign) + *(start - 1) = sign; + } + grow_buffer(n); } /** @@ -2920,22 +2968,21 @@ void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) { output << value; BasicStringRef<Char> str(&buffer[0], format_buf.size()); - typedef internal::MakeValue< BasicFormatter<Char> > MakeValue; - internal::Arg arg = MakeValue(str); - arg.type = static_cast<internal::Arg::Type>(MakeValue::type(str)); - format_str = f.format(format_str, arg); + typedef internal::MakeArg< BasicFormatter<Char> > MakeArg; + format_str = f.format(format_str, MakeArg(str)); } // Reports a system error without throwing an exception. // Can be used to report errors from destructors. -void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; +FMT_API void report_system_error(int error_code, + StringRef message) FMT_NOEXCEPT; #if FMT_USE_WINDOWS_H /** A Windows error. */ class WindowsError : public SystemError { private: - void init(int error_code, CStringRef format_str, ArgList args); + FMT_API void init(int error_code, CStringRef format_str, ArgList args); public: /** @@ -2974,7 +3021,8 @@ class WindowsError : public SystemError { // Reports a Windows error without throwing an exception. // Can be used to report errors from destructors. -void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT; +FMT_API void report_windows_error(int error_code, + StringRef message) FMT_NOEXCEPT; #endif @@ -2986,7 +3034,7 @@ enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; Example: print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); */ -void print_colored(Color c, CStringRef format, ArgList args); +FMT_API void print_colored(Color c, CStringRef format, ArgList args); /** \rst @@ -3018,7 +3066,7 @@ inline std::wstring format(WCStringRef format_str, ArgList args) { print(stderr, "Don't {}!", "panic"); \endrst */ -void print(std::FILE *f, CStringRef format_str, ArgList args); +FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); /** \rst @@ -3029,7 +3077,7 @@ void print(std::FILE *f, CStringRef format_str, ArgList args); print("Elapsed time: {0:.2f} seconds", 1.23); \endrst */ -void print(CStringRef format_str, ArgList args); +FMT_API void print(CStringRef format_str, ArgList args); template <typename Char> void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) { @@ -3066,7 +3114,7 @@ inline std::wstring sprintf(WCStringRef format, ArgList args) { fmt::fprintf(stderr, "Don't %s!", "panic"); \endrst */ -int fprintf(std::FILE *f, CStringRef format, ArgList args); +FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); /** \rst @@ -3132,10 +3180,10 @@ class FormatInt { explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} - /** - Returns the number of characters written to the output buffer. - */ - std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; } + /** Returns the number of characters written to the output buffer. */ + std::size_t size() const { + return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1); + } /** Returns a pointer to the output buffer content. No terminating null @@ -3165,7 +3213,8 @@ class FormatInt { // write a terminating null character. template <typename T> inline void format_decimal(char *&buffer, T value) { - typename internal::IntTraits<T>::MainType abs_value = value; + typedef typename internal::IntTraits<T>::MainType MainType; + MainType abs_value = static_cast<MainType>(value); if (internal::is_negative(value)) { *buffer++ = '-'; abs_value = 0 - abs_value; @@ -3245,10 +3294,11 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED; template <typename... Args> \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ const Args & ... args) { \ - typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \ + typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ + typename ArgArray::Type array{ \ + ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::internal::make_arg_list< \ - fmt::BasicFormatter<Char> >(array, args...)); \ + fmt::ArgList(fmt::internal::make_type(args...), array)); \ } #else // Defines a wrapper for a function taking __VA_ARGS__ arguments @@ -3361,8 +3411,20 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) print(cerr, "Don't {}!", "panic"); \endrst */ -void print(std::ostream &os, CStringRef format_str, ArgList args); +FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); FMT_VARIADIC(void, print, std::ostream &, CStringRef) + +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + fprintf(cerr, "Don't %s!", "panic"); + \endrst + */ +FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args); +FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) #endif namespace internal { @@ -3374,7 +3436,7 @@ inline bool is_name_start(Char c) { // Parses an unsigned integer advancing s to the end of the parsed input. // This function assumes that the first character of s is a digit. template <typename Char> -int parse_nonnegative_int(const Char *&s) { +unsigned parse_nonnegative_int(const Char *&s) { assert('0' <= *s && *s <= '9'); unsigned value = 0; do { @@ -3453,7 +3515,6 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_name(const Char *&s) { return arg; } -// Should be after FormatSpec template <typename Char> const Char *BasicFormatter<Char>::format( const Char *&format_str, const internal::Arg &arg) { diff --git a/dep/cppformat/posix.cc b/dep/cppformat/cppformat/posix.cc index 756281a0ebd..c6c2ae2c413 100644 --- a/dep/cppformat/posix.cc +++ b/dep/cppformat/cppformat/posix.cc @@ -173,7 +173,7 @@ std::size_t fmt::File::read(void *buffer, std::size_t count) { FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); if (result < 0) throw SystemError(errno, "cannot read from file"); - return result; + return internal::to_unsigned(result); } std::size_t fmt::File::write(const void *buffer, std::size_t count) { @@ -181,7 +181,7 @@ std::size_t fmt::File::write(const void *buffer, std::size_t count) { FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); if (result < 0) throw SystemError(errno, "cannot write to file"); - return result; + return internal::to_unsigned(result); } fmt::File fmt::File::dup(int fd) { diff --git a/dep/cppformat/posix.h b/dep/cppformat/cppformat/posix.h index 88bcb4f557b..bfbd3851838 100644 --- a/dep/cppformat/posix.h +++ b/dep/cppformat/cppformat/posix.h @@ -34,11 +34,17 @@ #endif #include <errno.h> -#include <fcntl.h> // for O_RDONLY +#include <fcntl.h> // for O_RDONLY +#include <locale.h> // for locale_t #include <stdio.h> +#include <stdlib.h> // for strtod_l #include <cstddef> +#ifdef __APPLE__ +# include <xlocale.h> // for LC_NUMERIC_MASK on OS X +#endif + #include "format.h" #ifndef FMT_POSIX @@ -299,7 +305,8 @@ class File { // Closes the file. void close(); - // Returns the file size. + // Returns the file size. The size has signed type for consistency with + // stat::st_size. LongLong size() const; // Attempts to read count bytes from the file into the specified buffer. @@ -331,6 +338,58 @@ class File { // Returns the memory page size. long getpagesize(); + +#if defined(LC_NUMERIC_MASK) || defined(_MSC_VER) +# define FMT_LOCALE +#endif + +#ifdef FMT_LOCALE +// A "C" numeric locale. +class Locale { + private: +# ifdef _MSC_VER + typedef _locale_t locale_t; + + enum { LC_NUMERIC_MASK = LC_NUMERIC }; + + static locale_t newlocale(int category_mask, const char *locale, locale_t) { + return _create_locale(category_mask, locale); + } + + static void freelocale(locale_t locale) { + _free_locale(locale); + } + + static double strtod_l(const char *nptr, char **endptr, _locale_t locale) { + return _strtod_l(nptr, endptr, locale); + } +# endif + + locale_t locale_; + + FMT_DISALLOW_COPY_AND_ASSIGN(Locale); + + public: + typedef locale_t Type; + + Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) { + if (!locale_) + throw fmt::SystemError(errno, "cannot create locale"); + } + ~Locale() { freelocale(locale_); } + + Type get() const { return locale_; } + + // Converts string to floating-point number and advances str past the end + // of the parsed input. + double strtod(const char *&str) const { + char *end = 0; + double result = strtod_l(str, &end, locale_); + str = end; + return result; + } +}; +#endif // FMT_LOCALE } // namespace fmt #if !FMT_USE_RVALUE_REFERENCES diff --git a/dep/efsw/.hg_archival.txt b/dep/efsw/.hg_archival.txt new file mode 100644 index 00000000000..19565afb668 --- /dev/null +++ b/dep/efsw/.hg_archival.txt @@ -0,0 +1,5 @@ +repo: 78c2ea8c48b213ee0078d6326a1dd719d0844764 +node: ff0b69daeca1edf7785a8a580518e462be5a6f3d +branch: default +latesttag: null +latesttagdistance: 144 diff --git a/dep/efsw/CMakeLists.txt b/dep/efsw/CMakeLists.txt new file mode 100644 index 00000000000..eecc5531944 --- /dev/null +++ b/dep/efsw/CMakeLists.txt @@ -0,0 +1,85 @@ +if (BUILD_SHARED_LIBS) + set(SRCS + src/efsw/DirectorySnapshot.cpp + src/efsw/DirectorySnapshotDiff.cpp + src/efsw/DirWatcherGeneric.cpp + src/efsw/FileInfo.cpp + src/efsw/FileSystem.cpp + src/efsw/FileWatcher.cpp + src/efsw/FileWatcherCWrapper.cpp + src/efsw/FileWatcherGeneric.cpp + src/efsw/FileWatcherImpl.cpp + src/efsw/Log.cpp + src/efsw/Mutex.cpp + src/efsw/String.cpp + src/efsw/System.cpp + src/efsw/Thread.cpp + src/efsw/Watcher.cpp + src/efsw/WatcherGeneric.cpp) + + if(WIN32) + list(APPEND SRCS + src/efsw/platform/win/FileSystemImpl.cpp + src/efsw/platform/win/MutexImpl.cpp + src/efsw/platform/win/SystemImpl.cpp + src/efsw/platform/win/ThreadImpl.cpp) + else() + list(APPEND SRCS + src/efsw/platform/posix/FileSystemImpl.cpp + src/efsw/platform/posix/MutexImpl.cpp + src/efsw/platform/posix/SystemImpl.cpp + src/efsw/platform/posix/ThreadImpl.cpp) + endif() + + if (WIN32) + list(APPEND SRCS + src/efsw/WatcherWin32.cpp + src/efsw/FileWatcherWin32.cpp) + elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + list(APPEND SRCS + src/efsw/FileWatcherInotify.cpp + src/efsw/WatcherInotify.cpp) + + if (NOT EXISTS "/usr/include/sys/inotify.h" AND NOT EXISTS "/usr/local/include/sys/inotify.h") + add_definitions(-DEFSW_INOTIFY_NOSYS) + endif() + elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR APPLE) + list(APPEND SRCS + src/efsw/FileWatcherKqueue.cpp + src/efsw/WatcherKqueue.cpp) + + if (APPLE) + list(APPEND SRCS + src/efsw/FileWatcherFSEvents.cpp + src/efsw/WatcherFSEvents.cpp) + + exec_program(uname ARGS -v OUTPUT_VARIABLE OSX_VERSION) + string(REGEX MATCH "[0-9]+" OSX_VERSION ${OSX_VERSION}) + if (NOT OSX_VERSION GREATER 9) + add_definitions(-DEFSW_FSEVENTS_NOT_SUPPORTED) + endif() + + set(OPTIONAL_MAC_LINK_LIBRARIES "-framework CoreFoundation" "-framework CoreServices") + endif() + endif() + + add_library(efsw STATIC ${SRCS}) + + target_include_directories(efsw + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src) + + target_link_libraries(efsw + PUBLIC + threads + ${OPTIONAL_MAC_LINK_LIBRARIES}) + + set_target_properties(efsw + PROPERTIES + FOLDER + "dep") +else() + add_library(efsw INTERFACE IMPORTED GLOBAL) +endif() diff --git a/dep/efsw/LICENSE b/dep/efsw/LICENSE new file mode 100644 index 00000000000..ac8ac28988d --- /dev/null +++ b/dep/efsw/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2012 MartÃn Lucas Golini + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) +http://code.google.com/p/simplefilewatcher/ also MIT licensed.
\ No newline at end of file diff --git a/dep/efsw/README.md b/dep/efsw/README.md new file mode 100644 index 00000000000..fda0bb599aa --- /dev/null +++ b/dep/efsw/README.md @@ -0,0 +1,138 @@ +Entropia File System Watcher +============================ +**efsw** is a C++ cross-platform file system watcher and notifier. + +**efsw** monitors the file system asynchronously for changes to files and directories by watching a list of specified paths, and raises events when a directory or file change. + +**efsw** supports recursive directories watch, tracking the entire sub directory tree. + +**efsw** currently supports the following platforms: + +* Linux via [inotify](http://en.wikipedia.org/wiki/Inotify) + +* Windows via [I/O Completion Ports](http://en.wikipedia.org/wiki/IOCP) + +* Mac OS X via [FSEvents](http://en.wikipedia.org/wiki/FSEvents) or [kqueue](http://en.wikipedia.org/wiki/Kqueue) + +* FreeBSD/BSD via [kqueue](http://en.wikipedia.org/wiki/Kqueue) + +* OS-independent generic watcher +(polling the disk for directory snapshots and comparing them periodically) + +If any of the backend fails to start by any reason, it will fallback to the OS-independent implementation. +This should never happen, except for the Kqueue implementation, see `Platform limitations and clarifications`. + +**Code License** +-------------- +[MIT License](http://www.opensource.org/licenses/mit-license.php) + +**Some example code:** +-------------------- + + :::c++ + // Inherits from the abstract listener class, and implements the the file action handler + class UpdateListener : public efsw::FileWatchListener + { + public: + UpdateListener() {} + + void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" ) + { + switch( action ) + { + case efsw::Actions::Add: + std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Added" << std::endl; + break; + case efsw::Actions::Delete: + std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Delete" << std::endl; + break; + case efsw::Actions::Modified: + std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Modified" << std::endl; + break; + case efsw::Actions::Moved: + std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Moved from (" << oldFilename << ")" << std::endl; + break; + default: + std::cout << "Should never happen!" << std::endl; + } + } + }; + + // Create the file system watcher instance + // efsw::FileWatcher allow a first boolean parameter that indicates if it should start with the generic file watcher instead of the platform specific backend + efsw::FileWatcher * fileWatcher = new efsw::FileWatcher(); + + // Create the instance of your efsw::FileWatcherListener implementation + UpdateListener * listener = new UpdateListener(); + + // Add a folder to watch, and get the efsw::WatchID + // It will watch the /tmp folder recursively ( the third parameter indicates that is recursive ) + // Reporting the files and directories changes to the instance of the listener + efsw::WatchID watchID = fileWatcher->addWatch( "/tmp", listener, true ); + + // Adds another directory to watch. This time as non-recursive. + efsw::WatchID watchID2 = fileWatcher->addWatch( "/usr", listener, false ); + + // Start watching asynchronously the directories + fileWatcher.watch(); + + // Remove the second watcher added + // You can also call removeWatch by passing the watch path ( it must end with an slash or backslash in windows, since that's how internally it's saved ) + fileWatcher->removeWatch( watchID2 ); + +**Dependencies** +-------------- +None :) + +**Compiling** +------------ +To generate project files you will need to [download and install](http://industriousone.com/premake/download) [Premake](http://industriousone.com/what-premake) + +Then you can generate the project for your platform just going to the project directory where the premake4.lua file is located and then execute: + +`premake4 gmake` to generate project Makefiles, then `cd make/*YOURPLATFORM*/`, and finally `make` or `make config=release` ( it will generate the static lib, the shared lib and the test application ). + +or + +`premake4 vs2010` to generate Visual Studio 2010 project. + +or + +`premake4 xcode4` to generate Xcode 4 project. + +There is also a cmake file that i don't oficially support but it works just fine, provided by [Mohammed Nafees](https://bitbucket.org/binaryking). + +**Platform limitations and clarifications** +------------------------------------------- + +Directory paths are expected to be encoded as UTF-8 strings in all platforms. + +handleFileAction returns UTF-8 strings in all platforms. + +Windows and FSEvents Mac OS X implementation can't follow symlinks ( it will ignore followSymlinks() and allowOutOfScopeLinks() ). + +Kqueue implementation is limited by the maximun number of file descriptors allowed per process by the OS, in the case of reaching the file descriptors limit ( in BSD around 18000 and in OS X around 10240 ) it will fallback to the generic file watcher. + +OS X will only use Kqueue if OS X version is below to 10.5, and this implementation needs to be compiled separately from the OS X >= 10.5 implementation. Since there's no way to compile FSEvents backend in OS X below 10.5. + +FSEvents for OS X Lion and beyond in some cases will generate more actions that in reality ocurred, since fine-grained implementation of FSEvents doesn't give the order of the actions retrieved, in some cases i need to guess/aproximate the order of them. + +Generic watcher relies on the inode information to detect file and directories renames/move. Since Windows has no concept of inodes as Unix platforms do, there is no current reliable way of determining file/directory movement on Windows without help from the Windows API ( this is replaced with Add/Delete events ). + +Linux versions below 2.6.13 are not supported, since inotify wasn't implemented yet. I'm not interested in support older kernels, since i don't see the point. If someone needs this open an issue in the issue tracker and i may consider implenent a dnotify backend. + +OS-independent watcher, Kqueue and FSEvents for OS X below 10.5 keep cache of the directories structures, to be able to detect changes in the directories. This means that there's a memory overhead for this backends. + +**Useful information** +-------------------- +The project also comes with a C API wrapper, contributed by [Sepul Sepehr Taghdisian](https://bitbucket.org/sepul). + +There's a string manipulation class not exposed in the efsw header ( efsw::String ) that can be used to make string encoding conversion. + + +**Clarifications** +---------------- + +This software started as a fork of the [simplefilewatcher](http://code.google.com/p/simplefilewatcher/) by James Wynn (james[at]jameswynn.com), [MIT licensed](http://www.opensource.org/licenses/mit-license.html). + +The icon used for the project is part of the [Haiku®'s Icons](http://www.haiku-inc.org/haiku-icons.html), [MIT licensed](http://www.opensource.org/licenses/mit-license.html). diff --git a/dep/efsw/include/efsw/efsw.h b/dep/efsw/include/efsw/efsw.h new file mode 100644 index 00000000000..28e63e2139e --- /dev/null +++ b/dep/efsw/include/efsw/efsw.h @@ -0,0 +1,151 @@ +/** + @author Sepul Sepehr Taghdisian + + Copyright (c) 2013 Martin Lucas Golini + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) + http://code.google.com/p/simplefilewatcher/ also MIT licensed. +*/ +/** This is the C API wrapper of EFSW */ +#ifndef ESFW_H +#define ESFW_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) + #ifdef EFSW_DYNAMIC + // Windows platforms + #ifdef EFSW_EXPORTS + // From DLL side, we must export + #define EFSW_API __declspec(dllexport) + #else + // From client application side, we must import + #define EFSW_API __declspec(dllimport) + #endif + #else + // No specific directive needed for static build + #ifndef EFSW_API + #define EFSW_API + #endif + #endif +#else + #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) + #define EFSW_API __attribute__ ((visibility("default"))) + #endif + + // Other platforms don't need to define anything + #ifndef EFSW_API + #define EFSW_API + #endif +#endif + +/// Type for a watch id +typedef long efsw_watchid; + +/// Type for watcher +typedef void* efsw_watcher; + +enum efsw_action +{ + EFSW_ADD = 1, /// Sent when a file is created or renamed + EFSW_DELETE = 2, /// Sent when a file is deleted or renamed + EFSW_MODIFIED = 3, /// Sent when a file is modified + EFSW_MOVED = 4 /// Sent when a file is moved +}; + +enum efsw_error +{ + EFSW_NOTFOUND = -1, + EFSW_REPEATED = -2, + EFSW_OUTOFSCOPE = -3, + EFSW_NOTREADABLE = -4, + EFSW_REMOTE = -5, + EFSW_UNSPECIFIED = -6 +}; + +/// Basic interface for listening for file events. +typedef void (*efsw_pfn_fileaction_callback) ( + efsw_watcher watcher, + efsw_watchid watchid, + const char* dir, + const char* filename, + enum efsw_action action, + const char* old_filename, + void* param +); + +/** + * Creates a new file-watcher + * @param generic_mode Force the use of the Generic file watcher + */ +efsw_watcher EFSW_API efsw_create(int generic_mode); + +/// Release the file-watcher and unwatch any directories +void EFSW_API efsw_release(efsw_watcher watcher); + +/// Retreive last error occured by file-watcher +EFSW_API const char* efsw_getlasterror(); + +/// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. +/// For backwards compatibility. +/// On error returns WatchID with Error type. +efsw_watchid EFSW_API efsw_addwatch(efsw_watcher watcher, const char* directory, + efsw_pfn_fileaction_callback callback_fn, int recursive, void* param); + +/// Remove a directory watch. This is a brute force search O(nlogn). +void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory); + +/// Remove a directory watch. This is a map lookup O(logn). +void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid); + +/// Starts watching ( in other thread ) +void EFSW_API efsw_watch(efsw_watcher watcher); + +/** + * Allow recursive watchers to follow symbolic links to other directories + * followSymlinks is disabled by default + */ +void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable); + +/** @return If can follow symbolic links to directorioes */ +int EFSW_API efsw_follow_symlinks_isenabled(efsw_watcher watcher); + +/** + * When enable this it will allow symlinks to watch recursively out of the pointed directory. + * follorSymlinks must be enabled to this work. + * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed, + * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion. + * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ). + * Buy enabling out of scope links, it will allow this behavior. + * allowOutOfScopeLinks are disabled by default. + */ +void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow); + +/// @return Returns if out of scope links are allowed +int EFSW_API efsw_outofscopelinks_isallowed(efsw_watcher watcher); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dep/efsw/include/efsw/efsw.hpp b/dep/efsw/include/efsw/efsw.hpp new file mode 100644 index 00000000000..0693bb296f0 --- /dev/null +++ b/dep/efsw/include/efsw/efsw.hpp @@ -0,0 +1,197 @@ +/** + @author MartÃn Lucas Golini + + Copyright (c) 2013 MartÃn Lucas Golini + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) + http://code.google.com/p/simplefilewatcher/ also MIT licensed. +*/ + +#ifndef ESFW_HPP +#define ESFW_HPP + +#include <string> +#include <list> + +#if defined(_WIN32) + #ifdef EFSW_DYNAMIC + // Windows platforms + #ifdef EFSW_EXPORTS + // From DLL side, we must export + #define EFSW_API __declspec(dllexport) + #else + // From client application side, we must import + #define EFSW_API __declspec(dllimport) + #endif + #else + // No specific directive needed for static build + #ifndef EFSW_API + #define EFSW_API + #endif + #endif +#else + #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) + #define EFSW_API __attribute__ ((visibility("default"))) + #endif + + // Other platforms don't need to define anything + #ifndef EFSW_API + #define EFSW_API + #endif +#endif + +namespace efsw { + +/// Type for a watch id +typedef long WatchID; + +// forward declarations +class FileWatcherImpl; +class FileWatchListener; + +/// Actions to listen for. Rename will send two events, one for +/// the deletion of the old file, and one for the creation of the +/// new file. +namespace Actions { + enum Action + { + /// Sent when a file is created or renamed + Add = 1, + /// Sent when a file is deleted or renamed + Delete = 2, + /// Sent when a file is modified + Modified = 3, + /// Sent when a file is moved + Moved = 4 + }; +} +typedef Actions::Action Action; + +/// Errors log namespace +namespace Errors { + +enum Error +{ + FileNotFound = -1, + FileRepeated = -2, + FileOutOfScope = -3, + FileNotReadable = -4, + FileRemote = -5, /** Directory in remote file system ( create a generic FileWatcher instance to watch this directory ). */ + Unspecified = -6 +}; + +class EFSW_API Log +{ + public: + /// @return The last error logged + static std::string getLastErrorLog(); + + /// Creates an error of the type specified + static Error createLastError( Error err, std::string log ); +}; + +} +typedef Errors::Error Error; + +/// Listens to files and directories and dispatches events +/// to notify the listener of files and directories changes. +/// @class FileWatcher +class EFSW_API FileWatcher +{ + public: + /// Default constructor, will use the default platform file watcher + FileWatcher(); + + /// Constructor that lets you force the use of the Generic File Watcher + FileWatcher( bool useGenericFileWatcher ); + + virtual ~FileWatcher(); + + /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. + /// For backwards compatibility. + /// On error returns WatchID with Error type. + WatchID addWatch(const std::string& directory, FileWatchListener* watcher); + + /// Add a directory watch + /// On error returns WatchID with Error type. + WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); + + /// Remove a directory watch. This is a brute force search O(nlogn). + void removeWatch(const std::string& directory); + + /// Remove a directory watch. This is a map lookup O(logn). + void removeWatch(WatchID watchid); + + /// Starts watching ( in other thread ) + void watch(); + + /// @return Returns a list of the directories that are being watched + std::list<std::string> directories(); + + /** Allow recursive watchers to follow symbolic links to other directories + * followSymlinks is disabled by default + */ + void followSymlinks( bool follow ); + + /** @return If can follow symbolic links to directorioes */ + const bool& followSymlinks() const; + + /** When enable this it will allow symlinks to watch recursively out of the pointed directory. + * follorSymlinks must be enabled to this work. + * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed, + * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion. + * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ). + * Buy enabling out of scope links, it will allow this behavior. + * allowOutOfScopeLinks are disabled by default. + */ + void allowOutOfScopeLinks( bool allow ); + + /// @return Returns if out of scope links are allowed + const bool& allowOutOfScopeLinks() const; + private: + /// The implementation + FileWatcherImpl * mImpl; + bool mFollowSymlinks; + bool mOutOfScopeLinks; +}; + +/// Basic interface for listening for file events. +/// @class FileWatchListener +class FileWatchListener +{ + public: + FileWatchListener() {} + + virtual ~FileWatchListener() {} + + /// Handles the action file action + /// @param watchid The watch id for the directory + /// @param dir The directory + /// @param filename The filename that was accessed (not full path) + /// @param action Action that was performed + /// @param oldFilename The name of the file or directory moved + virtual void handleFileAction(WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" ) = 0; + +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/Debug.cpp b/dep/efsw/src/efsw/Debug.cpp new file mode 100644 index 00000000000..9c4ee02e5b6 --- /dev/null +++ b/dep/efsw/src/efsw/Debug.cpp @@ -0,0 +1,85 @@ +#include <efsw/Debug.hpp> +#include <iostream> + +#ifdef EFSW_COMPILER_MSVC +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <crtdbg.h> +#endif + +#include <cassert> +#include <cstdio> +#include <cstdarg> + +namespace efsw { + +#ifdef DEBUG + +void efREPORT_ASSERT( const char * File, int Line, const char * Exp ) +{ + #ifdef EFSW_COMPILER_MSVC + _CrtDbgReport( _CRT_ASSERT, File, Line, "", Exp); + + DebugBreak(); + #else + std::cout << "ASSERT: " << Exp << " file: " << File << " line: " << Line << std::endl; + + #if defined(EFSW_COMPILER_GCC) && defined(EFSW_32BIT) && !defined(EFSW_ARM) + asm("int3"); + #else + assert( false ); + #endif + #endif +} + +void efPRINT( const char * format, ... ) +{ + char buf[2048]; + va_list args; + + va_start( args, format ); + + #ifdef EFSW_COMPILER_MSVC + _vsnprintf_s( buf, sizeof( buf ), sizeof( buf ) / sizeof( buf[0]), format, args ); + #else + vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args ); + #endif + + va_end( args ); + + #ifdef EFSW_COMPILER_MSVC + OutputDebugStringA( buf ); + #else + std::cout << buf; + #endif +} + +void efPRINTC( unsigned int cond, const char * format, ...) +{ + if ( 0 == cond ) + return; + + char buf[2048]; + va_list args; + + va_start( args, format ); + + #ifdef EFSW_COMPILER_MSVC + _vsnprintf_s( buf, efARRAY_SIZE( buf ), efARRAY_SIZE( buf ), format, args ); + #else + vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args ); + #endif + + va_end( args ); + + #ifdef EFSW_COMPILER_MSVC + OutputDebugStringA( buf ); + #else + std::cout << buf; + #endif +} + +#endif + +} + diff --git a/dep/efsw/src/efsw/Debug.hpp b/dep/efsw/src/efsw/Debug.hpp new file mode 100644 index 00000000000..75d6dce0466 --- /dev/null +++ b/dep/efsw/src/efsw/Debug.hpp @@ -0,0 +1,50 @@ +#ifndef EFSW_DEBUG_HPP +#define EFSW_DEBUG_HPP + +#include <efsw/base.hpp> + +namespace efsw { + +#ifdef DEBUG + +void efREPORT_ASSERT( const char * File, const int Line, const char * Exp ); + +#define efASSERT( expr ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #expr ); } +#define efASSERTM( expr, msg ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #msg ); } + +void efPRINT ( const char * format, ... ); +void efPRINTC ( unsigned int cond, const char * format, ... ); + +#else + +#define efASSERT( expr ) +#define efASSERTM( expr, msg ) + +#ifndef EFSW_COMPILER_MSVC + #define efPRINT( format, args... ) {} + #define efPRINTC( cond, format, args... ) {} +#else + #define efPRINT + #define efPRINTC +#endif + +#endif + +#ifdef EFSW_VERBOSE + #define efDEBUG efPRINT + #define efDEBUGC efPRINTC +#else + + #ifndef EFSW_COMPILER_MSVC + #define efDEBUG( format, args... ) {} + #define efDEBUGC( cond, format, args... ) {} + #else + #define efDEBUG + #define efDEBUGC + #endif + +#endif + +} + +#endif diff --git a/dep/efsw/src/efsw/DirWatcherGeneric.cpp b/dep/efsw/src/efsw/DirWatcherGeneric.cpp new file mode 100644 index 00000000000..b80c14d24ce --- /dev/null +++ b/dep/efsw/src/efsw/DirWatcherGeneric.cpp @@ -0,0 +1,451 @@ +#include <efsw/DirWatcherGeneric.hpp> +#include <efsw/FileSystem.hpp> +#include <efsw/Debug.hpp> +#include <efsw/String.hpp> + +namespace efsw { + +DirWatcherGeneric::DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive, bool reportNewFiles ) : + Parent( parent ), + Watch( ws ), + Recursive( recursive ), + Deleted( false ) +{ + resetDirectory( directory ); + + if ( !reportNewFiles ) + { + DirSnap.scan(); + } + else + { + DirectorySnapshotDiff Diff = DirSnap.scan(); + + if ( Diff.changed() ) + { + FileInfoList::iterator it; + + DiffIterator( FilesCreated ) + { + handleAction( ( *it ).Filepath, Actions::Add ); + } + } + } +} + +DirWatcherGeneric::~DirWatcherGeneric() +{ + /// If the directory was deleted mark the files as deleted + if ( Deleted ) + { + DirectorySnapshotDiff Diff = DirSnap.scan(); + + if ( !DirSnap.exists() ) + { + FileInfoList::iterator it; + + DiffIterator( FilesDeleted ) + { + handleAction( (*it).Filepath, Actions::Delete ); + } + + DiffIterator( DirsDeleted ) + { + handleAction( (*it).Filepath, Actions::Delete ); + } + } + } + + DirWatchMap::iterator it = Directories.begin(); + + for ( ; it != Directories.end(); it++ ) + { + if ( Deleted ) + { + /// If the directory was deleted, mark the flag for file deletion + it->second->Deleted = true; + } + + efSAFE_DELETE( it->second ); + } +} + +void DirWatcherGeneric::resetDirectory( std::string directory ) +{ + std::string dir( directory ); + + /// Is this a recursive watch? + if ( Watch->Directory != directory ) + { + if ( !( directory.size() && ( directory.at(0) == FileSystem::getOSSlash() || directory.at( directory.size() - 1 ) == FileSystem::getOSSlash() ) ) ) + { + /// Get the real directory + if ( NULL != Parent ) + { + FileSystem::dirAddSlashAtEnd(directory); + + dir = Parent->DirSnap.DirectoryInfo.Filepath + directory; + } + else + { + efDEBUG( "resetDirectory(): Parent is NULL. Fatal error." ); + } + } + } + + DirSnap.setDirectoryInfo( dir ); +} + +void DirWatcherGeneric::handleAction( const std::string &filename, unsigned long action, std::string oldFilename) +{ + Watch->Listener->handleFileAction( Watch->ID, DirSnap.DirectoryInfo.Filepath, FileSystem::fileNameFromPath( filename ), (Action)action, oldFilename ); +} + +void DirWatcherGeneric::addChilds( bool reportNewFiles ) +{ + if ( Recursive ) + { + /// Create the subdirectories watchers + std::string dir; + + for ( FileInfoMap::iterator it = DirSnap.Files.begin(); it != DirSnap.Files.end(); it++ ) + { + if ( it->second.isDirectory() && it->second.isReadable() && !FileSystem::isRemoteFS( it->second.Filepath ) ) + { + /// Check if the directory is a symbolic link + std::string curPath; + std::string link( FileSystem::getLinkRealPath( it->second.Filepath, curPath ) ); + + dir = it->first; + + if ( "" != link ) + { + /// Avoid adding symlinks directories if it's now enabled + if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) + { + continue; + } + + /// If it's a symlink check if the realpath exists as a watcher, or + /// if the path is outside the current dir + if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) ) + { + continue; + } + else + { + dir = link; + } + } + else + { + if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) + { + continue; + } + } + + if ( reportNewFiles ) + { + handleAction( dir, Actions::Add ); + } + + Directories[dir] = new DirWatcherGeneric( this, Watch, dir, Recursive, reportNewFiles ); + + Directories[dir]->addChilds( reportNewFiles ); + } + } + } +} + +void DirWatcherGeneric::watch( bool reportOwnChange ) +{ + DirectorySnapshotDiff Diff = DirSnap.scan(); + + if ( reportOwnChange && Diff.DirChanged && NULL != Parent ) + { + Watch->Listener->handleFileAction( Watch->ID, FileSystem::pathRemoveFileName( DirSnap.DirectoryInfo.Filepath ), FileSystem::fileNameFromPath( DirSnap.DirectoryInfo.Filepath ), Actions::Modified ); + } + + if ( Diff.changed() ) + { + FileInfoList::iterator it; + MovedList::iterator mit; + + /// Files + DiffIterator( FilesCreated ) + { + handleAction( (*it).Filepath, Actions::Add ); + } + + DiffIterator( FilesModified ) + { + handleAction( (*it).Filepath, Actions::Modified ); + } + + DiffIterator( FilesDeleted ) + { + handleAction( (*it).Filepath, Actions::Delete ); + } + + DiffMovedIterator( FilesMoved ) + { + handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first ); + } + + /// Directories + DiffIterator( DirsCreated ) + { + createDirectory( (*it).Filepath ); + } + + DiffIterator( DirsModified ) + { + handleAction( (*it).Filepath, Actions::Modified ); + } + + DiffIterator( DirsDeleted ) + { + handleAction( (*it).Filepath, Actions::Delete ); + removeDirectory( (*it).Filepath ); + } + + DiffMovedIterator( DirsMoved ) + { + handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first ); + moveDirectory( (*mit).first, (*mit).second.Filepath ); + } + } + + /// Process the subdirectories looking for changes + for ( DirWatchMap::iterator dit = Directories.begin(); dit != Directories.end(); dit++ ) + { + /// Just watch + dit->second->watch(); + } +} + +void DirWatcherGeneric::watchDir( std::string &dir ) +{ + DirWatcherGeneric * watcher = Watch->WatcherImpl->mFileWatcher->allowOutOfScopeLinks() ? + findDirWatcher( dir ) : + findDirWatcherFast( dir ); + + if ( NULL != watcher ) + { + watcher->watch( true ); + } +} + +DirWatcherGeneric * DirWatcherGeneric::findDirWatcherFast( std::string dir ) +{ + // remove the common base ( dir should always start with the same base as the watcher ) + efASSERT( !dir.empty() ); + efASSERT( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ); + efASSERT( DirSnap.DirectoryInfo.Filepath == dir.substr( 0, DirSnap.DirectoryInfo.Filepath.size() ) ); + + if ( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ) + { + dir = dir.substr( DirSnap.DirectoryInfo.Filepath.size() - 1 ); + } + + if ( dir.size() == 1 ) + { + efASSERT( dir[0] == FileSystem::getOSSlash() ); + return this; + } + + size_t level = 0; + std::vector<std::string> dirv = String::split( dir, FileSystem::getOSSlash(), false ); + + DirWatcherGeneric * watcher = this; + + while ( level < dirv.size() ) + { + // search the dir level in the current watcher + DirWatchMap::iterator it = watcher->Directories.find( dirv[ level ] ); + + // found? continue with the next level + if ( it != watcher->Directories.end() ) + { + watcher = it->second; + + level++; + } + else + { + // couldn't found the folder level? + // directory not watched + return NULL; + } + } + + return watcher; +} + +DirWatcherGeneric * DirWatcherGeneric::findDirWatcher( std::string dir ) +{ + if ( DirSnap.DirectoryInfo.Filepath == dir ) + { + return this; + } + else + { + DirWatcherGeneric * watcher = NULL; + + for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); it++ ) + { + watcher = it->second->findDirWatcher( dir ); + + if ( NULL != watcher ) + { + return watcher; + } + } + } + + return NULL; +} + +DirWatcherGeneric * DirWatcherGeneric::createDirectory( std::string newdir ) +{ + FileSystem::dirRemoveSlashAtEnd( newdir ); + newdir = FileSystem::fileNameFromPath( newdir ); + + DirWatcherGeneric * dw = NULL; + + /// Check if the directory is a symbolic link + std::string dir( DirSnap.DirectoryInfo.Filepath + newdir ); + + FileSystem::dirAddSlashAtEnd( dir ); + + FileInfo fi( dir ); + + if ( !fi.isDirectory() || !fi.isReadable() || FileSystem::isRemoteFS( dir ) ) + { + return NULL; + } + + std::string curPath; + std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); + bool skip = false; + + if ( "" != link ) + { + /// Avoid adding symlinks directories if it's now enabled + if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) + { + skip = true; + } + + /// If it's a symlink check if the realpath exists as a watcher, or + /// if the path is outside the current dir + if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) ) + { + skip = true; + } + else + { + dir = link; + } + } + else + { + if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) + { + skip = true; + } + } + + if ( !skip ) + { + handleAction( newdir, Actions::Add ); + + /// Creates the new directory watcher of the subfolder and check for new files + dw = new DirWatcherGeneric( this, Watch, dir, Recursive ); + + dw->addChilds(); + + dw->watch(); + + /// Add it to the list of directories + Directories[ newdir ] = dw; + } + + return dw; +} + +void DirWatcherGeneric::removeDirectory( std::string dir ) +{ + FileSystem::dirRemoveSlashAtEnd( dir ); + dir = FileSystem::fileNameFromPath( dir ); + + DirWatcherGeneric * dw = NULL; + DirWatchMap::iterator dit; + + /// Folder deleted + + /// Search the folder, it should exists + dit = Directories.find( dir ); + + if ( dit != Directories.end() ) + { + dw = dit->second; + + /// Flag it as deleted so it fire the event for every file inside deleted + dw->Deleted = true; + + /// Delete the DirWatcherGeneric + efSAFE_DELETE( dw ); + + /// Remove the directory from the map + Directories.erase( dit->first ); + } +} + +void DirWatcherGeneric::moveDirectory( std::string oldDir, std::string newDir ) +{ + FileSystem::dirRemoveSlashAtEnd( oldDir ); + oldDir = FileSystem::fileNameFromPath( oldDir ); + + FileSystem::dirRemoveSlashAtEnd( newDir ); + newDir = FileSystem::fileNameFromPath( newDir ); + + DirWatcherGeneric * dw = NULL; + DirWatchMap::iterator dit; + + /// Directory existed? + dit = Directories.find( oldDir ); + + if ( dit != Directories.end() ) + { + dw = dit->second; + + /// Remove the directory from the map + Directories.erase( dit->first ); + + Directories[ newDir ] = dw; + + dw->resetDirectory( newDir ); + } +} + +bool DirWatcherGeneric::pathInWatches( std::string path ) +{ + if ( DirSnap.DirectoryInfo.Filepath == path ) + { + return true; + } + + for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); it++ ) + { + if ( it->second->pathInWatches( path ) ) + { + return true; + } + } + + return false; +} + +} diff --git a/dep/efsw/src/efsw/DirWatcherGeneric.hpp b/dep/efsw/src/efsw/DirWatcherGeneric.hpp new file mode 100644 index 00000000000..a7581904422 --- /dev/null +++ b/dep/efsw/src/efsw/DirWatcherGeneric.hpp @@ -0,0 +1,55 @@ +#ifndef EFSW_DIRWATCHERGENERIC_HPP +#define EFSW_DIRWATCHERGENERIC_HPP + +#include <efsw/WatcherGeneric.hpp> +#include <efsw/FileInfo.hpp> +#include <efsw/DirectorySnapshot.hpp> +#include <map> + +namespace efsw { + +class DirWatcherGeneric +{ + public: + typedef std::map<std::string, DirWatcherGeneric*> DirWatchMap; + + DirWatcherGeneric * Parent; + WatcherGeneric * Watch; + DirectorySnapshot DirSnap; + DirWatchMap Directories; + bool Recursive; + + DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive, bool reportNewFiles = false ); + + ~DirWatcherGeneric(); + + void watch( bool reportOwnChange = false ); + + void watchDir( std::string& dir ); + + static bool isDir( const std::string& directory ); + + bool pathInWatches( std::string path ); + + void addChilds( bool reportNewFiles = true ); + + DirWatcherGeneric * findDirWatcher( std::string dir ); + + DirWatcherGeneric * findDirWatcherFast( std::string dir ); + protected: + bool Deleted; + + DirWatcherGeneric * createDirectory( std::string newdir ); + + void removeDirectory( std::string dir ); + + void moveDirectory( std::string oldDir, std::string newDir ); + + void resetDirectory( std::string directory ); + + void handleAction( const std::string& filename, unsigned long action, std::string oldFilename = ""); +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/DirectorySnapshot.cpp b/dep/efsw/src/efsw/DirectorySnapshot.cpp new file mode 100644 index 00000000000..c0ef747548a --- /dev/null +++ b/dep/efsw/src/efsw/DirectorySnapshot.cpp @@ -0,0 +1,261 @@ +#include <efsw/DirectorySnapshot.hpp> +#include <efsw/FileSystem.hpp> + +namespace efsw { + +DirectorySnapshot::DirectorySnapshot() +{ +} + +DirectorySnapshot::DirectorySnapshot( std::string directory ) +{ + init( directory ); +} + +DirectorySnapshot::~DirectorySnapshot() +{ +} + +void DirectorySnapshot::init( std::string directory ) +{ + setDirectoryInfo( directory ); + initFiles(); +} + +bool DirectorySnapshot::exists() +{ + return DirectoryInfo.exists(); +} + +void DirectorySnapshot::deleteAll( DirectorySnapshotDiff& Diff ) +{ + FileInfo fi; + + for ( FileInfoMap::iterator it = Files.begin(); it != Files.end(); it++ ) + { + fi = it->second; + + if ( fi.isDirectory() ) + { + Diff.DirsDeleted.push_back( fi ); + } + else + { + Diff.FilesDeleted.push_back( fi ); + } + } +} + +void DirectorySnapshot::setDirectoryInfo( std::string directory ) +{ + DirectoryInfo = FileInfo( directory ); +} + +void DirectorySnapshot::initFiles() +{ + Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); + + FileInfoMap::iterator it = Files.begin(); + std::list<std::string> eraseFiles; + + /// Remove all non regular files and non directories + for ( ; it != Files.end(); it++ ) + { + if ( !it->second.isRegularFile() && !it->second.isDirectory() ) + { + eraseFiles.push_back( it->first ); + } + } + + for ( std::list<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); eit++ ) + { + Files.erase( *eit ); + } +} + +DirectorySnapshotDiff DirectorySnapshot::scan() +{ + DirectorySnapshotDiff Diff; + + Diff.clear(); + + FileInfo curFI( DirectoryInfo.Filepath ); + + Diff.DirChanged = DirectoryInfo != curFI; + + if ( Diff.DirChanged ) + { + DirectoryInfo = curFI; + } + + /// If the directory was erased, create the events for files and directories deletion + if ( !curFI.exists() ) + { + deleteAll( Diff ); + + return Diff; + } + + FileInfoMap files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); + + if ( files.empty() && Files.empty() ) + { + return Diff; + } + + FileInfo fi; + FileInfoMap FilesCpy; + FileInfoMap::iterator it; + FileInfoMap::iterator fiIt; + + if ( Diff.DirChanged ) + { + FilesCpy = Files; + } + + for ( it = files.begin(); it != files.end(); it++ ) + { + fi = it->second; + + /// File existed before? + fiIt = Files.find( it->first ); + + if ( fiIt != Files.end() ) + { + /// Erase from the file list copy + FilesCpy.erase( it->first ); + + /// File changed? + if ( (*fiIt).second != fi ) + { + /// Update the new file info + Files[ it->first ] = fi; + + /// handle modified event + if ( fi.isDirectory() ) + { + Diff.DirsModified.push_back( fi ); + } + else + { + Diff.FilesModified.push_back( fi ); + } + } + } + /// Only add regular files or directories + else if ( fi.isRegularFile() || fi.isDirectory() ) + { + /// New file found + Files[ it->first ] = fi; + + FileInfoMap::iterator fit; + std::string oldFile = ""; + + /// Check if the same inode already existed + if ( ( fit = nodeInFiles( fi ) ) != Files.end() ) + { + oldFile = fit->first; + + /// Avoid firing a Delete event + FilesCpy.erase( fit->first ); + + /// Delete the old file name + Files.erase( fit->first ); + + if ( fi.isDirectory() ) + { + Diff.DirsMoved.push_back( std::make_pair( oldFile, fi ) ); + } + else + { + Diff.FilesMoved.push_back( std::make_pair( oldFile, fi ) ); + } + } + else + { + if ( fi.isDirectory() ) + { + Diff.DirsCreated.push_back( fi ); + } + else + { + Diff.FilesCreated.push_back( fi ); + } + } + } + } + + if ( !Diff.DirChanged ) + { + return Diff; + } + + /// The files or directories that remains were deleted + for ( it = FilesCpy.begin(); it != FilesCpy.end(); it++ ) + { + fi = it->second; + + if ( fi.isDirectory() ) + { + Diff.DirsDeleted.push_back( fi ); + } + else + { + Diff.FilesDeleted.push_back( fi ); + } + + /// Remove the file or directory from the list of files + Files.erase( it->first ); + } + + return Diff; +} + +FileInfoMap::iterator DirectorySnapshot::nodeInFiles( FileInfo& fi ) +{ + FileInfoMap::iterator it; + + if ( FileInfo::inodeSupported() ) + { + for ( it = Files.begin(); it != Files.end(); it++ ) + { + if ( it->second.sameInode( fi ) && it->second.Filepath != fi.Filepath ) + { + return it; + } + } + } + + return Files.end(); +} + +void DirectorySnapshot::addFile( std::string path ) +{ + std::string name( FileSystem::fileNameFromPath( path ) ); + Files[ name ] = FileInfo( path ); +} + +void DirectorySnapshot::removeFile( std::string path ) +{ + std::string name( FileSystem::fileNameFromPath( path ) ); + + FileInfoMap::iterator it = Files.find( name ); + + if ( Files.end() != it ) + { + Files.erase( it ); + } +} + +void DirectorySnapshot::moveFile( std::string oldPath, std::string newPath ) +{ + removeFile( oldPath ); + addFile( newPath ); +} + +void DirectorySnapshot::updateFile(std::string path) +{ + addFile( path ); +} + +} diff --git a/dep/efsw/src/efsw/DirectorySnapshot.hpp b/dep/efsw/src/efsw/DirectorySnapshot.hpp new file mode 100644 index 00000000000..1ada66fe980 --- /dev/null +++ b/dep/efsw/src/efsw/DirectorySnapshot.hpp @@ -0,0 +1,46 @@ +#ifndef EFSW_DIRECTORYSNAPSHOT_HPP +#define EFSW_DIRECTORYSNAPSHOT_HPP + +#include <efsw/DirectorySnapshotDiff.hpp> + +namespace efsw { + +class DirectorySnapshot +{ + public: + FileInfo DirectoryInfo; + FileInfoMap Files; + + void setDirectoryInfo( std::string directory ); + + DirectorySnapshot(); + + DirectorySnapshot( std::string directory ); + + ~DirectorySnapshot(); + + void init( std::string directory ); + + bool exists(); + + DirectorySnapshotDiff scan(); + + FileInfoMap::iterator nodeInFiles( FileInfo& fi ); + + void addFile( std::string path ); + + void removeFile( std::string path ); + + void moveFile( std::string oldPath, std::string newPath ); + + void updateFile( std::string path ); + protected: + void initFiles(); + + void deleteAll( DirectorySnapshotDiff &Diff ); +}; + +} + +#endif + diff --git a/dep/efsw/src/efsw/DirectorySnapshotDiff.cpp b/dep/efsw/src/efsw/DirectorySnapshotDiff.cpp new file mode 100644 index 00000000000..eabc6fdbda1 --- /dev/null +++ b/dep/efsw/src/efsw/DirectorySnapshotDiff.cpp @@ -0,0 +1,29 @@ +#include <efsw/DirectorySnapshotDiff.hpp> + +namespace efsw { + +void DirectorySnapshotDiff::clear() +{ + FilesCreated.clear(); + FilesModified.clear(); + FilesMoved.clear(); + FilesDeleted.clear(); + DirsCreated.clear(); + DirsModified.clear(); + DirsMoved.clear(); + DirsDeleted.clear(); +} + +bool DirectorySnapshotDiff::changed() +{ + return !FilesCreated.empty() || + !FilesModified.empty() || + !FilesMoved.empty() || + !FilesDeleted.empty() || + !DirsCreated.empty() || + !DirsModified.empty() || + !DirsMoved.empty() || + !DirsDeleted.empty(); +} + +} diff --git a/dep/efsw/src/efsw/DirectorySnapshotDiff.hpp b/dep/efsw/src/efsw/DirectorySnapshotDiff.hpp new file mode 100644 index 00000000000..042de9ce02c --- /dev/null +++ b/dep/efsw/src/efsw/DirectorySnapshotDiff.hpp @@ -0,0 +1,35 @@ +#ifndef EFSW_DIRECTORYSNAPSHOTDIFF_HPP +#define EFSW_DIRECTORYSNAPSHOTDIFF_HPP + +#include <efsw/FileInfo.hpp> + +namespace efsw { + +class DirectorySnapshotDiff +{ + public: + FileInfoList FilesDeleted; + FileInfoList FilesCreated; + FileInfoList FilesModified; + MovedList FilesMoved; + FileInfoList DirsDeleted; + FileInfoList DirsCreated; + FileInfoList DirsModified; + MovedList DirsMoved; + bool DirChanged; + + void clear(); + + bool changed(); +}; + +#define DiffIterator( FileInfoListName ) it = Diff.FileInfoListName.begin(); \ + for ( ; it != Diff.FileInfoListName.end(); it++ ) + +#define DiffMovedIterator( MovedListName ) mit = Diff.MovedListName.begin(); \ + for ( ; mit != Diff.MovedListName.end(); mit++ ) + +} + +#endif + diff --git a/dep/efsw/src/efsw/FileInfo.cpp b/dep/efsw/src/efsw/FileInfo.cpp new file mode 100644 index 00000000000..7003afc2a15 --- /dev/null +++ b/dep/efsw/src/efsw/FileInfo.cpp @@ -0,0 +1,274 @@ +#include <efsw/FileInfo.hpp> +#include <efsw/FileSystem.hpp> +#include <efsw/String.hpp> + +#ifndef _DARWIN_FEATURE_64_BIT_INODE +#define _DARWIN_FEATURE_64_BIT_INODE +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +#include <sys/stat.h> + +#include <limits.h> +#include <stdlib.h> + +#ifdef EFSW_COMPILER_MSVC + #ifndef S_ISDIR + #define S_ISDIR(f) ((f)&_S_IFDIR) + #endif + + #ifndef S_ISREG + #define S_ISREG(f) ((f)&_S_IFREG) + #endif + + #ifndef S_ISRDBL + #define S_ISRDBL(f) ((f)&_S_IREAD) + #endif +#else + #include <unistd.h> + + #ifndef S_ISRDBL + #define S_ISRDBL(f) ((f)&S_IRUSR) + #endif +#endif + +namespace efsw { + +bool FileInfo::exists( const std::string& filePath ) +{ + FileInfo fi( filePath ); + return fi.exists(); +} + +bool FileInfo::isLink( const std::string& filePath ) +{ + FileInfo fi( filePath, true ); + return fi.isLink(); +} + +bool FileInfo::inodeSupported() +{ + #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 + return true; + #else + return false; + #endif +} + +FileInfo::FileInfo() : + ModificationTime(0), + OwnerId(0), + GroupId(0), + Permissions(0), + Inode(0) +{} + +FileInfo::FileInfo( const std::string& filepath ) : + Filepath( filepath ), + ModificationTime(0), + OwnerId(0), + GroupId(0), + Permissions(0), + Inode(0) +{ + getInfo(); +} + +FileInfo::FileInfo( const std::string& filepath, bool linkInfo ) : + Filepath( filepath ), + ModificationTime(0), + OwnerId(0), + GroupId(0), + Permissions(0), + Inode(0) +{ + if ( linkInfo ) + { + getRealInfo(); + } + else + { + getInfo(); + } +} + +void FileInfo::getInfo() +{ + #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + if ( Filepath.size() == 3 && Filepath[1] == ':' && Filepath[2] == FileSystem::getOSSlash() ) + { + Filepath += FileSystem::getOSSlash(); + } + #endif + + /// Why i'm doing this? stat in mingw32 doesn't work for directories if the dir path ends with a path slash + bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); + + if ( slashAtEnd ) + { + FileSystem::dirRemoveSlashAtEnd( Filepath ); + } + + #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 + struct stat st; + int res = stat( Filepath.c_str(), &st ); + #else + struct _stat st; + int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st ); + #endif + + if ( 0 == res ) + { + ModificationTime = st.st_mtime; + Size = st.st_size; + OwnerId = st.st_uid; + GroupId = st.st_gid; + Permissions = st.st_mode; + Inode = st.st_ino; + } + + if ( slashAtEnd ) + { + FileSystem::dirAddSlashAtEnd( Filepath ); + } +} + +void FileInfo::getRealInfo() +{ + bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); + + if ( slashAtEnd ) + { + FileSystem::dirRemoveSlashAtEnd( Filepath ); + } + + #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 + struct stat st; + int res = lstat( Filepath.c_str(), &st ); + #else + struct _stat st; + int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st ); + #endif + + if ( 0 == res ) + { + ModificationTime = st.st_mtime; + Size = st.st_size; + OwnerId = st.st_uid; + GroupId = st.st_gid; + Permissions = st.st_mode; + Inode = st.st_ino; + } + + if ( slashAtEnd ) + { + FileSystem::dirAddSlashAtEnd( Filepath ); + } +} + +bool FileInfo::operator==( const FileInfo& Other ) const +{ + return ( ModificationTime == Other.ModificationTime && + Size == Other.Size && + OwnerId == Other.OwnerId && + GroupId == Other.GroupId && + Permissions == Other.Permissions && + Inode == Other.Inode + ); +} + +bool FileInfo::isDirectory() +{ + return 0 != S_ISDIR(Permissions); +} + +bool FileInfo::isRegularFile() +{ + return 0 != S_ISREG(Permissions); +} + +bool FileInfo::isReadable() +{ + return 0 != S_ISRDBL(Permissions); +} + +bool FileInfo::isLink() +{ +#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 + return S_ISLNK(Permissions); +#else + return false; +#endif +} + +std::string FileInfo::linksTo() +{ +#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 + if ( isLink() ) + { + char * ch = realpath( Filepath.c_str(), NULL); + + if ( NULL != ch ) + { + std::string tstr( ch ); + + free( ch ); + + return tstr; + } + } +#endif + return std::string(""); +} + +bool FileInfo::exists() +{ + bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); + + if ( slashAtEnd ) + { + FileSystem::dirRemoveSlashAtEnd(Filepath); + } + +#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 + struct stat st; + int res = stat( Filepath.c_str(), &st ); +#else + struct _stat st; + int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st ); +#endif + + if (slashAtEnd) + { + FileSystem::dirAddSlashAtEnd(Filepath); + } + + return 0 == res; +} + +FileInfo& FileInfo::operator=( const FileInfo& Other ) +{ + this->Filepath = Other.Filepath; + this->Size = Other.Size; + this->ModificationTime = Other.ModificationTime; + this->GroupId = Other.GroupId; + this->OwnerId = Other.OwnerId; + this->Permissions = Other.Permissions; + this->Inode = Other.Inode; + return *this; +} + +bool FileInfo::sameInode( const FileInfo& Other ) const +{ + return inodeSupported() && Inode == Other.Inode; +} + +bool FileInfo::operator!=( const FileInfo& Other ) const +{ + return !(*this == Other); +} + +} diff --git a/dep/efsw/src/efsw/FileInfo.hpp b/dep/efsw/src/efsw/FileInfo.hpp new file mode 100644 index 00000000000..45cca6a7953 --- /dev/null +++ b/dep/efsw/src/efsw/FileInfo.hpp @@ -0,0 +1,66 @@ +#ifndef EFSW_FILEINFO_HPP +#define EFSW_FILEINFO_HPP + +#include <efsw/base.hpp> +#include <string> +#include <map> +#include <list> + +namespace efsw { + +class FileInfo +{ + public: + static bool exists( const std::string& filePath ); + + static bool isLink( const std::string& filePath ); + + static bool inodeSupported(); + + FileInfo(); + + FileInfo( const std::string& filepath ); + + FileInfo( const std::string& filepath, bool linkInfo ); + + bool operator==( const FileInfo& Other ) const; + + bool operator!=( const FileInfo& Other ) const; + + FileInfo& operator=( const FileInfo& Other ); + + bool isDirectory(); + + bool isRegularFile(); + + bool isReadable(); + + bool sameInode( const FileInfo& Other ) const; + + bool isLink(); + + std::string linksTo(); + + bool exists(); + + void getInfo(); + + void getRealInfo(); + + std::string Filepath; + Uint64 ModificationTime; + Uint64 Size; + Uint32 OwnerId; + Uint32 GroupId; + Uint32 Permissions; + Uint64 Inode; +}; + +typedef std::map<std::string, FileInfo> FileInfoMap; +typedef std::list<FileInfo> FileInfoList; +typedef std::list< std::pair< std::string, FileInfo> > MovedList; + +} + +#endif + diff --git a/dep/efsw/src/efsw/FileSystem.cpp b/dep/efsw/src/efsw/FileSystem.cpp new file mode 100644 index 00000000000..e3afa0b4046 --- /dev/null +++ b/dep/efsw/src/efsw/FileSystem.cpp @@ -0,0 +1,124 @@ +#include <efsw/FileSystem.hpp> +#include <efsw/platform/platformimpl.hpp> + +#if EFSW_OS == EFSW_OS_MACOSX +#include <CoreFoundation/CoreFoundation.h> +#endif + +namespace efsw { + +bool FileSystem::isDirectory( const std::string& path ) +{ + return Platform::FileSystem::isDirectory( path ); +} + +FileInfoMap FileSystem::filesInfoFromPath( std::string path ) { + dirAddSlashAtEnd( path ); + + return Platform::FileSystem::filesInfoFromPath( path ); +} + +char FileSystem::getOSSlash() +{ + return Platform::FileSystem::getOSSlash(); +} + +bool FileSystem::slashAtEnd( std::string &dir ) +{ + return ( dir.size() && dir[ dir.size() - 1 ] == getOSSlash() ); +} + +void FileSystem::dirAddSlashAtEnd( std::string& dir ) +{ + if ( dir.size() > 1 && dir[ dir.size() - 1 ] != getOSSlash() ) + { + dir.push_back( getOSSlash() ); + } +} + +void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) +{ + if ( dir.size() > 1 && dir[ dir.size() - 1 ] == getOSSlash() ) + { + dir.erase( dir.size() - 1 ); + } +} + +std::string FileSystem::fileNameFromPath( std::string filepath ) +{ + dirRemoveSlashAtEnd( filepath ); + + size_t pos = filepath.find_last_of( getOSSlash() ); + + if ( pos != std::string::npos ) + { + return filepath.substr( pos + 1 ); + } + + return filepath; +} + +std::string FileSystem::pathRemoveFileName( std::string filepath ) +{ + dirRemoveSlashAtEnd( filepath ); + + size_t pos = filepath.find_last_of( getOSSlash() ); + + if ( pos != std::string::npos ) + { + return filepath.substr( 0, pos + 1 ); + } + + return filepath; +} + +std::string FileSystem::getLinkRealPath( std::string dir, std::string& curPath ) +{ + FileSystem::dirRemoveSlashAtEnd( dir ); + FileInfo fi( dir, true ); + + /// Check with lstat and see if it's a link + if ( fi.isLink() ) + { + /// get the real path of the link + std::string link( fi.linksTo() ); + + /// get the current path of the directory without the link dir path + curPath = FileSystem::pathRemoveFileName( dir ); + + /// ensure that ends with the os directory slash + FileSystem::dirAddSlashAtEnd( link ); + + return link; + } + + /// if it's not a link return nothing + return ""; +} + +std::string FileSystem::precomposeFileName( const std::string& name ) +{ +#if EFSW_OS == EFSW_OS_MACOSX + CFStringRef cfStringRef = CFStringCreateWithCString(kCFAllocatorDefault, name.c_str(), kCFStringEncodingUTF8); + CFMutableStringRef cfMutable = CFStringCreateMutableCopy(NULL, 0, cfStringRef); + + CFStringNormalize(cfMutable,kCFStringNormalizationFormC); + + char c_str[255 + 1]; + CFStringGetCString(cfMutable, c_str, sizeof(c_str)-1, kCFStringEncodingUTF8); + + CFRelease(cfStringRef); + CFRelease(cfMutable); + + return std::string(c_str); +#else + return name; +#endif +} + +bool FileSystem::isRemoteFS( const std::string& directory ) +{ + return Platform::FileSystem::isRemoteFS( directory ); +} + +} diff --git a/dep/efsw/src/efsw/FileSystem.hpp b/dep/efsw/src/efsw/FileSystem.hpp new file mode 100644 index 00000000000..4e2e1aeb7cd --- /dev/null +++ b/dep/efsw/src/efsw/FileSystem.hpp @@ -0,0 +1,40 @@ +#ifndef EFSW_FILESYSTEM_HPP +#define EFSW_FILESYSTEM_HPP + +#include <efsw/base.hpp> +#include <efsw/FileInfo.hpp> +#include <map> + +namespace efsw { + +class FileSystem +{ + public: + static bool isDirectory( const std::string& path ); + + static FileInfoMap filesInfoFromPath( std::string path ); + + static char getOSSlash(); + + static bool slashAtEnd( std::string& dir ); + + static void dirAddSlashAtEnd( std::string& dir ); + + static void dirRemoveSlashAtEnd( std::string& dir ); + + static std::string fileNameFromPath( std::string filepath ); + + static std::string pathRemoveFileName( std::string filepath ); + + static void realPath( std::string curdir, std::string& path ); + + static std::string getLinkRealPath( std::string dir, std::string& curPath ); + + static std::string precomposeFileName(const std::string& name); + + static bool isRemoteFS( const std::string& directory ); +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/FileWatcher.cpp b/dep/efsw/src/efsw/FileWatcher.cpp new file mode 100644 index 00000000000..e33d5ec46fb --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcher.cpp @@ -0,0 +1,145 @@ +#include <efsw/efsw.hpp> +#include <efsw/FileWatcherImpl.hpp> +#include <efsw/FileWatcherGeneric.hpp> +#include <efsw/FileSystem.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 +# include <efsw/FileWatcherWin32.hpp> +# define FILEWATCHER_IMPL FileWatcherWin32 +# define BACKEND_NAME "Win32" +#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY +# include <efsw/FileWatcherInotify.hpp> +# define FILEWATCHER_IMPL FileWatcherInotify +# define BACKEND_NAME "Inotify" +#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE +# include <efsw/FileWatcherKqueue.hpp> +# define FILEWATCHER_IMPL FileWatcherKqueue +# define BACKEND_NAME "Kqueue" +#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS +# include <efsw/FileWatcherFSEvents.hpp> +# define FILEWATCHER_IMPL FileWatcherFSEvents +# define BACKEND_NAME "FSEvents" +#else +# define FILEWATCHER_IMPL FileWatcherGeneric +# define BACKEND_NAME "Generic" +#endif + +#include <efsw/Debug.hpp> + +namespace efsw { + +FileWatcher::FileWatcher() : + mFollowSymlinks(false), + mOutOfScopeLinks(false) +{ + efDEBUG( "Using backend: %s\n", BACKEND_NAME ); + + mImpl = new FILEWATCHER_IMPL( this ); + + if ( !mImpl->initOK() ) + { + efSAFE_DELETE( mImpl ); + + efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); + + mImpl = new FileWatcherGeneric( this ); + } +} + +FileWatcher::FileWatcher( bool useGenericFileWatcher ) : + mFollowSymlinks(false), + mOutOfScopeLinks(false) +{ + if ( useGenericFileWatcher ) + { + efDEBUG( "Using backend: Generic\n" ); + + mImpl = new FileWatcherGeneric( this ); + } + else + { + efDEBUG( "Using backend: %s\n", BACKEND_NAME ); + + mImpl = new FILEWATCHER_IMPL( this ); + + if ( !mImpl->initOK() ) + { + efSAFE_DELETE( mImpl ); + + efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); + + mImpl = new FileWatcherGeneric( this ); + } + } +} + +FileWatcher::~FileWatcher() +{ + efSAFE_DELETE( mImpl ); +} + +WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher) +{ + if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) + { + return mImpl->addWatch(directory, watcher, false); + } + else + { + return Errors::Log::createLastError( Errors::FileRemote, directory ); + } +} + +WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) +{ + if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) + { + return mImpl->addWatch(directory, watcher, recursive); + } + else + { + return Errors::Log::createLastError( Errors::FileRemote, directory ); + } +} + +void FileWatcher::removeWatch(const std::string& directory) +{ + mImpl->removeWatch(directory); +} + +void FileWatcher::removeWatch(WatchID watchid) +{ + mImpl->removeWatch(watchid); +} + +void FileWatcher::watch() +{ + mImpl->watch(); +} + +std::list<std::string> FileWatcher::directories() +{ + return mImpl->directories(); +} + +void FileWatcher::followSymlinks( bool follow ) +{ + mFollowSymlinks = follow; +} + +const bool& FileWatcher::followSymlinks() const +{ + return mFollowSymlinks; +} + +void FileWatcher::allowOutOfScopeLinks( bool allow ) +{ + mOutOfScopeLinks = allow; +} + +const bool& FileWatcher::allowOutOfScopeLinks() const +{ + return mOutOfScopeLinks; +} + +} diff --git a/dep/efsw/src/efsw/FileWatcherCWrapper.cpp b/dep/efsw/src/efsw/FileWatcherCWrapper.cpp new file mode 100644 index 00000000000..2739e756bb2 --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherCWrapper.cpp @@ -0,0 +1,132 @@ +#include <efsw/efsw.h> +#include <efsw/efsw.hpp> +#include <vector> + +#define TOBOOL(i) ((i) == 0 ? false : true) + +/*************************************************************************************************/ +class Watcher_CAPI : public efsw::FileWatchListener +{ +public: + efsw_watcher mWatcher; + efsw_pfn_fileaction_callback mFn; + void* mParam; +public: + Watcher_CAPI(efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param) + { + mWatcher = watcher; + mFn = fn; + mParam = param; + } + + void handleFileAction(efsw::WatchID watchid, const std::string& dir, const std::string& filename, + efsw::Action action, std::string oldFilename = "") + { + mFn(mWatcher, watchid, dir.c_str(), filename.c_str(), (enum efsw_action)action, + oldFilename.c_str(), mParam ); + } +}; + +/************************************************************************************************* + * globals + */ +static std::vector<Watcher_CAPI*> g_callbacks; + +Watcher_CAPI* find_callback(efsw_watcher watcher, efsw_pfn_fileaction_callback fn) +{ + for (std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); i++ ) + { + Watcher_CAPI* callback = *i; + + if (callback->mFn == fn && callback->mWatcher == watcher) + return *i; + } + + return NULL; +} + +Watcher_CAPI* remove_callback(efsw_watcher watcher) +{ + std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); + + while (i != g_callbacks.end()) { + Watcher_CAPI* callback = *i; + + if (callback->mWatcher == watcher) + i = g_callbacks.erase(i); + else + i++; + } + + return NULL; +} + + +/*************************************************************************************************/ +efsw_watcher efsw_create(int generic_mode) +{ + return (efsw_watcher)new efsw::FileWatcher(TOBOOL(generic_mode)); +} + +void efsw_release(efsw_watcher watcher) +{ + remove_callback(watcher); + delete (efsw::FileWatcher*)watcher; +} + +const char* efsw_getlasterror() +{ + static std::string log_str; + log_str = efsw::Errors::Log::getLastErrorLog(); + return log_str.c_str(); +} + +efsw_watchid efsw_addwatch(efsw_watcher watcher, const char* directory, + efsw_pfn_fileaction_callback callback_fn, int recursive, void * param) +{ + Watcher_CAPI* callback = find_callback(watcher, callback_fn); + + if (callback == NULL) { + callback = new Watcher_CAPI(watcher, callback_fn, param); + g_callbacks.push_back(callback); + } + + return ((efsw::FileWatcher*)watcher)->addWatch(std::string(directory), callback, + TOBOOL(recursive)); +} + +void efsw_removewatch(efsw_watcher watcher, const char* directory) +{ + ((efsw::FileWatcher*)watcher)->removeWatch(std::string(directory)); +} + +void efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid) +{ + ((efsw::FileWatcher*)watcher)->removeWatch(watchid); +} + +void efsw_watch(efsw_watcher watcher) +{ + ((efsw::FileWatcher*)watcher)->watch(); +} + +void efsw_follow_symlinks(efsw_watcher watcher, int enable) +{ + ((efsw::FileWatcher*)watcher)->followSymlinks(TOBOOL(enable)); +} + +int efsw_follow_symlinks_isenabled(efsw_watcher watcher) +{ + return (int)((efsw::FileWatcher*)watcher)->followSymlinks(); +} + +void efsw_allow_outofscopelinks(efsw_watcher watcher, int allow) +{ + ((efsw::FileWatcher*)watcher)->allowOutOfScopeLinks(TOBOOL(allow)); +} + +int efsw_outofscopelinks_isallowed(efsw_watcher watcher) +{ + return (int)((efsw::FileWatcher*)watcher)->allowOutOfScopeLinks(); +} + diff --git a/dep/efsw/src/efsw/FileWatcherFSEvents.cpp b/dep/efsw/src/efsw/FileWatcherFSEvents.cpp new file mode 100644 index 00000000000..40156674132 --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherFSEvents.cpp @@ -0,0 +1,278 @@ +#include <efsw/FileWatcherFSEvents.hpp> +#include <efsw/FileSystem.hpp> +#include <efsw/System.hpp> +#include <efsw/Debug.hpp> +#include <efsw/String.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS + +#include <sys/utsname.h> + +namespace efsw +{ + +int getOSXReleaseNumber() +{ + static int osxR = -1; + + if ( -1 == osxR ) + { + struct utsname os; + + if ( -1 != uname( &os ) ) { + std::string release( os.release ); + + size_t pos = release.find_first_of( '.' ); + + if ( pos != std::string::npos ) + { + release = release.substr( 0, pos ); + } + + int rel = 0; + + if ( String::fromString<int>( rel, release ) ) + { + osxR = rel; + } + } + } + + return osxR; +} + +bool FileWatcherFSEvents::isGranular() +{ + return getOSXReleaseNumber() >= 11; +} + +void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef, + void *userData, + size_t numEvents, + void *eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[] ) +{ + WatcherFSEvents * watcher = static_cast<WatcherFSEvents*>( userData ); + + std::vector<FSEvent> events; + events.reserve( numEvents ); + + for ( size_t i = 0; i < numEvents; i++ ) + { + events.push_back( FSEvent( std::string( ((char**)eventPaths)[i] ), (long)eventFlags[i], (Uint64)eventIds[i] ) ); + } + + watcher->handleActions( events ); + + watcher->process(); + + efDEBUG( "\n" ); +} + +FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher * parent ) : + FileWatcherImpl( parent ), + mRunLoopRef( NULL ), + mLastWatchID(0), + mThread( NULL ) +{ + mInitOK = true; + + watch(); +} + +FileWatcherFSEvents::~FileWatcherFSEvents() +{ + WatchMap::iterator iter = mWatches.begin(); + + for( ; iter != mWatches.end(); ++iter ) + { + WatcherFSEvents * watch = iter->second; + + efSAFE_DELETE( watch ); + } + + mWatches.clear(); + + mInitOK = false; + + if ( NULL != mRunLoopRef ) + { + CFRunLoopStop( mRunLoopRef ); + } + + efSAFE_DELETE( mThread ); +} + +WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ) +{ + /// Wait to the RunLoopRef to be ready + while ( NULL == mRunLoopRef ) + { + System::sleep( 1 ); + } + + std::string dir( directory ); + + FileInfo fi( dir ); + + if ( !fi.isDirectory() ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + else if ( !fi.isReadable() ) + { + return Errors::Log::createLastError( Errors::FileNotReadable, dir ); + } + + FileSystem::dirAddSlashAtEnd( dir ); + + if ( pathInWatches( dir ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, directory ); + } + + /// Check if the directory is a symbolic link + std::string curPath; + std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); + + if ( "" != link ) + { + /// If it's a symlink check if the realpath exists as a watcher, or + /// if the path is outside the current dir + if ( pathInWatches( link ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, directory ); + } + else if ( !linkAllowed( curPath, link ) ) + { + return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); + } + else + { + dir = link; + } + } + + mLastWatchID++; + + WatcherFSEvents * pWatch = new WatcherFSEvents(); + pWatch->Listener = watcher; + pWatch->ID = mLastWatchID; + pWatch->Directory = dir; + pWatch->Recursive = recursive; + pWatch->FWatcher = this; + + pWatch->init(); + + mWatchesLock.lock(); + mWatches.insert(std::make_pair(mLastWatchID, pWatch)); + mWatchesLock.unlock(); + + return pWatch->ID; +} + +void FileWatcherFSEvents::removeWatch(const std::string& directory) +{ + mWatchesLock.lock(); + + WatchMap::iterator iter = mWatches.begin(); + + for(; iter != mWatches.end(); ++iter) + { + if( directory == iter->second->Directory ) + { + removeWatch( iter->second->ID ); + return; + } + } + + mWatchesLock.unlock(); +} + +void FileWatcherFSEvents::removeWatch(WatchID watchid) +{ + mWatchesLock.lock(); + + WatchMap::iterator iter = mWatches.find( watchid ); + + if( iter == mWatches.end() ) + return; + + WatcherFSEvents * watch = iter->second; + + mWatches.erase( iter ); + + efDEBUG( "Removed watch %s\n", watch->Directory.c_str() ); + + efSAFE_DELETE( watch ); + + mWatchesLock.unlock(); +} + +void FileWatcherFSEvents::watch() +{ + if ( NULL == mThread ) + { + mThread = new Thread( &FileWatcherFSEvents::run, this ); + mThread->launch(); + } +} + +void FileWatcherFSEvents::run() +{ + mRunLoopRef = CFRunLoopGetCurrent(); + + while ( mInitOK ) + { + if ( !mNeedInit.empty() ) + { + for ( std::list<WatcherFSEvents*>::iterator it = mNeedInit.begin(); it != mNeedInit.end(); it++ ) + { + (*it)->initAsync(); + } + + mNeedInit.clear(); + } + + CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut ); + } +} + +void FileWatcherFSEvents::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename) +{ + /// Not used +} + +std::list<std::string> FileWatcherFSEvents::directories() +{ + std::list<std::string> dirs; + + mWatchesLock.lock(); + + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + dirs.push_back( std::string( it->second->Directory ) ); + } + + mWatchesLock.unlock(); + + return dirs; +} + +bool FileWatcherFSEvents::pathInWatches( const std::string& path ) +{ + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + if ( it->second->Directory == path ) + { + return true; + } + } + + return false; +} + +} + +#endif diff --git a/dep/efsw/src/efsw/FileWatcherFSEvents.hpp b/dep/efsw/src/efsw/FileWatcherFSEvents.hpp new file mode 100644 index 00000000000..6aafbc0b5ea --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherFSEvents.hpp @@ -0,0 +1,107 @@ +#ifndef EFSW_FILEWATCHERFSEVENTS_HPP +#define EFSW_FILEWATCHERFSEVENTS_HPP + +#include <efsw/FileWatcherImpl.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS + +#include <CoreFoundation/CoreFoundation.h> +#include <CoreServices/CoreServices.h> +#include <efsw/WatcherFSEvents.hpp> +#include <map> +#include <list> +#include <vector> + +namespace efsw +{ + +/* OSX < 10.7 has no file events */ +/* So i declare the events constants */ +enum FSEventEvents +{ + efswFSEventStreamCreateFlagFileEvents = 0x00000010, + efswFSEventStreamEventFlagItemCreated = 0x00000100, + efswFSEventStreamEventFlagItemRemoved = 0x00000200, + efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, + efswFSEventStreamEventFlagItemRenamed = 0x00000800, + efswFSEventStreamEventFlagItemModified = 0x00001000, + efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, + efswFSEventStreamEventFlagItemChangeOwner = 0x00004000, + efswFSEventStreamEventFlagItemXattrMod = 0x00008000, + efswFSEventStreamEventFlagItemIsFile = 0x00010000, + efswFSEventStreamEventFlagItemIsDir = 0x00020000, + efswFSEventStreamEventFlagItemIsSymlink = 0x00040000, + efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod | + efswFSEventStreamEventFlagItemModified | + efswFSEventStreamEventFlagItemInodeMetaMod | + efswFSEventStreamEventFlagItemChangeOwner | + efswFSEventStreamEventFlagItemXattrMod +}; + +/// Implementation for Win32 based on ReadDirectoryChangesW. +/// @class FileWatcherFSEvents +class FileWatcherFSEvents : public FileWatcherImpl +{ + friend class WatcherFSEvents; + public: + /// @return If FSEvents supports file-level notifications ( true if OS X >= 10.7 ) + static bool isGranular(); + + /// type for a map from WatchID to WatcherWin32 pointer + typedef std::map<WatchID, WatcherFSEvents*> WatchMap; + + FileWatcherFSEvents( FileWatcher * parent ); + + virtual ~FileWatcherFSEvents(); + + /// Add a directory watch + /// On error returns WatchID with Error type. + WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); + + /// Remove a directory watch. This is a brute force lazy search O(nlogn). + void removeWatch(const std::string& directory); + + /// Remove a directory watch. This is a map lookup O(logn). + void removeWatch(WatchID watchid); + + /// Updates the watcher. Must be called often. + void watch(); + + /// Handles the action + void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); + + /// @return Returns a list of the directories that are being watched + std::list<std::string> directories(); + protected: + static void FSEventCallback( ConstFSEventStreamRef streamRef, + void *userData, + size_t numEvents, + void *eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[] + ); + + CFRunLoopRef mRunLoopRef; + + /// Vector of WatcherWin32 pointers + WatchMap mWatches; + + /// The last watchid + WatchID mLastWatchID; + + Thread * mThread; + + Mutex mWatchesLock; + + bool pathInWatches( const std::string& path ); + + std::list<WatcherFSEvents*> mNeedInit; + private: + void run(); +}; + +} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/FileWatcherGeneric.cpp b/dep/efsw/src/efsw/FileWatcherGeneric.cpp new file mode 100644 index 00000000000..1534b6a9279 --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherGeneric.cpp @@ -0,0 +1,197 @@ +#include <efsw/FileWatcherGeneric.hpp> +#include <efsw/FileSystem.hpp> +#include <efsw/System.hpp> + +namespace efsw +{ + +FileWatcherGeneric::FileWatcherGeneric( FileWatcher * parent ) : + FileWatcherImpl( parent ), + mThread( NULL ), + mLastWatchID( 0 ) +{ + mInitOK = true; + mIsGeneric = true; +} + +FileWatcherGeneric::~FileWatcherGeneric() +{ + mInitOK = false; + + mThread->wait(); + + efSAFE_DELETE( mThread ); + + /// Delete the watches + WatchList::iterator it = mWatches.begin(); + + for ( ; it != mWatches.end(); it++ ) + { + efSAFE_DELETE( (*it) ); + } +} + +WatchID FileWatcherGeneric::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) +{ + std::string dir( directory ); + + FileSystem::dirAddSlashAtEnd( dir ); + + FileInfo fi( dir ); + + if ( !fi.isDirectory() ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + else if ( !fi.isReadable() ) + { + return Errors::Log::createLastError( Errors::FileNotReadable, dir ); + } + else if ( pathInWatches( dir ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, dir ); + } + + std::string curPath; + std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); + + if ( "" != link ) + { + if ( pathInWatches( link ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, dir ); + } + else if ( !linkAllowed( curPath, link ) ) + { + return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); + } + else + { + dir = link; + } + } + + mLastWatchID++; + + WatcherGeneric * pWatch = new WatcherGeneric( mLastWatchID, dir, watcher, this, recursive ); + + mWatchesLock.lock(); + mWatches.push_back(pWatch); + mWatchesLock.unlock(); + + return pWatch->ID; +} + +void FileWatcherGeneric::removeWatch( const std::string& directory ) +{ + WatchList::iterator it = mWatches.begin(); + + for ( ; it != mWatches.end(); it++ ) + { + if ( (*it)->Directory == directory ) + { + WatcherGeneric * watch = (*it); + + mWatchesLock.lock(); + + mWatches.erase( it ); + + efSAFE_DELETE( watch ) ; + + mWatchesLock.unlock(); + + return; + } + } +} + +void FileWatcherGeneric::removeWatch(WatchID watchid) +{ + WatchList::iterator it = mWatches.begin(); + + for ( ; it != mWatches.end(); it++ ) + { + if ( (*it)->ID == watchid ) + { + WatcherGeneric * watch = (*it); + + mWatchesLock.lock(); + + mWatches.erase( it ); + + efSAFE_DELETE( watch ) ; + + mWatchesLock.unlock(); + + return; + } + } +} + +void FileWatcherGeneric::watch() +{ + if ( NULL == mThread ) + { + mThread = new Thread( &FileWatcherGeneric::run, this ); + mThread->launch(); + } +} + +void FileWatcherGeneric::run() +{ + do + { + mWatchesLock.lock(); + + WatchList::iterator it = mWatches.begin(); + + for ( ; it != mWatches.end(); it++ ) + { + (*it)->watch(); + } + + mWatchesLock.unlock(); + + if ( mInitOK ) System::sleep( 1000 ); + } while ( mInitOK ); +} + +void FileWatcherGeneric::handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename) +{ + /// Not used +} + +std::list<std::string> FileWatcherGeneric::directories() +{ + std::list<std::string> dirs; + + mWatchesLock.lock(); + + WatchList::iterator it = mWatches.begin(); + + for ( ; it != mWatches.end(); it++ ) + { + dirs.push_back( (*it)->Directory ); + } + + mWatchesLock.unlock(); + + return dirs; +} + +bool FileWatcherGeneric::pathInWatches( const std::string& path ) +{ + WatchList::iterator it = mWatches.begin(); + + for ( ; it != mWatches.end(); it++ ) + { + if ( (*it)->Directory == path || (*it)->pathInWatches( path ) ) + { + return true; + } + } + + return false; +} + +} diff --git a/dep/efsw/src/efsw/FileWatcherGeneric.hpp b/dep/efsw/src/efsw/FileWatcherGeneric.hpp new file mode 100644 index 00000000000..fc9826580ab --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherGeneric.hpp @@ -0,0 +1,59 @@ +#ifndef EFSW_FILEWATCHERGENERIC_HPP +#define EFSW_FILEWATCHERGENERIC_HPP + +#include <efsw/FileWatcherImpl.hpp> +#include <efsw/WatcherGeneric.hpp> +#include <efsw/DirWatcherGeneric.hpp> +#include <list> + +namespace efsw +{ + +/// Implementation for Generic File Watcher. +/// @class FileWatcherGeneric +class FileWatcherGeneric : public FileWatcherImpl +{ + public: + typedef std::list<WatcherGeneric*> WatchList; + + FileWatcherGeneric( FileWatcher * parent ); + + virtual ~FileWatcherGeneric(); + + /// Add a directory watch + /// On error returns WatchID with Error type. + WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); + + /// Remove a directory watch. This is a brute force lazy search O(nlogn). + void removeWatch(const std::string& directory); + + /// Remove a directory watch. This is a map lookup O(logn). + void removeWatch(WatchID watchid); + + /// Updates the watcher. Must be called often. + void watch(); + + /// Handles the action + void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); + + /// @return Returns a list of the directories that are being watched + std::list<std::string> directories(); + protected: + Thread * mThread; + + /// The last watchid + WatchID mLastWatchID; + + /// Map of WatchID to WatchStruct pointers + WatchList mWatches; + + Mutex mWatchesLock; + + bool pathInWatches( const std::string& path ); + private: + void run(); +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/FileWatcherImpl.cpp b/dep/efsw/src/efsw/FileWatcherImpl.cpp new file mode 100644 index 00000000000..e6e0fc72a13 --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherImpl.cpp @@ -0,0 +1,29 @@ +#include <efsw/FileWatcherImpl.hpp> +#include <efsw/String.hpp> +#include <efsw/System.hpp> + +namespace efsw { + +FileWatcherImpl::FileWatcherImpl( FileWatcher * parent ) : + mFileWatcher( parent ), + mInitOK( false ), + mIsGeneric( false ) +{ + System::maxFD(); +} + +FileWatcherImpl::~FileWatcherImpl() +{ +} + +bool FileWatcherImpl::initOK() +{ + return mInitOK; +} + +bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) +{ + return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || -1 != String::strStartsWith( curPath, link ); +} + +} diff --git a/dep/efsw/src/efsw/FileWatcherImpl.hpp b/dep/efsw/src/efsw/FileWatcherImpl.hpp new file mode 100644 index 00000000000..8f472bf56c5 --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherImpl.hpp @@ -0,0 +1,54 @@ +#ifndef EFSW_FILEWATCHERIMPL_HPP +#define EFSW_FILEWATCHERIMPL_HPP + +#include <efsw/base.hpp> +#include <efsw/efsw.hpp> +#include <efsw/Watcher.hpp> +#include <efsw/Thread.hpp> +#include <efsw/Mutex.hpp> + +namespace efsw { + +class FileWatcherImpl +{ + public: + FileWatcherImpl( FileWatcher * parent ); + + virtual ~FileWatcherImpl(); + + /// Add a directory watch + /// On error returns WatchID with Error type. + virtual WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) = 0; + + /// Remove a directory watch. This is a brute force lazy search O(nlogn). + virtual void removeWatch(const std::string& directory) = 0; + + /// Remove a directory watch. This is a map lookup O(logn). + virtual void removeWatch(WatchID watchid) = 0; + + /// Updates the watcher. Must be called often. + virtual void watch() = 0; + + /// Handles the action + virtual void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "") = 0; + + /// @return Returns a list of the directories that are being watched + virtual std::list<std::string> directories() = 0; + + /// @return true if the backend init successfully + virtual bool initOK(); + + /// @return If the link is allowed according to the current path and the state of out scope links + virtual bool linkAllowed( const std::string& curPath, const std::string& link ); + + /// Search if a directory already exists in the watches + virtual bool pathInWatches( const std::string& path ) = 0; + + FileWatcher * mFileWatcher; + bool mInitOK; + bool mIsGeneric; +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/FileWatcherInotify.cpp b/dep/efsw/src/efsw/FileWatcherInotify.cpp new file mode 100644 index 00000000000..19c20761663 --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherInotify.cpp @@ -0,0 +1,531 @@ +#include <efsw/FileWatcherInotify.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY + +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + +#ifdef EFSW_INOTIFY_NOSYS +#include <efsw/inotify-nosys.h> +#else +#include <sys/inotify.h> +#endif + +#include <efsw/FileSystem.hpp> +#include <efsw/System.hpp> +#include <efsw/Debug.hpp> + +#define BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024) + +namespace efsw +{ + +FileWatcherInotify::FileWatcherInotify( FileWatcher * parent ) : + FileWatcherImpl( parent ), + mFD(-1), + mThread(NULL) +{ + mFD = inotify_init(); + + if (mFD < 0) + { + efDEBUG( "Error: %s\n", strerror(errno) ); + } + else + { + mInitOK = true; + } +} + +FileWatcherInotify::~FileWatcherInotify() +{ + mInitOK = false; + + efSAFE_DELETE( mThread ); + + WatchMap::iterator iter = mWatches.begin(); + WatchMap::iterator end = mWatches.end(); + + for(; iter != end; ++iter) + { + efSAFE_DELETE( iter->second ); + } + + mWatches.clear(); + + if ( mFD != -1 ) + { + close(mFD); + mFD = -1; + } +} + +WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ) +{ + return addWatch( directory, watcher, recursive, NULL ); +} + +WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent ) +{ + std::string dir( directory ); + + FileSystem::dirAddSlashAtEnd( dir ); + + FileInfo fi( dir ); + + if ( !fi.isDirectory() ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + else if ( !fi.isReadable() ) + { + return Errors::Log::createLastError( Errors::FileNotReadable, dir ); + } + else if ( pathInWatches( dir ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, directory ); + } + else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) + { + return Errors::Log::createLastError( Errors::FileRemote, dir ); + } + + /// Check if the directory is a symbolic link + std::string curPath; + std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); + + if ( "" != link ) + { + /// Avoid adding symlinks directories if it's now enabled + if ( NULL != parent && !mFileWatcher->followSymlinks() ) + { + return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); + } + + /// If it's a symlink check if the realpath exists as a watcher, or + /// if the path is outside the current dir + if ( pathInWatches( link ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, directory ); + } + else if ( !linkAllowed( curPath, link ) ) + { + return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); + } + else + { + dir = link; + } + } + + int wd = inotify_add_watch (mFD, dir.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE | IN_MODIFY); + + if ( wd < 0 ) + { + if( errno == ENOENT ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + else + { + return Errors::Log::createLastError( Errors::Unspecified, std::string(strerror(errno)) ); + } + } + + efDEBUG( "Added watch %s with id: %d\n", dir.c_str(), wd ); + + WatcherInotify * pWatch = new WatcherInotify(); + pWatch->Listener = watcher; + pWatch->ID = wd; + pWatch->Directory = dir; + pWatch->Recursive = recursive; + pWatch->Parent = parent; + + mWatchesLock.lock(); + mWatches.insert(std::make_pair(wd, pWatch)); + mWatchesLock.unlock(); + + if ( NULL == pWatch->Parent ) + { + mRealWatches[ pWatch->ID ] = pWatch; + } + + if ( pWatch->Recursive ) + { + std::map<std::string, FileInfo> files = FileSystem::filesInfoFromPath( pWatch->Directory ); + std::map<std::string, FileInfo>::iterator it = files.begin(); + + for ( ; it != files.end(); it++ ) + { + FileInfo fi = it->second; + + if ( fi.isDirectory() && fi.isReadable() ) + { + addWatch( fi.Filepath, watcher, recursive, pWatch ); + } + } + } + + return wd; +} + +void FileWatcherInotify::removeWatchLocked(WatchID watchid) +{ + WatchMap::iterator iter = mWatches.find( watchid ); + + WatcherInotify * watch = iter->second; + + if ( watch->Recursive ) + { + WatchMap::iterator it = mWatches.begin(); + std::list<WatchID> eraseWatches; + + for(; it != mWatches.end(); ++it) + { + if ( it->second != watch && + it->second->inParentTree( watch ) + ) + { + eraseWatches.push_back( it->second->ID ); + } + } + + for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); eit++ ) + { + removeWatch( *eit ); + } + } + + mWatches.erase( iter ); + + if ( NULL == watch->Parent ) + { + WatchMap::iterator eraseit = mRealWatches.find( watch->ID ); + + if ( eraseit != mRealWatches.end() ) + { + mRealWatches.erase( eraseit ); + } + } + + int err = inotify_rm_watch(mFD, watchid); + + if ( err < 0 ) + { + efDEBUG( "Error removing watch %d: %s\n", watchid, strerror(errno) ); + } + else + { + efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watchid ); + } + + efSAFE_DELETE( watch ); +} + +void FileWatcherInotify::removeWatch(const std::string& directory) +{ + mWatchesLock.lock(); + + WatchMap::iterator iter = mWatches.begin(); + + for(; iter != mWatches.end(); ++iter) + { + if( directory == iter->second->Directory ) + { + WatcherInotify * watch = iter->second; + + if ( watch->Recursive ) + { + WatchMap::iterator it = mWatches.begin(); + std::list<WatchID> eraseWatches; + + for(; it != mWatches.end(); ++it) + { + if ( it->second->inParentTree( watch ) ) + { + eraseWatches.push_back( it->second->ID ); + } + } + + for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); eit++ ) + { + removeWatchLocked( *eit ); + } + } + + mWatches.erase( iter ); + + if ( NULL == watch->Parent ) + { + WatchMap::iterator eraseit = mRealWatches.find( watch->ID ); + + if ( eraseit != mRealWatches.end() ) + { + mRealWatches.erase( eraseit ); + } + } + + int err = inotify_rm_watch(mFD, watch->ID); + + if ( err < 0 ) + { + efDEBUG( "Error removing watch %d: %s\n", watch->ID, strerror(errno) ); + } + else + { + efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watch->ID ); + } + + efSAFE_DELETE( watch ); + + break; + } + } + + mWatchesLock.unlock(); +} + +void FileWatcherInotify::removeWatch( WatchID watchid ) +{ + mWatchesLock.lock(); + + WatchMap::iterator iter = mWatches.find( watchid ); + + if( iter == mWatches.end() ) + { + mWatchesLock.unlock(); + + return; + } + + removeWatchLocked( watchid ); + + mWatchesLock.unlock(); +} + +void FileWatcherInotify::watch() +{ + if ( NULL == mThread ) + { + mThread = new Thread( &FileWatcherInotify::run, this ); + mThread->launch(); + } +} + +void FileWatcherInotify::run() +{ + static char buff[BUFF_SIZE] = {0}; + WatchMap::iterator wit; + std::list<WatcherInotify*> movedOutsideWatches; + + do + { + fd_set rfds; + FD_ZERO (&rfds); + FD_SET (mFD, &rfds); + timeval timeout; + timeout.tv_sec=0; + timeout.tv_usec=100000; + + if( select (FD_SETSIZE, &rfds, NULL, NULL, &timeout) > 0 ) + { + ssize_t len, i = 0; + + len = read (mFD, buff, BUFF_SIZE); + + if (len != -1) + { + while (i < len) + { + struct inotify_event *pevent = (struct inotify_event *)&buff[i]; + + mWatchesLock.lock(); + + wit = mWatches.find( pevent->wd ); + + if ( wit != mWatches.end() ) + { + handleAction(wit->second, pevent->name, pevent->mask); + + /// Keep track of the IN_MOVED_FROM events to known if the IN_MOVED_TO event is also fired + if ( !wit->second->OldFileName.empty() ) + { + movedOutsideWatches.push_back( wit->second ); + } + } + + mWatchesLock.unlock(); + + i += sizeof(struct inotify_event) + pevent->len; + } + + if ( !movedOutsideWatches.empty() ) + { + /// In case that the IN_MOVED_TO is never fired means that the file was moved to other folder + for ( std::list<WatcherInotify*>::iterator it = movedOutsideWatches.begin(); it != movedOutsideWatches.end(); it++ ) + { + if ( !(*it)->OldFileName.empty() ) + { + /// So we send a IN_DELETE event for files that where moved outside of our scope + handleAction( *it, (*it)->OldFileName, IN_DELETE ); + + /// Remove the OldFileName + (*it)->OldFileName = ""; + } + } + + movedOutsideWatches.clear(); + } + } + } + } while( mInitOK ); +} + +void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath ) +{ + FileSystem::dirAddSlashAtEnd( fpath ); + + /// If the watcher is recursive, checks if the new file is a folder, and creates a watcher + if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) + { + bool found = false; + + /// First check if exists + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + if ( it->second->Directory == fpath ) + { + found = true; + break; + } + } + + if ( !found ) + { + addWatch( fpath, watch->Listener, watch->Recursive, static_cast<WatcherInotify*>( watch ) ); + } + } +} + +void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename ) +{ + if ( !watch || !watch->Listener ) + { + return; + } + + std::string fpath( watch->Directory + filename ); + + if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) ) + { + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified ); + } + else if( IN_MOVED_TO & action ) + { + /// If OldFileName doesn't exist means that the file has been moved from other folder, so we just send the Add event + if ( watch->OldFileName.empty() ) + { + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add ); + + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified ); + + checkForNewWatcher( watch, fpath ); + } + else + { + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Moved, watch->OldFileName ); + } + + if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) + { + /// Update the new directory path + std::string opath( watch->Directory + watch->OldFileName ); + FileSystem::dirAddSlashAtEnd( opath ); + FileSystem::dirAddSlashAtEnd( fpath ); + + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + if ( it->second->Directory == opath && it->second->DirInfo.Inode == FileInfo( opath ).Inode ) + { + it->second->Directory = fpath; + it->second->DirInfo = FileInfo( fpath ); + + break; + } + } + } + + watch->OldFileName = ""; + } + else if( IN_CREATE & action ) + { + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add ); + + checkForNewWatcher( watch, fpath ); + } + else if ( IN_MOVED_FROM & action ) + { + watch->OldFileName = filename; + } + else if( IN_DELETE & action ) + { + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Delete ); + + FileSystem::dirAddSlashAtEnd( fpath ); + + /// If the file erased is a directory and recursive is enabled, removes the directory erased + if ( watch->Recursive ) + { + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + if ( it->second->Directory == fpath ) + { + removeWatch( it->second->ID ); + break; + } + } + } + } +} + +std::list<std::string> FileWatcherInotify::directories() +{ + std::list<std::string> dirs; + + mWatchesLock.lock(); + + WatchMap::iterator it = mRealWatches.begin(); + + for ( ; it != mRealWatches.end(); it++ ) + { + dirs.push_back( it->second->Directory ); + } + + mWatchesLock.unlock(); + + return dirs; +} + +bool FileWatcherInotify::pathInWatches( const std::string& path ) +{ + /// Search in the real watches, since it must allow adding a watch already watched as a subdir + WatchMap::iterator it = mRealWatches.begin(); + + for ( ; it != mRealWatches.end(); it++ ) + { + if ( it->second->Directory == path ) + { + return true; + } + } + + return false; +} + +} + +#endif diff --git a/dep/efsw/src/efsw/FileWatcherInotify.hpp b/dep/efsw/src/efsw/FileWatcherInotify.hpp new file mode 100644 index 00000000000..43ee9ca6afc --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherInotify.hpp @@ -0,0 +1,73 @@ +#ifndef EFSW_FILEWATCHERLINUX_HPP +#define EFSW_FILEWATCHERLINUX_HPP + +#include <efsw/FileWatcherImpl.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY + +#include <efsw/WatcherInotify.hpp> +#include <map> + +namespace efsw +{ + +/// Implementation for Linux based on inotify. +/// @class FileWatcherInotify +class FileWatcherInotify : public FileWatcherImpl +{ + public: + /// type for a map from WatchID to WatchStruct pointer + typedef std::map<WatchID, WatcherInotify*> WatchMap; + + FileWatcherInotify( FileWatcher * parent ); + + virtual ~FileWatcherInotify(); + + /// Add a directory watch + /// On error returns WatchID with Error type. + WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); + + /// Remove a directory watch. This is a brute force lazy search O(nlogn). + void removeWatch(const std::string& directory); + + /// Remove a directory watch. This is a map lookup O(logn). + void removeWatch(WatchID watchid); + + /// Updates the watcher. Must be called often. + void watch(); + + /// Handles the action + void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); + + /// @return Returns a list of the directories that are being watched + std::list<std::string> directories(); + protected: + /// Map of WatchID to WatchStruct pointers + WatchMap mWatches; + + /// User added watches + WatchMap mRealWatches; + + /// inotify file descriptor + int mFD; + + Thread * mThread; + + Mutex mWatchesLock; + + WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent = NULL ); + + bool pathInWatches( const std::string& path ); + private: + void run(); + + void removeWatchLocked(WatchID watchid); + + void checkForNewWatcher( Watcher* watch, std::string fpath ); +}; + +} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/FileWatcherKqueue.cpp b/dep/efsw/src/efsw/FileWatcherKqueue.cpp new file mode 100644 index 00000000000..600fd085b35 --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherKqueue.cpp @@ -0,0 +1,274 @@ +#include <efsw/FileWatcherKqueue.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS + +#include <sys/time.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <string.h> +#include <efsw/FileSystem.hpp> +#include <efsw/System.hpp> +#include <efsw/Debug.hpp> +#include <efsw/WatcherGeneric.hpp> + +namespace efsw +{ + +FileWatcherKqueue::FileWatcherKqueue( FileWatcher * parent ) : + FileWatcherImpl( parent ), + mLastWatchID(0), + mThread( NULL ), + mFileDescriptorCount( 1 ), + mAddingWatcher( false ) +{ + mTimeOut.tv_sec = 0; + mTimeOut.tv_nsec = 0; + mInitOK = true; +} + +FileWatcherKqueue::~FileWatcherKqueue() +{ + WatchMap::iterator iter = mWatches.begin(); + + for(; iter != mWatches.end(); ++iter) + { + efSAFE_DELETE( iter->second ); + } + + mWatches.clear(); + + mInitOK = false; + + mThread->wait(); + + efSAFE_DELETE( mThread ); +} + +WatchID FileWatcherKqueue::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) +{ + static bool s_ug = false; + + std::string dir( directory ); + + FileSystem::dirAddSlashAtEnd( dir ); + + FileInfo fi( dir ); + + if ( !fi.isDirectory() ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + else if ( !fi.isReadable() ) + { + return Errors::Log::createLastError( Errors::FileNotReadable, dir ); + } + else if ( pathInWatches( dir ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, directory ); + } + + std::string curPath; + std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); + + if ( "" != link ) + { + if ( pathInWatches( link ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, directory ); + } + else if ( !linkAllowed( curPath, link ) ) + { + return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); + } + else + { + dir = link; + } + } + + /// Check first if are enough file descriptors available to create another kqueue watcher, otherwise it creates a generic watcher + if ( availablesFD() ) + { + mAddingWatcher = true; + + WatcherKqueue * watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this ); + + mWatchesLock.lock(); + mWatches.insert(std::make_pair(mLastWatchID, watch)); + mWatchesLock.unlock(); + + watch->addAll(); + + // if failed to open the directory... erase the watcher + if ( !watch->initOK() ) + { + int le = watch->lastErrno(); + + mWatches.erase( watch->ID ); + + efSAFE_DELETE( watch ); + + mLastWatchID--; + + // Probably the folder has too many files, create a generic watcher + if ( EACCES != le ) + { + WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); + + mWatchesLock.lock(); + mWatches.insert(std::make_pair(mLastWatchID, watch)); + mWatchesLock.unlock(); + } + else + { + return Errors::Log::createLastError( Errors::Unspecified, link ); + } + } + + mAddingWatcher = false; + } + else + { + if ( !s_ug ) + { + efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n", mFileDescriptorCount ); + s_ug = true; + } + + WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); + + mWatchesLock.lock(); + mWatches.insert(std::make_pair(mLastWatchID, watch)); + mWatchesLock.unlock(); + } + + return mLastWatchID; +} + +void FileWatcherKqueue::removeWatch(const std::string& directory) +{ + mWatchesLock.lock(); + + WatchMap::iterator iter = mWatches.begin(); + + for(; iter != mWatches.end(); ++iter) + { + if(directory == iter->second->Directory) + { + removeWatch(iter->first); + return; + } + } + + mWatchesLock.unlock(); +} + +void FileWatcherKqueue::removeWatch(WatchID watchid) +{ + mWatchesLock.lock(); + + WatchMap::iterator iter = mWatches.find(watchid); + + if(iter == mWatches.end()) + return; + + Watcher* watch = iter->second; + + mWatches.erase(iter); + + efSAFE_DELETE( watch ); + + mWatchesLock.unlock(); +} + +bool FileWatcherKqueue::isAddingWatcher() const +{ + return mAddingWatcher; +} + +void FileWatcherKqueue::watch() +{ + if ( NULL == mThread ) + { + mThread = new Thread( &FileWatcherKqueue::run, this ); + mThread->launch(); + } +} + +void FileWatcherKqueue::run() +{ + do + { + mWatchesLock.lock(); + + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) + { + it->second->watch(); + } + + mWatchesLock.unlock(); + + System::sleep( 500 ); + } while( mInitOK ); +} + +void FileWatcherKqueue::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename) +{ +} + +std::list<std::string> FileWatcherKqueue::directories() +{ + std::list<std::string> dirs; + + mWatchesLock.lock(); + + WatchMap::iterator it = mWatches.begin(); + + for ( ; it != mWatches.end(); it++ ) + { + dirs.push_back( it->second->Directory ); + } + + mWatchesLock.unlock(); + + return dirs; +} + +bool FileWatcherKqueue::pathInWatches( const std::string& path ) +{ + WatchMap::iterator it = mWatches.begin(); + + for ( ; it != mWatches.end(); it++ ) + { + if ( it->second->Directory == path ) + { + return true; + } + } + + return false; +} + +void FileWatcherKqueue::addFD() +{ + mFileDescriptorCount++; +} + +void FileWatcherKqueue::removeFD() +{ + mFileDescriptorCount--; +} + +bool FileWatcherKqueue::availablesFD() +{ + return mFileDescriptorCount <= (Int64)System::getMaxFD() - 500; +} + +} + +#endif diff --git a/dep/efsw/src/efsw/FileWatcherKqueue.hpp b/dep/efsw/src/efsw/FileWatcherKqueue.hpp new file mode 100644 index 00000000000..0a2431e3777 --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherKqueue.hpp @@ -0,0 +1,78 @@ +#ifndef EFSW_FILEWATCHEROSX_HPP +#define EFSW_FILEWATCHEROSX_HPP + +#include <efsw/FileWatcherImpl.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS + +#include <efsw/WatcherKqueue.hpp> + +namespace efsw +{ + +/// Implementation for OSX based on kqueue. +/// @class FileWatcherKqueue +class FileWatcherKqueue : public FileWatcherImpl +{ + friend class WatcherKqueue; + public: + FileWatcherKqueue( FileWatcher * parent ); + + virtual ~FileWatcherKqueue(); + + /// Add a directory watch + /// On error returns WatchID with Error type. + WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); + + /// Remove a directory watch. This is a brute force lazy search O(nlogn). + void removeWatch(const std::string& directory); + + /// Remove a directory watch. This is a map lookup O(logn). + void removeWatch(WatchID watchid); + + /// Updates the watcher. Must be called often. + void watch(); + + /// Handles the action + void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); + + /// @return Returns a list of the directories that are being watched + std::list<std::string> directories(); + protected: + /// Map of WatchID to WatchStruct pointers + WatchMap mWatches; + + /// time out data + struct timespec mTimeOut; + + /// WatchID allocator + int mLastWatchID; + + Thread * mThread; + + Mutex mWatchesLock; + + std::list<WatchID> mRemoveList; + + long mFileDescriptorCount; + + bool mAddingWatcher; + + bool isAddingWatcher() const; + + bool pathInWatches( const std::string& path ); + + void addFD(); + + void removeFD(); + + bool availablesFD(); + private: + void run(); +}; + +} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/FileWatcherWin32.cpp b/dep/efsw/src/efsw/FileWatcherWin32.cpp new file mode 100644 index 00000000000..fe78dd122cf --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherWin32.cpp @@ -0,0 +1,291 @@ +#include <efsw/FileWatcherWin32.hpp> +#include <efsw/FileSystem.hpp> +#include <efsw/System.hpp> +#include <efsw/String.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +namespace efsw +{ + +FileWatcherWin32::FileWatcherWin32( FileWatcher * parent ) : + FileWatcherImpl( parent ), + mLastWatchID(0), + mThread( NULL ) +{ + mInitOK = true; +} + +FileWatcherWin32::~FileWatcherWin32() +{ + WatchVector::iterator iter = mWatches.begin(); + + mWatchesLock.lock(); + + for(; iter != mWatches.end(); ++iter) + { + DestroyWatch((*iter)); + } + + mHandles.clear(); + mWatches.clear(); + + mInitOK = false; + + mWatchesLock.unlock(); + + efSAFE_DELETE( mThread ); +} + +WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) +{ + std::string dir( directory ); + + FileInfo fi( dir ); + + if ( !fi.isDirectory() ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + else if ( !fi.isReadable() ) + { + return Errors::Log::createLastError( Errors::FileNotReadable, dir ); + } + + FileSystem::dirAddSlashAtEnd( dir ); + + WatchID watchid = ++mLastWatchID; + + mWatchesLock.lock(); + + WatcherStructWin32 * watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), recursive, FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_SIZE + ); + + if( NULL == watch ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + + if ( pathInWatches( dir ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, dir ); + } + + // Add the handle to the handles vector + watch->Watch->ID = watchid; + watch->Watch->Watch = this; + watch->Watch->Listener = watcher; + watch->Watch->DirName = new char[dir.length()+1]; + strcpy(watch->Watch->DirName, dir.c_str()); + + mHandles.push_back( watch->Watch->DirHandle ); + mWatches.push_back( watch ); + mWatchesLock.unlock(); + + return watchid; +} + +void FileWatcherWin32::removeWatch(const std::string& directory) +{ + mWatchesLock.lock(); + + WatchVector::iterator iter = mWatches.begin(); + + for(; iter != mWatches.end(); ++iter) + { + if(directory == (*iter)->Watch->DirName) + { + removeWatch((*iter)->Watch->ID); + return; + } + } + + mWatchesLock.unlock(); +} + +void FileWatcherWin32::removeWatch(WatchID watchid) +{ + mWatchesLock.lock(); + + WatchVector::iterator iter = mWatches.begin(); + + WatcherStructWin32* watch = NULL; + + for(; iter != mWatches.end(); ++iter) + { + // Find the watch ID + if ( (*iter)->Watch->ID == watchid ) + { + watch = (*iter); + + mWatches.erase( iter ); + + // Remove handle from the handle vector + HandleVector::iterator it = mHandles.begin(); + + for ( ; it != mHandles.end(); it++ ) + { + if ( watch->Watch->DirHandle == (*it) ) + { + mHandles.erase( it ); + break; + } + } + + DestroyWatch(watch); + + break; + } + } + + mWatchesLock.unlock(); +} + +void FileWatcherWin32::watch() +{ + if ( NULL == mThread ) + { + mThread = new Thread( &FileWatcherWin32::run, this ); + mThread->launch(); + } +} + +void FileWatcherWin32::run() +{ + if ( mHandles.empty() ) + { + return; + } + + do + { + if ( !mHandles.empty() ) + { + mWatchesLock.lock(); + + for ( std::size_t i = 0; i < mWatches.size(); i++ ) + { + WatcherStructWin32 * watch = mWatches[ i ]; + + // If the overlapped struct was cancelled ( because the creator thread doesn't exists anymore ), + // we recreate the overlapped in the current thread and refresh the watch + if ( /*STATUS_CANCELED*/0xC0000120 == watch->Overlapped.Internal ) + { + watch->Overlapped = OVERLAPPED(); + RefreshWatch(watch); + } + + // First ensure that the handle is the same, this means that the watch was not removed. + if ( HasOverlappedIoCompleted( &watch->Overlapped ) && mHandles[ i ] == watch->Watch->DirHandle ) + { + DWORD bytes; + + if ( GetOverlappedResult( watch->Watch->DirHandle, &watch->Overlapped, &bytes, FALSE ) ) + { + WatchCallback( ERROR_SUCCESS, bytes, &watch->Overlapped ); + } + } + } + + mWatchesLock.unlock(); + + if ( mInitOK ) + { + System::sleep( 10 ); + } + } + else + { + // Wait for a new handle to be added + System::sleep( 10 ); + } + } while ( mInitOK ); +} + +void FileWatcherWin32::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename) +{ + Action fwAction; + + switch(action) + { + case FILE_ACTION_RENAMED_OLD_NAME: + watch->OldFileName = filename; + return; + case FILE_ACTION_ADDED: + fwAction = Actions::Add; + break; + case FILE_ACTION_RENAMED_NEW_NAME: + { + fwAction = Actions::Moved; + + std::string fpath( watch->Directory + filename ); + + // Update the directory path + if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) + { + // Update the new directory path + std::string opath( watch->Directory + watch->OldFileName ); + FileSystem::dirAddSlashAtEnd( opath ); + FileSystem::dirAddSlashAtEnd( fpath ); + + for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + if ( (*it)->Watch->Directory == opath ) + { + (*it)->Watch->Directory = fpath; + + break; + } + } + } + + watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction, watch->OldFileName); + return; + } + case FILE_ACTION_REMOVED: + fwAction = Actions::Delete; + break; + case FILE_ACTION_MODIFIED: + fwAction = Actions::Modified; + break; + }; + + watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction); +} + +std::list<std::string> FileWatcherWin32::directories() +{ + std::list<std::string> dirs; + + mWatchesLock.lock(); + + for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + dirs.push_back( std::string( (*it)->Watch->DirName ) ); + } + + mWatchesLock.unlock(); + + return dirs; +} + +bool FileWatcherWin32::pathInWatches( const std::string& path ) +{ + for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + if ( (*it)->Watch->DirName == path ) + { + return true; + } + } + + return false; +} + +} + +#endif diff --git a/dep/efsw/src/efsw/FileWatcherWin32.hpp b/dep/efsw/src/efsw/FileWatcherWin32.hpp new file mode 100644 index 00000000000..505cd772b82 --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherWin32.hpp @@ -0,0 +1,69 @@ +#ifndef EFSW_FILEWATCHERWIN32_HPP +#define EFSW_FILEWATCHERWIN32_HPP + +#include <efsw/base.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +#include <efsw/WatcherWin32.hpp> +#include <vector> +#include <map> + +namespace efsw +{ + +/// Implementation for Win32 based on ReadDirectoryChangesW. +/// @class FileWatcherWin32 +class FileWatcherWin32 : public FileWatcherImpl +{ + public: + /// type for a map from WatchID to WatcherWin32 pointer + typedef std::vector<WatcherStructWin32*> WatchVector; + typedef std::vector<HANDLE> HandleVector; + + FileWatcherWin32( FileWatcher * parent ); + + virtual ~FileWatcherWin32(); + + /// Add a directory watch + /// On error returns WatchID with Error type. + WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); + + /// Remove a directory watch. This is a brute force lazy search O(nlogn). + void removeWatch(const std::string& directory); + + /// Remove a directory watch. This is a map lookup O(logn). + void removeWatch(WatchID watchid); + + /// Updates the watcher. Must be called often. + void watch(); + + /// Handles the action + void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); + + /// @return Returns a list of the directories that are being watched + std::list<std::string> directories(); + protected: + /// Vector of WatcherWin32 pointers + WatchVector mWatches; + + /// Keeps an updated handles vector + HandleVector mHandles; + + /// The last watchid + WatchID mLastWatchID; + + Thread * mThread; + + Mutex mWatchesLock; + + bool pathInWatches( const std::string& path ); + private: + void run(); +}; + +} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/Log.cpp b/dep/efsw/src/efsw/Log.cpp new file mode 100644 index 00000000000..8e2860ac099 --- /dev/null +++ b/dep/efsw/src/efsw/Log.cpp @@ -0,0 +1,27 @@ +#include <efsw/efsw.hpp> + +namespace efsw { namespace Errors { + +static std::string LastError; + +std::string Log::getLastErrorLog() +{ + return LastError; +} + +Error Log::createLastError( Error err, std::string log ) +{ + switch ( err ) + { + case FileNotFound: LastError = "File not found ( " + log + " )"; break; + case FileRepeated: LastError = "File reapeated in watches ( " + log + " )"; break; + case FileOutOfScope: LastError = "Symlink file out of scope ( " + log + " )"; break; + case FileRemote: LastError = "File is located in a remote file system, use a generic watcher. ( " + log + " )"; break; + case Unspecified: + default: LastError = log; + } + + return err; +} + +}} diff --git a/dep/efsw/src/efsw/Mutex.cpp b/dep/efsw/src/efsw/Mutex.cpp new file mode 100644 index 00000000000..b34ba066ee9 --- /dev/null +++ b/dep/efsw/src/efsw/Mutex.cpp @@ -0,0 +1,26 @@ +#include <efsw/Mutex.hpp> +#include <efsw/platform/platformimpl.hpp> + +namespace efsw { + +Mutex::Mutex() : + mMutexImpl( new Platform::MutexImpl() ) +{ +} + +Mutex::~Mutex() +{ + efSAFE_DELETE( mMutexImpl ); +} + +void Mutex::lock() +{ + mMutexImpl->lock(); +} + +void Mutex::unlock() +{ + mMutexImpl->unlock(); +} + +} diff --git a/dep/efsw/src/efsw/Mutex.hpp b/dep/efsw/src/efsw/Mutex.hpp new file mode 100644 index 00000000000..e6e89def175 --- /dev/null +++ b/dep/efsw/src/efsw/Mutex.hpp @@ -0,0 +1,28 @@ +#ifndef EFSW_MUTEX_HPP +#define EFSW_MUTEX_HPP + +#include <efsw/base.hpp> + +namespace efsw { + +namespace Platform { class MutexImpl; } + +/** Simple mutex class */ +class Mutex { + public: + Mutex(); + + ~Mutex(); + + /** Lock the mutex */ + void lock(); + + /** Unlock the mutex */ + void unlock(); + private: + Platform::MutexImpl * mMutexImpl; +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/String.cpp b/dep/efsw/src/efsw/String.cpp new file mode 100644 index 00000000000..f703d25cb35 --- /dev/null +++ b/dep/efsw/src/efsw/String.cpp @@ -0,0 +1,813 @@ +#include <iterator> +#include <efsw/String.hpp> +#include <efsw/Utf.hpp> + +namespace efsw { + +const std::size_t String::InvalidPos = StringType::npos; + +std::vector < std::string > String::split ( const std::string& str, const char& splitchar, const bool& pushEmptyString ) +{ + std::vector < std::string > tmp; + std::string tmpstr; + + for ( size_t i = 0; i < str.size(); i++ ) + { + if ( str[i] == splitchar ) + { + if ( pushEmptyString || tmpstr.size() ) + { + tmp.push_back(tmpstr); + tmpstr = ""; + } + } + else + { + tmpstr += str[i]; + } + } + + if ( tmpstr.size() ) + { + tmp.push_back( tmpstr ); + } + + return tmp; +} + +std::vector < String > String::split ( const String& str, const Uint32& splitchar, const bool& pushEmptyString ) +{ + std::vector < String > tmp; + String tmpstr; + + for ( size_t i = 0; i < str.size(); i++ ) + { + if ( str[i] == splitchar ) + { + if ( pushEmptyString || tmpstr.size() ) + { + tmp.push_back(tmpstr); + tmpstr = ""; + } + } + else + { + tmpstr += str[i]; + } + } + + if ( tmpstr.size() ) + { + tmp.push_back( tmpstr ); + } + + return tmp; +} + +int String::strStartsWith( const std::string& start, const std::string& str ) +{ + int pos = -1; + size_t size = start.size(); + + if ( str.size() >= size ) + { + for ( std::size_t i = 0; i < size; i++ ) + { + if ( start[i] == str[i] ) + { + pos = (int)i; + } + else + { + pos = -1; + break; + } + } + } + + return pos; +} + +int String::strStartsWith( const String& start, const String& str ) +{ + int pos = -1; + size_t size = start.size(); + + if ( str.size() >= size ) + { + for ( std::size_t i = 0; i < size; i++ ) + { + if ( start[i] == str[i] ) + { + pos = (int)i; + } + else + { + pos = -1; + break; + } + } + } + + return pos; +} + +String::String() +{ +} + +String::String(char ansiChar, const std::locale& locale) +{ + mString += Utf32::DecodeAnsi(ansiChar, locale); +} + +#ifndef EFSW_NO_WIDECHAR +String::String(wchar_t wideChar) +{ + mString += Utf32::DecodeWide(wideChar); +} +#endif + +String::String(StringBaseType utf32Char) +{ + mString += utf32Char; +} + +String::String( const char* uf8String ) { + if (uf8String) + { + std::size_t length = strlen(uf8String); + + if (length > 0) + { + mString.reserve(length + 1); + + Utf8::ToUtf32(uf8String, uf8String + length, std::back_inserter(mString)); + } + } +} + +String::String( const std::string& utf8String ) { + mString.reserve( utf8String.length() + 1 ); + + Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( mString ) ); +} + +String::String(const char* ansiString, const std::locale& locale) +{ + if (ansiString) + { + std::size_t length = strlen(ansiString); + if (length > 0) + { + mString.reserve(length + 1); + Utf32::FromAnsi(ansiString, ansiString + length, std::back_inserter(mString), locale); + } + } +} + +String::String(const std::string& ansiString, const std::locale& locale) +{ + mString.reserve(ansiString.length() + 1); + Utf32::FromAnsi(ansiString.begin(), ansiString.end(), std::back_inserter(mString), locale); +} + +#ifndef EFSW_NO_WIDECHAR +String::String(const wchar_t* wideString) +{ + if (wideString) + { + std::size_t length = std::wcslen(wideString); + if (length > 0) + { + mString.reserve(length + 1); + Utf32::FromWide(wideString, wideString + length, std::back_inserter(mString)); + } + } +} + +String::String(const std::wstring& wideString) +{ + mString.reserve(wideString.length() + 1); + Utf32::FromWide(wideString.begin(), wideString.end(), std::back_inserter(mString)); +} +#endif + +String::String(const StringBaseType* utf32String) +{ + if (utf32String) + mString = utf32String; +} + +String::String(const StringType& utf32String) : +mString(utf32String) +{ +} + +String::String(const String& str) : +mString(str.mString) +{ +} + +String String::fromUtf8( const std::string& utf8String ) +{ + String::StringType utf32; + + utf32.reserve( utf8String.length() + 1 ); + + Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( utf32 ) ); + + return String( utf32 ); +} + +String::operator std::string() const +{ + return toAnsiString(); +} + +std::string String::toAnsiString(const std::locale& locale) const +{ + // Prepare the output string + std::string output; + output.reserve(mString.length() + 1); + + // Convert + Utf32::ToAnsi(mString.begin(), mString.end(), std::back_inserter(output), 0, locale); + + return output; +} + +#ifndef EFSW_NO_WIDECHAR +std::wstring String::toWideString() const +{ + // Prepare the output string + std::wstring output; + output.reserve(mString.length() + 1); + + // Convert + Utf32::ToWide(mString.begin(), mString.end(), std::back_inserter(output), 0); + + return output; +} +#endif + +std::string String::toUtf8() const { + // Prepare the output string + std::string output; + output.reserve(mString.length() + 1); + + // Convert + Utf32::toUtf8(mString.begin(), mString.end(), std::back_inserter(output) ); + + return output; +} + +String& String::operator =(const String& right) +{ + mString = right.mString; + return *this; +} + +String& String::operator =( const StringBaseType& right ) +{ + mString = right; + return *this; +} + +String& String::operator +=(const String& right) +{ + mString += right.mString; + return *this; +} + +String& String::operator +=( const StringBaseType& right ) +{ + mString += right; + return *this; +} + + +String::StringBaseType String::operator [](std::size_t index) const +{ + return mString[index]; +} + +String::StringBaseType& String::operator [](std::size_t index) +{ + return mString[index]; +} + +String::StringBaseType String::at( std::size_t index ) const +{ + return mString.at( index ); +} + +void String::push_back( StringBaseType c ) +{ + mString.push_back( c ); +} + +void String::swap ( String& str ) +{ + mString.swap( str.mString ); +} + +void String::clear() +{ + mString.clear(); +} + +std::size_t String::size() const +{ + return mString.size(); +} + +std::size_t String::length() const +{ + return mString.length(); +} + +bool String::empty() const +{ + return mString.empty(); +} + +void String::erase(std::size_t position, std::size_t count) +{ + mString.erase(position, count); +} + +String& String::insert(std::size_t position, const String& str) +{ + mString.insert(position, str.mString); + return *this; +} + +String& String::insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n ) +{ + mString.insert( pos1, str.mString, pos2, n ); + return *this; +} + +String& String::insert ( size_t pos1, const char* s, size_t n ) +{ + String tmp( s ); + + mString.insert( pos1, tmp.data(), n ); + + return *this; +} + +String& String::insert ( size_t pos1, size_t n, char c ) +{ + mString.insert( pos1, n, c ); + return *this; +} + +String& String::insert ( size_t pos1, const char* s ) +{ + String tmp( s ); + + mString.insert( pos1, tmp.data() ); + + return *this; +} + +String::Iterator String::insert ( Iterator p, char c ) +{ + return mString.insert( p, c ); +} + +void String::insert ( Iterator p, size_t n, char c ) +{ + mString.insert( p, n, c ); +} + +const String::StringBaseType* String::c_str() const +{ + return mString.c_str(); +} + +const String::StringBaseType* String::data() const +{ + return mString.data(); +} + +String::Iterator String::begin() +{ + return mString.begin(); +} + +String::ConstIterator String::begin() const +{ + return mString.begin(); +} + +String::Iterator String::end() +{ + return mString.end(); +} + +String::ConstIterator String::end() const +{ + return mString.end(); +} + +String::ReverseIterator String::rbegin() +{ + return mString.rbegin(); +} + +String::ConstReverseIterator String::rbegin() const +{ + return mString.rbegin(); +} + +String::ReverseIterator String::rend() +{ + return mString.rend(); +} + +String::ConstReverseIterator String::rend() const +{ + return mString.rend(); +} + +void String::resize( std::size_t n, StringBaseType c ) +{ + mString.resize( n, c ); +} + +void String::resize( std::size_t n ) +{ + mString.resize( n ); +} + +std::size_t String::max_size() const +{ + return mString.max_size(); +} + +void String::reserve( size_t res_arg ) +{ + mString.reserve( res_arg ); +} + +std::size_t String::capacity() const +{ + return mString.capacity(); +} + +String& String::assign ( const String& str ) +{ + mString.assign( str.mString ); + return *this; +} + +String& String::assign ( const String& str, size_t pos, size_t n ) +{ + mString.assign( str.mString, pos, n ); + return *this; +} + +String& String::assign ( const char* s, size_t n ) +{ + String tmp( s ); + + mString.assign( tmp.mString ); + + return *this; +} + +String& String::assign ( const char* s ) +{ + String tmp( s ); + + mString.assign( tmp.mString ); + + return *this; +} + +String& String::assign ( size_t n, char c ) +{ + mString.assign( n, c ); + + return *this; +} + +String& String::append ( const String& str ) +{ + mString.append( str.mString ); + + return *this; +} + +String& String::append ( const String& str, size_t pos, size_t n ) +{ + mString.append( str.mString, pos, n ); + + return *this; +} + +String& String::append ( const char* s, size_t n ) +{ + String tmp( s ); + + mString.append( tmp.mString ); + + return *this; +} + +String& String::append ( const char* s ) +{ + String tmp( s ); + + mString.append( tmp.mString ); + + return *this; +} + +String& String::append ( size_t n, char c ) +{ + mString.append( n, c ); + + return *this; +} + +String& String::append ( std::size_t n, StringBaseType c ) +{ + mString.append( n, c ); + + return *this; +} + +String& String::replace ( size_t pos1, size_t n1, const String& str ) +{ + mString.replace( pos1, n1, str.mString ); + + return *this; +} + +String& String::replace ( Iterator i1, Iterator i2, const String& str ) +{ + mString.replace( i1, i2, str.mString ); + + return *this; +} + +String& String::replace ( size_t pos1, size_t n1, const String& str, size_t pos2, size_t n2 ) +{ + mString.replace( pos1, n1, str.mString, pos2, n2 ); + + return *this; +} + +String& String::replace ( size_t pos1, size_t n1, const char* s, size_t n2 ) +{ + String tmp( s ); + + mString.replace( pos1, n1, tmp.data(), n2 ); + + return *this; +} + +String& String::replace ( Iterator i1, Iterator i2, const char* s, size_t n2 ) +{ + String tmp( s ); + + mString.replace( i1, i2, tmp.data(), n2 ); + + return *this; +} + +String& String::replace ( size_t pos1, size_t n1, const char* s ) +{ + String tmp( s ); + + mString.replace( pos1, n1, tmp.mString ); + + return *this; +} + +String& String::replace ( Iterator i1, Iterator i2, const char* s ) +{ + String tmp( s ); + + mString.replace( i1, i2, tmp.mString ); + + return *this; +} + +String& String::replace ( size_t pos1, size_t n1, size_t n2, char c ) +{ + mString.replace( pos1, n1, n2, (StringBaseType)c ); + + return *this; +} + +String& String::replace ( Iterator i1, Iterator i2, size_t n2, char c ) +{ + mString.replace( i1, i2, n2, (StringBaseType)c ); + + return *this; +} + +std::size_t String::find( const String& str, std::size_t start ) const +{ + return mString.find( str.mString, start ); +} + +std::size_t String::find ( const char* s, std::size_t pos, std::size_t n ) const +{ + return find( String( s ), pos ); +} + +std::size_t String::find ( const char* s, std::size_t pos ) const +{ + return find( String( s ), pos ); +} + +size_t String::find ( char c, std::size_t pos ) const +{ + return mString.find( (StringBaseType)c, pos ); +} + +std::size_t String::rfind ( const String& str, std::size_t pos ) const +{ + return mString.rfind( str.mString, pos ); +} + +std::size_t String::rfind ( const char* s, std::size_t pos, std::size_t n ) const +{ + return rfind( String( s ), pos ); +} + +std::size_t String::rfind ( const char* s, std::size_t pos ) const +{ + return rfind( String( s ), pos ); +} + +std::size_t String::rfind ( char c, std::size_t pos ) const +{ + return mString.rfind( c, pos ); +} + +std::size_t String::copy ( StringBaseType* s, std::size_t n, std::size_t pos ) const +{ + return mString.copy( s, n, pos ); +} + +String String::substr ( std::size_t pos, std::size_t n ) const +{ + return String( mString.substr( pos, n ) ); +} + +int String::compare ( const String& str ) const +{ + return mString.compare( str.mString ); +} + +int String::compare ( const char* s ) const +{ + return compare( String( s ) ); +} + +int String::compare ( std::size_t pos1, std::size_t n1, const String& str ) const +{ + return mString.compare( pos1, n1, str.mString ); +} + +int String::compare ( std::size_t pos1, std::size_t n1, const char* s) const +{ + return compare( pos1, n1, String( s ) ); +} + +int String::compare ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ) const +{ + return mString.compare( pos1, n1, str.mString, pos2, n2 ); +} + +int String::compare ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2) const +{ + return compare( pos1, n1, String( s ), 0, n2 ); +} + +std::size_t String::find_first_of ( const String& str, std::size_t pos ) const +{ + return mString.find_first_of( str.mString, pos ); +} + +std::size_t String::find_first_of ( const char* s, std::size_t pos, std::size_t n ) const +{ + return find_first_of( String( s ), pos ); +} + +std::size_t String::find_first_of ( const char* s, std::size_t pos ) const +{ + return find_first_of( String( s ), pos ); +} + +std::size_t String::find_first_of ( StringBaseType c, std::size_t pos ) const +{ + return mString.find_first_of( c, pos ); +} + +std::size_t String::find_last_of ( const String& str, std::size_t pos ) const +{ + return mString.find_last_of( str.mString, pos ); +} + +std::size_t String::find_last_of ( const char* s, std::size_t pos, std::size_t n ) const +{ + return find_last_of( String( s ), pos ); +} + +std::size_t String::find_last_of ( const char* s, std::size_t pos ) const +{ + return find_last_of( String( s ), pos ); +} + +std::size_t String::find_last_of ( StringBaseType c, std::size_t pos) const +{ + return mString.find_last_of( c, pos ); +} + +std::size_t String::find_first_not_of ( const String& str, std::size_t pos ) const +{ + return mString.find_first_not_of( str.mString, pos ); +} + +std::size_t String::find_first_not_of ( const char* s, std::size_t pos, std::size_t n ) const +{ + return find_first_not_of( String( s ), pos ); +} + +std::size_t String::find_first_not_of ( const char* s, std::size_t pos ) const +{ + return find_first_not_of( String( s ), pos ); +} + +std::size_t String::find_first_not_of ( StringBaseType c, std::size_t pos ) const +{ + return mString.find_first_not_of( c, pos ); +} + +std::size_t String::find_last_not_of ( const String& str, std::size_t pos ) const +{ + return mString.find_last_not_of( str.mString, pos ); +} + +std::size_t String::find_last_not_of ( const char* s, std::size_t pos, std::size_t n ) const +{ + return find_last_not_of( String( s ), pos ); +} + +std::size_t String::find_last_not_of ( const char* s, std::size_t pos ) const +{ + return find_last_not_of( String( s ), pos ); +} + +std::size_t String::find_last_not_of ( StringBaseType c, std::size_t pos ) const +{ + return mString.find_last_not_of( c, pos ); +} + +bool operator ==(const String& left, const String& right) +{ + return left.mString == right.mString; +} + +bool operator !=(const String& left, const String& right) +{ + return !(left == right); +} + +bool operator <(const String& left, const String& right) +{ + return left.mString < right.mString; +} + +bool operator >(const String& left, const String& right) +{ + return right < left; +} + +bool operator <=(const String& left, const String& right) +{ + return !(right < left); +} + +bool operator >=(const String& left, const String& right) +{ + return !(left < right); +} + +String operator +(const String& left, const String& right) +{ + String string = left; + string += right; + + return string; +} + +} diff --git a/dep/efsw/src/efsw/String.hpp b/dep/efsw/src/efsw/String.hpp new file mode 100644 index 00000000000..ce7e3b75f89 --- /dev/null +++ b/dep/efsw/src/efsw/String.hpp @@ -0,0 +1,629 @@ +/** NOTE: +* This code is based on the Utf implementation from SFML2. License zlib/png ( http://www.sfml-dev.org/license.php ) +* The class was modified to fit efsw own needs. This is not the original implementation from SFML2. +* Functions and methods are the same that in std::string to facilitate portability. +**/ + +#ifndef EFSW_STRING_HPP +#define EFSW_STRING_HPP + +#include <efsw/base.hpp> +#include <locale> +#include <string> +#include <cstring> +#include <cstdlib> +#include <iostream> +#include <fstream> +#include <sstream> +#include <vector> + +namespace efsw { + +/** @brief Utility string class that automatically handles conversions between types and encodings **/ +class String +{ + public : + typedef Uint32 StringBaseType; + typedef std::basic_string<StringBaseType> StringType; + typedef StringType::iterator Iterator; //! Iterator type + typedef StringType::const_iterator ConstIterator; //! Constant iterator type + typedef StringType::reverse_iterator ReverseIterator; //! Reverse Iterator type + typedef StringType::const_reverse_iterator ConstReverseIterator; //! Constant iterator type + + static const std::size_t InvalidPos; ///< Represents an invalid position in the string + + template <class T> + static std::string toStr(const T& i) { + std::ostringstream ss; + ss << i; + return ss.str(); + } + + /** Converts from a string to type */ + template <class T> + static bool fromString(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&) = std::dec ) { + std::istringstream iss(s); + return !(iss >> f >> t).fail(); + } + + /** Converts from a String to type */ + template <class T> + static bool fromString(T& t, const String& s, std::ios_base& (*f)(std::ios_base&) = std::dec ) { + std::istringstream iss( s.toUtf8() ); + return !(iss >> f >> t).fail(); + } + + /** Split a string and hold it on a vector */ + static std::vector < std::string > split( const std::string& str, const char& splitchar, const bool& pushEmptyString = false ); + + /** Split a string and hold it on a vector */ + static std::vector < String > split( const String& str, const Uint32& splitchar, const bool& pushEmptyString = false ); + + /** Determine if a string starts with the string passed + ** @param start The substring expected to start + ** @param str The string to compare + ** @return -1 if the substring is no in str, otherwise the size of the substring + */ + static int strStartsWith( const std::string& start, const std::string& str ); + + static int strStartsWith( const String& start, const String& str ); + + /** @brief Construct from an UTF-8 string to UTF-32 according + ** @param uf8String UTF-8 string to convert + **/ + static String fromUtf8( const std::string& utf8String ); + + /** @brief Default constructor + ** This constructor creates an empty string. + **/ + String(); + + /** @brief Construct from a single ANSI character and a locale + ** The source character is converted to UTF-32 according + ** to the given locale. If you want to use the current global + ** locale, rather use the other constructor. + ** @param ansiChar ANSI character to convert + ** @param locale Locale to use for conversion + **/ + String( char ansiChar, const std::locale& locale = std::locale() ); + +#ifndef EFSW_NO_WIDECHAR + /** @brief Construct from single wide character + ** @param wideChar Wide character to convert + **/ + String( wchar_t wideChar ); +#endif + + /** @brief Construct from single UTF-32 character + ** @param utf32Char UTF-32 character to convert + **/ + String( StringBaseType utf32Char ); + + /** @brief Construct from an from a null-terminated C-style UTF-8 string to UTF-32 + ** @param uf8String UTF-8 string to convert + **/ + String( const char* uf8String ); + + /** @brief Construct from an UTF-8 string to UTF-32 according + ** @param uf8String UTF-8 string to convert + **/ + String( const std::string& utf8String ); + + /** @brief Construct from a null-terminated C-style ANSI string and a locale + ** The source string is converted to UTF-32 according + ** to the given locale. If you want to use the current global + ** locale, rather use the other constructor. + ** @param ansiString ANSI string to convert + ** @param locale Locale to use for conversion + **/ + String( const char* ansiString, const std::locale& locale ); + + /** @brief Construct from an ANSI string and a locale + ** The source string is converted to UTF-32 according + ** to the given locale. If you want to use the current global + ** locale, rather use the other constructor. + ** @param ansiString ANSI string to convert + ** @param locale Locale to use for conversion + **/ + String( const std::string& ansiString, const std::locale& locale ); + +#ifndef EFSW_NO_WIDECHAR + /** @brief Construct from null-terminated C-style wide string + ** @param wideString Wide string to convert + **/ + String( const wchar_t* wideString ); + + /** @brief Construct from a wide string + ** @param wideString Wide string to convert + **/ + String( const std::wstring& wideString ); +#endif + + /** @brief Construct from a null-terminated C-style UTF-32 string + ** @param utf32String UTF-32 string to assign + **/ + String( const StringBaseType* utf32String ); + + /** @brief Construct from an UTF-32 string + ** @param utf32String UTF-32 string to assign + **/ + String( const StringType& utf32String ); + + + /** @brief Copy constructor + ** @param str Instance to copy + **/ + String( const String& str ); + + /** @brief Implicit cast operator to std::string (ANSI string) + ** The current global locale is used for conversion. If you + ** want to explicitely specify a locale, see toAnsiString. + ** Characters that do not fit in the target encoding are + ** discarded from the returned string. + ** This operator is defined for convenience, and is equivalent + ** to calling toAnsiString(). + ** @return Converted ANSI string + ** @see toAnsiString, operator String + **/ + operator std::string() const; + + /** @brief Convert the unicode string to an ANSI string + ** The UTF-32 string is converted to an ANSI string in + ** the encoding defined by \a locale. If you want to use + ** the current global locale, see the other overload + ** of toAnsiString. + ** Characters that do not fit in the target encoding are + ** discarded from the returned string. + ** @param locale Locale to use for conversion + ** @return Converted ANSI string + ** @see toWideString, operator std::string + **/ + std::string toAnsiString( const std::locale& locale = std::locale() ) const; + +#ifndef EFSW_NO_WIDECHAR + /** @brief Convert the unicode string to a wide string + ** Characters that do not fit in the target encoding are + ** discarded from the returned string. + ** @return Converted wide string + ** @see toAnsiString, operator String + **/ + std::wstring toWideString() const; +#endif + + std::string toUtf8() const; + + /** @brief Overload of assignment operator + ** @param right Instance to assign + ** @return Reference to self + **/ + String& operator =(const String& right); + + String& operator =( const StringBaseType& right ); + + /** @brief Overload of += operator to append an UTF-32 string + ** @param right String to append + ** @return Reference to self + **/ + String& operator +=(const String& right); + + String& operator +=( const StringBaseType& right ); + + /** @brief Overload of [] operator to access a character by its position + ** This function provides read-only access to characters. + ** Note: this function doesn't throw if \a index is out of range. + ** @param index Index of the character to get + ** @return Character at position \a index + **/ + StringBaseType operator [](std::size_t index) const; + + /** @brief Overload of [] operator to access a character by its position + ** This function provides read and write access to characters. + ** Note: this function doesn't throw if \a index is out of range. + ** @param index Index of the character to get + ** @return Reference to the character at position \a index + **/ + + StringBaseType& operator [](std::size_t index); + + /** @brief Get character in string + ** Performs a range check, throwing an exception of type out_of_range in case that pos is not an actual position in the string. + ** @return The character at position pos in the string. + */ + StringBaseType at( std::size_t index ) const; + + /** @brief clear the string + ** This function removes all the characters from the string. + ** @see empty, erase + **/ + void clear(); + + /** @brief Get the size of the string + ** @return Number of characters in the string + ** @see empty + **/ + std::size_t size() const; + + /** @see size() */ + std::size_t length() const; + + /** @brief Check whether the string is empty or not + ** @return True if the string is empty (i.e. contains no character) + ** @see clear, size + **/ + bool empty() const; + + /** @brief Erase one or more characters from the string + ** This function removes a sequence of \a count characters + ** starting from \a position. + ** @param position Position of the first character to erase + ** @param count Number of characters to erase + **/ + void erase(std::size_t position, std::size_t count = 1); + + + /** @brief Insert one or more characters into the string + ** This function inserts the characters of \a str + ** into the string, starting from \a position. + ** @param position Position of insertion + ** @param str Characters to insert + **/ + String& insert(std::size_t position, const String& str); + + String& insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n ); + + String& insert ( std::size_t pos1, const char* s, std::size_t n ); + + String& insert ( std::size_t pos1, const char* s ); + + String& insert ( std::size_t pos1, size_t n, char c ); + + Iterator insert ( Iterator p, char c ); + + void insert ( Iterator p, std::size_t n, char c ); + + template<class InputIterator> + void insert ( Iterator p, InputIterator first, InputIterator last ) + { + mString.insert( p, first, last ); + } + + /** @brief Find a sequence of one or more characters in the string + ** This function searches for the characters of \a str + ** into the string, starting from \a start. + ** @param str Characters to find + ** @param start Where to begin searching + ** @return Position of \a str in the string, or String::InvalidPos if not found + **/ + std::size_t find( const String& str, std::size_t start = 0 ) const; + + std::size_t find ( const char* s, std::size_t pos, std::size_t n ) const; + + std::size_t find ( const char* s, std::size_t pos = 0 ) const; + + std::size_t find ( char c, std::size_t pos = 0 ) const; + + /** @brief Get a pointer to the C-style array of characters + ** This functions provides a read-only access to a + ** null-terminated C-style representation of the string. + ** The returned pointer is temporary and is meant only for + ** immediate use, thus it is not recommended to store it. + ** @return Read-only pointer to the array of characters + **/ + const StringBaseType* c_str() const; + + /** @brief Get string data + ** Notice that no terminating null character is appended (see member c_str for such a functionality). + ** The returned array points to an internal location which should not be modified directly in the program. + ** Its contents are guaranteed to remain unchanged only until the next call to a non-constant member function of the string object. + ** @return Pointer to an internal array containing the same content as the string. + **/ + const StringBaseType* data() const; + + /** @brief Return an iterator to the beginning of the string + ** @return Read-write iterator to the beginning of the string characters + ** @see end + **/ + Iterator begin(); + + /** @brief Return an iterator to the beginning of the string + ** @return Read-only iterator to the beginning of the string characters + ** @see end + **/ + ConstIterator begin() const; + + /** @brief Return an iterator to the beginning of the string + ** The end iterator refers to 1 position past the last character; + ** thus it represents an invalid character and should never be + ** accessed. + ** @return Read-write iterator to the end of the string characters + ** @see begin + **/ + Iterator end(); + + /** @brief Return an iterator to the beginning of the string + ** The end iterator refers to 1 position past the last character; + ** thus it represents an invalid character and should never be + ** accessed. + ** @return Read-only iterator to the end of the string characters + ** @see begin + **/ + ConstIterator end() const; + + /** @brief Return an reverse iterator to the beginning of the string + ** @return Read-write reverse iterator to the beginning of the string characters + ** @see end + **/ + ReverseIterator rbegin(); + + /** @brief Return an reverse iterator to the beginning of the string + ** @return Read-only reverse iterator to the beginning of the string characters + ** @see end + **/ + ConstReverseIterator rbegin() const; + + /** @brief Return an reverse iterator to the beginning of the string + ** The end reverse iterator refers to 1 position past the last character; + ** thus it represents an invalid character and should never be + ** accessed. + ** @return Read-write reverse iterator to the end of the string characters + ** @see begin + **/ + ReverseIterator rend(); + + + /** @brief Return an reverse iterator to the beginning of the string + ** The end reverse iterator refers to 1 position past the last character; + ** thus it represents an invalid character and should never be + ** accessed. + ** @return Read-only reverse iterator to the end of the string characters + ** @see begin + **/ + ConstReverseIterator rend() const; + + /** @brief Resize String */ + void resize ( std::size_t n, StringBaseType c ); + + /** @brief Resize String */ + void resize ( std::size_t n ); + + /** @return Maximum size of string */ + std::size_t max_size() const; + + /** @brief Request a change in capacity */ + void reserve ( size_t res_arg=0 ); + + /** @return Size of allocated storage */ + std::size_t capacity() const; + + /** @brief Append character to string */ + void push_back( StringBaseType c ); + + /** @brief Swap contents with another string */ + void swap ( String& str ); + + String& assign ( const String& str ); + + String& assign ( const String& str, std::size_t pos, std::size_t n ); + + String& assign ( const char* s, std::size_t n ); + + String& assign ( const char* s ); + + String& assign ( std::size_t n, char c ); + + template <class InputIterator> + String& assign ( InputIterator first, InputIterator last ) + { + mString.assign( first, last ); + return *this; + } + + String& append ( const String& str ); + + String& append ( const String& str, std::size_t pos, std::size_t n ); + + String& append ( const char* s, std::size_t n ); + + String& append ( const char* s ); + + String& append ( std::size_t n, char c ); + + String& append ( std::size_t n, StringBaseType c ); + + template <class InputIterator> + String& append ( InputIterator first, InputIterator last ) + { + mString.append( first, last ); + return *this; + } + + String& replace ( std::size_t pos1, std::size_t n1, const String& str ); + + String& replace ( Iterator i1, Iterator i2, const String& str ); + + String& replace ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ); + + String& replace ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 ); + + String& replace ( Iterator i1, Iterator i2, const char* s, std::size_t n2 ); + + String& replace ( std::size_t pos1, std::size_t n1, const char* s ); + + String& replace ( Iterator i1, Iterator i2, const char* s ); + + String& replace ( std::size_t pos1, std::size_t n1, std::size_t n2, char c ); + + String& replace ( Iterator i1, Iterator i2, std::size_t n2, char c ); + + template<class InputIterator> + String& replace ( Iterator i1, Iterator i2, InputIterator j1, InputIterator j2 ) + { + mString.replace( i1, i2, j1, j2 ); + return *this; + } + + std::size_t rfind ( const String& str, std::size_t pos = StringType::npos ) const; + + std::size_t rfind ( const char* s, std::size_t pos, std::size_t n ) const; + + std::size_t rfind ( const char* s, std::size_t pos = StringType::npos ) const; + + std::size_t rfind ( char c, std::size_t pos = StringType::npos ) const; + + String substr ( std::size_t pos = 0, std::size_t n = StringType::npos ) const; + + std::size_t copy ( StringBaseType* s, std::size_t n, std::size_t pos = 0 ) const; + + int compare ( const String& str ) const; + + int compare ( const char* s ) const; + + int compare ( std::size_t pos1, std::size_t n1, const String& str ) const; + + int compare ( std::size_t pos1, std::size_t n1, const char* s) const; + + int compare ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ) const; + + int compare ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2) const; + + std::size_t find_first_of ( const String& str, std::size_t pos = 0 ) const; + + std::size_t find_first_of ( const char* s, std::size_t pos, std::size_t n ) const; + + std::size_t find_first_of ( const char* s, std::size_t pos = 0 ) const; + + std::size_t find_first_of ( StringBaseType c, std::size_t pos = 0 ) const; + + std::size_t find_last_of ( const String& str, std::size_t pos = StringType::npos ) const; + + std::size_t find_last_of ( const char* s, std::size_t pos, std::size_t n ) const; + + std::size_t find_last_of ( const char* s, std::size_t pos = StringType::npos ) const; + + std::size_t find_last_of ( StringBaseType c, std::size_t pos = StringType::npos ) const; + + std::size_t find_first_not_of ( const String& str, std::size_t pos = 0 ) const; + + std::size_t find_first_not_of ( const char* s, std::size_t pos, std::size_t n ) const; + + std::size_t find_first_not_of ( const char* s, std::size_t pos = 0 ) const; + + std::size_t find_first_not_of ( StringBaseType c, std::size_t pos = 0 ) const; + + std::size_t find_last_not_of ( const String& str, std::size_t pos = StringType::npos ) const; + + std::size_t find_last_not_of ( const char* s, std::size_t pos, std::size_t n ) const; + + std::size_t find_last_not_of ( const char* s, std::size_t pos = StringType::npos ) const; + + std::size_t find_last_not_of ( StringBaseType c, std::size_t pos = StringType::npos ) const; +private : + friend bool operator ==(const String& left, const String& right); + friend bool operator <(const String& left, const String& right); + + StringType mString; ///< Internal string of UTF-32 characters +}; + +/** @relates String +** @brief Overload of == operator to compare two UTF-32 strings +** @param left Left operand (a string) +** @param right Right operand (a string) +** @return True if both strings are equal +**/ + bool operator ==(const String& left, const String& right); + +/** @relates String +** @brief Overload of != operator to compare two UTF-32 strings +** @param left Left operand (a string) +** @param right Right operand (a string) +** @return True if both strings are different +**/ + bool operator !=(const String& left, const String& right); + +/** @relates String +** @brief Overload of < operator to compare two UTF-32 strings +** @param left Left operand (a string) +** @param right Right operand (a string) +** @return True if \a left is alphabetically lesser than \a right +**/ + bool operator <(const String& left, const String& right); + +/** @relates String +** @brief Overload of > operator to compare two UTF-32 strings +** @param left Left operand (a string) +** @param right Right operand (a string) +** @return True if \a left is alphabetically greater than \a right +**/ + bool operator >(const String& left, const String& right); + +/** @relates String +** @brief Overload of <= operator to compare two UTF-32 strings +** @param left Left operand (a string) +** @param right Right operand (a string) +** @return True if \a left is alphabetically lesser or equal than \a right +**/ + bool operator <=(const String& left, const String& right); + +/** @relates String +** @brief Overload of >= operator to compare two UTF-32 strings +** @param left Left operand (a string) +** @param right Right operand (a string) +** @return True if \a left is alphabetically greater or equal than \a right +**/ + bool operator >=(const String& left, const String& right); + +/** @relates String +** @brief Overload of binary + operator to concatenate two strings +** @param left Left operand (a string) +** @param right Right operand (a string) +** @return Concatenated string +**/ + String operator +( const String& left, const String& right ); + +} + +#endif + +/** @class efsw::String +** @ingroup system +** efsw::String is a utility string class defined mainly for +** convenience. It is a Unicode string (implemented using +** UTF-32), thus it can store any character in the world +** (european, chinese, arabic, hebrew, etc.). +** It automatically handles conversions from/to ANSI and +** wide strings, so that you can work with standard string +** classes and still be compatible with functions taking a +** efsw::String. +** @code +** efsw::String s; +** std::string s1 = s; // automatically converted to ANSI string +** String s2 = s; // automatically converted to wide string +** s = "hello"; // automatically converted from ANSI string +** s = L"hello"; // automatically converted from wide string +** s += 'a'; // automatically converted from ANSI string +** s += L'a'; // automatically converted from wide string +** @endcode +** Conversions involving ANSI strings use the default user locale. However +** it is possible to use a custom locale if necessary: +** @code +** std::locale locale; +** efsw::String s; +** ... +** std::string s1 = s.toAnsiString(locale); +** s = efsw::String("hello", locale); +** @endcode +** +** efsw::String defines the most important functions of the +** standard std::string class: removing, random access, iterating, +** appending, comparing, etc. However it is a simple class +** provided for convenience, and you may have to consider using +** a more optimized class if your program requires complex string +** handling. The automatic conversion functions will then take +** care of converting your string to efsw::String whenever EE +** requires it. +** +** Please note that EE also defines a low-level, generic +** interface for Unicode handling, see the efsw::Utf classes. +** +** All credits to Laurent Gomila, i just modified and expanded a little bit the implementation. +**/ diff --git a/dep/efsw/src/efsw/System.cpp b/dep/efsw/src/efsw/System.cpp new file mode 100644 index 00000000000..f8767cbc58f --- /dev/null +++ b/dep/efsw/src/efsw/System.cpp @@ -0,0 +1,26 @@ +#include <efsw/System.hpp> +#include <efsw/platform/platformimpl.hpp> + +namespace efsw { + +void System::sleep( const unsigned long& ms ) +{ + Platform::System::sleep( ms ); +} + +std::string System::getProcessPath() +{ + return Platform::System::getProcessPath(); +} + +void System::maxFD() +{ + Platform::System::maxFD(); +} + +Uint64 System::getMaxFD() +{ + return Platform::System::getMaxFD(); +} + +} diff --git a/dep/efsw/src/efsw/System.hpp b/dep/efsw/src/efsw/System.hpp new file mode 100644 index 00000000000..1d6f4a70f91 --- /dev/null +++ b/dep/efsw/src/efsw/System.hpp @@ -0,0 +1,26 @@ +#ifndef EFSW_SYSTEM_HPP +#define EFSW_SYSTEM_HPP + +#include <efsw/base.hpp> + +namespace efsw { + +class System +{ + public: + /// Sleep for x milliseconds + static void sleep( const unsigned long& ms ); + + /// @return The process binary path + static std::string getProcessPath(); + + /// Maximize the number of file descriptors allowed per process in the current OS + static void maxFD(); + + /// @return The number of supported file descriptors for the process + static Uint64 getMaxFD(); +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/Thread.cpp b/dep/efsw/src/efsw/Thread.cpp new file mode 100644 index 00000000000..fff41517dc1 --- /dev/null +++ b/dep/efsw/src/efsw/Thread.cpp @@ -0,0 +1,51 @@ +#include <efsw/Thread.hpp> +#include <efsw/platform/platformimpl.hpp> + +namespace efsw { + +Thread::Thread() : + mThreadImpl(NULL), + mEntryPoint(NULL) +{ +} + +Thread::~Thread() +{ + wait(); + + efSAFE_DELETE( mEntryPoint ); +} + +void Thread::launch() +{ + wait(); + + mThreadImpl = new Platform::ThreadImpl( this ); +} + +void Thread::wait() +{ + if ( mThreadImpl ) + { + mThreadImpl->wait(); + + efSAFE_DELETE( mThreadImpl ); + } +} + +void Thread::terminate() +{ + if ( mThreadImpl ) + { + mThreadImpl->terminate(); + + efSAFE_DELETE( mThreadImpl ); + } +} + +void Thread::run() +{ + mEntryPoint->run(); +} + +} diff --git a/dep/efsw/src/efsw/Thread.hpp b/dep/efsw/src/efsw/Thread.hpp new file mode 100644 index 00000000000..c7da9e8b33c --- /dev/null +++ b/dep/efsw/src/efsw/Thread.hpp @@ -0,0 +1,111 @@ +#ifndef EFSW_THREAD_HPP +#define EFSW_THREAD_HPP + +#include <efsw/base.hpp> + +namespace efsw { + +namespace Platform { class ThreadImpl; } +namespace Private { struct ThreadFunc; } + +/** @brief Thread manager class */ +class Thread { + public: + typedef void (*FuncType)(void*); + + template <typename F> + Thread( F function ); + + template <typename F, typename A> + Thread( F function, A argument ); + + template <typename C> + Thread( void(C::*function)(), C* object ); + + virtual ~Thread(); + + /** Launch the thread */ + virtual void launch(); + + /** Wait the thread until end */ + void wait(); + + /** Terminate the thread */ + void terminate(); + protected: + Thread(); + private: + friend class Platform::ThreadImpl; + + /** The virtual function to run in the thread */ + virtual void run(); + + Platform::ThreadImpl * mThreadImpl; ///< OS-specific implementation of the thread + Private::ThreadFunc * mEntryPoint; ///< Abstraction of the function to run +}; + +//! NOTE: Taken from SFML2 threads +namespace Private { + +// Base class for abstract thread functions +struct ThreadFunc +{ + virtual ~ThreadFunc() {} + virtual void run() = 0; +}; + +// Specialization using a functor (including free functions) with no argument +template <typename T> +struct ThreadFunctor : ThreadFunc +{ + ThreadFunctor(T functor) : m_functor(functor) {} + virtual void run() {m_functor();} + T m_functor; +}; + +// Specialization using a functor (including free functions) with one argument +template <typename F, typename A> +struct ThreadFunctorWithArg : ThreadFunc +{ + ThreadFunctorWithArg(F function, A arg) : m_function(function), m_arg(arg) {} + virtual void run() {m_function(m_arg);} + F m_function; + A m_arg; +}; + +// Specialization using a member function +template <typename C> +struct ThreadMemberFunc : ThreadFunc +{ + ThreadMemberFunc(void(C::*function)(), C* object) : m_function(function), m_object(object) {} + virtual void run() {(m_object->*m_function)();} + void(C::*m_function)(); + C* m_object; +}; + +} + +template <typename F> +Thread::Thread(F functor) : + mThreadImpl (NULL), + mEntryPoint( new Private::ThreadFunctor<F>(functor) ) +{ +} + +template <typename F, typename A> +Thread::Thread(F function, A argument) : + mThreadImpl(NULL), + mEntryPoint( new Private::ThreadFunctorWithArg<F efCOMMA A>(function, argument) ) +{ +} + +template <typename C> +Thread::Thread(void(C::*function)(), C* object) : + mThreadImpl(NULL), + mEntryPoint( new Private::ThreadMemberFunc<C>(function, object) ) +{ +} + +} + +#endif diff --git a/dep/efsw/src/efsw/Utf.hpp b/dep/efsw/src/efsw/Utf.hpp new file mode 100644 index 00000000000..925a7cc149b --- /dev/null +++ b/dep/efsw/src/efsw/Utf.hpp @@ -0,0 +1,748 @@ +/** NOTE: +* This code is based on the Utf implementation from SFML2. License zlib/png ( http://www.sfml-dev.org/license.php ) +* The class was modified to fit efsw own needs. This is not the original implementation from SFML2. +* */ + +#ifndef EFSW_UTF_HPP +#define EFSW_UTF_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <locale> +#include <string> +#include <cstdlib> +#include <efsw/base.hpp> + +namespace efsw { + +template <unsigned int N> +class Utf; + +//////////////////////////////////////////////////////////// +/// \brief Specialization of the Utf template for UTF-8 +/// +//////////////////////////////////////////////////////////// +template <> +class Utf<8> { +public : + //////////////////////////////////////////////////////////// + /// \brief Decode a single UTF-8 character + /// + /// Decoding a character means finding its unique 32-bits + /// code (called the codepoint) in the Unicode standard. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Codepoint of the decoded UTF-8 character + /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template <typename In> + static In Decode(In begin, In end, Uint32& output, Uint32 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-8 character + /// + /// Encoding a character means converting a unique 32-bits + /// code (called the codepoint) in the target encoding, UTF-8. + /// + /// \param input Codepoint to encode as UTF-8 + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename Out> + static Out Encode(Uint32 input, Out output, Uint8 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Advance to the next UTF-8 character + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template <typename In> + static In Next(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Count the number of characters of a UTF-8 sequence + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element, thus the + /// total size can be different from (begin - end). + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template <typename In> + static std::size_t Count(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Convert an ANSI characters range to UTF-8 + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out FromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Convert a wide characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out FromWide(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out FromLatin1(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-8 characters range to ANSI characters + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale()); + +#ifndef EFSW_NO_WIDECHAR + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-8 characters range to wide characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToWide(In begin, In end, Out output, wchar_t replacement = 0); +#endif + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToLatin1(In begin, In end, Out output, char replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-8 characters range to UTF-8 + /// + /// This functions does nothing more than a direct copy; + /// it is defined only to provide the same interface as other + /// specializations of the efsw::Utf<> template, and allow + /// generic code to be written on top of it. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out toUtf8(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-8 characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToUtf16(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-8 characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToUtf32(In begin, In end, Out output); +}; + +//////////////////////////////////////////////////////////// +/// \brief Specialization of the Utf template for UTF-16 +/// +//////////////////////////////////////////////////////////// +template <> +class Utf<16> +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Decode a single UTF-16 character + /// + /// Decoding a character means finding its unique 32-bits + /// code (called the codepoint) in the Unicode standard. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Codepoint of the decoded UTF-16 character + /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template <typename In> + static In Decode(In begin, In end, Uint32& output, Uint32 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-16 character + /// + /// Encoding a character means converting a unique 32-bits + /// code (called the codepoint) in the target encoding, UTF-16. + /// + /// \param input Codepoint to encode as UTF-16 + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename Out> + static Out Encode(Uint32 input, Out output, Uint16 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Advance to the next UTF-16 character + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template <typename In> + static In Next(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Count the number of characters of a UTF-16 sequence + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element, thus the + /// total size can be different from (begin - end). + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template <typename In> + static std::size_t Count(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Convert an ANSI characters range to UTF-16 + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out FromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Convert a wide characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out FromWide(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out FromLatin1(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to ANSI characters + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale()); + +#ifndef EFSW_NO_WIDECHAR + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to wide characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToWide(In begin, In end, Out output, wchar_t replacement = 0); +#endif + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToLatin1(In begin, In end, Out output, char replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-16 characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out toUtf8(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-16 characters range to UTF-16 + /// + /// This functions does nothing more than a direct copy; + /// it is defined only to provide the same interface as other + /// specializations of the efsw::Utf<> template, and allow + /// generic code to be written on top of it. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToUtf16(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-16 characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToUtf32(In begin, In end, Out output); +}; + +//////////////////////////////////////////////////////////// +/// \brief Specialization of the Utf template for UTF-32 +/// +//////////////////////////////////////////////////////////// +template <> +class Utf<32> +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Decode a single UTF-32 character + /// + /// Decoding a character means finding its unique 32-bits + /// code (called the codepoint) in the Unicode standard. + /// For UTF-32, the character value is the same as the codepoint. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Codepoint of the decoded UTF-32 character + /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template <typename In> + static In Decode(In begin, In end, Uint32& output, Uint32 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-32 character + /// + /// Encoding a character means converting a unique 32-bits + /// code (called the codepoint) in the target encoding, UTF-32. + /// For UTF-32, the codepoint is the same as the character value. + /// + /// \param input Codepoint to encode as UTF-32 + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename Out> + static Out Encode(Uint32 input, Out output, Uint32 replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Advance to the next UTF-32 character + /// + /// This function is trivial for UTF-32, which can store + /// every character in a single storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template <typename In> + static In Next(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Count the number of characters of a UTF-32 sequence + /// + /// This function is trivial for UTF-32, which can store + /// every character in a single storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template <typename In> + static std::size_t Count(In begin, In end); + + //////////////////////////////////////////////////////////// + /// \brief Convert an ANSI characters range to UTF-32 + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out FromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Convert a wide characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out FromWide(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out FromLatin1(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-32 characters range to ANSI characters + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale()); + +#ifndef EFSW_NO_WIDECHAR + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-32 characters range to wide characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToWide(In begin, In end, Out output, wchar_t replacement = 0); +#endif + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToLatin1(In begin, In end, Out output, char replacement = 0); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-32 characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out toUtf8(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-32 characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToUtf16(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-32 characters range to UTF-32 + /// + /// This functions does nothing more than a direct copy; + /// it is defined only to provide the same interface as other + /// specializations of the efsw::Utf<> template, and allow + /// generic code to be written on top of it. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename In, typename Out> + static Out ToUtf32(In begin, In end, Out output); + + //////////////////////////////////////////////////////////// + /// \brief Decode a single ANSI character to UTF-32 + /// + /// This function does not exist in other specializations + /// of efsw::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param input Input ANSI character + /// \param locale Locale to use for conversion + /// + /// \return Converted character + /// + //////////////////////////////////////////////////////////// + template <typename In> + static Uint32 DecodeAnsi(In input, const std::locale& locale = std::locale()); + + //////////////////////////////////////////////////////////// + /// \brief Decode a single wide character to UTF-32 + /// + /// This function does not exist in other specializations + /// of efsw::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param input Input wide character + /// + /// \return Converted character + /// + //////////////////////////////////////////////////////////// + template <typename In> + static Uint32 DecodeWide(In input); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-32 character to ANSI + /// + /// This function does not exist in other specializations + /// of efsw::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param codepoint Iterator pointing to the beginning of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to skip it) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename Out> + static Out EncodeAnsi(Uint32 codepoint, Out output, char replacement = 0, const std::locale& locale = std::locale()); + +#ifndef EFSW_NO_WIDECHAR + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-32 character to wide + /// + /// This function does not exist in other specializations + /// of efsw::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param codepoint Iterator pointing to the beginning of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement if the input character is not convertible to wide (use 0 to skip it) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template <typename Out> + static Out EncodeWide(Uint32 codepoint, Out output, wchar_t replacement = 0); +#endif +}; + +#include "Utf.inl" + +// Make typedefs to get rid of the template syntax +typedef Utf<8> Utf8; +typedef Utf<16> Utf16; +typedef Utf<32> Utf32; + +} +#endif + +//////////////////////////////////////////////////////////// +/// \class efsw::Utf +/// \ingroup system +/// +/// Utility class providing generic functions for UTF conversions. +/// +/// efsw::Utf is a low-level, generic interface for counting, iterating, +/// encoding and decoding Unicode characters and strings. It is able +/// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. +/// +/// efsw::Utf<X> functions are all static, these classes are not meant to +/// be instanciated. All the functions are template, so that you +/// can use any character / string type for a given encoding. +/// +/// It has 3 specializations: +/// \li efsw::Utf<8> (typedef'd to efsw::Utf8) +/// \li efsw::Utf<16> (typedef'd to efsw::Utf16) +/// \li efsw::Utf<32> (typedef'd to efsw::Utf32) +/// +//////////////////////////////////////////////////////////// diff --git a/dep/efsw/src/efsw/Utf.inl b/dep/efsw/src/efsw/Utf.inl new file mode 100644 index 00000000000..db8fd5d61ee --- /dev/null +++ b/dep/efsw/src/efsw/Utf.inl @@ -0,0 +1,671 @@ +// References : +// http://www.unicode.org/ +// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c +// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h +// http://people.w3.org/rishida/scripts/uniview/conversion +//////////////////////////////////////////////////////////// + +template <typename In> +In Utf<8>::Decode(In begin, In end, Uint32& output, Uint32 replacement) +{ + // Some useful precomputed data + static const int trailing[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 + }; + static const Uint32 offsets[6] = + { + 0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080 + }; + + // Decode the character + int trailingBytes = trailing[static_cast<Uint8>(*begin)]; + if (begin + trailingBytes < end) + { + output = 0; + switch (trailingBytes) + { + case 5 : output += static_cast<Uint8>(*begin++); output <<= 6; + case 4 : output += static_cast<Uint8>(*begin++); output <<= 6; + case 3 : output += static_cast<Uint8>(*begin++); output <<= 6; + case 2 : output += static_cast<Uint8>(*begin++); output <<= 6; + case 1 : output += static_cast<Uint8>(*begin++); output <<= 6; + case 0 : output += static_cast<Uint8>(*begin++); + } + output -= offsets[trailingBytes]; + } + else + { + // Incomplete character + begin = end; + output = replacement; + } + + return begin; +} + +template <typename Out> +Out Utf<8>::Encode(Uint32 input, Out output, Uint8 replacement) +{ + // Some useful precomputed data + static const Uint8 firstBytes[7] = + { + 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC + }; + + // Encode the character + if ((input > 0x0010FFFF) || ((input >= 0xD800) && (input <= 0xDBFF))) + { + // Invalid character + if (replacement) + *output++ = replacement; + } + else + { + // Valid character + + // Get the number of bytes to write + int bytesToWrite = 1; + if (input < 0x80) bytesToWrite = 1; + else if (input < 0x800) bytesToWrite = 2; + else if (input < 0x10000) bytesToWrite = 3; + else if (input <= 0x0010FFFF) bytesToWrite = 4; + + // Extract the bytes to write + Uint8 bytes[4]; + switch (bytesToWrite) + { + case 4 : bytes[3] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6; + case 3 : bytes[2] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6; + case 2 : bytes[1] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6; + case 1 : bytes[0] = static_cast<Uint8> (input | firstBytes[bytesToWrite]); + } + + // Add them to the output + const Uint8* currentByte = bytes; + switch (bytesToWrite) + { + case 4 : *output++ = *currentByte++; + case 3 : *output++ = *currentByte++; + case 2 : *output++ = *currentByte++; + case 1 : *output++ = *currentByte++; + } + } + + return output; +} + +template <typename In> +In Utf<8>::Next(In begin, In end) +{ + Uint32 codepoint; + return Decode(begin, end, codepoint); +} + +template <typename In> +std::size_t Utf<8>::Count(In begin, In end) +{ + std::size_t length = 0; + while (begin < end) + { + begin = Next(begin, end); + ++length; + } + + return length; +} + +template <typename In, typename Out> +Out Utf<8>::FromAnsi(In begin, In end, Out output, const std::locale& locale) +{ + while (begin < end) + { + Uint32 codepoint = Utf<32>::DecodeAnsi(*begin++, locale); + output = Encode(codepoint, output); + } + + return output; +} + +template <typename In, typename Out> +Out Utf<8>::FromWide(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint = Utf<32>::DecodeWide(*begin++); + output = Encode(codepoint, output); + } + + return output; +} + +template <typename In, typename Out> +Out Utf<8>::FromLatin1(In begin, In end, Out output) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + output = Encode(*begin++, output); + + return output; +} + +template <typename In, typename Out> +Out Utf<8>::ToAnsi(In begin, In end, Out output, char replacement, const std::locale& locale) +{ + while (begin < end) + { + Uint32 codepoint; + begin = Decode(begin, end, codepoint); + output = Utf<32>::EncodeAnsi(codepoint, output, replacement, locale); + } + + return output; +} + +#ifndef EFSW_NO_WIDECHAR +template <typename In, typename Out> +Out Utf<8>::ToWide(In begin, In end, Out output, wchar_t replacement) +{ + while (begin < end) + { + Uint32 codepoint; + begin = Decode(begin, end, codepoint); + output = Utf<32>::EncodeWide(codepoint, output, replacement); + } + + return output; +} +#endif + +template <typename In, typename Out> +Out Utf<8>::ToLatin1(In begin, In end, Out output, char replacement) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + { + Uint32 codepoint; + begin = Decode(begin, end, codepoint); + *output++ = codepoint < 256 ? static_cast<char>(codepoint) : replacement; + } + + return output; +} + +template <typename In, typename Out> +Out Utf<8>::toUtf8(In begin, In end, Out output) +{ + while (begin < end) + *output++ = *begin++; + + return output; +} + +template <typename In, typename Out> +Out Utf<8>::ToUtf16(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint; + begin = Decode(begin, end, codepoint); + output = Utf<16>::Encode(codepoint, output); + } + + return output; +} + +template <typename In, typename Out> +Out Utf<8>::ToUtf32(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint; + begin = Decode(begin, end, codepoint); + *output++ = codepoint; + } + + return output; +} + +template <typename In> +In Utf<16>::Decode(In begin, In end, Uint32& output, Uint32 replacement) +{ + Uint16 first = *begin++; + + // If it's a surrogate pair, first convert to a single UTF-32 character + if ((first >= 0xD800) && (first <= 0xDBFF)) + { + if (begin < end) + { + Uint32 second = *begin++; + if ((second >= 0xDC00) && (second <= 0xDFFF)) + { + // The second element is valid: convert the two elements to a UTF-32 character + output = static_cast<Uint32>(((first - 0xD800) << 10) + (second - 0xDC00) + 0x0010000); + } + else + { + // Invalid character + output = replacement; + } + } + else + { + // Invalid character + begin = end; + output = replacement; + } + } + else + { + // We can make a direct copy + output = first; + } + + return begin; +} + +template <typename Out> +Out Utf<16>::Encode(Uint32 input, Out output, Uint16 replacement) +{ + if (input < 0xFFFF) + { + // The character can be copied directly, we just need to check if it's in the valid range + if ((input >= 0xD800) && (input <= 0xDFFF)) + { + // Invalid character (this range is reserved) + if (replacement) + *output++ = replacement; + } + else + { + // Valid character directly convertible to a single UTF-16 character + *output++ = static_cast<Uint16>(input); + } + } + else if (input > 0x0010FFFF) + { + // Invalid character (greater than the maximum unicode value) + if (replacement) + *output++ = replacement; + } + else + { + // The input character will be converted to two UTF-16 elements + input -= 0x0010000; + *output++ = static_cast<Uint16>((input >> 10) + 0xD800); + *output++ = static_cast<Uint16>((input & 0x3FFUL) + 0xDC00); + } + + return output; +} + +template <typename In> +In Utf<16>::Next(In begin, In end) +{ + Uint32 codepoint; + return Decode(begin, end, codepoint); +} + +template <typename In> +std::size_t Utf<16>::Count(In begin, In end) +{ + std::size_t length = 0; + while (begin < end) + { + begin = Next(begin, end); + ++length; + } + + return length; +} + +template <typename In, typename Out> +Out Utf<16>::FromAnsi(In begin, In end, Out output, const std::locale& locale) +{ + while (begin < end) + { + Uint32 codepoint = Utf<32>::DecodeAnsi(*begin++, locale); + output = Encode(codepoint, output); + } + + return output; +} + +template <typename In, typename Out> +Out Utf<16>::FromWide(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint = Utf<32>::DecodeWide(*begin++); + output = Encode(codepoint, output); + } + + return output; +} + +template <typename In, typename Out> +Out Utf<16>::FromLatin1(In begin, In end, Out output) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + *output++ = *begin++; + + return output; +} + +template <typename In, typename Out> +Out Utf<16>::ToAnsi(In begin, In end, Out output, char replacement, const std::locale& locale) +{ + while (begin < end) + { + Uint32 codepoint; + begin = Decode(begin, end, codepoint); + output = Utf<32>::EncodeAnsi(codepoint, output, replacement, locale); + } + + return output; +} + +#ifndef EFSW_NO_WIDECHAR +template <typename In, typename Out> +Out Utf<16>::ToWide(In begin, In end, Out output, wchar_t replacement) +{ + while (begin < end) + { + Uint32 codepoint; + begin = Decode(begin, end, codepoint); + output = Utf<32>::EncodeWide(codepoint, output, replacement); + } + + return output; +} +#endif + +template <typename In, typename Out> +Out Utf<16>::ToLatin1(In begin, In end, Out output, char replacement) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + { + *output++ = *begin < 256 ? static_cast<char>(*begin) : replacement; + begin++; + } + + return output; +} + +template <typename In, typename Out> +Out Utf<16>::toUtf8(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint; + begin = Decode(begin, end, codepoint); + output = Utf<8>::Encode(codepoint, output); + } + + return output; +} + +template <typename In, typename Out> +Out Utf<16>::ToUtf16(In begin, In end, Out output) +{ + while (begin < end) + *output++ = *begin++; + + return output; +} + +template <typename In, typename Out> +Out Utf<16>::ToUtf32(In begin, In end, Out output) +{ + while (begin < end) + { + Uint32 codepoint; + begin = Decode(begin, end, codepoint); + *output++ = codepoint; + } + + return output; +} + +template <typename In> +In Utf<32>::Decode(In begin, In end, Uint32& output, Uint32) +{ + output = *begin++; + return begin; +} + +template <typename Out> +Out Utf<32>::Encode(Uint32 input, Out output, Uint32 replacement) +{ + *output++ = input; + return output; +} + +template <typename In> +In Utf<32>::Next(In begin, In end) +{ + return ++begin; +} + +template <typename In> +std::size_t Utf<32>::Count(In begin, In end) +{ + return begin - end; +} + +template <typename In, typename Out> +Out Utf<32>::FromAnsi(In begin, In end, Out output, const std::locale& locale) +{ + while (begin < end) + *output++ = DecodeAnsi(*begin++, locale); + + return output; +} + +template <typename In, typename Out> +Out Utf<32>::FromWide(In begin, In end, Out output) +{ + while (begin < end) + *output++ = DecodeWide(*begin++); + + return output; +} + +template <typename In, typename Out> +Out Utf<32>::FromLatin1(In begin, In end, Out output) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + *output++ = *begin++; + + return output; +} + +template <typename In, typename Out> +Out Utf<32>::ToAnsi(In begin, In end, Out output, char replacement, const std::locale& locale) +{ + while (begin < end) + output = EncodeAnsi(*begin++, output, replacement, locale); + + return output; +} + +#ifndef EFSW_NO_WIDECHAR +template <typename In, typename Out> +Out Utf<32>::ToWide(In begin, In end, Out output, wchar_t replacement) +{ + while (begin < end) + output = EncodeWide(*begin++, output, replacement); + + return output; +} +#endif + +template <typename In, typename Out> +Out Utf<32>::ToLatin1(In begin, In end, Out output, char replacement) +{ + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while (begin < end) + { + *output++ = *begin < 256 ? static_cast<char>(*begin) : replacement; + begin++; + } + + return output; +} + +template <typename In, typename Out> +Out Utf<32>::toUtf8(In begin, In end, Out output) +{ + while (begin < end) + output = Utf<8>::Encode(*begin++, output); + + return output; +} + +template <typename In, typename Out> +Out Utf<32>::ToUtf16(In begin, In end, Out output) +{ + while (begin < end) + output = Utf<16>::Encode(*begin++, output); + + return output; +} + +template <typename In, typename Out> +Out Utf<32>::ToUtf32(In begin, In end, Out output) +{ + while (begin < end) + *output++ = *begin++; + + return output; +} + +template <typename In> +Uint32 Utf<32>::DecodeAnsi(In input, const std::locale& locale) +{ + // On Windows, gcc's standard library (glibc++) has almost + // no support for Unicode stuff. As a consequence, in this + // context we can only use the default locale and ignore + // the one passed as parameter. + + #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ + (defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \ + !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */ + + wchar_t character = 0; + mbtowc(&character, &input, 1); + return static_cast<Uint32>(character); + + #else + // Get the facet of the locale which deals with character conversion + #ifndef EFSW_NO_WIDECHAR + const std::ctype<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale); + #else + const std::ctype<char>& facet = std::use_facet< std::ctype<char> >(locale); + #endif + + // Use the facet to convert each character of the input string + return static_cast<Uint32>(facet.widen(input)); + + #endif +} + +template <typename In> +Uint32 Utf<32>::DecodeWide(In input) +{ + // The encoding of wide characters is not well defined and is left to the system; + // however we can safely assume that it is UCS-2 on Windows and + // UCS-4 on Unix systems. + // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, + // and UCS-4 *is* UTF-32). + + return input; +} + +template <typename Out> +Out Utf<32>::EncodeAnsi(Uint32 codepoint, Out output, char replacement, const std::locale& locale) +{ + // On Windows, gcc's standard library (glibc++) has almost + // no support for Unicode stuff. As a consequence, in this + // context we can only use the default locale and ignore + // the one passed as parameter. + + #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ + (defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \ + !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */ + + char character = 0; + if (wctomb(&character, static_cast<wchar_t>(codepoint)) >= 0) + *output++ = character; + else if (replacement) + *output++ = replacement; + + return output; + + #else + // Get the facet of the locale which deals with character conversion + #ifndef EFSW_NO_WIDECHAR + const std::ctype<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale); + #else + const std::ctype<char>& facet = std::use_facet< std::ctype<char> >(locale); + #endif + + // Use the facet to convert each character of the input string + *output++ = facet.narrow(static_cast<wchar_t>(codepoint), replacement); + + return output; + + #endif +} + +#ifndef EFSW_NO_WIDECHAR +template <typename Out> +Out Utf<32>::EncodeWide(Uint32 codepoint, Out output, wchar_t replacement) +{ + // The encoding of wide characters is not well defined and is left to the system; + // however we can safely assume that it is UCS-2 on Windows and + // UCS-4 on Unix systems. + // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). + // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). + + switch (sizeof(wchar_t)) + { + case 4: + { + *output++ = static_cast<wchar_t>(codepoint); + break; + } + + default: + { + if ((codepoint <= 0xFFFF) && ((codepoint < 0xD800) || (codepoint > 0xDFFF))) + { + *output++ = static_cast<wchar_t>(codepoint); + } + else if (replacement) + { + *output++ = replacement; + } + break; + } + } + + return output; +} +#endif diff --git a/dep/efsw/src/efsw/Watcher.cpp b/dep/efsw/src/efsw/Watcher.cpp new file mode 100644 index 00000000000..d81c84228ad --- /dev/null +++ b/dep/efsw/src/efsw/Watcher.cpp @@ -0,0 +1,21 @@ +#include <efsw/Watcher.hpp> + +namespace efsw { + +Watcher::Watcher() : + ID(0), + Directory(""), + Listener(NULL), + Recursive(false) +{ +} + +Watcher::Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive ) : + ID( id ), + Directory( directory ), + Listener( listener ), + Recursive( recursive ) +{ +} + +} diff --git a/dep/efsw/src/efsw/Watcher.hpp b/dep/efsw/src/efsw/Watcher.hpp new file mode 100644 index 00000000000..5a35cb9a2ac --- /dev/null +++ b/dep/efsw/src/efsw/Watcher.hpp @@ -0,0 +1,30 @@ +#ifndef EFSW_WATCHERIMPL_HPP +#define EFSW_WATCHERIMPL_HPP + +#include <efsw/base.hpp> +#include <efsw/efsw.hpp> + +namespace efsw { + +/** @brief Base Watcher class */ +class Watcher +{ + public: + Watcher(); + + Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive ); + + virtual ~Watcher() {} + + virtual void watch() {} + + WatchID ID; + std::string Directory; + FileWatchListener * Listener; + bool Recursive; + std::string OldFileName; +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/WatcherFSEvents.cpp b/dep/efsw/src/efsw/WatcherFSEvents.cpp new file mode 100644 index 00000000000..3a9700c77ec --- /dev/null +++ b/dep/efsw/src/efsw/WatcherFSEvents.cpp @@ -0,0 +1,264 @@ +#include <efsw/WatcherFSEvents.hpp> +#include <efsw/FileWatcherFSEvents.hpp> +#include <efsw/FileSystem.hpp> +#include <efsw/Debug.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS + +namespace efsw { + +WatcherFSEvents::WatcherFSEvents() : + Watcher(), + FWatcher( NULL ), + FSStream( NULL ), + WatcherGen( NULL ), + initializedAsync( false ) +{ +} + +WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent ) : + Watcher( id, directory, listener, recursive ), + FWatcher( NULL ), + FSStream( NULL ), + WatcherGen( NULL ), + initializedAsync( false ) +{ +} + +WatcherFSEvents::~WatcherFSEvents() +{ + if ( initializedAsync ) + { + FSEventStreamStop( FSStream ); + FSEventStreamInvalidate( FSStream ); + } + + if ( NULL != FSStream ) + { + FSEventStreamRelease( FSStream ); + } + + efSAFE_DELETE( WatcherGen ); +} + +void WatcherFSEvents::init() +{ + CFStringRef CFDirectory = CFStringCreateWithCString( NULL, Directory.c_str(), kCFStringEncodingUTF8 ); + CFArrayRef CFDirectoryArray = CFArrayCreate( NULL, (const void **)&CFDirectory, 1, NULL ); + + Uint32 streamFlags = kFSEventStreamCreateFlagNone; + + if ( FileWatcherFSEvents::isGranular() ) + { + streamFlags = efswFSEventStreamCreateFlagFileEvents; + } + else + { + WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher, Recursive ); + } + + FSEventStreamContext ctx; + /* Initialize context */ + ctx.version = 0; + ctx.info = this; + ctx.retain = NULL; + ctx.release = NULL; + ctx.copyDescription = NULL; + + FSStream = FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags ); + + FWatcher->mNeedInit.push_back( this ); + + CFRelease( CFDirectoryArray ); + CFRelease( CFDirectory ); +} + +void WatcherFSEvents::initAsync() +{ + FSEventStreamScheduleWithRunLoop( FSStream, FWatcher->mRunLoopRef, kCFRunLoopDefaultMode ); + FSEventStreamStart( FSStream ); + initializedAsync = true; +} + +void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename ) +{ + Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), FileSystem::precomposeFileName( filename ), action, oldFilename ); +} + +void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, std::string& filePath ) +{ + if ( flags & efswFSEventStreamEventFlagItemCreated ) + { + if ( FileInfo::exists( path ) ) + { + sendFileAction( ID, dirPath, filePath, Actions::Add ); + } + } + + if ( flags & efswFSEventsModified ) + { + sendFileAction( ID, dirPath, filePath, Actions::Modified ); + } + + if ( flags & efswFSEventStreamEventFlagItemRemoved ) + { + // Since i don't know the order, at least i try to keep the data consistent with the real state + if ( !FileInfo::exists( path ) ) + { + sendFileAction( ID, dirPath, filePath, Actions::Delete ); + } + } +} + +void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) +{ + size_t esize = events.size(); + + for ( size_t i = 0; i < esize; i++ ) + { + FSEvent& event = events[i]; + + if ( event.Flags & ( kFSEventStreamEventFlagUserDropped | + kFSEventStreamEventFlagKernelDropped | + kFSEventStreamEventFlagEventIdsWrapped | + kFSEventStreamEventFlagHistoryDone | + kFSEventStreamEventFlagMount | + kFSEventStreamEventFlagUnmount | + kFSEventStreamEventFlagRootChanged ) ) + { + continue; + } + + if ( !Recursive ) + { + /** In case that is not recursive the watcher, ignore the events from subfolders */ + if ( event.Path.find_last_of( FileSystem::getOSSlash() ) != Directory.size() - 1 ) + { + continue; + } + } + + if ( FileWatcherFSEvents::isGranular() ) + { + std::string dirPath( FileSystem::pathRemoveFileName( event.Path ) ); + std::string filePath( FileSystem::fileNameFromPath( event.Path ) ); + + if ( event.Flags & ( efswFSEventStreamEventFlagItemCreated | + efswFSEventStreamEventFlagItemRemoved | + efswFSEventStreamEventFlagItemRenamed ) + ) + { + if ( dirPath != Directory ) + { + DirsChanged.insert( dirPath ); + } + } + + // This is a mess. But it's FSEvents faults, because shrinks events from the same file in one single event ( so there's no order for them ) + // For example a file could have been added modified and erased, but i can't know if first was erased and then added and modified, or added, then modified and then erased. + // I don't know what they were thinking by doing this... + efDEBUG( "Event in: %s - flags: %ld\n", path.c_str(), event.Flags ); + + if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) + { + if ( ( i + 1 < esize ) && + ( events[ i + 1 ].Flags & efswFSEventStreamEventFlagItemRenamed ) && + ( events[ i + 1 ].Id == event.Id + 1 ) + ) + { + FSEvent& nEvent = events[ i + 1 ]; + std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) ); + std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) ); + + if ( event.Path != nEvent.Path ) + { + if ( dirPath == newDir ) + { + if ( !FileInfo::exists( event.Path ) ) + { + sendFileAction( ID, dirPath, newFilepath, Actions::Moved, filePath ); + } + else + { + sendFileAction( ID, dirPath, filePath, Actions::Moved, newFilepath ); + } + } + else + { + sendFileAction( ID, dirPath, filePath, Actions::Delete ); + sendFileAction( ID, newDir, newFilepath, Actions::Add ); + + if ( nEvent.Flags & efswFSEventsModified ) + { + sendFileAction( ID, newDir, newFilepath, Actions::Modified ); + } + } + } + else + { + handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath ); + } + + if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated | + efswFSEventStreamEventFlagItemRemoved | + efswFSEventStreamEventFlagItemRenamed ) + ) + { + if ( newDir != Directory ) + { + DirsChanged.insert( newDir ); + } + } + + // Skip the renamed file + i++; + } + else if ( FileInfo::exists( event.Path ) ) + { + sendFileAction( ID, dirPath, filePath, Actions::Add ); + + if ( event.Flags & efswFSEventsModified ) + { + sendFileAction( ID, dirPath, filePath, Actions::Modified ); + } + } + else + { + sendFileAction( ID, dirPath, filePath, Actions::Delete ); + } + } + else + { + handleAddModDel( event.Flags, event.Path, dirPath, filePath ); + } + } + else + { + efDEBUG( "Directory: %s changed\n", event.Path.c_str() ); + DirsChanged.insert( event.Path ); + } + } +} + +void WatcherFSEvents::process() +{ + std::set<std::string>::iterator it = DirsChanged.begin(); + + for ( ; it != DirsChanged.end(); it++ ) + { + if ( !FileWatcherFSEvents::isGranular() ) + { + WatcherGen->watchDir( (*it) ); + } + else + { + sendFileAction( ID, FileSystem::pathRemoveFileName( (*it) ), FileSystem::fileNameFromPath( (*it) ), Actions::Modified ); + } + } + + DirsChanged.clear(); +} + +} + +#endif diff --git a/dep/efsw/src/efsw/WatcherFSEvents.hpp b/dep/efsw/src/efsw/WatcherFSEvents.hpp new file mode 100644 index 00000000000..d4fc5c9a8d3 --- /dev/null +++ b/dep/efsw/src/efsw/WatcherFSEvents.hpp @@ -0,0 +1,70 @@ +#ifndef EFSW_WATCHERINOTIFY_HPP +#define EFSW_WATCHERINOTIFY_HPP + +#include <efsw/FileWatcherImpl.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS + +#include <efsw/WatcherGeneric.hpp> +#include <efsw/FileInfo.hpp> +#include <CoreFoundation/CoreFoundation.h> +#include <CoreServices/CoreServices.h> +#include <set> +#include <vector> + +namespace efsw { + +class FileWatcherFSEvents; + +class FSEvent +{ + public: + FSEvent( std::string path, long flags, Uint64 id ) : + Path( path ), + Flags( flags ), + Id ( id ) + { + } + + std::string Path; + long Flags; + Uint64 Id; +}; + +class WatcherFSEvents : public Watcher +{ + public: + WatcherFSEvents(); + + WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent = NULL ); + + ~WatcherFSEvents(); + + void init(); + + void initAsync(); + + void handleActions( std::vector<FSEvent> & events ); + + void process(); + + FileWatcherFSEvents * FWatcher; + + FSEventStreamRef FSStream; + protected: + void handleAddModDel( const Uint32 &flags, const std::string &path, std::string &dirPath, std::string &filePath ); + + WatcherGeneric * WatcherGen; + + bool initializedAsync; + + std::set<std::string> DirsChanged; + + void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" ); +}; + +} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/WatcherGeneric.cpp b/dep/efsw/src/efsw/WatcherGeneric.cpp new file mode 100644 index 00000000000..94170d3ce87 --- /dev/null +++ b/dep/efsw/src/efsw/WatcherGeneric.cpp @@ -0,0 +1,40 @@ +#include <efsw/WatcherGeneric.hpp> +#include <efsw/FileSystem.hpp> +#include <efsw/DirWatcherGeneric.hpp> + +namespace efsw +{ + +WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive ) : + Watcher( id, directory, fwl, recursive ), + WatcherImpl( fw ), + DirWatch( NULL ) +{ + FileSystem::dirAddSlashAtEnd( Directory ); + + DirWatch = new DirWatcherGeneric( NULL, this, directory, recursive, false ); + + DirWatch->addChilds( false ); +} + +WatcherGeneric::~WatcherGeneric() +{ + efSAFE_DELETE( DirWatch ); +} + +void WatcherGeneric::watch() +{ + DirWatch->watch(); +} + +void WatcherGeneric::watchDir( std::string dir ) +{ + DirWatch->watchDir( dir ); +} + +bool WatcherGeneric::pathInWatches( std::string path ) +{ + return DirWatch->pathInWatches( path ); +} + +} diff --git a/dep/efsw/src/efsw/WatcherGeneric.hpp b/dep/efsw/src/efsw/WatcherGeneric.hpp new file mode 100644 index 00000000000..8794e921b40 --- /dev/null +++ b/dep/efsw/src/efsw/WatcherGeneric.hpp @@ -0,0 +1,30 @@ +#ifndef EFSW_WATCHERGENERIC_HPP +#define EFSW_WATCHERGENERIC_HPP + +#include <efsw/FileWatcherImpl.hpp> + +namespace efsw +{ + +class DirWatcherGeneric; + +class WatcherGeneric : public Watcher +{ + public: + FileWatcherImpl * WatcherImpl; + DirWatcherGeneric * DirWatch; + + WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive ); + + ~WatcherGeneric(); + + void watch(); + + void watchDir( std::string dir ); + + bool pathInWatches( std::string path ); +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/WatcherInotify.cpp b/dep/efsw/src/efsw/WatcherInotify.cpp new file mode 100644 index 00000000000..741641bf43c --- /dev/null +++ b/dep/efsw/src/efsw/WatcherInotify.cpp @@ -0,0 +1,35 @@ +#include <efsw/WatcherInotify.hpp> + +namespace efsw { + +WatcherInotify::WatcherInotify() : + Watcher(), + Parent( NULL ) +{ +} + +WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent ) : + Watcher( id, directory, listener, recursive ), + Parent( parent ), + DirInfo( directory ) +{ +} + +bool WatcherInotify::inParentTree( WatcherInotify * parent ) +{ + WatcherInotify * tNext = Parent; + + while ( NULL != tNext ) + { + if ( tNext == parent ) + { + return true; + } + + tNext = tNext->Parent; + } + + return false; +} + +} diff --git a/dep/efsw/src/efsw/WatcherInotify.hpp b/dep/efsw/src/efsw/WatcherInotify.hpp new file mode 100644 index 00000000000..1caf399679b --- /dev/null +++ b/dep/efsw/src/efsw/WatcherInotify.hpp @@ -0,0 +1,25 @@ +#ifndef EFSW_WATCHERINOTIFY_HPP +#define EFSW_WATCHERINOTIFY_HPP + +#include <efsw/FileWatcherImpl.hpp> +#include <efsw/FileInfo.hpp> + +namespace efsw { + +class WatcherInotify : public Watcher +{ + public: + WatcherInotify(); + + WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent = NULL ); + + bool inParentTree( WatcherInotify * parent ); + + WatcherInotify * Parent; + + FileInfo DirInfo; +}; + +} + +#endif diff --git a/dep/efsw/src/efsw/WatcherKqueue.cpp b/dep/efsw/src/efsw/WatcherKqueue.cpp new file mode 100644 index 00000000000..8347fb53439 --- /dev/null +++ b/dep/efsw/src/efsw/WatcherKqueue.cpp @@ -0,0 +1,667 @@ +#include <efsw/WatcherKqueue.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS + +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <efsw/Debug.hpp> +#include <efsw/String.hpp> +#include <efsw/System.hpp> +#include <efsw/FileSystem.hpp> +#include <efsw/WatcherGeneric.hpp> +#include <efsw/FileWatcherKqueue.hpp> + +#define KEVENT_RESERVE_VALUE (10) + +#ifndef O_EVTONLY +#define O_EVTONLY (O_RDONLY | O_NONBLOCK) +#endif + +namespace efsw { + +int comparator(const void* ke1, const void* ke2) +{ + const KEvent * kev1 = reinterpret_cast<const KEvent*>( ke1 ); + const KEvent * kev2 = reinterpret_cast<const KEvent*>( ke2 ); + + if ( NULL != kev2->udata ) + { + FileInfo * fi1 = reinterpret_cast<FileInfo*>( kev1->udata ); + FileInfo * fi2 = reinterpret_cast<FileInfo*>( kev2->udata ); + + return strcmp( fi1->Filepath.c_str(), fi2->Filepath.c_str() ); + } + + return 1; +} + +WatcherKqueue::WatcherKqueue(WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent ) : + Watcher( watchid, dirname, listener, recursive ), + mLastWatchID(0), + mChangeListCount( 0 ), + mKqueue( kqueue() ), + mWatcher( watcher ), + mParent( parent ), + mInitOK( true ), + mErrno(0) +{ + if ( -1 == mKqueue ) + { + efDEBUG( "kqueue() returned invalid descriptor for directory %s. File descriptors count: %ld\n", Directory.c_str(), mWatcher->mFileDescriptorCount ); + + mInitOK = false; + mErrno = errno; + } + else + { + mWatcher->addFD(); + } +} + +WatcherKqueue::~WatcherKqueue() +{ + // Remove the childs watchers ( sub-folders watches ) + removeAll(); + + for ( size_t i = 0; i < mChangeListCount; i++ ) + { + if ( NULL != mChangeList[i].udata ) + { + FileInfo * fi = reinterpret_cast<FileInfo*>( mChangeList[i].udata ); + + efSAFE_DELETE( fi ); + } + } + + close( mKqueue ); + + mWatcher->removeFD(); +} + +void WatcherKqueue::addAll() +{ + if ( -1 == mKqueue ) + { + return; + } + + // scan directory and call addFile(name, false) on each file + FileSystem::dirAddSlashAtEnd( Directory ); + + efDEBUG( "addAll(): Added folder: %s\n", Directory.c_str()); + + // add base dir + int fd = open( Directory.c_str(), O_EVTONLY ); + + if ( -1 == fd ) + { + efDEBUG( "addAll(): Couldn't open folder: %s\n", Directory.c_str() ); + + if ( EACCES != errno ) + { + mInitOK = false; + } + + mErrno = errno; + + return; + } + + mDirSnap.setDirectoryInfo( Directory ); + mDirSnap.scan(); + + mChangeList.resize( KEVENT_RESERVE_VALUE ); + + // Creates the kevent for the folder + EV_SET( + &mChangeList[0], + fd, + EVFILT_VNODE, + EV_ADD | EV_ENABLE | EV_ONESHOT, + NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, + 0, + 0 + ); + + mWatcher->addFD(); + + // Get the files and directories from the directory + FileInfoMap files = FileSystem::filesInfoFromPath( Directory ); + + for ( FileInfoMap::iterator it = files.begin(); it != files.end(); it++ ) + { + FileInfo& fi = it->second; + + if ( fi.isRegularFile() ) + { + // Add the regular files kevent + addFile( fi.Filepath , false ); + } + else if ( Recursive && fi.isDirectory() && fi.isReadable() ) + { + // Create another watcher for the subfolders ( if recursive ) + WatchID id = addWatch( fi.Filepath, Listener, Recursive, this ); + + // If the watcher is not adding the watcher means that the directory was created + if ( id > 0 && !mWatcher->isAddingWatcher() ) + { + handleFolderAction( fi.Filepath, Actions::Add ); + } + } + } +} + +void WatcherKqueue::removeAll() +{ + efDEBUG( "removeAll(): Removing all child watchers\n" ); + + std::list<WatchID> erase; + + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() ); + + erase.push_back( it->second->ID ); + } + + for ( std::list<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ ) + { + removeWatch( *eit ); + } +} + +void WatcherKqueue::addFile(const std::string& name, bool emitEvents) +{ + efDEBUG( "addFile(): Added: %s\n", name.c_str() ); + + // Open the file to get the file descriptor + int fd = open( name.c_str(), O_EVTONLY ); + + if( fd == -1 ) + { + efDEBUG( "addFile(): Could open file descriptor for %s. File descriptor count: %ld\n", name.c_str(), mWatcher->mFileDescriptorCount ); + + Errors::Log::createLastError( Errors::FileNotReadable, name ); + + if ( EACCES != errno ) + { + mInitOK = false; + } + + mErrno = errno; + + return; + } + + mWatcher->addFD(); + + // increase the file kevent file count + mChangeListCount++; + + if ( mChangeListCount + KEVENT_RESERVE_VALUE > mChangeList.size() && + mChangeListCount % KEVENT_RESERVE_VALUE == 0 ) + { + size_t reserve_size = mChangeList.size() + KEVENT_RESERVE_VALUE; + mChangeList.resize( reserve_size ); + efDEBUG( "addFile(): Reserverd more KEvents space for %s, space reserved %ld, list actual size %ld.\n", Directory.c_str(), reserve_size, mChangeListCount ); + } + + // create entry + FileInfo * entry = new FileInfo( name ); + + // set the event data at the end of the list + EV_SET( + &mChangeList[mChangeListCount], + fd, + EVFILT_VNODE, + EV_ADD | EV_ENABLE | EV_ONESHOT, + NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, + 0, + (void*)entry + ); + + // qsort sort the list by name + qsort(&mChangeList[1], mChangeListCount, sizeof(KEvent), comparator); + + // handle action + if( emitEvents ) + { + handleAction(name, Actions::Add); + } +} + +void WatcherKqueue::removeFile( const std::string& name, bool emitEvents ) +{ + efDEBUG( "removeFile(): Trying to remove file: %s\n", name.c_str() ); + + // bsearch + KEvent target; + + // Create a temporary file info to search the kevent ( searching the directory ) + FileInfo tempEntry( name ); + + target.udata = &tempEntry; + + // Search the kevent + KEvent * ke = (KEvent*)bsearch(&target, &mChangeList[0], mChangeListCount + 1, sizeof(KEvent), comparator); + + // Trying to remove a non-existing file? + if( !ke ) + { + Errors::Log::createLastError( Errors::FileNotFound, name ); + efDEBUG( "File not removed\n" ); + return; + } + + efDEBUG( "File removed\n" ); + + // handle action + if ( emitEvents ) + { + handleAction( name, Actions::Delete ); + } + + // Delete the user data ( FileInfo ) from the kevent closed + FileInfo * del = reinterpret_cast<FileInfo*>( ke->udata ); + + efSAFE_DELETE( del ); + + // close the file descriptor from the kevent + close( ke->ident ); + + mWatcher->removeFD(); + + memset(ke, 0, sizeof(KEvent)); + + // move end to current + memcpy(ke, &mChangeList[mChangeListCount], sizeof(KEvent)); + memset(&mChangeList[mChangeListCount], 0, sizeof(KEvent)); + --mChangeListCount; +} + +void WatcherKqueue::rescan() +{ + efDEBUG( "rescan(): Rescanning: %s\n", Directory.c_str() ); + + DirectorySnapshotDiff Diff = mDirSnap.scan(); + + if ( Diff.DirChanged ) + { + sendDirChanged(); + } + + if ( Diff.changed() ) + { + FileInfoList::iterator it; + MovedList::iterator mit; + + /// Files + DiffIterator( FilesCreated ) + { + addFile( (*it).Filepath ); + } + + DiffIterator( FilesModified ) + { + handleAction( (*it).Filepath, Actions::Modified ); + } + + DiffIterator( FilesDeleted ) + { + removeFile( (*it).Filepath ); + } + + DiffMovedIterator( FilesMoved ) + { + handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first ); + removeFile( Directory + (*mit).first, false ); + addFile( (*mit).second.Filepath, false ); + } + + /// Directories + DiffIterator( DirsCreated ) + { + handleFolderAction( (*it).Filepath, Actions::Add ); + addWatch( (*it).Filepath, Listener, Recursive, this ); + } + + DiffIterator( DirsModified ) + { + handleFolderAction( (*it).Filepath, Actions::Modified ); + } + + DiffIterator( DirsDeleted ) + { + handleFolderAction( (*it).Filepath, Actions::Delete ); + + Watcher * watch = findWatcher( (*it).Filepath ); + + if ( NULL != watch ) + { + removeWatch( watch->ID ); + + } + } + + DiffMovedIterator( DirsMoved ) + { + moveDirectory( Directory + (*mit).first, (*mit).second.Filepath ); + } + } +} + +WatchID WatcherKqueue::watchingDirectory( std::string dir ) +{ + Watcher * watch = findWatcher( dir ); + + if ( NULL != watch ) + { + return watch->ID; + } + + return Errors::FileNotFound; +} + +void WatcherKqueue::handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename ) +{ + Listener->handleFileAction( ID, Directory, FileSystem::fileNameFromPath( filename ), action, FileSystem::fileNameFromPath( oldFilename ) ); +} + +void WatcherKqueue::handleFolderAction( std::string filename, efsw::Action action , const std::string &oldFilename ) +{ + FileSystem::dirRemoveSlashAtEnd( filename ); + + handleAction( filename, action, oldFilename ); +} + +void WatcherKqueue::sendDirChanged() +{ + if ( NULL != mParent ) + { + Listener->handleFileAction( mParent->ID, mParent->Directory, FileSystem::fileNameFromPath( Directory ), Actions::Modified ); + } +} + +void WatcherKqueue::watch() +{ + if ( -1 == mKqueue ) + { + return; + } + + int nev = 0; + KEvent event; + + // First iterate the childs, to get the events from the deepest folder, to the watcher childs + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) + { + it->second->watch(); + } + + bool needScan = false; + + // Then we get the the events of the current folder + while( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1, &mWatcher->mTimeOut ) ) != 0 ) + { + // An error ocurred? + if( nev == -1 ) + { + efDEBUG( "watch(): Error on directory %s\n", Directory.c_str() ); + perror("kevent"); + break; + } + else + { + FileInfo * entry = NULL; + + // If udate == NULL means that it is the fisrt element of the change list, the folder. + // otherwise it is an event of some file inside the folder + if( ( entry = reinterpret_cast<FileInfo*> ( event.udata ) ) != NULL ) + { + efDEBUG( "watch(): File: %s ", entry->Filepath.c_str() ); + + // If the event flag is delete... the file was deleted + if ( event.fflags & NOTE_DELETE ) + { + efDEBUG( "deleted\n" ); + + mDirSnap.removeFile( entry->Filepath ); + + removeFile( entry->Filepath ); + } + else if ( event.fflags & NOTE_EXTEND || + event.fflags & NOTE_WRITE || + event.fflags & NOTE_ATTRIB + ) + { + // The file was modified + efDEBUG( "modified\n" ); + + FileInfo fi( entry->Filepath ); + + if ( fi != *entry ) + { + *entry = fi; + + mDirSnap.updateFile( entry->Filepath ); + + handleAction( entry->Filepath, efsw::Actions::Modified ); + } + } + else if ( event.fflags & NOTE_RENAME ) + { + efDEBUG( "moved\n" ); + + needScan = true; + } + } + else + { + needScan = true; + } + } + } + + if ( needScan ) + { + rescan(); + } +} + +Watcher * WatcherKqueue::findWatcher( const std::string path ) +{ + WatchMap::iterator it = mWatches.begin(); + + for ( ; it != mWatches.end(); it++ ) + { + if ( it->second->Directory == path ) + { + return it->second; + } + } + + return NULL; +} + +void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, bool emitEvents ) +{ + // Update the directory path if it's a watcher + std::string opath2( oldPath ); + FileSystem::dirAddSlashAtEnd( opath2 ); + + Watcher * watch = findWatcher( opath2 ); + + if ( NULL != watch ) + { + watch->Directory = opath2; + } + + if ( emitEvents ) + { + handleFolderAction( newPath, efsw::Actions::Moved, oldPath ); + } +} + +WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive , WatcherKqueue *parent) +{ + static long s_fc = 0; + static bool s_ug = false; + + std::string dir( directory ); + + FileSystem::dirAddSlashAtEnd( dir ); + + // This should never happen here + if( !FileSystem::isDirectory( dir ) ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + else if ( pathInWatches( dir ) || pathInParent( dir ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, directory ); + } + else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) + { + return Errors::Log::createLastError( Errors::FileRemote, dir ); + } + + std::string curPath; + std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); + + if ( "" != link ) + { + /// Avoid adding symlinks directories if it's now enabled + if ( NULL != parent && !mWatcher->mFileWatcher->followSymlinks() ) + { + return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); + } + + if ( pathInWatches( link ) || pathInParent( link ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, link ); + } + else if ( !mWatcher->linkAllowed( curPath, link ) ) + { + return Errors::Log::createLastError( Errors::FileOutOfScope, link ); + } + else + { + dir = link; + } + } + + if ( mWatcher->availablesFD() ) + { + WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, mWatcher, parent ); + + mWatches.insert(std::make_pair(mLastWatchID, watch)); + + watch->addAll(); + + s_fc++; + + // if failed to open the directory... erase the watcher + if ( !watch->initOK() ) + { + int le = watch->lastErrno(); + + mWatches.erase( watch->ID ); + + efSAFE_DELETE( watch ); + + mLastWatchID--; + + // Probably the folder has too many files, create a generic watcher + if ( EACCES != le ) + { + WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive ); + + mWatches.insert(std::make_pair(mLastWatchID, watch)); + } + else + { + return Errors::Log::createLastError( Errors::Unspecified, link ); + } + } + } + else + { + if ( !s_ug ) + { + efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld. Folders added: %ld\n", mWatcher->mFileDescriptorCount, s_fc ); + s_ug = true; + } + + WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive ); + + mWatches.insert(std::make_pair(mLastWatchID, watch)); + } + + return mLastWatchID; +} + +bool WatcherKqueue::initOK() +{ + return mInitOK; +} + +void WatcherKqueue::removeWatch( WatchID watchid ) +{ + WatchMap::iterator iter = mWatches.find(watchid); + + if(iter == mWatches.end()) + return; + + Watcher * watch = iter->second; + + mWatches.erase(iter); + + efSAFE_DELETE( watch ); +} + +bool WatcherKqueue::pathInWatches( const std::string& path ) +{ + return NULL != findWatcher( path ); +} + +bool WatcherKqueue::pathInParent( const std::string &path ) +{ + WatcherKqueue * pNext = mParent; + + while ( NULL != pNext ) + { + if ( pNext->pathInWatches( path ) ) + { + return true; + } + + pNext = pNext->mParent; + } + + if ( mWatcher->pathInWatches( path ) ) + { + return true; + } + + if ( path == Directory ) + { + return true; + } + + return false; +} + +int WatcherKqueue::lastErrno() +{ + return mErrno; +} + +} + +#endif diff --git a/dep/efsw/src/efsw/WatcherKqueue.hpp b/dep/efsw/src/efsw/WatcherKqueue.hpp new file mode 100644 index 00000000000..4babbe73354 --- /dev/null +++ b/dep/efsw/src/efsw/WatcherKqueue.hpp @@ -0,0 +1,94 @@ +#ifndef EFSW_WATCHEROSX_HPP +#define EFSW_WATCHEROSX_HPP + +#include <efsw/FileWatcherImpl.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS + +#include <map> +#include <vector> +#include <sys/types.h> +#include <sys/event.h> +#include <efsw/DirectorySnapshot.hpp> + +namespace efsw +{ + +class FileWatcherKqueue; +class WatcherKqueue; + +typedef struct kevent KEvent; + +/// type for a map from WatchID to WatcherKqueue pointer +typedef std::map<WatchID, Watcher*> WatchMap; + +class WatcherKqueue : public Watcher +{ + public: + WatcherKqueue( WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent = NULL ); + + virtual ~WatcherKqueue(); + + void addFile( const std::string& name, bool emitEvents = true ); + + void removeFile( const std::string& name, bool emitEvents = true ); + + // called when the directory is actually changed + // means a file has been added or removed + // rescans the watched directory adding/removing files and sending notices + void rescan(); + + void handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename = "" ); + + void handleFolderAction( std::string filename, efsw::Action action, const std::string& oldFilename = "" ); + + void addAll(); + + void removeAll(); + + WatchID watchingDirectory( std::string dir ); + + void watch(); + + WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherKqueue * parent); + + void removeWatch (WatchID watchid ); + + bool initOK(); + + int lastErrno(); + protected: + WatchMap mWatches; + int mLastWatchID; + + // index 0 is always the directory + std::vector<KEvent> mChangeList; + size_t mChangeListCount; + DirectorySnapshot mDirSnap; + + /// The descriptor for the kqueue + int mKqueue; + + FileWatcherKqueue * mWatcher; + + WatcherKqueue * mParent; + + bool mInitOK; + int mErrno; + + bool pathInWatches( const std::string& path ); + + bool pathInParent( const std::string& path ); + + Watcher * findWatcher( const std::string path ); + + void moveDirectory( std::string oldPath, std::string newPath, bool emitEvents = true ); + + void sendDirChanged(); +}; + +} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/WatcherWin32.cpp b/dep/efsw/src/efsw/WatcherWin32.cpp new file mode 100644 index 00000000000..01d7b0fcd99 --- /dev/null +++ b/dep/efsw/src/efsw/WatcherWin32.cpp @@ -0,0 +1,150 @@ +#include <efsw/WatcherWin32.hpp> +#include <efsw/String.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +namespace efsw +{ + +/// Unpacks events and passes them to a user defined callback. +void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) +{ + char szFile[MAX_PATH]; + PFILE_NOTIFY_INFORMATION pNotify; + WatcherStructWin32 * tWatch = (WatcherStructWin32*) lpOverlapped; + WatcherWin32 * pWatch = tWatch->Watch; + size_t offset = 0; + + if (dwNumberOfBytesTransfered == 0) + { + RefreshWatch(tWatch); // If dwNumberOfBytesTransfered == 0, it means the buffer overflowed (too many changes between GetOverlappedResults calls). Those events are lost, but at least we can refresh so subsequent changes are seen again. + return; + } + + if (dwErrorCode == ERROR_SUCCESS) + { + do + { + bool skip = false; + + pNotify = (PFILE_NOTIFY_INFORMATION) &pWatch->mBuffer[offset]; + offset += pNotify->NextEntryOffset; + + int count = WideCharToMultiByte(CP_UTF8, 0, pNotify->FileName, + pNotify->FileNameLength / sizeof(WCHAR), + szFile, MAX_PATH - 1, NULL, NULL); + szFile[count] = TEXT('\0'); + + std::string nfile( szFile ); + + if ( FILE_ACTION_MODIFIED == pNotify->Action ) + { + FileInfo fifile( std::string( pWatch->DirName ) + nfile ); + + if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime && pWatch->LastModifiedEvent.file.Size == fifile.Size && pWatch->LastModifiedEvent.fileName == nfile ) + { + skip = true; + } + + pWatch->LastModifiedEvent.fileName = nfile; + pWatch->LastModifiedEvent.file = fifile; + } + + if ( !skip ) + { + pWatch->Watch->handleAction(pWatch, nfile, pNotify->Action); + } + } while (pNotify->NextEntryOffset != 0); + } + + if (!pWatch->StopNow) + { + RefreshWatch(tWatch); + } +} + +/// Refreshes the directory monitoring. +bool RefreshWatch(WatcherStructWin32* pWatch) +{ + return ReadDirectoryChangesW( + pWatch->Watch->DirHandle, + pWatch->Watch->mBuffer, + sizeof(pWatch->Watch->mBuffer), + pWatch->Watch->Recursive, + pWatch->Watch->NotifyFilter, + NULL, + &pWatch->Overlapped, + NULL + ) != 0; +} + +/// Stops monitoring a directory. +void DestroyWatch(WatcherStructWin32* pWatch) +{ + if (pWatch) + { + WatcherWin32 * tWatch = pWatch->Watch; + + tWatch->StopNow = true; + + CancelIo(tWatch->DirHandle); + + RefreshWatch(pWatch); + + if (!HasOverlappedIoCompleted(&pWatch->Overlapped)) + { + SleepEx(5, TRUE); + } + + CloseHandle(pWatch->Overlapped.hEvent); + CloseHandle(pWatch->Watch->DirHandle); + efSAFE_DELETE_ARRAY( pWatch->Watch->DirName ); + efSAFE_DELETE( pWatch->Watch ); + HeapFree(GetProcessHeap(), 0, pWatch); + } +} + +/// Starts monitoring a directory. +WatcherStructWin32* CreateWatch(LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter) +{ + WatcherStructWin32 * tWatch; + size_t ptrsize = sizeof(*tWatch); + tWatch = static_cast<WatcherStructWin32*>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize)); + + WatcherWin32 * pWatch = new WatcherWin32(); + tWatch->Watch = pWatch; + + pWatch->DirHandle = CreateFileW( + szDirectory, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, + NULL + ); + + if (pWatch->DirHandle != INVALID_HANDLE_VALUE) + { + tWatch->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + pWatch->NotifyFilter = NotifyFilter; + pWatch->Recursive = recursive; + + if (RefreshWatch(tWatch)) + { + return tWatch; + } + else + { + CloseHandle(tWatch->Overlapped.hEvent); + CloseHandle(pWatch->DirHandle); + } + } + + HeapFree(GetProcessHeap(), 0, tWatch); + return NULL; +} + +} + + #endif diff --git a/dep/efsw/src/efsw/WatcherWin32.hpp b/dep/efsw/src/efsw/WatcherWin32.hpp new file mode 100644 index 00000000000..3c6d988fbf4 --- /dev/null +++ b/dep/efsw/src/efsw/WatcherWin32.hpp @@ -0,0 +1,77 @@ +#ifndef EFSW_WATCHERWIN32_HPP +#define EFSW_WATCHERWIN32_HPP + +#include <efsw/FileWatcherImpl.hpp> +#include <efsw/FileInfo.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +#include <windows.h> + +#ifdef EFSW_COMPILER_MSVC + #pragma comment(lib, "comctl32.lib") + #pragma comment(lib, "user32.lib") + #pragma comment(lib, "ole32.lib") + + // disable secure warnings + #pragma warning (disable: 4996) +#endif + +namespace efsw +{ + +class WatcherWin32; + +/// Internal watch data +struct WatcherStructWin32 +{ + OVERLAPPED Overlapped; + WatcherWin32 * Watch; +}; + +class cLastModifiedEvent +{ + public: + cLastModifiedEvent() {} + FileInfo file; + std::string fileName; +}; + +bool RefreshWatch(WatcherStructWin32* pWatch); + +void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped); + +void DestroyWatch(WatcherStructWin32* pWatch); + +WatcherStructWin32* CreateWatch(LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter); + +class WatcherWin32 : public Watcher +{ + public: + WatcherWin32() : + Struct( NULL ), + DirHandle( NULL ), + lParam( 0 ), + NotifyFilter( 0 ), + StopNow( false ), + Watch( NULL ), + DirName( NULL ) + { + } + + WatcherStructWin32 * Struct; + HANDLE DirHandle; + BYTE mBuffer[63 * 1024]; // do NOT make this bigger than 64K because it will fail if the folder being watched is on the network! (see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) + LPARAM lParam; + DWORD NotifyFilter; + bool StopNow; + FileWatcherImpl* Watch; + char* DirName; + cLastModifiedEvent LastModifiedEvent; +}; + +} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/base.hpp b/dep/efsw/src/efsw/base.hpp new file mode 100644 index 00000000000..26108c76985 --- /dev/null +++ b/dep/efsw/src/efsw/base.hpp @@ -0,0 +1,110 @@ +#ifndef EFSW_BASE +#define EFSW_BASE + +#include <efsw/sophist.h> +#include <efsw/efsw.hpp> + +namespace efsw { + +typedef SOPHIST_int8 Int8; +typedef SOPHIST_uint8 Uint8; +typedef SOPHIST_int16 Int16; +typedef SOPHIST_uint16 Uint16; +typedef SOPHIST_int32 Int32; +typedef SOPHIST_uint32 Uint32; +typedef SOPHIST_int64 Int64; +typedef SOPHIST_uint64 Uint64; + +#define EFSW_OS_WIN 1 +#define EFSW_OS_LINUX 2 +#define EFSW_OS_MACOSX 3 +#define EFSW_OS_BSD 4 +#define EFSW_OS_SOLARIS 5 +#define EFSW_OS_HAIKU 6 +#define EFSW_OS_ANDROID 7 +#define EFSW_OS_IOS 8 + +#define EFSW_PLATFORM_WIN32 1 +#define EFSW_PLATFORM_INOTIFY 2 +#define EFSW_PLATFORM_KQUEUE 3 +#define EFSW_PLATFORM_FSEVENTS 4 +#define EFSW_PLATFORM_GENERIC 5 + +#if defined(_WIN32) + /// Any Windows platform + #define EFSW_OS EFSW_OS_WIN + #define EFSW_PLATFORM EFSW_PLATFORM_WIN32 + + #if ( defined( _MSCVER ) || defined( _MSC_VER ) ) + #define EFSW_COMPILER_MSVC + #endif + +#elif defined( __FreeBSD__ ) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined( __DragonFly__ ) + #define EFSW_OS EFSW_OS_BSD + #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE + +#elif defined( __APPLE_CC__ ) || defined ( __APPLE__ ) + #include <TargetConditionals.h> + + #if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || ( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR ) + #define EFSW_OS EFSW_OS_IOS + #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE + #else + #define EFSW_OS EFSW_OS_MACOSX + + #if defined(EFSW_FSEVENTS_NOT_SUPPORTED) + #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE + #else + #define EFSW_PLATFORM EFSW_PLATFORM_FSEVENTS + #endif + #endif + +#elif defined(__linux__) + /// This includes Linux and Android + #ifndef EFSW_KQUEUE + #define EFSW_PLATFORM EFSW_PLATFORM_INOTIFY + #else + /// This is for testing libkqueue, sadly it doesnt work + #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE + #endif + + #if defined( __ANDROID__ ) || defined( ANDROID ) + #define EFSW_OS EFSW_OS_ANDROID + #else + #define EFSW_OS EFSW_OS_LINUX + #endif + +#else + #if defined( __SVR4 ) + #define EFSW_OS EFSW_OS_SOLARIS + #elif defined( __HAIKU__ ) || defined( __BEOS__ ) + #define EFSW_OS EFSW_OS_HAIKU + #endif + + /// Everything else + #define EFSW_PLATFORM EFSW_PLATFORM_GENERIC +#endif + +#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 + #define EFSW_PLATFORM_POSIX +#endif + +#if 1 == SOPHIST_pointer64 + #define EFSW_64BIT +#else + #define EFSW_32BIT +#endif + +#if defined(arm) || defined(__arm__) + #define EFSW_ARM +#endif + +#define efCOMMA , + +#define efSAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } +#define efSAFE_DELETE_ARRAY(p) { if(p) { delete [] (p); (p)=NULL; } } +#define efARRAY_SIZE(__array) ( sizeof(__array) / sizeof(__array[0]) ) + +} + +#endif diff --git a/dep/efsw/src/efsw/inotify-nosys.h b/dep/efsw/src/efsw/inotify-nosys.h new file mode 100644 index 00000000000..75df5d3ced3 --- /dev/null +++ b/dep/efsw/src/efsw/inotify-nosys.h @@ -0,0 +1,159 @@ +#ifndef _LINUX_INOTIFY_H +#define _LINUX_INOTIFY_H + +#include <stdint.h> +#include <sys/syscall.h> +#include <unistd.h> + +/* + * struct inotify_event - structure read from the inotify device for each event + * + * When you are watching a directory, you will receive the filename for events + * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd. + */ +struct inotify_event { + int wd; /* watch descriptor */ + uint32_t mask; /* watch mask */ + uint32_t cookie; /* cookie to synchronize two events */ + uint32_t len; /* length (including nulls) of name */ + char name __flexarr; /* stub for possible name */ +}; + +/* the following are legal, implemented events that user-space can watch for */ +#define IN_ACCESS 0x00000001 /* File was accessed */ +#define IN_MODIFY 0x00000002 /* File was modified */ +#define IN_ATTRIB 0x00000004 /* Metadata changed */ +#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */ +#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ +#define IN_OPEN 0x00000020 /* File was opened */ +#define IN_MOVED_FROM 0x00000040 /* File was moved from X */ +#define IN_MOVED_TO 0x00000080 /* File was moved to Y */ +#define IN_CREATE 0x00000100 /* Subfile was created */ +#define IN_DELETE 0x00000200 /* Subfile was deleted */ +#define IN_DELETE_SELF 0x00000400 /* Self was deleted */ +#define IN_MOVE_SELF 0x00000800 /* Self was moved */ + +/* the following are legal events. they are sent as needed to any watch */ +#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */ +#define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ +#define IN_IGNORED 0x00008000 /* File was ignored */ + +/* helper events */ +#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */ +#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */ + +/* special flags */ +#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */ +#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */ +#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */ +#define IN_ISDIR 0x40000000 /* event occurred against dir */ +#define IN_ONESHOT 0x80000000 /* only send event once */ + +/* + * All of the events - we build the list by hand so that we can add flags in + * the future and not break backward compatibility. Apps will get only the + * events that they originally wanted. Be sure to add new events here! + */ +#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \ + IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \ + IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \ + IN_MOVE_SELF) + +#if defined (__alpha__) +# define __NR_inotify_init 444 +# define __NR_inotify_add_watch 445 +# define __NR_inotify_rm_watch 446 + +#elif defined (__arm__) +# define __NR_inotify_init (__NR_SYSCALL_BASE+316) +# define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317) +# define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318) + +#elif defined (__frv__) +# define __NR_inotify_init 291 +# define __NR_inotify_add_watch 292 +# define __NR_inotify_rm_watch 293 + +#elif defined(__i386__) +# define __NR_inotify_init 291 +# define __NR_inotify_add_watch 292 +# define __NR_inotify_rm_watch 293 + +#elif defined (__ia64__) +# define __NR_inotify_init 1277 +# define __NR_inotify_add_watch 1278 +# define __NR_inotify_rm_watch 1279 + +#elif defined (__mips__) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_inotify_init (__NR_Linux + 284) +# define __NR_inotify_add_watch (__NR_Linux + 285) +# define __NR_inotify_rm_watch (__NR_Linux + 286) +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_inotify_init (__NR_Linux + 243) +# define __NR_inotify_add_watch (__NR_Linux + 243) +# define __NR_inotify_rm_watch (__NR_Linux + 243) +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_inotify_init (__NR_Linux + 247) +# define __NR_inotify_add_watch (__NR_Linux + 248) +# define __NR_inotify_rm_watch (__NR_Linux + 249) +# endif + +#elif defined(__parisc__) +# define __NR_inotify_init (__NR_Linux + 269) +# define __NR_inotify_add_watch (__NR_Linux + 270) +# define __NR_inotify_rm_watch (__NR_Linux + 271) + +#elif defined(__powerpc__) || defined(__powerpc64__) +# define __NR_inotify_init 275 +# define __NR_inotify_add_watch 276 +# define __NR_inotify_rm_watch 277 + +#elif defined (__s390__) +# define __NR_inotify_init 284 +# define __NR_inotify_add_watch 285 +# define __NR_inotify_rm_watch 286 + +#elif defined (__sh__) +# define __NR_inotify_init 290 +# define __NR_inotify_add_watch 291 +# define __NR_inotify_rm_watch 292 + +#elif defined (__sh64__) +# define __NR_inotify_init 318 +# define __NR_inotify_add_watch 319 +# define __NR_inotify_rm_watch 320 + +#elif defined (__sparc__) || defined (__sparc64__) +# define __NR_inotify_init 151 +# define __NR_inotify_add_watch 152 +# define __NR_inotify_rm_watch 156 + +#elif defined(__x86_64__) +# define __NR_inotify_init 253 +# define __NR_inotify_add_watch 254 +# define __NR_inotify_rm_watch 255 + +#else +# error "Unsupported architecture!" +#endif + +static inline int inotify_init (void) +{ + return syscall (__NR_inotify_init); +} + +static inline int inotify_add_watch (int fd, const char *name, uint32_t mask) +{ + return syscall (__NR_inotify_add_watch, fd, name, mask); +} + +static inline int inotify_rm_watch (int fd, uint32_t wd) +{ + return syscall (__NR_inotify_rm_watch, fd, wd); +} + + +#endif /* _LINUX_INOTIFY_H */ diff --git a/dep/efsw/src/efsw/platform/platformimpl.hpp b/dep/efsw/src/efsw/platform/platformimpl.hpp new file mode 100644 index 00000000000..86a74eee0c8 --- /dev/null +++ b/dep/efsw/src/efsw/platform/platformimpl.hpp @@ -0,0 +1,20 @@ +#ifndef EFSW_PLATFORMIMPL_HPP +#define EFSW_PLATFORMIMPL_HPP + +#include <efsw/base.hpp> + +#if defined( EFSW_PLATFORM_POSIX ) + #include <efsw/platform/posix/ThreadImpl.hpp> + #include <efsw/platform/posix/MutexImpl.hpp> + #include <efsw/platform/posix/SystemImpl.hpp> + #include <efsw/platform/posix/FileSystemImpl.hpp> +#elif EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + #include <efsw/platform/win/ThreadImpl.hpp> + #include <efsw/platform/win/MutexImpl.hpp> + #include <efsw/platform/win/SystemImpl.hpp> + #include <efsw/platform/win/FileSystemImpl.hpp> +#else + #error Thread, Mutex, and System not implemented for this platform. +#endif + +#endif diff --git a/dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp new file mode 100644 index 00000000000..e061b25d56b --- /dev/null +++ b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp @@ -0,0 +1,144 @@ +#include <efsw/platform/posix/FileSystemImpl.hpp> + +#if defined( EFSW_PLATFORM_POSIX ) + +#include <efsw/FileInfo.hpp> +#include <efsw/FileSystem.hpp> +#include <dirent.h> +#include <cstring> + +#ifndef _DARWIN_FEATURE_64_BIT_INODE +#define _DARWIN_FEATURE_64_BIT_INODE +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +#include <sys/stat.h> +#include <cstdlib> + +#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID +#include <sys/vfs.h> +#elif EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_IOS +#include <sys/param.h> +#include <sys/mount.h> +#endif + +/** Remote file systems codes */ +#define S_MAGIC_AFS 0x5346414F +#define S_MAGIC_AUFS 0x61756673 +#define S_MAGIC_CEPH 0x00C36400 +#define S_MAGIC_CIFS 0xFF534D42 +#define S_MAGIC_CODA 0x73757245 +#define S_MAGIC_FHGFS 0x19830326 +#define S_MAGIC_FUSEBLK 0x65735546 +#define S_MAGIC_FUSECTL 0x65735543 +#define S_MAGIC_GFS 0x01161970 +#define S_MAGIC_GPFS 0x47504653 +#define S_MAGIC_KAFS 0x6B414653 +#define S_MAGIC_LUSTRE 0x0BD00BD0 +#define S_MAGIC_NCP 0x564C +#define S_MAGIC_NFS 0x6969 +#define S_MAGIC_NFSD 0x6E667364 +#define S_MAGIC_OCFS2 0x7461636F +#define S_MAGIC_PANFS 0xAAD7AAEA +#define S_MAGIC_PIPEFS 0x50495045 +#define S_MAGIC_SMB 0x517B +#define S_MAGIC_SNFS 0xBEEFDEAD +#define S_MAGIC_VMHGFS 0xBACBACBC +#define S_MAGIC_VXFS 0xA501FCF5 + +namespace efsw { namespace Platform { + +FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) +{ + FileInfoMap files; + + DIR *dp; + struct dirent *dirp; + + if( ( dp = opendir( path.c_str() ) ) == NULL) + return files; + + while ( ( dirp = readdir(dp) ) != NULL) + { + if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 ) + { + std::string name( dirp->d_name ); + std::string fpath( path + name ); + + files[ name ] = FileInfo( fpath ); + } + } + + closedir(dp); + + return files; +} + +char FileSystem::getOSSlash() +{ + return '/'; +} + +bool FileSystem::isDirectory( const std::string& path ) +{ + struct stat st; + int res = stat( path.c_str(), &st ); + + if ( 0 == res ) + { + return static_cast<bool>( S_ISDIR(st.st_mode) ); + } + + return false; +} + +bool FileSystem::isRemoteFS( const std::string& directory ) +{ +#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID || EFSW_OS == EFSW_OS_IOS + struct statfs statfsbuf; + + statfs( directory.c_str(), &statfsbuf ); + + switch ( statfsbuf.f_type | 0UL ) + { + case S_MAGIC_AFS: /* 0x5346414F remote */ + case S_MAGIC_AUFS: /* 0x61756673 remote */ + case S_MAGIC_CEPH: /* 0x00C36400 remote */ + case S_MAGIC_CIFS: /* 0xFF534D42 remote */ + case S_MAGIC_CODA: /* 0x73757245 remote */ + case S_MAGIC_FHGFS: /* 0x19830326 remote */ + case S_MAGIC_FUSEBLK: /* 0x65735546 remote */ + case S_MAGIC_FUSECTL: /* 0x65735543 remote */ + case S_MAGIC_GFS: /* 0x01161970 remote */ + case S_MAGIC_GPFS: /* 0x47504653 remote */ + case S_MAGIC_KAFS: /* 0x6B414653 remote */ + case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */ + case S_MAGIC_NCP: /* 0x564C remote */ + case S_MAGIC_NFS: /* 0x6969 remote */ + case S_MAGIC_NFSD: /* 0x6E667364 remote */ + case S_MAGIC_OCFS2: /* 0x7461636F remote */ + case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */ + case S_MAGIC_PIPEFS: /* 0x50495045 remote */ + case S_MAGIC_SMB: /* 0x517B remote */ + case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */ + case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */ + case S_MAGIC_VXFS: /* 0xA501FCF5 remote */ + { + return true; + } + default: + { + return false; + } + } +#endif + + return false; +} + +}} + +#endif diff --git a/dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp new file mode 100644 index 00000000000..865b3f8dfdf --- /dev/null +++ b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp @@ -0,0 +1,27 @@ +#ifndef EFSW_FILESYSTEMIMPLPOSIX_HPP +#define EFSW_FILESYSTEMIMPLPOSIX_HPP + +#include <efsw/base.hpp> +#include <efsw/FileInfo.hpp> + +#if defined( EFSW_PLATFORM_POSIX ) + +namespace efsw { namespace Platform { + +class FileSystem +{ + public: + static FileInfoMap filesInfoFromPath( const std::string& path ); + + static char getOSSlash(); + + static bool isDirectory( const std::string& path ); + + static bool isRemoteFS( const std::string& directory ); +}; + +}} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/platform/posix/MutexImpl.cpp b/dep/efsw/src/efsw/platform/posix/MutexImpl.cpp new file mode 100644 index 00000000000..6f2af5abc61 --- /dev/null +++ b/dep/efsw/src/efsw/platform/posix/MutexImpl.cpp @@ -0,0 +1,32 @@ +#include <efsw/platform/posix/MutexImpl.hpp> + +#if defined( EFSW_PLATFORM_POSIX ) + +namespace efsw { namespace Platform { + +MutexImpl::MutexImpl() +{ + pthread_mutexattr_t attributes; + pthread_mutexattr_init(&attributes); + pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mMutex, &attributes); +} + +MutexImpl::~MutexImpl() +{ + pthread_mutex_destroy(&mMutex); +} + +void MutexImpl::lock() +{ + pthread_mutex_lock(&mMutex); +} + +void MutexImpl::unlock() +{ + pthread_mutex_unlock(&mMutex); +} + +}} + +#endif diff --git a/dep/efsw/src/efsw/platform/posix/MutexImpl.hpp b/dep/efsw/src/efsw/platform/posix/MutexImpl.hpp new file mode 100644 index 00000000000..d51eecb16aa --- /dev/null +++ b/dep/efsw/src/efsw/platform/posix/MutexImpl.hpp @@ -0,0 +1,31 @@ +#ifndef EFSW_MUTEXIMPLPOSIX_HPP +#define EFSW_MUTEXIMPLPOSIX_HPP + +#include <efsw/base.hpp> + +#if defined( EFSW_PLATFORM_POSIX ) + +#include <pthread.h> + +namespace efsw { namespace Platform { + +class MutexImpl +{ + public: + MutexImpl(); + + ~MutexImpl(); + + void lock(); + + void unlock(); + private: + pthread_mutex_t mMutex; +}; + +}} + +#endif + +#endif + diff --git a/dep/efsw/src/efsw/platform/posix/SystemImpl.cpp b/dep/efsw/src/efsw/platform/posix/SystemImpl.cpp new file mode 100644 index 00000000000..22e37095afd --- /dev/null +++ b/dep/efsw/src/efsw/platform/posix/SystemImpl.cpp @@ -0,0 +1,180 @@ +#include <efsw/platform/posix/SystemImpl.hpp> + +#if defined( EFSW_PLATFORM_POSIX ) + +#include <cstdio> +#include <pthread.h> +#include <sys/time.h> +#include <limits.h> +#include <sys/resource.h> + +#include <efsw/FileSystem.hpp> +#include <efsw/Debug.hpp> + +#if EFSW_OS == EFSW_OS_MACOSX + #include <CoreFoundation/CoreFoundation.h> +#elif EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_ANDROID + #include <libgen.h> + #include <unistd.h> +#elif EFSW_OS == EFSW_OS_HAIKU + #include <kernel/OS.h> + #include <kernel/image.h> +#elif EFSW_OS == EFSW_OS_SOLARIS + #include <stdlib.h> +#elif EFSW_OS == EFSW_OS_BSD + #include <sys/sysctl.h> +#endif + +namespace efsw { namespace Platform { + +void System::sleep( const unsigned long& ms ) +{ + // usleep( static_cast<unsigned long>( ms * 1000 ) ); + + // usleep is not reliable enough (it might block the + // whole process instead of just the current thread) + // so we must use pthread_cond_timedwait instead + + // this implementation is inspired from Qt + // and taken from SFML + + unsigned long long usecs = ms * 1000; + + // get the current time + timeval tv; + gettimeofday(&tv, NULL); + + // construct the time limit (current time + time to wait) + timespec ti; + ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000; + ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000); + ti.tv_nsec %= 1000000000; + + // create a mutex and thread condition + pthread_mutex_t mutex; + pthread_mutex_init(&mutex, 0); + pthread_cond_t condition; + pthread_cond_init(&condition, 0); + + // wait... + pthread_mutex_lock(&mutex); + pthread_cond_timedwait(&condition, &mutex, &ti); + pthread_mutex_unlock(&mutex); + + // destroy the mutex and condition + pthread_cond_destroy(&condition); +} + +std::string System::getProcessPath() +{ +#if EFSW_OS == EFSW_OS_MACOSX + char exe_file[FILENAME_MAX + 1]; + + CFBundleRef mainBundle = CFBundleGetMainBundle(); + + if (mainBundle) + { + CFURLRef mainURL = CFBundleCopyBundleURL(mainBundle); + + if (mainURL) + { + int ok = CFURLGetFileSystemRepresentation ( mainURL, (Boolean) true, (UInt8*)exe_file, FILENAME_MAX ); + + if (ok) + { + return std::string(exe_file) + "/"; + } + } + } + + return "./"; +#elif EFSW_OS == EFSW_OS_LINUX + char exe_file[FILENAME_MAX + 1]; + + int size; + + size = readlink("/proc/self/exe", exe_file, FILENAME_MAX); + + if (size < 0) + { + return std::string( "./" ); + } + else + { + exe_file[size] = '\0'; + return std::string( dirname( exe_file ) ) + "/"; + } + +#elif EFSW_OS == EFSW_OS_BSD + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + char buf[1024]; + size_t cb = sizeof(buf); + sysctl(mib, 4, buf, &cb, NULL, 0); + + return FileSystem::pathRemoveFileName( std::string( buf ) ); + +#elif EFSW_OS == EFSW_OS_SOLARIS + return FileSystem::pathRemoveFileName( std::string( getexecname() ) ); + +#elif EFSW_OS == EFSW_OS_HAIKU + image_info info; + int32 cookie = 0; + + while ( B_OK == get_next_image_info( 0, &cookie, &info ) ) + { + if ( info.type == B_APP_IMAGE ) + break; + } + + return FileSystem::pathRemoveFileName( std::string( info.name ) ); + +#elif EFSW_OS == EFSW_OS_ANDROID + return "/sdcard/"; + +#else + #warning getProcessPath() not implemented on this platform. ( will return "./" ) + return "./"; + +#endif +} + +void System::maxFD() +{ + static bool maxed = false; + + if ( !maxed ) + { + struct rlimit limit; + getrlimit( RLIMIT_NOFILE, &limit ); + limit.rlim_cur = limit.rlim_max; + setrlimit( RLIMIT_NOFILE, &limit ); + + getrlimit( RLIMIT_NOFILE, &limit ); + + efDEBUG( "File descriptor limit %ld\n", limit.rlim_cur ); + + maxed = true; + } +} + +Uint64 System::getMaxFD() +{ + static rlim_t max_fd = 0; + + if ( max_fd == 0 ) + { + struct rlimit limit; + getrlimit( RLIMIT_NOFILE, &limit ); + max_fd = limit.rlim_cur; + } + + return max_fd; +} + +}} + +#endif diff --git a/dep/efsw/src/efsw/platform/posix/SystemImpl.hpp b/dep/efsw/src/efsw/platform/posix/SystemImpl.hpp new file mode 100644 index 00000000000..34734104467 --- /dev/null +++ b/dep/efsw/src/efsw/platform/posix/SystemImpl.hpp @@ -0,0 +1,26 @@ +#ifndef EFSW_SYSTEMIMPLPOSIX_HPP +#define EFSW_SYSTEMIMPLPOSIX_HPP + +#include <efsw/base.hpp> + +#if defined( EFSW_PLATFORM_POSIX ) + +namespace efsw { namespace Platform { + +class System +{ + public: + static void sleep( const unsigned long& ms ); + + static std::string getProcessPath(); + + static void maxFD(); + + static Uint64 getMaxFD(); +}; + +}} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp b/dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp new file mode 100644 index 00000000000..2d3671db9b8 --- /dev/null +++ b/dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp @@ -0,0 +1,68 @@ +#include <efsw/platform/posix/ThreadImpl.hpp> +#include <efsw/Thread.hpp> + +#if defined( EFSW_PLATFORM_POSIX ) + +#include <cassert> +#include <iostream> +#include <efsw/Debug.hpp> + +namespace efsw { namespace Platform { + +ThreadImpl::ThreadImpl( Thread * owner ) : + mIsActive(false) +{ + mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; + + if ( !mIsActive ) + { + efDEBUG( "Failed to create thread\n" ); + } +} + +void ThreadImpl::wait() +{ + // Wait for the thread to finish, no timeout + if ( mIsActive ) + { + assert( pthread_equal( pthread_self(), mThread ) == 0 ); + + pthread_join( mThread, NULL ); + + mIsActive = false; // Reset the thread state + } +} + +void ThreadImpl::terminate() +{ + if ( mIsActive ) + { + #if !defined( __ANDROID__ ) && !defined( ANDROID ) + pthread_cancel( mThread ); + #else + pthread_kill( mThread , SIGUSR1 ); + #endif + + mIsActive = false; + } +} + +void * ThreadImpl::entryPoint( void * userData ) +{ + // The Thread instance is stored in the user data + Thread * owner = static_cast<Thread*>( userData ); + + // Tell the thread to handle cancel requests immediatly + #ifdef PTHREAD_CANCEL_ASYNCHRONOUS + pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); + #endif + + // Forward to the owner + owner->run(); + + return NULL; +} + +}} + +#endif diff --git a/dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp b/dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp new file mode 100644 index 00000000000..be6dc1b3e58 --- /dev/null +++ b/dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp @@ -0,0 +1,35 @@ +#ifndef EFSW_THREADIMPLPOSIX_HPP +#define EFSW_THREADIMPLPOSIX_HPP + +#include <efsw/base.hpp> + +#if defined( EFSW_PLATFORM_POSIX ) + +#include <pthread.h> + +namespace efsw { + +class Thread; + +namespace Platform { + +class ThreadImpl +{ + public: + ThreadImpl( Thread * owner ); + + void wait(); + + void terminate(); + protected: + static void * entryPoint( void* userData ); + + pthread_t mThread; + bool mIsActive; +}; + +}} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp b/dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp new file mode 100644 index 00000000000..376a474e662 --- /dev/null +++ b/dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp @@ -0,0 +1,89 @@ +#include <efsw/platform/win/FileSystemImpl.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +#ifndef EFSW_COMPILER_MSVC +#include <dirent.h> +#endif + +namespace efsw { namespace Platform { + +FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) +{ + FileInfoMap files; + + String tpath( path ); + + if ( tpath[ tpath.size() - 1 ] == '/' || tpath[ tpath.size() - 1 ] == '\\' ) + { + tpath += "*"; + } + else + { + tpath += "\\*"; + } + + WIN32_FIND_DATAW findFileData; + HANDLE hFind = FindFirstFileW( (LPCWSTR)tpath.toWideString().c_str(), &findFileData ); + + if( hFind != INVALID_HANDLE_VALUE ) + { + std::string name( String( findFileData.cFileName ).toUtf8() ); + std::string fpath( path + name ); + + if ( name != "." && name != ".." ) + { + files[ name ] = FileInfo( fpath ); + } + + while( FindNextFileW( hFind, &findFileData ) ) + { + name = String( findFileData.cFileName ).toUtf8(); + fpath = path + name; + + if ( name != "." && name != ".." ) + { + files[ name ] = FileInfo( fpath ); + } + } + + FindClose( hFind ); + } + + return files; +} + +char FileSystem::getOSSlash() +{ + return '\\'; +} + +bool FileSystem::isDirectory( const std::string& path ) +{ + return 0 != ( GetFileAttributesW( String( path ).toWideString().c_str() ) & FILE_ATTRIBUTE_DIRECTORY ); +} + +bool FileSystem::isRemoteFS( const std::string& directory ) +{ + if ((directory[0] == '\\' || directory[0] == '/') && + (directory[1] == '\\' || directory[1] == '/')) + { + return true; + } + + if ( directory.size() >= 3 ) + { + return 4 == GetDriveTypeA( directory.substr( 0, 3 ).c_str() ); + } + + return false; +} + +}} + +#endif diff --git a/dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp b/dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp new file mode 100644 index 00000000000..597edc4a647 --- /dev/null +++ b/dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp @@ -0,0 +1,28 @@ +#ifndef EFSW_FILESYSTEMIMPLWIN_HPP +#define EFSW_FILESYSTEMIMPLWIN_HPP + +#include <efsw/base.hpp> +#include <efsw/String.hpp> +#include <efsw/FileInfo.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +namespace efsw { namespace Platform { + +class FileSystem +{ + public: + static FileInfoMap filesInfoFromPath( const std::string& path ); + + static char getOSSlash(); + + static bool isDirectory( const std::string& path ); + + static bool isRemoteFS( const std::string& directory ); +}; + +}} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/platform/win/MutexImpl.cpp b/dep/efsw/src/efsw/platform/win/MutexImpl.cpp new file mode 100644 index 00000000000..0c8c36d8b39 --- /dev/null +++ b/dep/efsw/src/efsw/platform/win/MutexImpl.cpp @@ -0,0 +1,29 @@ +#include <efsw/platform/win/MutexImpl.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +namespace efsw { namespace Platform { + +MutexImpl::MutexImpl() +{ + InitializeCriticalSection(&mMutex); +} + +MutexImpl::~MutexImpl() +{ + DeleteCriticalSection(&mMutex); +} + +void MutexImpl::lock() +{ + EnterCriticalSection(&mMutex); +} + +void MutexImpl::unlock() +{ + LeaveCriticalSection(&mMutex); +} + +}} + +#endif diff --git a/dep/efsw/src/efsw/platform/win/MutexImpl.hpp b/dep/efsw/src/efsw/platform/win/MutexImpl.hpp new file mode 100644 index 00000000000..da1e20c5fa9 --- /dev/null +++ b/dep/efsw/src/efsw/platform/win/MutexImpl.hpp @@ -0,0 +1,34 @@ +#ifndef EFSW_MUTEXIMPLWIN_HPP +#define EFSW_MUTEXIMPLWIN_HPP + +#include <efsw/base.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +namespace efsw { namespace Platform { + +class MutexImpl +{ + public: + MutexImpl(); + + ~MutexImpl(); + + void lock(); + + void unlock(); + private: + CRITICAL_SECTION mMutex; +}; + +}} + +#endif + +#endif + diff --git a/dep/efsw/src/efsw/platform/win/SystemImpl.cpp b/dep/efsw/src/efsw/platform/win/SystemImpl.cpp new file mode 100644 index 00000000000..ddbe1e5c45c --- /dev/null +++ b/dep/efsw/src/efsw/platform/win/SystemImpl.cpp @@ -0,0 +1,50 @@ +#include <efsw/platform/win/SystemImpl.hpp> +#include <efsw/String.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <cstdlib> + +namespace efsw { namespace Platform { + +void System::sleep( const unsigned long& ms ) +{ + ::Sleep( ms ); +} + +std::string System::getProcessPath() +{ + // Get path to executable: + WCHAR szDrive[_MAX_DRIVE]; + WCHAR szDir[_MAX_DIR]; + WCHAR szFilename[_MAX_DIR]; + WCHAR szExt[_MAX_DIR]; + std::wstring dllName( _MAX_DIR, 0 ); + + GetModuleFileNameW(0, &dllName[0], _MAX_PATH); + + #ifdef EFSW_COMPILER_MSVC + _wsplitpath_s( dllName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, szExt, _MAX_DIR ); + #else + _wsplitpath( dllName.c_str(), szDrive, szDir, szFilename, szExt); + #endif + + return String( szDrive ).toUtf8() + String( szDir ).toUtf8(); +} + +void System::maxFD() +{ +} + +Uint64 System::getMaxFD() +{ // Number of ReadDirectory per thread + return 60; +} + +}} + +#endif diff --git a/dep/efsw/src/efsw/platform/win/SystemImpl.hpp b/dep/efsw/src/efsw/platform/win/SystemImpl.hpp new file mode 100644 index 00000000000..2f785e3565c --- /dev/null +++ b/dep/efsw/src/efsw/platform/win/SystemImpl.hpp @@ -0,0 +1,26 @@ +#ifndef EFSW_SYSTEMIMPLWIN_HPP +#define EFSW_SYSTEMIMPLWIN_HPP + +#include <efsw/base.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +namespace efsw { namespace Platform { + +class System +{ + public: + static void sleep( const unsigned long& ms ); + + static std::string getProcessPath(); + + static void maxFD(); + + static Uint64 getMaxFD(); +}; + +}} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/platform/win/ThreadImpl.cpp b/dep/efsw/src/efsw/platform/win/ThreadImpl.cpp new file mode 100644 index 00000000000..2fa30f30060 --- /dev/null +++ b/dep/efsw/src/efsw/platform/win/ThreadImpl.cpp @@ -0,0 +1,56 @@ +#include <efsw/platform/win/ThreadImpl.hpp> +#include <efsw/Thread.hpp> +#include <assert.h> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +#include <efsw/Debug.hpp> + +namespace efsw { namespace Platform { + +ThreadImpl::ThreadImpl( Thread *owner ) +{ + mThread = reinterpret_cast<HANDLE>( _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); + + if ( !mThread ) + { + efDEBUG( "Failed to create thread\n" ); + } +} + +void ThreadImpl::wait() +{ + // Wait for the thread to finish, no timeout + if ( mThread ) + { + assert( mThreadId != GetCurrentThreadId() ); // A thread cannot wait for itself! + + WaitForSingleObject( mThread, INFINITE ); + } +} + +void ThreadImpl::terminate() +{ + if ( mThread ) + { + TerminateThread( mThread, 0 ); + } +} + +unsigned int __stdcall ThreadImpl::entryPoint( void * userData ) +{ + // The Thread instance is stored in the user data + Thread * owner = static_cast<Thread*>( userData ); + + // Forward to the owner + owner->run(); + + // Optional, but it is cleaner + _endthreadex(0); + + return 0; +} + +}} + +#endif diff --git a/dep/efsw/src/efsw/platform/win/ThreadImpl.hpp b/dep/efsw/src/efsw/platform/win/ThreadImpl.hpp new file mode 100644 index 00000000000..506c659c675 --- /dev/null +++ b/dep/efsw/src/efsw/platform/win/ThreadImpl.hpp @@ -0,0 +1,39 @@ +#ifndef EFSW_THREADIMPLWIN_HPP +#define EFSW_THREADIMPLWIN_HPP + +#include <efsw/base.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <process.h> + +namespace efsw { + +class Thread; + +namespace Platform { + +class ThreadImpl +{ + public: + ThreadImpl( Thread * owner ); + + void wait(); + + void terminate(); + protected: + static unsigned int __stdcall entryPoint(void* userData); + + HANDLE mThread; + unsigned int mThreadId; +}; + +}} + +#endif + +#endif diff --git a/dep/efsw/src/efsw/sophist.h b/dep/efsw/src/efsw/sophist.h new file mode 100644 index 00000000000..3a645040e2f --- /dev/null +++ b/dep/efsw/src/efsw/sophist.h @@ -0,0 +1,147 @@ +/* sophist.h - 0.3 - public domain - Sean Barrett 2010 +** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net +** Sophist provides portable types; you typedef/#define them to your own names +** +** defines: +** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian +** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined +** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit +** +** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer +** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 +** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 +** - SOPHIST_int64_constant(number) - macros for creating 64-bit +** - SOPHIST_uint64_constant(number) integer constants +** - SOPHIST_printf_format64 - string for printf format for int64 +*/ + +#ifndef __INCLUDE_SOPHIST_H__ +#define __INCLUDE_SOPHIST_H__ + +#define SOPHIST_compiletime_assert(name,val) \ + typedef int SOPHIST__assert##name[(val) ? 1 : -1] + +/* define a couple synthetic rules to make code more readable */ +#if (defined(__sparc__) || defined(__sparc)) && \ + (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) + #define SOPHIST_sparc64 +#endif + +#if (defined(linux) || defined(__linux__)) && \ + (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) + #define SOPHIST_linux64 +#endif + +/* basic types */ +typedef signed char SOPHIST_int8; +typedef unsigned char SOPHIST_uint8; + +typedef signed short SOPHIST_int16; +typedef unsigned short SOPHIST_uint16; + +#ifdef __palmos__ + typedef signed long SOPHIST_int32; + typedef unsigned long SOPHIST_uint32; +#else + typedef signed int SOPHIST_int32; + typedef unsigned int SOPHIST_uint32; +#endif + +#ifndef SOPHIST_NO_64 + #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ + || (defined(__alpha) && defined(__DECC)) + + typedef signed __int64 SOPHIST_int64; + typedef unsigned __int64 SOPHIST_uint64; + #define SOPHIST_has_64 1 + #define SOPHIST_int64_constant(x) (x##i64) + #define SOPHIST_uint64_constant(x) (x##ui64) + #define SOPHIST_printf_format64 "I64" + + #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) + + typedef signed long SOPHIST_int64; + typedef unsigned long SOPHIST_uint64; + + #define SOPHIST_has_64 1 + #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) + #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) + #define SOPHIST_printf_format64 "l" + + #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ + || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ + || defined(sgi) || defined (__sgi) || defined(__sgi__) \ + || defined(_CRAYC) + + typedef signed long long SOPHIST_int64; + typedef unsigned long long SOPHIST_uint64; + + #define SOPHIST_has_64 1 + #define SOPHIST_int64_constant(x) (x##LL) + #define SOPHIST_uint64_constant(x) (x##ULL) + #define SOPHIST_printf_format64 "ll" + #endif +#endif + +#ifndef SOPHIST_has_64 +#define SOPHIST_has_64 0 +#endif + +SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); +SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); +SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); +SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); + +#if SOPHIST_has_64 + SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); + SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); +#endif + +/* determine whether pointers are 64-bit */ + +#if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ + || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ + || defined(__64BIT__) \ + || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ + || defined(_ADDR64) || defined(_CRAYC) \ + + #define SOPHIST_pointer64 1 + + SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); + + typedef SOPHIST_int64 SOPHIST_intptr; + typedef SOPHIST_uint64 SOPHIST_uintptr; +#else + + #define SOPHIST_pointer64 0 + + SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); + + /* do we care about pointers that are only 16-bit? */ + typedef SOPHIST_int32 SOPHIST_intptr; + typedef SOPHIST_uint32 SOPHIST_uintptr; + +#endif + +SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); + +/* enumerate known little endian cases; fallback to big-endian */ + +#define SOPHIST_little_endian 1 +#define SOPHIST_big_endian 2 + +#if defined(__386__) || defined(i386) || defined(__i386__) \ + || defined(__X86) || defined(_M_IX86) \ + || defined(_M_X64) || defined(__x86_64__) \ + || defined(alpha) || defined(__alpha) || defined(__alpha__) \ + || defined(_M_ALPHA) \ + || defined(ARM) || defined(_ARM) || defined(__arm__) \ + || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ + || defined(_WIN32_WCE) || defined(__NT__) \ + || defined(__MIPSEL__) + #define SOPHIST_endian SOPHIST_little_endian +#else + #define SOPHIST_endian SOPHIST_big_endian +#endif + +#endif /* __INCLUDE_SOPHIST_H__ */ diff --git a/dep/efsw/src/test/efsw-test.cpp b/dep/efsw/src/test/efsw-test.cpp new file mode 100644 index 00000000000..a49e3414fcc --- /dev/null +++ b/dep/efsw/src/test/efsw-test.cpp @@ -0,0 +1,151 @@ +#include <efsw/efsw.hpp> +#include <efsw/System.hpp> +#include <efsw/FileSystem.hpp> +#include <signal.h> +#include <iostream> + +bool STOP = false; + +void sigend(int signal) +{ + std::cout << std::endl << "Bye bye" << std::endl; + STOP = true; +} + +/// Processes a file action +class UpdateListener : public efsw::FileWatchListener +{ + public: + UpdateListener() {} + + std::string getActionName( efsw::Action action ) + { + switch ( action ) + { + case efsw::Actions::Add: return "Add"; + case efsw::Actions::Modified: return "Modified"; + case efsw::Actions::Delete: return "Delete"; + case efsw::Actions::Moved: return "Moved"; + default: return "Bad Action"; + } + } + + void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" ) + { + std::cout << "DIR (" << dir + ") FILE (" + ( oldFilename.empty() ? "" : "from file " + oldFilename + " to " ) + filename + ") has event " << getActionName( action ) << std::endl; + } +}; + +efsw::WatchID handleWatchID( efsw::WatchID watchid ) +{ + switch ( watchid ) + { + case efsw::Errors::FileNotFound: + case efsw::Errors::FileRepeated: + case efsw::Errors::FileOutOfScope: + case efsw::Errors::FileRemote: + case efsw::Errors::Unspecified: + { + std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl; + break; + } + default: + { + std::cout << "Added WatchID: " << watchid << std::endl; + } + } + + return watchid; +} + +int main(int argc, char **argv) +{ + signal( SIGABRT , sigend ); + signal( SIGINT , sigend ); + signal( SIGTERM , sigend ); + + std::cout << "Press ^C to exit demo" << std::endl; + + bool commonTest = true; + bool useGeneric = false; + std::string path; + + if ( argc >= 2 ) + { + path = std::string( argv[1] ); + + if ( efsw::FileSystem::isDirectory( path ) ) + { + commonTest = false; + } + + if ( argc >= 3 ) + { + if ( std::string( argv[2] ) == "true" ) + { + useGeneric = true; + } + } + } + + UpdateListener * ul = new UpdateListener(); + + /// create the file watcher object + efsw::FileWatcher fileWatcher( useGeneric ); + + fileWatcher.followSymlinks( false ); + fileWatcher.allowOutOfScopeLinks( false ); + + if ( commonTest ) + { + std::string CurPath( efsw::System::getProcessPath() ); + + std::cout << "CurPath: " << CurPath.c_str() << std::endl; + + /// add a watch to the system + handleWatchID( fileWatcher.addWatch( CurPath + "test", ul, true ) ); + + /// starts watching + fileWatcher.watch(); + + /// adds another watch after started watching... + efsw::System::sleep( 100 ); + + efsw::WatchID watchID = handleWatchID( fileWatcher.addWatch( CurPath + "test2", ul, true ) ); + + /// delete the watch + if ( watchID > 0 ) + { + efsw::System::sleep( 1000 ); + fileWatcher.removeWatch( watchID ); + } + } + else + { + efsw::WatchID err; + + if ( ( err = fileWatcher.addWatch( path, ul, true ) ) > 0 ) + { + fileWatcher.watch(); + + std::cout << "Watching directory: " << path.c_str() << std::endl; + + if ( useGeneric ) + { + std::cout << "Using generic backend watcher" << std::endl; + } + } + else + { + std::cout << "Error trying to watch directory: " << path.c_str() << std::endl; + std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl; + } + } + + while( !STOP ) + { + efsw::System::sleep( 100 ); + } + + return 0; +} diff --git a/dep/g3dlite/CMakeLists.txt b/dep/g3dlite/CMakeLists.txt index f1166c72e6d..4e579951d63 100644 --- a/dep/g3dlite/CMakeLists.txt +++ b/dep/g3dlite/CMakeLists.txt @@ -8,7 +8,6 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - set(g3dlib_STAT_SRCS source/AABox.cpp source/Any.cpp @@ -55,20 +54,18 @@ set(g3dlib_STAT_SRCS source/Vector4.cpp ) -if(WIN32) - include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_SOURCE_DIR}/dep/zlib - ) -else() - include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/include - ) -endif() - add_library(g3dlib STATIC ${g3dlib_STAT_SRCS}) +target_include_directories(g3dlib + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include) + target_link_libraries(g3dlib - ${ZLIB_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} -) + PUBLIC + zlib + threads) + +set_target_properties(g3dlib + PROPERTIES + FOLDER + "dep") diff --git a/dep/gsoap/CMakeLists.txt b/dep/gsoap/CMakeLists.txt index b5fed7809af..bdcadf6e4dc 100644 --- a/dep/gsoap/CMakeLists.txt +++ b/dep/gsoap/CMakeLists.txt @@ -10,17 +10,22 @@ file(GLOB sources *.cpp *.h) -set(gsoap_STAT_SRCS - ${sources} -) +add_library(gsoap STATIC ${sources}) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} -) +set_target_properties(gsoap PROPERTIES LINKER_LANGUAGE CXX) -# Little fix for MSVC / Windows platforms -add_definitions(-D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=0) +target_include_directories(gsoap + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}) -add_library(gsoap STATIC ${gsoap_STAT_SRCS}) +set_target_properties(gsoap + PROPERTIES + FOLDER + "dep") -set_target_properties(gsoap PROPERTIES LINKER_LANGUAGE CXX) +if (MSVC) + # Little fix for MSVC / Windows platforms + target_compile_definitions(gsoap + PRIVATE + -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=0) +endif() diff --git a/dep/jemalloc/CMakeLists.txt b/dep/jemalloc/CMakeLists.txt index cf0ac435f0a..6774e5a75d2 100644 --- a/dep/jemalloc/CMakeLists.txt +++ b/dep/jemalloc/CMakeLists.txt @@ -8,54 +8,79 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# We need to generate the jemalloc_def.h header based on platform-specific settings -if (PLATFORM EQUAL 32) - set(JEM_SIZEDEF 2) - set(JEM_TLSMODEL) +if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT NOJEM) + # We need to generate the jemalloc_def.h header based on platform-specific settings + if (PLATFORM EQUAL 32) + set(JEM_SIZEDEF 2) + set(JEM_TLSMODEL) + else() + set(JEM_SIZEDEF 3) + set(JEM_TLSMODEL "__attribute__\(\(tls_model\(\"initial-exec\"\)\)\)") + endif() + + # Create the header, so we can use it + configure_file( + "${CMAKE_SOURCE_DIR}/dep/jemalloc/jemalloc_defs.h.in.cmake" + "${BUILDDIR}/jemalloc_defs.h" + @ONLY + ) + + # Done, let's continue + set(jemalloc_STAT_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/src/arena.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/base.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/bitmap.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_dss.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_mmap.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/ckh.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/ctl.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/extent.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/hash.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/huge.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/jemalloc.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/mb.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/mutex.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/prof.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/quarantine.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/rtree.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/stats.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcache.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/tsd.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/util.c + ) + + add_library(jemalloc STATIC ${jemalloc_STAT_SRC}) + + target_include_directories(jemalloc + PRIVATE + ${BUILDDIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include) + + target_compile_definitions(jemalloc + PUBLIC + -DNO_BUFFERPOOL + PRIVATE + -D_GNU_SOURCE + -D_REENTRAN) + + target_link_libraries(jemalloc + PUBLIC + threads + valgrind) + + set_target_properties(jemalloc + PROPERTIES + FOLDER + "dep") + else() - set(JEM_SIZEDEF 3) - set(JEM_TLSMODEL "__attribute__\(\(tls_model\(\"initial-exec\"\)\)\)") -endif() + # Provide a dummy target for jemalloc which is used when jemalloc + # is disabled or not supported. + add_library(jemalloc INTERFACE) + target_link_libraries(jemalloc + INTERFACE + valgrind) -# Create the header, so we can use it -configure_file( - "${CMAKE_SOURCE_DIR}/dep/jemalloc/jemalloc_defs.h.in.cmake" - "${BUILDDIR}/jemalloc_defs.h" - @ONLY -) - -# Done, let's continue -set(jemalloc_STAT_SRC - ${CMAKE_CURRENT_SOURCE_DIR}/src/arena.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/atomic.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/base.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/bitmap.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_dss.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_mmap.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/ckh.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/ctl.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/extent.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/hash.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/huge.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/jemalloc.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/mb.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/mutex.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/prof.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/quarantine.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/rtree.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/stats.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/tcache.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/tsd.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/util.c -) - -include_directories( - ${BUILDDIR}/ - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${VALGRIND_INCLUDE_DIR} -) - -add_definitions(-D_GNU_SOURCE -D_REENTRANT) - -add_library(jemalloc STATIC ${jemalloc_STAT_SRC}) +endif() diff --git a/dep/libmpq/CMakeLists.txt b/dep/libmpq/CMakeLists.txt index 1213e6b11b7..e8b420fca53 100644 --- a/dep/libmpq/CMakeLists.txt +++ b/dep/libmpq/CMakeLists.txt @@ -8,27 +8,29 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -file(GLOB sources_mpq libmpq/*.c libmpq/*.h) +file(GLOB sources libmpq/*.c libmpq/*.h) -set(mpq_STAT_SRCS - ${sources_mpq} -) +add_library(mpq STATIC ${sources}) -if( UNIX ) - include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/dep/zlib - ${CMAKE_SOURCE_DIR}/dep/bzip2 - ) -elseif( WIN32 ) - include_directories( +set_target_properties(mpq PROPERTIES LINKER_LANGUAGE CXX) + +if(WIN32) + set(WIN_EXTRA_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/win) +endif() + +target_include_directories(mpq + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/win + ${WIN_EXTRA_INCLUDE} ${CMAKE_SOURCE_DIR}/dep/zlib - ${CMAKE_SOURCE_DIR}/dep/bzip2 - ) -endif() + ${CMAKE_SOURCE_DIR}/dep/bzip2) -add_library(mpq STATIC ${mpq_STAT_SRCS}) +target_link_libraries(mpq + PUBLIC + zlib + bzip2) -set_target_properties(mpq PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(mpq + PROPERTIES + FOLDER + "dep") diff --git a/dep/mysql/CMakeLists.txt b/dep/mysql/CMakeLists.txt new file mode 100644 index 00000000000..472535b0356 --- /dev/null +++ b/dep/mysql/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +if (NOT MYSQL_FOUND) + message(FATAL_ERROR "MySQL wasn't found on your system but it's required to build the servers!") +endif() + +add_library(mysql STATIC IMPORTED GLOBAL) + +set_target_properties(mysql + PROPERTIES + IMPORTED_LOCATION + "${MYSQL_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES + "${MYSQL_INCLUDE_DIR}") diff --git a/dep/openssl/CMakeLists.txt b/dep/openssl/CMakeLists.txt new file mode 100644 index 00000000000..98561b2a0ed --- /dev/null +++ b/dep/openssl/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + +# basic packagesearching and setup +# (further support will be needed, this is a preliminary release!) +set(OPENSSL_EXPECTED_VERSION 1.0.0) + +find_package(OpenSSL REQUIRED) + +add_library(openssl INTERFACE) + +target_link_libraries(openssl + INTERFACE + ${OPENSSL_LIBRARIES}) + +target_include_directories(openssl + INTERFACE + ${OPENSSL_INCLUDE_DIR}) diff --git a/dep/process/CMakeLists.txt b/dep/process/CMakeLists.txt new file mode 100644 index 00000000000..5a51917a00c --- /dev/null +++ b/dep/process/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +add_library(process INTERFACE) + +target_include_directories(process + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(process + INTERFACE + boost) diff --git a/dep/readline/CMakeLists.txt b/dep/readline/CMakeLists.txt new file mode 100644 index 00000000000..0e8679ba718 --- /dev/null +++ b/dep/readline/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +if( UNIX ) + # find Readline (terminal input library) includes and library + # + # READLINE_INCLUDE_DIR - where the directory containing the READLINE headers can be found + # READLINE_LIBRARY - full path to the READLINE library + find_path(READLINE_INCLUDE_DIR readline/readline.h) + find_library(READLINE_LIBRARY NAMES readline) + + message(STATUS "Found Readline library: ${READLINE_LIBRARY}") + message(STATUS "Include dir is: ${READLINE_INCLUDE_DIR}") + + if (NOT READLINE_INCLUDE_DIR OR NOT READLINE_LIBRARY) + message(FATAL_ERROR "** Readline library not found!\n** Your distro may provide a binary for Readline e.g. for ubuntu try apt-get install libreadline5-dev") + endif () + + add_library(readline SHARED IMPORTED GLOBAL) + + set_target_properties(readline + PROPERTIES + IMPORTED_LOCATION + "${READLINE_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES + "${READLINE_INCLUDE_DIR}") + +else() + # Provide a dummy target + add_library(readline INTERFACE) +endif() diff --git a/dep/recastnavigation/Detour/CMakeLists.txt b/dep/recastnavigation/Detour/CMakeLists.txt index b21e4ca6273..12be71d32b4 100644 --- a/dep/recastnavigation/Detour/CMakeLists.txt +++ b/dep/recastnavigation/Detour/CMakeLists.txt @@ -16,14 +16,18 @@ set(Detour_STAT_SRCS Source/DetourNavMeshQuery.cpp Source/DetourNode.cpp ) -include_directories(Include) - -if(WIN32) - include_directories( - ${CMAKE_SOURCE_DIR}/dep/zlib - ) -endif() add_library(Detour STATIC ${Detour_STAT_SRCS}) -target_link_libraries(Detour ${ZLIB_LIBRARIES}) +target_include_directories(Detour + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/Include) + +target_link_libraries(Detour + PUBLIC + zlib) + +set_target_properties(Detour + PROPERTIES + FOLDER + "dep") diff --git a/dep/recastnavigation/Recast/CMakeLists.txt b/dep/recastnavigation/Recast/CMakeLists.txt index 738c010eb05..1eac4e75399 100644 --- a/dep/recastnavigation/Recast/CMakeLists.txt +++ b/dep/recastnavigation/Recast/CMakeLists.txt @@ -14,21 +14,24 @@ set(Recast_STAT_SRCS Source/RecastArea.cpp Source/RecastContour.cpp Source/RecastFilter.cpp - Source/RecastLayers.cpp + Source/RecastLayers.cpp Source/RecastMesh.cpp Source/RecastMeshDetail.cpp Source/RecastRasterization.cpp Source/RecastRegion.cpp ) -include_directories(Include) +add_library(Recast STATIC ${Recast_STAT_SRCS}) -if(WIN32) - include_directories( - ${CMAKE_SOURCE_DIR}/dep/zlib - ) -endif() +target_include_directories(Recast + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/Include) -add_library(Recast STATIC ${Recast_STAT_SRCS}) +target_link_libraries(Recast + PUBLIC + zlib) -target_link_libraries(Recast ${ZLIB_LIBRARIES})
\ No newline at end of file +set_target_properties(Recast + PROPERTIES + FOLDER + "dep") diff --git a/dep/threads/CMakeLists.txt b/dep/threads/CMakeLists.txt new file mode 100644 index 00000000000..48e5eb00723 --- /dev/null +++ b/dep/threads/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +find_package(Threads REQUIRED) + +add_library(threads INTERFACE) +target_link_libraries(threads + INTERFACE + ${CMAKE_THREAD_LIBS_INIT}) diff --git a/dep/utf8cpp/CMakeLists.txt b/dep/utf8cpp/CMakeLists.txt new file mode 100644 index 00000000000..edf8604d44c --- /dev/null +++ b/dep/utf8cpp/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +add_library(utf8cpp INTERFACE) + +target_include_directories(utf8cpp + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/dep/valgrind/CMakeLists.txt b/dep/valgrind/CMakeLists.txt new file mode 100644 index 00000000000..d67cd33b426 --- /dev/null +++ b/dep/valgrind/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +add_library(valgrind INTERFACE) + +target_include_directories(valgrind + INTERFACE + "${VALGRIND_INCLUDE_DIR}") diff --git a/dep/zlib/CMakeLists.txt b/dep/zlib/CMakeLists.txt index 7feb134bcd5..b3e3d58fe55 100644 --- a/dep/zlib/CMakeLists.txt +++ b/dep/zlib/CMakeLists.txt @@ -8,22 +8,43 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -SET(zlib_STAT_SRCS - adler32.c - compress.c - crc32.c - deflate.c - infback.c - inffast.c - inflate.c - inftrees.c - trees.c - uncompr.c - zutil.c -) +if(UNIX) + # Look for an installed zlib on unix + find_package(ZLIB REQUIRED) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} -) + add_library(zlib SHARED IMPORTED GLOBAL) -add_library(zlib STATIC ${zlib_STAT_SRCS}) + set_target_properties(zlib + PROPERTIES + IMPORTED_LOCATION + "${ZLIB_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES + "${ZLIB_INCLUDE_DIRS}") +else() + # Use the bundled source on windows + SET(zlib_STAT_SRCS + adler32.c + compress.c + crc32.c + deflate.c + infback.c + inffast.c + inflate.c + inftrees.c + trees.c + uncompr.c + zutil.c + ) + + add_library(zlib STATIC + ${zlib_STAT_SRCS}) + + target_include_directories(zlib + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}) + + set_target_properties(zlib + PROPERTIES + FOLDER + "dep") +endif() diff --git a/issue_template.md b/issue_template.md index 87f2e21af41..8653726f830 100644 --- a/issue_template.md +++ b/issue_template.md @@ -6,17 +6,19 @@ **Steps to reproduce the problem**: -1. -2. -3. +1. +2. +3. -**Branch(es)**: 335/6x +**Branch(es)**: 335/6x -**TC hash/commit**: +**TC hash/commit**: -**TDB version**: +**TDB version**: -**Operating system**: +**Operating system**: + +**Linking model**: static/dynamic [//]: # (This template is for problem reports, for other type of reports edit it accordingly) diff --git a/pull_request_template.md b/pull_request_template.md index 7438ed561cf..f0066dc8f66 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -1,13 +1,16 @@ **Changes proposed**: -- -- -- +- +- +- **Target branch(es)**: 335/6x **Issues addressed**: Fixes # -**Tests performed**: (Does it build? Tested in-game?) +**Tests performed**: (Does it build, tested in-game, etc) **Known issues and TODO list**: + +- [ ] +- [ ] diff --git a/revision_data.h.in.cmake b/revision_data.h.in.cmake index 2e2fe2c318c..14faa04a0bc 100644 --- a/revision_data.h.in.cmake +++ b/revision_data.h.in.cmake @@ -3,11 +3,11 @@ #define _HASH "@rev_hash@" #define _DATE "@rev_date@" #define _BRANCH "@rev_branch@" - #define _CMAKE_COMMAND "@CMAKE_COMMAND@" - #define _SOURCE_DIRECTORY "@CMAKE_SOURCE_DIR@" - #define _BUILD_DIRECTORY "@BUILDDIR@" - #define _MYSQL_EXECUTABLE "@MYSQL_EXECUTABLE@" - #define _FULL_DATABASE "TDB_full_world_335.60_2015_11_07.sql" + #define _CMAKE_COMMAND R"(@CMAKE_COMMAND@)" + #define _SOURCE_DIRECTORY R"(@CMAKE_SOURCE_DIR@)" + #define _BUILD_DIRECTORY R"(@BUILDDIR@)" + #define _MYSQL_EXECUTABLE R"(@MYSQL_EXECUTABLE@)" + #define _FULL_DATABASE "TDB_full_world_335.61_2016_04_11.sql" #define VER_COMPANYNAME_STR "TrinityCore Developers" #define VER_LEGALCOPYRIGHT_STR "(c)2008-2016 TrinityCore" #define VER_FILEVERSION 0,0,0 diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 0ac0ffaf9d1..6dc81ab211e 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -1,6 +1,6 @@ -- MySQL dump 10.13 Distrib 5.6.26, for Win64 (x86_64) -- --- Host: localhost Database: auth335 +-- Host: localhost Database: auth -- ------------------------------------------------------ -- Server version 5.6.26-log @@ -486,7 +486,7 @@ CREATE TABLE `updates` ( LOCK TABLES `updates` WRITE; /*!40000 ALTER TABLE `updates` DISABLE KEYS */; -INSERT INTO `updates` VALUES ('2014_11_10_00_auth.sql','0E3CB119442D09DD88E967015319BBC8DAFBBFE0','ARCHIVED','2015-03-21 21:44:12',0),('2014_11_10_01_auth.sql','327E77A1DA3546D5275AB249915DD57EDD6FDD3D','ARCHIVED','2015-03-21 21:44:12',0),('2014_12_10_00_auth.sql','821703A96D80F9080074852B5A46E2909C9562EA','ARCHIVED','2015-03-21 21:44:12',0),('2014_12_21_00_auth.sql','CE2E5D2CD82E79C25294539ADED27A1429105B43','ARCHIVED','2015-03-21 21:44:12',0),('2015_03_20_00_auth.sql','E8C5B74BB45F0F35DEC182C72BACF435C7066FB0','ARCHIVED','2015-03-21 21:44:12',0),('2015_03_20_01_auth.sql','862961815354DA2746F5F71FBC8155F57CBE75AB','ARCHIVED','2015-03-21 21:44:12',0),('2015_03_20_02_auth.sql','33E4F94086590768EF5D4855DD43D7DE7C06ADA4','ARCHIVED','2015-03-21 21:44:51',0),('2015_08_21_00_auth.sql','C31A9E1D28E11B60BE8F8198637DD51F6D75123F','ARCHIVED','2015-10-05 23:16:19',0),('2015_11_07_00_auth.sql','BAF9F6B8F97A30D04BDBBA8127A62A1720F9B904','RELEASED','2015-11-07 15:40:47',0),('2016_01_13_00_auth.sql','24615CC69B3CD7BB4699874647C35BA86E8A93FD','RELEASED','2016-01-13 00:00:00',0); +INSERT INTO `updates` VALUES ('2014_11_10_00_auth.sql','0E3CB119442D09DD88E967015319BBC8DAFBBFE0','ARCHIVED','2015-03-21 21:44:12',0),('2014_11_10_01_auth.sql','327E77A1DA3546D5275AB249915DD57EDD6FDD3D','ARCHIVED','2015-03-21 21:44:12',0),('2014_12_10_00_auth.sql','821703A96D80F9080074852B5A46E2909C9562EA','ARCHIVED','2015-03-21 21:44:12',0),('2014_12_21_00_auth.sql','CE2E5D2CD82E79C25294539ADED27A1429105B43','ARCHIVED','2015-03-21 21:44:12',0),('2015_03_20_00_auth.sql','E8C5B74BB45F0F35DEC182C72BACF435C7066FB0','ARCHIVED','2015-03-21 21:44:12',0),('2015_03_20_01_auth.sql','862961815354DA2746F5F71FBC8155F57CBE75AB','ARCHIVED','2015-03-21 21:44:12',0),('2015_03_20_02_auth.sql','33E4F94086590768EF5D4855DD43D7DE7C06ADA4','ARCHIVED','2015-03-21 21:44:51',0),('2015_08_21_00_auth.sql','C31A9E1D28E11B60BE8F8198637DD51F6D75123F','ARCHIVED','2015-10-05 23:16:19',0),('2015_11_07_00_auth.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-04-11 00:42:36',92),('2016_01_13_00_auth.sql','24615CC69B3CD7BB4699874647C35BA86E8A93FD','ARCHIVED','2016-01-13 00:00:00',0),('2016_04_11_00_auth.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','2016-04-11 03:18:17','2016-04-11 03:18:17',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; @@ -549,4 +549,4 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2015-11-07 14:42:34 +-- Dump completed on 2016-04-11 2:32:16 diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 02061aaf976..1f071db3781 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -1,6 +1,6 @@ -- MySQL dump 10.13 Distrib 5.6.26, for Win64 (x86_64) -- --- Host: localhost Database: characters335 +-- Host: localhost Database: characters -- ------------------------------------------------------ -- Server version 5.6.26-log @@ -783,7 +783,7 @@ CREATE TABLE `character_instance` ( `guid` int(10) unsigned NOT NULL DEFAULT '0', `instance` int(10) unsigned NOT NULL DEFAULT '0', `permanent` tinyint(3) unsigned NOT NULL DEFAULT '0', - `extendState` TINYINT(2) UNSIGNED NOT NULL DEFAULT '1', + `extendState` tinyint(2) unsigned NOT NULL DEFAULT '1', PRIMARY KEY (`guid`,`instance`), KEY `instance` (`instance`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -1272,8 +1272,13 @@ CREATE TABLE `characters` ( `level` tinyint(3) unsigned NOT NULL DEFAULT '0', `xp` int(10) unsigned NOT NULL DEFAULT '0', `money` int(10) unsigned NOT NULL DEFAULT '0', - `playerBytes` int(10) unsigned NOT NULL DEFAULT '0', - `playerBytes2` int(10) unsigned NOT NULL DEFAULT '0', + `skin` tinyint(3) unsigned NOT NULL DEFAULT '0', + `face` tinyint(3) unsigned NOT NULL DEFAULT '0', + `hairStyle` tinyint(3) unsigned NOT NULL DEFAULT '0', + `hairColor` tinyint(3) unsigned NOT NULL DEFAULT '0', + `facialStyle` tinyint(3) unsigned NOT NULL DEFAULT '0', + `bankSlots` tinyint(3) unsigned NOT NULL DEFAULT '0', + `restState` tinyint(3) unsigned NOT NULL DEFAULT '0', `playerFlags` int(10) unsigned NOT NULL DEFAULT '0', `position_x` float NOT NULL DEFAULT '0', `position_y` float NOT NULL DEFAULT '0', @@ -2540,7 +2545,7 @@ CREATE TABLE `updates` ( LOCK TABLES `updates` WRITE; /*!40000 ALTER TABLE `updates` DISABLE KEYS */; -INSERT INTO `updates` VALUES ('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_01_characters.sql','894F08B70449A5481FFAF394EE5571D7FC4D8A3A','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_02_characters.sql','97D7BE0CAADC79F3F11B9FD296B8C6CD40FE593B','ARCHIVED','2015-03-21 21:44:51',0),('2015_06_26_00_characters_335.sql','C2CC6E50AFA1ACCBEBF77CC519AAEB09F3BBAEBC','ARCHIVED','2015-07-13 23:49:22',0),('2015_09_28_00_characters_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-28 21:00:00',0),('2015_08_26_00_characters_335.sql','C7D6A3A00FECA3EBFF1E71744CA40D3076582374','ARCHIVED','2015-08-26 21:00:00',0),('2015_10_06_00_characters.sql','16842FDD7E8547F2260D3312F53EFF8761EFAB35','ARCHIVED','2015-10-06 16:06:38',0),('2015_10_07_00_characters.sql','E15AB463CEBE321001D7BFDEA4B662FF618728FD','ARCHIVED','2015-10-07 23:32:00',0),('2015_10_12_00_characters.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-10-12 15:35:47',0),('2015_10_28_00_characters.sql','622A9CA8FCE690429EBE23BA071A37C7A007BF8B','ARCHIVED','2015-10-19 14:32:22',0),('2015_10_29_00_characters_335.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-10-29 17:05:43',0),('2015_11_03_00_characters.sql','CC045717B8FDD9733351E52A5302560CD08AAD57','ARCHIVED','2015-10-12 15:23:33',0),('2015_11_07_00_characters.sql','BAF9F6B8F97A30D04BDBBA8127A62A1720F9B904','RELEASED','2015-11-07 15:40:47',0),('2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','RELEASED','2016-02-10 00:00:00',0); +INSERT INTO `updates` VALUES ('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_01_characters.sql','894F08B70449A5481FFAF394EE5571D7FC4D8A3A','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_02_characters.sql','97D7BE0CAADC79F3F11B9FD296B8C6CD40FE593B','ARCHIVED','2015-03-21 21:44:51',0),('2015_06_26_00_characters_335.sql','C2CC6E50AFA1ACCBEBF77CC519AAEB09F3BBAEBC','ARCHIVED','2015-07-13 23:49:22',0),('2015_09_28_00_characters_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-28 21:00:00',0),('2015_08_26_00_characters_335.sql','C7D6A3A00FECA3EBFF1E71744CA40D3076582374','ARCHIVED','2015-08-26 21:00:00',0),('2015_10_06_00_characters.sql','16842FDD7E8547F2260D3312F53EFF8761EFAB35','ARCHIVED','2015-10-06 16:06:38',0),('2015_10_07_00_characters.sql','E15AB463CEBE321001D7BFDEA4B662FF618728FD','ARCHIVED','2015-10-07 23:32:00',0),('2015_10_12_00_characters.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-10-12 15:35:47',0),('2015_10_28_00_characters.sql','622A9CA8FCE690429EBE23BA071A37C7A007BF8B','ARCHIVED','2015-10-19 14:32:22',0),('2015_10_29_00_characters_335.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-10-29 17:05:43',0),('2015_11_03_00_characters.sql','CC045717B8FDD9733351E52A5302560CD08AAD57','ARCHIVED','2015-10-12 15:23:33',0),('2015_11_07_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-04-11 00:42:36',94),('2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','ARCHIVED','2016-02-10 00:00:00',0),('2016_03_13_2016_01_05_00_characters.sql','0EAD24977F40DE2476B4567DA2B477867CC0DA1A','ARCHIVED','2016-03-13 20:03:56',0),('2016_04_11_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','RELEASED','2016-04-11 03:18:17',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; @@ -2625,4 +2630,4 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2015-11-07 14:42:34 +-- Dump completed on 2016-04-11 2:32:17 diff --git a/sql/base/dev/world_database.sql b/sql/base/dev/world_database.sql index 02318987448..85e7c2391da 100644 --- a/sql/base/dev/world_database.sql +++ b/sql/base/dev/world_database.sql @@ -1,6 +1,6 @@ -- MySQL dump 10.13 Distrib 5.6.26, for Win64 (x86_64) -- --- Host: localhost Database: world335 +-- Host: localhost Database: world -- ------------------------------------------------------ -- Server version 5.6.26-log @@ -1022,7 +1022,7 @@ CREATE TABLE `game_tele` ( `map` smallint(5) unsigned NOT NULL DEFAULT '0', `name` varchar(100) NOT NULL DEFAULT '', PRIMARY KEY (`id`) -) ENGINE=MyISAM AUTO_INCREMENT=1425 DEFAULT CHARSET=utf8 COMMENT='Tele Command'; +) ENGINE=MyISAM AUTO_INCREMENT=1429 DEFAULT CHARSET=utf8 COMMENT='Tele Command'; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -3785,4 +3785,4 @@ CREATE TABLE `waypoints` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2015-11-07 14:42:45 +-- Dump completed on 2016-04-11 2:32:19 diff --git a/sql/updates/auth/2015_11_07_00_auth.sql b/sql/old/3.3.5a/auth/60_2016_04_11/2015_11_07_00_auth.sql index be8a4d21b66..be8a4d21b66 100644 --- a/sql/updates/auth/2015_11_07_00_auth.sql +++ b/sql/old/3.3.5a/auth/60_2016_04_11/2015_11_07_00_auth.sql diff --git a/sql/updates/auth/2016_01_13_00_auth.sql b/sql/old/3.3.5a/auth/60_2016_04_11/2016_01_13_00_auth.sql index c70d4c09468..c70d4c09468 100644 --- a/sql/updates/auth/2016_01_13_00_auth.sql +++ b/sql/old/3.3.5a/auth/60_2016_04_11/2016_01_13_00_auth.sql diff --git a/sql/updates/characters/2015_11_07_00_characters.sql b/sql/old/3.3.5a/characters/60_2016_04_11/2015_11_07_00_characters.sql index be8a4d21b66..be8a4d21b66 100644 --- a/sql/updates/characters/2015_11_07_00_characters.sql +++ b/sql/old/3.3.5a/characters/60_2016_04_11/2015_11_07_00_characters.sql diff --git a/sql/updates/characters/2016_02_10_00_characters.sql b/sql/old/3.3.5a/characters/60_2016_04_11/2016_02_10_00_characters.sql index d49ed155bc8..d49ed155bc8 100644 --- a/sql/updates/characters/2016_02_10_00_characters.sql +++ b/sql/old/3.3.5a/characters/60_2016_04_11/2016_02_10_00_characters.sql diff --git a/sql/old/3.3.5a/characters/60_2016_04_11/2016_03_13_2016_01_05_00_characters.sql b/sql/old/3.3.5a/characters/60_2016_04_11/2016_03_13_2016_01_05_00_characters.sql new file mode 100644 index 00000000000..11850067be9 --- /dev/null +++ b/sql/old/3.3.5a/characters/60_2016_04_11/2016_03_13_2016_01_05_00_characters.sql @@ -0,0 +1,19 @@ +ALTER TABLE `characters` + ADD `skin` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `money`, + ADD `face` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `skin`, + ADD `hairStyle` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `face`, + ADD `hairColor` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `hairStyle`, + ADD `facialStyle` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `hairColor`, + ADD `bankSlots` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `facialStyle`, + ADD `restState` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `bankSlots`; + +UPDATE `characters` SET + `skin`=`playerBytes`&0xFF, + `face`=(`playerBytes`>>8)&0xFF, + `hairStyle`=(`playerBytes`>>16)&0xFF, + `hairColor`=(`playerBytes`>>24)&0xFF, + `facialStyle`=`playerBytes2`&0xFF, + `bankSlots`=(`playerBytes2`>>16)&0xFF, + `restState`=(`playerBytes2`>>24)&0xFF; + +ALTER TABLE `characters` DROP `playerBytes`, DROP `playerBytes2`; diff --git a/sql/updates/world/2015_11_07_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_07_02_world.sql index 3e23e0e629b..3e23e0e629b 100644 --- a/sql/updates/world/2015_11_07_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_07_02_world.sql diff --git a/sql/updates/world/2015_11_08_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_08_00_world.sql index fea6f43bc64..fea6f43bc64 100644 --- a/sql/updates/world/2015_11_08_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_08_00_world.sql diff --git a/sql/updates/world/2015_11_08_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_08_01_world.sql index f5642f73af4..f5642f73af4 100644 --- a/sql/updates/world/2015_11_08_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_08_01_world.sql diff --git a/sql/updates/world/2015_11_09_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_09_00_world.sql index 6fd5dec39b7..6fd5dec39b7 100644 --- a/sql/updates/world/2015_11_09_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_09_00_world.sql diff --git a/sql/updates/world/2015_11_09_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_09_01_world.sql index e9360cf8963..e9360cf8963 100644 --- a/sql/updates/world/2015_11_09_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_09_01_world.sql diff --git a/sql/updates/world/2015_11_09_02_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_09_02_world_335.sql index 84c0fd423ad..84c0fd423ad 100644 --- a/sql/updates/world/2015_11_09_02_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_09_02_world_335.sql diff --git a/sql/updates/world/2015_11_10_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_10_00_world.sql index 6e969f288f1..6e969f288f1 100644 --- a/sql/updates/world/2015_11_10_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_10_00_world.sql diff --git a/sql/updates/world/2015_11_10_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_10_01_world.sql index fe9c0b1b8e2..fe9c0b1b8e2 100644 --- a/sql/updates/world/2015_11_10_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_10_01_world.sql diff --git a/sql/updates/world/2015_11_10_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_10_02_world.sql index 8ff255defa4..8ff255defa4 100644 --- a/sql/updates/world/2015_11_10_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_10_02_world.sql diff --git a/sql/updates/world/2015_11_11_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_11_00_world.sql index 07393641f3f..07393641f3f 100644 --- a/sql/updates/world/2015_11_11_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_11_00_world.sql diff --git a/sql/updates/world/2015_11_11_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_11_01_world.sql index 3c1ce85ec17..3c1ce85ec17 100644 --- a/sql/updates/world/2015_11_11_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_11_01_world.sql diff --git a/sql/updates/world/2015_11_12_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_12_00_world.sql index 79c2461e5ff..79c2461e5ff 100644 --- a/sql/updates/world/2015_11_12_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_12_00_world.sql diff --git a/sql/updates/world/2015_11_12_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_12_01_world.sql index c08ebda2471..c08ebda2471 100644 --- a/sql/updates/world/2015_11_12_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_12_01_world.sql diff --git a/sql/updates/world/2015_11_20_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_20_00_world.sql index 7c5fe7ea426..7c5fe7ea426 100644 --- a/sql/updates/world/2015_11_20_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_20_00_world.sql diff --git a/sql/updates/world/2015_11_22_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_22_00_world.sql index 2b70a2c97b6..2b70a2c97b6 100644 --- a/sql/updates/world/2015_11_22_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_22_00_world.sql diff --git a/sql/updates/world/2015_11_22_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_22_01_world.sql index ba63c72ba16..ba63c72ba16 100644 --- a/sql/updates/world/2015_11_22_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_22_01_world.sql diff --git a/sql/updates/world/2015_11_22_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_22_02_world.sql index 7fcbc7ec9aa..7fcbc7ec9aa 100644 --- a/sql/updates/world/2015_11_22_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_22_02_world.sql diff --git a/sql/updates/world/2015_11_22_03_world_355.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_22_03_world_355.sql index 9bf71a146d0..9bf71a146d0 100644 --- a/sql/updates/world/2015_11_22_03_world_355.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_22_03_world_355.sql diff --git a/sql/updates/world/2015_11_23_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_00_world_335.sql index fffc4531e5e..fffc4531e5e 100644 --- a/sql/updates/world/2015_11_23_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_00_world_335.sql diff --git a/sql/updates/world/2015_11_23_01_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_01_world_335.sql index 8432c2d14fd..8432c2d14fd 100644 --- a/sql/updates/world/2015_11_23_01_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_01_world_335.sql diff --git a/sql/updates/world/2015_11_23_02_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_02_world_335.sql index ba569d1420f..ba569d1420f 100644 --- a/sql/updates/world/2015_11_23_02_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_02_world_335.sql diff --git a/sql/updates/world/2015_11_23_03_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_03_world_335.sql index 9ef011f551e..9ef011f551e 100644 --- a/sql/updates/world/2015_11_23_03_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_03_world_335.sql diff --git a/sql/updates/world/2015_11_23_04_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_04_world_335.sql index 845eefeb7ca..845eefeb7ca 100644 --- a/sql/updates/world/2015_11_23_04_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_04_world_335.sql diff --git a/sql/updates/world/2015_11_23_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_05_world.sql index 579af5a5ca1..579af5a5ca1 100644 --- a/sql/updates/world/2015_11_23_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_23_05_world.sql diff --git a/sql/updates/world/2015_11_24_00_world_355.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_24_00_world_355.sql index 0983d03e649..0983d03e649 100644 --- a/sql/updates/world/2015_11_24_00_world_355.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_24_00_world_355.sql diff --git a/sql/updates/world/2015_11_27_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_27_00_world.sql index 632dec537dd..632dec537dd 100644 --- a/sql/updates/world/2015_11_27_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_27_00_world.sql diff --git a/sql/updates/world/2015_11_28_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_28_00_world.sql index 0a1dd574fb4..0a1dd574fb4 100644 --- a/sql/updates/world/2015_11_28_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_28_00_world.sql diff --git a/sql/updates/world/2015_11_28_01_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_28_01_world_335.sql index 4bec178ecee..4bec178ecee 100644 --- a/sql/updates/world/2015_11_28_01_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_28_01_world_335.sql diff --git a/sql/updates/world/2015_11_29_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_29_00_world.sql index fd64b65bd02..fd64b65bd02 100644 --- a/sql/updates/world/2015_11_29_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_29_00_world.sql diff --git a/sql/updates/world/2015_11_29_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_29_01_world.sql index cd46800c5dd..cd46800c5dd 100644 --- a/sql/updates/world/2015_11_29_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_11_29_01_world.sql diff --git a/sql/updates/world/2015_12_01_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_01_00_world.sql index 1572245a517..1572245a517 100644 --- a/sql/updates/world/2015_12_01_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_01_00_world.sql diff --git a/sql/updates/world/2015_12_04_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_04_00_world.sql index ee721273bef..ee721273bef 100644 --- a/sql/updates/world/2015_12_04_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_04_00_world.sql diff --git a/sql/updates/world/2015_12_05_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_05_00_world.sql index c2c90164a4f..c2c90164a4f 100644 --- a/sql/updates/world/2015_12_05_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_05_00_world.sql diff --git a/sql/updates/world/2015_12_06_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_06_00_world.sql index b60d4d3e88c..b60d4d3e88c 100644 --- a/sql/updates/world/2015_12_06_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_06_00_world.sql diff --git a/sql/updates/world/2015_12_08_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_08_00_world_335.sql index e742130b1a4..e742130b1a4 100644 --- a/sql/updates/world/2015_12_08_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_08_00_world_335.sql diff --git a/sql/updates/world/2015_12_08_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_08_01_world.sql index 9e24acd91db..9e24acd91db 100644 --- a/sql/updates/world/2015_12_08_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_08_01_world.sql diff --git a/sql/updates/world/2015_12_08_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_08_02_world.sql index 375d0941adb..375d0941adb 100644 --- a/sql/updates/world/2015_12_08_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_08_02_world.sql diff --git a/sql/updates/world/2015_12_09_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_09_00_world.sql index 6ac4da31404..6ac4da31404 100644 --- a/sql/updates/world/2015_12_09_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_09_00_world.sql diff --git a/sql/updates/world/2015_12_09_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_09_01_world.sql index d27bc7ff49a..d27bc7ff49a 100644 --- a/sql/updates/world/2015_12_09_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_09_01_world.sql diff --git a/sql/updates/world/2015_12_11_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_11_00_world.sql index dc5fd8c40b6..dc5fd8c40b6 100644 --- a/sql/updates/world/2015_12_11_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_11_00_world.sql diff --git a/sql/updates/world/2015_12_14_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_14_00_world.sql index 85faf4448e2..85faf4448e2 100644 --- a/sql/updates/world/2015_12_14_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_14_00_world.sql diff --git a/sql/updates/world/2015_12_15_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_15_00_world.sql index f27bb448bbd..f27bb448bbd 100644 --- a/sql/updates/world/2015_12_15_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_15_00_world.sql diff --git a/sql/updates/world/2015_12_15_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_15_01_world.sql index 86fbec83c38..86fbec83c38 100644 --- a/sql/updates/world/2015_12_15_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_15_01_world.sql diff --git a/sql/updates/world/2015_12_15_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_15_02_world.sql index eda5c26550f..eda5c26550f 100644 --- a/sql/updates/world/2015_12_15_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_15_02_world.sql diff --git a/sql/updates/world/2015_12_15_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_15_03_world.sql index 99cc9e14646..99cc9e14646 100644 --- a/sql/updates/world/2015_12_15_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_15_03_world.sql diff --git a/sql/updates/world/2015_12_16_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_16_00_world.sql index 62d640117f7..62d640117f7 100644 --- a/sql/updates/world/2015_12_16_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_16_00_world.sql diff --git a/sql/updates/world/2015_12_16_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_16_01_world.sql index 73c9675e5be..73c9675e5be 100644 --- a/sql/updates/world/2015_12_16_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_16_01_world.sql diff --git a/sql/updates/world/2015_12_16_02_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_16_02_world_335.sql index 20c1ac94a39..20c1ac94a39 100644 --- a/sql/updates/world/2015_12_16_02_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_16_02_world_335.sql diff --git a/sql/updates/world/2015_12_17_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_17_00_world.sql index 8419473b203..8419473b203 100644 --- a/sql/updates/world/2015_12_17_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_17_00_world.sql diff --git a/sql/updates/world/2015_12_18_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_00_world_335.sql index 3fb3e5a6e1e..3fb3e5a6e1e 100644 --- a/sql/updates/world/2015_12_18_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_00_world_335.sql diff --git a/sql/updates/world/2015_12_18_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_01_world.sql index 2ccc93def23..2ccc93def23 100644 --- a/sql/updates/world/2015_12_18_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_01_world.sql diff --git a/sql/updates/world/2015_12_18_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_02_world.sql index f590d18a8ab..f590d18a8ab 100644 --- a/sql/updates/world/2015_12_18_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_02_world.sql diff --git a/sql/updates/world/2015_12_18_03_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_03_world_335.sql index de778343a0e..de778343a0e 100644 --- a/sql/updates/world/2015_12_18_03_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_03_world_335.sql diff --git a/sql/updates/world/2015_12_18_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_04_world.sql index c8c3352319c..c8c3352319c 100644 --- a/sql/updates/world/2015_12_18_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_18_04_world.sql diff --git a/sql/updates/world/2015_12_20_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_20_00_world.sql index 7c658877f13..7c658877f13 100644 --- a/sql/updates/world/2015_12_20_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_20_00_world.sql diff --git a/sql/updates/world/2015_12_24_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_24_00_world.sql index 52d83bb63c3..52d83bb63c3 100644 --- a/sql/updates/world/2015_12_24_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_24_00_world.sql diff --git a/sql/updates/world/2015_12_26_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_26_00_world.sql index 02c0acbedae..02c0acbedae 100644 --- a/sql/updates/world/2015_12_26_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_26_00_world.sql diff --git a/sql/updates/world/2015_12_26_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_26_01_world.sql index 92a9d21af25..92a9d21af25 100644 --- a/sql/updates/world/2015_12_26_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_26_01_world.sql diff --git a/sql/updates/world/2015_12_26_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_26_02_world.sql index 021dec0be80..021dec0be80 100644 --- a/sql/updates/world/2015_12_26_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_26_02_world.sql diff --git a/sql/updates/world/2015_12_29_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_00_world.sql index da6de123190..da6de123190 100644 --- a/sql/updates/world/2015_12_29_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_00_world.sql diff --git a/sql/updates/world/2015_12_29_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_01_world.sql index 24b201b4d06..24b201b4d06 100644 --- a/sql/updates/world/2015_12_29_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_01_world.sql diff --git a/sql/updates/world/2015_12_29_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_02_world.sql index 3bfd0ba2a25..3bfd0ba2a25 100644 --- a/sql/updates/world/2015_12_29_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_02_world.sql diff --git a/sql/updates/world/2015_12_29_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_03_world.sql index f928061c269..f928061c269 100644 --- a/sql/updates/world/2015_12_29_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_03_world.sql diff --git a/sql/updates/world/2015_12_29_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_04_world.sql index 22a1ee3edcf..22a1ee3edcf 100644 --- a/sql/updates/world/2015_12_29_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_04_world.sql diff --git a/sql/updates/world/2015_12_29_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_05_world.sql index 056ea4fe230..056ea4fe230 100644 --- a/sql/updates/world/2015_12_29_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_05_world.sql diff --git a/sql/updates/world/2015_12_29_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_06_world.sql index 167c4c23005..167c4c23005 100644 --- a/sql/updates/world/2015_12_29_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_06_world.sql diff --git a/sql/updates/world/2015_12_29_07_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_07_world.sql index ec71d28c787..ec71d28c787 100644 --- a/sql/updates/world/2015_12_29_07_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_07_world.sql diff --git a/sql/updates/world/2015_12_29_08_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_08_world.sql index ce874d7a8d2..ce874d7a8d2 100644 --- a/sql/updates/world/2015_12_29_08_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_08_world.sql diff --git a/sql/updates/world/2015_12_29_09_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_09_world.sql index d57785e8d88..d57785e8d88 100644 --- a/sql/updates/world/2015_12_29_09_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_09_world.sql diff --git a/sql/updates/world/2015_12_29_10_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_10_world.sql index 919309dd558..919309dd558 100644 --- a/sql/updates/world/2015_12_29_10_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_10_world.sql diff --git a/sql/updates/world/2015_12_29_11_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_11_world.sql index 930baf15f78..930baf15f78 100644 --- a/sql/updates/world/2015_12_29_11_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_11_world.sql diff --git a/sql/updates/world/2015_12_29_12_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_12_world.sql index c065e1d6a18..c065e1d6a18 100644 --- a/sql/updates/world/2015_12_29_12_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_12_world.sql diff --git a/sql/updates/world/2015_12_29_13_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_13_world.sql index fc182ae49fb..fc182ae49fb 100644 --- a/sql/updates/world/2015_12_29_13_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_29_13_world.sql diff --git a/sql/updates/world/2015_12_31_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_31_00_world.sql index b7c310323ed..b7c310323ed 100644 --- a/sql/updates/world/2015_12_31_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_31_00_world.sql diff --git a/sql/updates/world/2015_12_31_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_31_01_world.sql index 3bee62963ef..3bee62963ef 100644 --- a/sql/updates/world/2015_12_31_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2015_12_31_01_world.sql diff --git a/sql/updates/world/2016_01_01_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_01_00_world.sql index 38991837113..38991837113 100644 --- a/sql/updates/world/2016_01_01_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_01_00_world.sql diff --git a/sql/updates/world/2016_01_01_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_01_01_world.sql index 025f2c07f9c..025f2c07f9c 100644 --- a/sql/updates/world/2016_01_01_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_01_01_world.sql diff --git a/sql/updates/world/2016_01_02_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_02_00_world_335.sql index b46a41bc6e9..b46a41bc6e9 100644 --- a/sql/updates/world/2016_01_02_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_02_00_world_335.sql diff --git a/sql/updates/world/2016_01_02_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_02_01_world.sql index b862cc0e644..b862cc0e644 100644 --- a/sql/updates/world/2016_01_02_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_02_01_world.sql diff --git a/sql/updates/world/2016_01_03_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_00_world_335.sql index 658b180a41a..658b180a41a 100644 --- a/sql/updates/world/2016_01_03_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_00_world_335.sql diff --git a/sql/updates/world/2016_01_03_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_01_world.sql index 3ddb56a9c72..3ddb56a9c72 100644 --- a/sql/updates/world/2016_01_03_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_01_world.sql diff --git a/sql/updates/world/2016_01_03_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_02_world.sql index 79eba012e41..79eba012e41 100644 --- a/sql/updates/world/2016_01_03_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_02_world.sql diff --git a/sql/updates/world/2016_01_03_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_03_world.sql index 1b1766ee557..1b1766ee557 100644 --- a/sql/updates/world/2016_01_03_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_03_world.sql diff --git a/sql/updates/world/2016_01_03_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_04_world.sql index ffe8eb07fd5..ffe8eb07fd5 100644 --- a/sql/updates/world/2016_01_03_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_04_world.sql diff --git a/sql/updates/world/2016_01_03_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_05_world.sql index 4c2fe0817f0..4c2fe0817f0 100644 --- a/sql/updates/world/2016_01_03_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_03_05_world.sql diff --git a/sql/updates/world/2016_01_04_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_04_00_world.sql index 57236a6f66e..57236a6f66e 100644 --- a/sql/updates/world/2016_01_04_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_04_00_world.sql diff --git a/sql/updates/world/2016_01_05_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_05_00_world.sql index 3f7f01449fc..3f7f01449fc 100644 --- a/sql/updates/world/2016_01_05_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_05_00_world.sql diff --git a/sql/updates/world/2016_01_05_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_05_01_world.sql index dc1064a75b9..dc1064a75b9 100644 --- a/sql/updates/world/2016_01_05_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_05_01_world.sql diff --git a/sql/updates/world/2016_01_05_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_05_02_world.sql index 64909129e60..64909129e60 100644 --- a/sql/updates/world/2016_01_05_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_05_02_world.sql diff --git a/sql/updates/world/2016_01_07_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_07_00_world.sql index d36dda80e50..d36dda80e50 100644 --- a/sql/updates/world/2016_01_07_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_07_00_world.sql diff --git a/sql/updates/world/2016_01_07_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_07_01_world.sql index 4a15aa405ec..4a15aa405ec 100644 --- a/sql/updates/world/2016_01_07_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_07_01_world.sql diff --git a/sql/updates/world/2016_01_07_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_07_02_world.sql index 7724b42ac9d..7724b42ac9d 100644 --- a/sql/updates/world/2016_01_07_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_07_02_world.sql diff --git a/sql/updates/world/2016_01_08_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_08_00_world.sql index 55ed3ddf336..55ed3ddf336 100644 --- a/sql/updates/world/2016_01_08_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_08_00_world.sql diff --git a/sql/updates/world/2016_01_08_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_08_01_world.sql index ebf4560d326..ebf4560d326 100644 --- a/sql/updates/world/2016_01_08_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_08_01_world.sql diff --git a/sql/updates/world/2016_01_08_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_08_02_world.sql index 28e55dfba3b..28e55dfba3b 100644 --- a/sql/updates/world/2016_01_08_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_08_02_world.sql diff --git a/sql/updates/world/2016_01_08_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_08_03_world.sql index 2899c6e06eb..2899c6e06eb 100644 --- a/sql/updates/world/2016_01_08_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_08_03_world.sql diff --git a/sql/updates/world/2016_01_09_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_09_00_world.sql index 534e17ccb00..534e17ccb00 100644 --- a/sql/updates/world/2016_01_09_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_09_00_world.sql diff --git a/sql/updates/world/2016_01_10_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_00_world.sql index 83ed21c8489..83ed21c8489 100644 --- a/sql/updates/world/2016_01_10_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_00_world.sql diff --git a/sql/updates/world/2016_01_10_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_01_world.sql index c79c157a1a1..c79c157a1a1 100644 --- a/sql/updates/world/2016_01_10_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_01_world.sql diff --git a/sql/updates/world/2016_01_10_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_02_world.sql index eca8ef07849..eca8ef07849 100644 --- a/sql/updates/world/2016_01_10_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_02_world.sql diff --git a/sql/updates/world/2016_01_10_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_03_world.sql index 5ac352ffe10..5ac352ffe10 100644 --- a/sql/updates/world/2016_01_10_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_03_world.sql diff --git a/sql/updates/world/2016_01_10_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_04_world.sql index da6eed191ad..da6eed191ad 100644 --- a/sql/updates/world/2016_01_10_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_04_world.sql diff --git a/sql/updates/world/2016_01_10_05_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_05_world_335.sql index 7fb021cc9dd..7fb021cc9dd 100644 --- a/sql/updates/world/2016_01_10_05_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_10_05_world_335.sql diff --git a/sql/updates/world/2016_01_12_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_00_world.sql index 8ed4099450b..8ed4099450b 100644 --- a/sql/updates/world/2016_01_12_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_00_world.sql diff --git a/sql/updates/world/2016_01_12_01_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_01_world_335.sql index c3206e70ac4..c3206e70ac4 100644 --- a/sql/updates/world/2016_01_12_01_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_01_world_335.sql diff --git a/sql/updates/world/2016_01_12_02_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_02_world_335.sql index 354d0bc129d..354d0bc129d 100644 --- a/sql/updates/world/2016_01_12_02_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_02_world_335.sql diff --git a/sql/updates/world/2016_01_12_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_03_world.sql index 6ff3a769918..6ff3a769918 100644 --- a/sql/updates/world/2016_01_12_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_03_world.sql diff --git a/sql/updates/world/2016_01_12_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_04_world.sql index 7cee9220060..7cee9220060 100644 --- a/sql/updates/world/2016_01_12_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_12_04_world.sql diff --git a/sql/updates/world/2016_01_13_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_13_00_world.sql index cba5d3a18a1..cba5d3a18a1 100644 --- a/sql/updates/world/2016_01_13_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_13_00_world.sql diff --git a/sql/updates/world/2016_01_15_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_15_00_world.sql index b5f3da2dd99..b5f3da2dd99 100644 --- a/sql/updates/world/2016_01_15_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_15_00_world.sql diff --git a/sql/updates/world/2016_01_16_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_00_world_335.sql index 14362432555..14362432555 100644 --- a/sql/updates/world/2016_01_16_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_00_world_335.sql diff --git a/sql/updates/world/2016_01_16_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_01_world.sql index 235378a7a84..235378a7a84 100644 --- a/sql/updates/world/2016_01_16_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_01_world.sql diff --git a/sql/updates/world/2016_01_16_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_02_world.sql index b36d7d69ff6..b36d7d69ff6 100644 --- a/sql/updates/world/2016_01_16_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_02_world.sql diff --git a/sql/updates/world/2016_01_16_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_03_world.sql index 5a06cfaecca..5a06cfaecca 100644 --- a/sql/updates/world/2016_01_16_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_03_world.sql diff --git a/sql/updates/world/2016_01_16_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_04_world.sql index a6bb7ae185c..a6bb7ae185c 100644 --- a/sql/updates/world/2016_01_16_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_04_world.sql diff --git a/sql/updates/world/2016_01_16_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_05_world.sql index 46511cb0de8..46511cb0de8 100644 --- a/sql/updates/world/2016_01_16_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_16_05_world.sql diff --git a/sql/updates/world/2016_01_17_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_00_world_335.sql index abb3579fb07..abb3579fb07 100644 --- a/sql/updates/world/2016_01_17_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_00_world_335.sql diff --git a/sql/updates/world/2016_01_17_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_01_world.sql index 8e5bcd22a07..8e5bcd22a07 100644 --- a/sql/updates/world/2016_01_17_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_01_world.sql diff --git a/sql/updates/world/2016_01_17_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_02_world.sql index f019b927228..f019b927228 100644 --- a/sql/updates/world/2016_01_17_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_02_world.sql diff --git a/sql/updates/world/2016_01_17_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_03_world.sql index cf43c650888..cf43c650888 100644 --- a/sql/updates/world/2016_01_17_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_03_world.sql diff --git a/sql/updates/world/2016_01_17_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_04_world.sql index 6d72807e0b1..6d72807e0b1 100644 --- a/sql/updates/world/2016_01_17_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_04_world.sql diff --git a/sql/updates/world/2016_01_17_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_05_world.sql index 2d253bae713..2d253bae713 100644 --- a/sql/updates/world/2016_01_17_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_05_world.sql diff --git a/sql/updates/world/2016_01_17_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_06_world.sql index 659f146845a..659f146845a 100644 --- a/sql/updates/world/2016_01_17_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_06_world.sql diff --git a/sql/updates/world/2016_01_17_07_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_07_world.sql index df588168d38..df588168d38 100644 --- a/sql/updates/world/2016_01_17_07_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_07_world.sql diff --git a/sql/updates/world/2016_01_17_08_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_08_world.sql index 48cd420a242..48cd420a242 100644 --- a/sql/updates/world/2016_01_17_08_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_08_world.sql diff --git a/sql/updates/world/2016_01_17_09_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_09_world.sql index 85e6f535866..85e6f535866 100644 --- a/sql/updates/world/2016_01_17_09_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_09_world.sql diff --git a/sql/updates/world/2016_01_17_10_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_10_world.sql index 0fdc04eb60f..0fdc04eb60f 100644 --- a/sql/updates/world/2016_01_17_10_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_10_world.sql diff --git a/sql/updates/world/2016_01_17_11_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_11_world.sql index 9ab963a2ff2..9ab963a2ff2 100644 --- a/sql/updates/world/2016_01_17_11_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_11_world.sql diff --git a/sql/updates/world/2016_01_17_12_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_12_world.sql index e4e8ab5e9e2..e4e8ab5e9e2 100644 --- a/sql/updates/world/2016_01_17_12_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_12_world.sql diff --git a/sql/updates/world/2016_01_17_13_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_13_world.sql index 163aa3fb659..163aa3fb659 100644 --- a/sql/updates/world/2016_01_17_13_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_13_world.sql diff --git a/sql/updates/world/2016_01_17_14_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_14_world.sql index c8b9405abff..c8b9405abff 100644 --- a/sql/updates/world/2016_01_17_14_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_14_world.sql diff --git a/sql/updates/world/2016_01_17_15_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_15_world.sql index da949d7100d..da949d7100d 100644 --- a/sql/updates/world/2016_01_17_15_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_17_15_world.sql diff --git a/sql/updates/world/2016_01_18_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_00_world.sql index 85f41cfc0c5..85f41cfc0c5 100644 --- a/sql/updates/world/2016_01_18_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_00_world.sql diff --git a/sql/updates/world/2016_01_18_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_01_world.sql index 9768ecda6c0..9768ecda6c0 100644 --- a/sql/updates/world/2016_01_18_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_01_world.sql diff --git a/sql/updates/world/2016_01_18_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_02_world.sql index ec9a8748cc8..ec9a8748cc8 100644 --- a/sql/updates/world/2016_01_18_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_02_world.sql diff --git a/sql/updates/world/2016_01_18_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_03_world.sql index 4b8eb4ae0c9..4b8eb4ae0c9 100644 --- a/sql/updates/world/2016_01_18_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_03_world.sql diff --git a/sql/updates/world/2016_01_18_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_04_world.sql index 28ab2d96731..28ab2d96731 100644 --- a/sql/updates/world/2016_01_18_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_04_world.sql diff --git a/sql/updates/world/2016_01_18_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_05_world.sql index 0d28cd17642..0d28cd17642 100644 --- a/sql/updates/world/2016_01_18_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_05_world.sql diff --git a/sql/updates/world/2016_01_18_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_06_world.sql index f8b90c15f54..f8b90c15f54 100644 --- a/sql/updates/world/2016_01_18_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_18_06_world.sql diff --git a/sql/updates/world/2016_01_19_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_00_world.sql index f210b95c13a..f210b95c13a 100644 --- a/sql/updates/world/2016_01_19_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_00_world.sql diff --git a/sql/updates/world/2016_01_19_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_01_world.sql index a10bc7e278f..a10bc7e278f 100644 --- a/sql/updates/world/2016_01_19_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_01_world.sql diff --git a/sql/updates/world/2016_01_19_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_02_world.sql index 7c71156b248..7c71156b248 100644 --- a/sql/updates/world/2016_01_19_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_02_world.sql diff --git a/sql/updates/world/2016_01_19_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_03_world.sql index 0d559ace044..0d559ace044 100644 --- a/sql/updates/world/2016_01_19_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_03_world.sql diff --git a/sql/updates/world/2016_01_19_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_04_world.sql index f4fe95f5539..f4fe95f5539 100644 --- a/sql/updates/world/2016_01_19_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_04_world.sql diff --git a/sql/updates/world/2016_01_19_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_05_world.sql index 5afd9e2b8a5..5afd9e2b8a5 100644 --- a/sql/updates/world/2016_01_19_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_05_world.sql diff --git a/sql/updates/world/2016_01_19_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_06_world.sql index cece0c623bf..cece0c623bf 100644 --- a/sql/updates/world/2016_01_19_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_06_world.sql diff --git a/sql/updates/world/2016_01_19_07_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_07_world.sql index e1a72398a5f..e1a72398a5f 100644 --- a/sql/updates/world/2016_01_19_07_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_07_world.sql diff --git a/sql/updates/world/2016_01_19_08_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_08_world.sql index d078c059201..d078c059201 100644 --- a/sql/updates/world/2016_01_19_08_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_19_08_world.sql diff --git a/sql/updates/world/2016_01_20_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_20_00_world.sql index 26ce069edd8..26ce069edd8 100644 --- a/sql/updates/world/2016_01_20_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_20_00_world.sql diff --git a/sql/updates/world/2016_01_20_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_20_01_world.sql index b1c6e0de756..b1c6e0de756 100644 --- a/sql/updates/world/2016_01_20_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_20_01_world.sql diff --git a/sql/updates/world/2016_01_20_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_20_02_world.sql index d026c3cb478..d026c3cb478 100644 --- a/sql/updates/world/2016_01_20_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_20_02_world.sql diff --git a/sql/updates/world/2016_01_23_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_23_00_world.sql index 02eaa7c370d..02eaa7c370d 100644 --- a/sql/updates/world/2016_01_23_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_23_00_world.sql diff --git a/sql/updates/world/2016_01_24_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_24_00_world.sql index a28b3fa25b8..a28b3fa25b8 100644 --- a/sql/updates/world/2016_01_24_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_24_00_world.sql diff --git a/sql/updates/world/2016_01_26_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_26_00_world.sql index 71fe8dc21e3..71fe8dc21e3 100644 --- a/sql/updates/world/2016_01_26_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_26_00_world.sql diff --git a/sql/updates/world/2016_01_28_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_28_00_world_335.sql index 64b32cb2d89..64b32cb2d89 100644 --- a/sql/updates/world/2016_01_28_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_28_00_world_335.sql diff --git a/sql/updates/world/2016_01_28_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_28_01_world.sql index 3c4cadb310d..3c4cadb310d 100644 --- a/sql/updates/world/2016_01_28_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_28_01_world.sql diff --git a/sql/updates/world/2016_01_30_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_00_world_335.sql index 43025f581d7..43025f581d7 100644 --- a/sql/updates/world/2016_01_30_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_00_world_335.sql diff --git a/sql/updates/world/2016_01_30_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_01_world.sql index c9405c4ee61..c9405c4ee61 100644 --- a/sql/updates/world/2016_01_30_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_01_world.sql diff --git a/sql/updates/world/2016_01_30_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_02_world.sql index 25325dddd7a..25325dddd7a 100644 --- a/sql/updates/world/2016_01_30_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_02_world.sql diff --git a/sql/updates/world/2016_01_30_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_03_world.sql index 06c4b0826c0..06c4b0826c0 100644 --- a/sql/updates/world/2016_01_30_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_03_world.sql diff --git a/sql/updates/world/2016_01_30_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_04_world.sql index b90e7b95810..b90e7b95810 100644 --- a/sql/updates/world/2016_01_30_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_04_world.sql diff --git a/sql/updates/world/2016_01_30_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_05_world.sql index 1e341506dfc..1e341506dfc 100644 --- a/sql/updates/world/2016_01_30_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_30_05_world.sql diff --git a/sql/updates/world/2016_01_31_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_31_00_world.sql index f64d9182784..f64d9182784 100644 --- a/sql/updates/world/2016_01_31_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_01_31_00_world.sql diff --git a/sql/updates/world/2016_02_02_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_02_00_world.sql index ce561af3a61..ce561af3a61 100644 --- a/sql/updates/world/2016_02_02_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_02_00_world.sql diff --git a/sql/updates/world/2016_02_02_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_02_01_world.sql index f1b181a29e3..f1b181a29e3 100644 --- a/sql/updates/world/2016_02_02_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_02_01_world.sql diff --git a/sql/updates/world/2016_02_04_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_04_00_world.sql index 758286544af..758286544af 100644 --- a/sql/updates/world/2016_02_04_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_04_00_world.sql diff --git a/sql/updates/world/2016_02_05_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_05_00_world.sql index 46f2b488b9a..46f2b488b9a 100644 --- a/sql/updates/world/2016_02_05_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_05_00_world.sql diff --git a/sql/updates/world/2016_02_06_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_00_world.sql index d303a8b5b85..d303a8b5b85 100644 --- a/sql/updates/world/2016_02_06_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_00_world.sql diff --git a/sql/updates/world/2016_02_06_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_01_world.sql index 6812c4af52e..6812c4af52e 100644 --- a/sql/updates/world/2016_02_06_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_01_world.sql diff --git a/sql/updates/world/2016_02_06_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_02_world.sql index b9fd7cd9d63..b9fd7cd9d63 100644 --- a/sql/updates/world/2016_02_06_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_02_world.sql diff --git a/sql/updates/world/2016_02_06_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_03_world.sql index 85f8d3c6ae7..85f8d3c6ae7 100644 --- a/sql/updates/world/2016_02_06_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_03_world.sql diff --git a/sql/updates/world/2016_02_06_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_04_world.sql index 188b3b5f2a7..188b3b5f2a7 100644 --- a/sql/updates/world/2016_02_06_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_04_world.sql diff --git a/sql/updates/world/2016_02_06_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_05_world.sql index 823a8abaca6..823a8abaca6 100644 --- a/sql/updates/world/2016_02_06_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_05_world.sql diff --git a/sql/updates/world/2016_02_06_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_06_world.sql index 37df2ef0868..37df2ef0868 100644 --- a/sql/updates/world/2016_02_06_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_06_world.sql diff --git a/sql/updates/world/2016_02_06_07_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_07_world.sql index c5d6434321a..c5d6434321a 100644 --- a/sql/updates/world/2016_02_06_07_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_07_world.sql diff --git a/sql/updates/world/2016_02_06_08_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_08_world.sql index f0855ba348a..f0855ba348a 100644 --- a/sql/updates/world/2016_02_06_08_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_08_world.sql diff --git a/sql/updates/world/2016_02_06_09_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_09_world.sql index bf92b89e1c2..bf92b89e1c2 100644 --- a/sql/updates/world/2016_02_06_09_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_09_world.sql diff --git a/sql/updates/world/2016_02_06_10_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_10_world.sql index 291bd0bb333..291bd0bb333 100644 --- a/sql/updates/world/2016_02_06_10_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_10_world.sql diff --git a/sql/updates/world/2016_02_06_11_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_11_world.sql index cea352fec36..cea352fec36 100644 --- a/sql/updates/world/2016_02_06_11_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_11_world.sql diff --git a/sql/updates/world/2016_02_06_12_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_12_world.sql index df550156bc1..df550156bc1 100644 --- a/sql/updates/world/2016_02_06_12_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_12_world.sql diff --git a/sql/updates/world/2016_02_06_13_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_13_world_335.sql index 22bd5596d98..22bd5596d98 100644 --- a/sql/updates/world/2016_02_06_13_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_13_world_335.sql diff --git a/sql/updates/world/2016_02_06_14_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_14_world.sql index 7bf05b61c71..7bf05b61c71 100644 --- a/sql/updates/world/2016_02_06_14_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_06_14_world.sql diff --git a/sql/updates/world/2016_02_07_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_00_world.sql index 5a49f8fd310..5a49f8fd310 100644 --- a/sql/updates/world/2016_02_07_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_00_world.sql diff --git a/sql/updates/world/2016_02_07_01_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_01_world_335.sql index 5f1d5f4280e..5f1d5f4280e 100644 --- a/sql/updates/world/2016_02_07_01_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_01_world_335.sql diff --git a/sql/updates/world/2016_02_07_02_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_02_world_335.sql index ea4608f3a6b..ea4608f3a6b 100644 --- a/sql/updates/world/2016_02_07_02_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_02_world_335.sql diff --git a/sql/updates/world/2016_02_07_03_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_03_world_335.sql index 8322ff59c4c..8322ff59c4c 100644 --- a/sql/updates/world/2016_02_07_03_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_03_world_335.sql diff --git a/sql/updates/world/2016_02_07_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_04_world.sql index 3a3a7a393d7..3a3a7a393d7 100644 --- a/sql/updates/world/2016_02_07_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_04_world.sql diff --git a/sql/updates/world/2016_02_07_05_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_05_world_335.sql index 794b3d80411..794b3d80411 100644 --- a/sql/updates/world/2016_02_07_05_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_05_world_335.sql diff --git a/sql/updates/world/2016_02_07_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_06_world.sql index 31ecf826660..31ecf826660 100644 --- a/sql/updates/world/2016_02_07_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_06_world.sql diff --git a/sql/updates/world/2016_02_07_07_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_07_world_335.sql index af323a47bda..af323a47bda 100644 --- a/sql/updates/world/2016_02_07_07_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_07_world_335.sql diff --git a/sql/updates/world/2016_02_07_08_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_08_world_335.sql index 2b78a317f95..2b78a317f95 100644 --- a/sql/updates/world/2016_02_07_08_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_08_world_335.sql diff --git a/sql/updates/world/2016_02_07_09_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_09_world.sql index 8057534fbb8..8057534fbb8 100644 --- a/sql/updates/world/2016_02_07_09_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_09_world.sql diff --git a/sql/updates/world/2016_02_07_10_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_10_world.sql index c2e59c15d9c..c2e59c15d9c 100644 --- a/sql/updates/world/2016_02_07_10_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_10_world.sql diff --git a/sql/updates/world/2016_02_07_11_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_11_world.sql index c40b663c205..c40b663c205 100644 --- a/sql/updates/world/2016_02_07_11_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_11_world.sql diff --git a/sql/updates/world/2016_02_07_12_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_12_world.sql index c85265d857d..c85265d857d 100644 --- a/sql/updates/world/2016_02_07_12_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_12_world.sql diff --git a/sql/updates/world/2016_02_07_13_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_13_world.sql index 612fef2274d..612fef2274d 100644 --- a/sql/updates/world/2016_02_07_13_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_13_world.sql diff --git a/sql/updates/world/2016_02_07_14_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_14_world.sql index 6550e53f9c9..6550e53f9c9 100644 --- a/sql/updates/world/2016_02_07_14_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_14_world.sql diff --git a/sql/updates/world/2016_02_07_15_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_15_world.sql index ceec02f881b..ceec02f881b 100644 --- a/sql/updates/world/2016_02_07_15_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_07_15_world.sql diff --git a/sql/updates/world/2016_02_08_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_00_world_335.sql index 83091035e3c..83091035e3c 100644 --- a/sql/updates/world/2016_02_08_00_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_00_world_335.sql diff --git a/sql/updates/world/2016_02_08_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_01_world.sql index 9f8fa3dc4ed..9f8fa3dc4ed 100644 --- a/sql/updates/world/2016_02_08_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_01_world.sql diff --git a/sql/updates/world/2016_02_08_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_02_world.sql index 0f22abafe8e..0f22abafe8e 100644 --- a/sql/updates/world/2016_02_08_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_02_world.sql diff --git a/sql/updates/world/2016_02_08_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_03_world.sql index fe429cf42c8..fe429cf42c8 100644 --- a/sql/updates/world/2016_02_08_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_03_world.sql diff --git a/sql/updates/world/2016_02_08_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_04_world.sql index f8a9e2c776a..f8a9e2c776a 100644 --- a/sql/updates/world/2016_02_08_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_04_world.sql diff --git a/sql/updates/world/2016_02_08_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_05_world.sql index d2cc597a6ac..d2cc597a6ac 100644 --- a/sql/updates/world/2016_02_08_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_05_world.sql diff --git a/sql/updates/world/2016_02_08_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_06_world.sql index c9e93889790..c9e93889790 100644 --- a/sql/updates/world/2016_02_08_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_06_world.sql diff --git a/sql/updates/world/2016_02_08_07_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_07_world.sql index 1d90630d829..1d90630d829 100644 --- a/sql/updates/world/2016_02_08_07_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_07_world.sql diff --git a/sql/updates/world/2016_02_08_08_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_08_world.sql index ae4f454bc91..ae4f454bc91 100644 --- a/sql/updates/world/2016_02_08_08_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_08_08_world.sql diff --git a/sql/updates/world/2016_02_09_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_00_world.sql index c93a1d8fed1..c93a1d8fed1 100644 --- a/sql/updates/world/2016_02_09_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_00_world.sql diff --git a/sql/updates/world/2016_02_09_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_01_world.sql index 7878ea7faa2..7878ea7faa2 100644 --- a/sql/updates/world/2016_02_09_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_01_world.sql diff --git a/sql/updates/world/2016_02_09_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_02_world.sql index 891c8c2ff4b..891c8c2ff4b 100644 --- a/sql/updates/world/2016_02_09_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_02_world.sql diff --git a/sql/updates/world/2016_02_09_02_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_02_world_335.sql index a8612c5d88d..a8612c5d88d 100644 --- a/sql/updates/world/2016_02_09_02_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_02_world_335.sql diff --git a/sql/updates/world/2016_02_09_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_03_world.sql index bd012f0d172..bd012f0d172 100644 --- a/sql/updates/world/2016_02_09_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_03_world.sql diff --git a/sql/updates/world/2016_02_09_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_04_world.sql index 015ab519557..015ab519557 100644 --- a/sql/updates/world/2016_02_09_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_04_world.sql diff --git a/sql/updates/world/2016_02_09_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_05_world.sql index 3612c270d02..3612c270d02 100644 --- a/sql/updates/world/2016_02_09_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_05_world.sql diff --git a/sql/updates/world/2016_02_09_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_06_world.sql index 03fe998cca5..03fe998cca5 100644 --- a/sql/updates/world/2016_02_09_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_06_world.sql diff --git a/sql/updates/world/2016_02_09_07_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_07_world.sql index 84d65e2eda5..84d65e2eda5 100644 --- a/sql/updates/world/2016_02_09_07_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_07_world.sql diff --git a/sql/updates/world/2016_02_09_08_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_08_world.sql index 307a9f9a0b3..307a9f9a0b3 100644 --- a/sql/updates/world/2016_02_09_08_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_09_08_world.sql diff --git a/sql/updates/world/2016_02_10_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_00_world.sql index 872861b08dc..872861b08dc 100644 --- a/sql/updates/world/2016_02_10_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_00_world.sql diff --git a/sql/updates/world/2016_02_10_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_01_world.sql index 9ffe2e81c1c..9ffe2e81c1c 100644 --- a/sql/updates/world/2016_02_10_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_01_world.sql diff --git a/sql/updates/world/2016_02_10_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_02_world.sql index 92ee165dd83..92ee165dd83 100644 --- a/sql/updates/world/2016_02_10_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_02_world.sql diff --git a/sql/updates/world/2016_02_10_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_03_world.sql index f52872c3431..f52872c3431 100644 --- a/sql/updates/world/2016_02_10_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_03_world.sql diff --git a/sql/updates/world/2016_02_10_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_04_world.sql index 1349b83f442..1349b83f442 100644 --- a/sql/updates/world/2016_02_10_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_04_world.sql diff --git a/sql/updates/world/2016_02_10_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_05_world.sql index c19dd8feb06..c19dd8feb06 100644 --- a/sql/updates/world/2016_02_10_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_05_world.sql diff --git a/sql/updates/world/2016_02_10_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_06_world.sql index 9e24ab31ce1..9e24ab31ce1 100644 --- a/sql/updates/world/2016_02_10_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_06_world.sql diff --git a/sql/updates/world/2016_02_10_07_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_07_world.sql index 5feb4f44163..5feb4f44163 100644 --- a/sql/updates/world/2016_02_10_07_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_10_07_world.sql diff --git a/sql/updates/world/2016_02_11_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_00_world.sql index b130133a2ca..b130133a2ca 100644 --- a/sql/updates/world/2016_02_11_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_00_world.sql diff --git a/sql/updates/world/2016_02_11_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_01_world.sql index ec1c98659e1..ec1c98659e1 100644 --- a/sql/updates/world/2016_02_11_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_01_world.sql diff --git a/sql/updates/world/2016_02_11_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_02_world.sql index 9228e2d99d7..9228e2d99d7 100644 --- a/sql/updates/world/2016_02_11_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_02_world.sql diff --git a/sql/updates/world/2016_02_11_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_03_world.sql index 4dfefb12281..4dfefb12281 100644 --- a/sql/updates/world/2016_02_11_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_03_world.sql diff --git a/sql/updates/world/2016_02_11_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_04_world.sql index 41f648b5f6e..41f648b5f6e 100644 --- a/sql/updates/world/2016_02_11_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_04_world.sql diff --git a/sql/updates/world/2016_02_11_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_05_world.sql index 76b59765d08..76b59765d08 100644 --- a/sql/updates/world/2016_02_11_05_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_05_world.sql diff --git a/sql/updates/world/2016_02_11_06_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_06_world.sql index bbf9880dca9..bbf9880dca9 100644 --- a/sql/updates/world/2016_02_11_06_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_06_world.sql diff --git a/sql/updates/world/2016_02_11_07_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_07_world.sql index e34106cb44c..e34106cb44c 100644 --- a/sql/updates/world/2016_02_11_07_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_11_07_world.sql diff --git a/sql/updates/world/2016_02_12_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_12_00_world.sql index af599148e04..af599148e04 100644 --- a/sql/updates/world/2016_02_12_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_12_00_world.sql diff --git a/sql/updates/world/2016_02_13_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_00_world.sql index 2341e33a8b5..2341e33a8b5 100644 --- a/sql/updates/world/2016_02_13_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_00_world.sql diff --git a/sql/updates/world/2016_02_13_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_01_world.sql index 29f94a9f41d..29f94a9f41d 100644 --- a/sql/updates/world/2016_02_13_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_01_world.sql diff --git a/sql/updates/world/2016_02_13_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_02_world.sql index 5a4633fee41..5a4633fee41 100644 --- a/sql/updates/world/2016_02_13_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_02_world.sql diff --git a/sql/updates/world/2016_02_13_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_03_world.sql index 136a068bd9e..136a068bd9e 100644 --- a/sql/updates/world/2016_02_13_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_03_world.sql diff --git a/sql/updates/world/2016_02_13_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_04_world.sql index 83d95745052..83d95745052 100644 --- a/sql/updates/world/2016_02_13_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_13_04_world.sql diff --git a/sql/updates/world/2016_02_14_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_00_world.sql index 961ecd74d4d..961ecd74d4d 100644 --- a/sql/updates/world/2016_02_14_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_00_world.sql diff --git a/sql/updates/world/2016_02_14_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_01_world.sql index 2ce06020621..2ce06020621 100644 --- a/sql/updates/world/2016_02_14_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_01_world.sql diff --git a/sql/updates/world/2016_02_14_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_02_world.sql index 1459b702cf0..1459b702cf0 100644 --- a/sql/updates/world/2016_02_14_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_02_world.sql diff --git a/sql/updates/world/2016_02_14_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_03_world.sql index 9a0237725c0..9a0237725c0 100644 --- a/sql/updates/world/2016_02_14_03_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_03_world.sql diff --git a/sql/updates/world/2016_02_14_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_04_world.sql index 58e0aaee311..58e0aaee311 100644 --- a/sql/updates/world/2016_02_14_04_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_14_04_world.sql diff --git a/sql/updates/world/2016_02_15_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_15_00_world.sql index 43c2ae69382..43c2ae69382 100644 --- a/sql/updates/world/2016_02_15_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_15_00_world.sql diff --git a/sql/updates/world/2016_02_17_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_17_00_world.sql index 8f22aaa3e4e..8f22aaa3e4e 100644 --- a/sql/updates/world/2016_02_17_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_17_00_world.sql diff --git a/sql/updates/world/2016_02_17_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_17_01_world.sql index 20f3605b197..20f3605b197 100644 --- a/sql/updates/world/2016_02_17_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_17_01_world.sql diff --git a/sql/updates/world/2016_02_17_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_17_02_world.sql index 6590396b7d9..6590396b7d9 100644 --- a/sql/updates/world/2016_02_17_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_17_02_world.sql diff --git a/sql/updates/world/2016_02_18_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_18_00_world.sql index c20196ddc80..c20196ddc80 100644 --- a/sql/updates/world/2016_02_18_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_18_00_world.sql diff --git a/sql/updates/world/2016_02_18_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_18_01_world.sql index c3ffdbb6344..c3ffdbb6344 100644 --- a/sql/updates/world/2016_02_18_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_18_01_world.sql diff --git a/sql/updates/world/2016_02_18_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_18_02_world.sql index 414c6fd9c3a..414c6fd9c3a 100644 --- a/sql/updates/world/2016_02_18_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_18_02_world.sql diff --git a/sql/updates/world/2016_02_19_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_19_00_world.sql index bee93f7bdd4..bee93f7bdd4 100644 --- a/sql/updates/world/2016_02_19_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_19_00_world.sql diff --git a/sql/updates/world/2016_02_19_01_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_19_01_world_335.sql index f7fee657170..f7fee657170 100644 --- a/sql/updates/world/2016_02_19_01_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_19_01_world_335.sql diff --git a/sql/updates/world/2016_02_22_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_22_00_world.sql index d92ea91681a..d92ea91681a 100644 --- a/sql/updates/world/2016_02_22_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_22_00_world.sql diff --git a/sql/updates/world/2016_02_22_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_22_01_world.sql index b1345bb1aab..b1345bb1aab 100644 --- a/sql/updates/world/2016_02_22_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_22_01_world.sql diff --git a/sql/updates/world/2016_02_22_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_22_02_world.sql index dd62e6dce29..dd62e6dce29 100644 --- a/sql/updates/world/2016_02_22_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_22_02_world.sql diff --git a/sql/updates/world/2016_02_23_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_23_00_world.sql index 871ce608f1c..871ce608f1c 100644 --- a/sql/updates/world/2016_02_23_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_23_00_world.sql diff --git a/sql/updates/world/2016_02_23_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_23_01_world.sql index 0773487dbc7..0773487dbc7 100644 --- a/sql/updates/world/2016_02_23_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_23_01_world.sql diff --git a/sql/updates/world/2016_02_23_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_23_02_world.sql index 9e2c550dd65..9e2c550dd65 100644 --- a/sql/updates/world/2016_02_23_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_23_02_world.sql diff --git a/sql/updates/world/2016_02_24_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_24_00_world.sql index 06c7c29bd72..06c7c29bd72 100644 --- a/sql/updates/world/2016_02_24_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_24_00_world.sql diff --git a/sql/updates/world/2016_02_25_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_25_00_world.sql index 346c77bee43..346c77bee43 100644 --- a/sql/updates/world/2016_02_25_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_25_00_world.sql diff --git a/sql/updates/world/2016_02_25_01_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_25_01_world_335.sql index 473cbd506ce..473cbd506ce 100644 --- a/sql/updates/world/2016_02_25_01_world_335.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_25_01_world_335.sql diff --git a/sql/updates/world/2016_02_25_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_25_02_world.sql index c5355b13c29..c5355b13c29 100644 --- a/sql/updates/world/2016_02_25_02_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_25_02_world.sql diff --git a/sql/updates/world/2016_02_26_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_26_00_world.sql index d08d5055089..d08d5055089 100644 --- a/sql/updates/world/2016_02_26_00_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_26_00_world.sql diff --git a/sql/updates/world/2016_02_26_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_26_01_world.sql index b30b3cba35f..b30b3cba35f 100644 --- a/sql/updates/world/2016_02_26_01_world.sql +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_26_01_world.sql diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_02_27_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_27_00_world.sql new file mode 100644 index 00000000000..b9288b2ddfb --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_27_00_world.sql @@ -0,0 +1,4 @@ +-- fix "Val'anyr, Hammer of Ancient Kings" to properly provide shields from Earth Shield charges and Glyph of Holy Light heals (as well as others) +DELETE FROM `spell_proc_event` WHERE `entry`=64411; +INSERT INTO `spell_proc_event` (`entry`,`procFlags`) VALUES +(64411,0x00044400); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_02_28_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_28_00_world.sql new file mode 100644 index 00000000000..5a5694e0320 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_28_00_world.sql @@ -0,0 +1,2 @@ +-- remove script from core requires removing ScriptName from creature_template +UPDATE `creature_template` SET `ScriptName`= '' WHERE `entry`IN (1749,2708); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_02_29_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_29_00_world.sql new file mode 100644 index 00000000000..280f2f901ef --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_29_00_world.sql @@ -0,0 +1,27 @@ +-- creature text 23576 Nalorakk + sound ID + broadcast_text ID +DELETE FROM `creature_text` WHERE `entry` = 23576 AND `type` = 14; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`BroadcastTextId`,`TextRange`,`comment`) VALUES +(23576, 0,0, "Get da move on, guards! It be killin' time!", 14,0,100,0,0, 12066, 22144, 1, 'Nalorakk - YELL_NALORAKK_WAVE1'), +(23576, 1,0, "Guards, go already! Who you more afraid of, dem... or me?", 14,0,100,0,0, 12067, 22146, 1, 'Nalorakk - YELL_NALORAKK_WAVE2'), +(23576, 2,0, "Ride now! Ride out dere and bring me back some heads!", 14,0,100,0,0, 12068, 22151, 1, 'Nalorakk - YELL_NALORAKK_WAVE3'), +(23576, 3,0, "I be losin' me patience! Go on: make dem wish dey was never born!", 14,0,100,0,0, 12069, 22155, 1, 'Nalorakk - YELL_NALORAKK_WAVE4'), +(23576, 4,0, "You be dead soon enough!", 14,0,100,0,0, 12070, 23166, 1, 'Nalorakk - YELL_AGGRO'), +(23576, 5,0, "I bring da pain!", 14,0,100,0,0, 12071, 23167, 1, 'Nalorakk - YELL_SURGE'), +(23576, 6,0, "You call on da beast, you gonna get more dan you bargain for!", 14,0,100,0,0, 12072, 23168, 1, 'Nalorakk - YELL_SHIFTEDTOBEAR '), +(23576, 7,0, "Make way for da Nalorakk!", 14,0,100,0,0, 12073, 23169, 1, 'Nalorakk - YELL_SHIFTEDTOTROLL'), +(23576, 8,0, "You had your chance; now it be too late!", 14,0,100,0,0, 12074, 23170, 1, 'Nalorakk - YELL_BERSERK'), +(23576, 9,0, "Now whatchoo got to say?", 14,0,100,0,0, 12075, 23171, 1, 'Nalorakk - YELL_KILL_ONE'), +(23576, 10,0, "Da Amani gonna rule again!", 14,0,100,0,0, 12076, 23172, 1, 'Nalorakk - YELL_KILL_TWO'), +(23576, 11,0, "I... be waitin' on da udda side....", 14,0,100,0,0, 12077, 23173, 1, 'Nalorakk - YELL_DEATH'), +(23576, 12,0, "What could be better than servin' da bear spirit for eternity? Come closer now. Bring your souls to me!", 14,0,100,0,0, 12078, 23305, 1, 'Nalorakk - YELL_NALORAKK_EVENT1'), +(23576, 13,0, "I smell you, strangers. Don't be delayin' your fate. Come to me now. I make your sacrifice quick.", 14,0,100,0,0, 12079, 23306, 1, 'Nalorakk - YELL_NALORAKK_EVENT1'); + +-- creature text 24239 Hex Lord Malacrass + sound ID + broadcast_text ID +DELETE FROM `creature_text` WHERE `entry` = 24239 AND `type` = 14; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`BroadcastTextId`,`TextRange`,`comment`) VALUES +(24239, 0,0, "Da shadow gonna fall on you....", 14,0,100,0,0, 12041, 23591, 1, 'Hex Lord Malacrass - YELL_AGGRO'), +(24239, 1,0, "Dis a nightmare ya don' wake up from!", 14,0,100,0,0, 12043, 23593, 1, 'Hex Lord Malacrass - YELL_KILL_ONE'), +(24239, 2,0, "Azzaga choogo zinn!", 14,0,100,0,0, 12044, 23594, 1, 'Hex Lord Malacrass - YELL_KILL_TWO'), +(24239, 3,0, "Darkness comin' for you....", 14,0,100,0,0, 12046, 23596, 1, 'Hex Lord Malacrass - YELL_DRAIN_POWER'), +(24239, 4,0, "Your soul gonna bleed!", 14,0,100,0,0, 12047, 23597, 1, 'Hex Lord Malacrass - YELL_SPIRIT_BOLTS'), +(24239, 5,0, "Dis not... da end for me!", 14,0,100,0,0, 12051, 23601, 1, 'Hex Lord Malacrass - YELL_DEATH'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_02_29_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_29_01_world.sql new file mode 100644 index 00000000000..40343440d9a --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_02_29_01_world.sql @@ -0,0 +1 @@ +DELETE FROM `game_event_gameobject` WHERE `guid` IN (24399, 24400, 24401, 24402, 24405); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_01_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_01_00_world_335.sql new file mode 100644 index 00000000000..36c48379190 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_01_00_world_335.sql @@ -0,0 +1,75 @@ +SET @Pool := 370; + +UPDATE `quest_template_addon` SET `PrevQuestID`=0 WHERE `ID` IN(12604,12541,12502,12509,12519,12502,12509,12519,12588,12591,12594,12557,12597,12598,12599,12564,12568,12585); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN(19,20) AND`SourceEntry` IN(12541,12604,12502,12509,12519,12502,12509,12519,12588,12591,12594,12557,12597,12598,12599,12564,12568,12585); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(19, 0, 12604, 0, 0, 1, 0, 51573, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Congratulations!' if player has aura 51573 'On Patrol'."), +(20, 0, 12604, 0, 0, 1, 0, 51573, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Congratulations!' if player has aura 51573 'On Patrol'."), +(19, 0, 12604, 0, 0, 1, 0, 53707, 0, 0, 1, 0, 0, '', "Show quest mark 12604 'Congratulations!' if player has no aura 51573 'On Patrol Heartbeat Script'."), +(20, 0, 12604, 0, 0, 1, 0, 53707, 0, 0, 1, 0, 0, '', "Show quest mark 12604 'Congratulations!' if player has no aura 51573 'On Patrol Heartbeat Script'."), +(19, 0, 12541, 0, 0, 9, 0, 12501, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Troll Patrol: The Alchemists Apprentice' if player has quest Troll patrol'."), +(20, 0, 12541, 0, 0, 9, 0, 12501, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Troll Patrol: The Alchemists Apprentice' if player has quest Troll patrol'."), +(19, 0, 12541, 0, 1, 9, 0, 12563, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Troll Patrol: The Alchemists Apprentice' if player has quest Troll patrol'."), +(20, 0, 12541, 0, 1, 9, 0, 12563, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Troll Patrol: The Alchemists Apprentice' if player has quest Troll patrol'."), +(19, 0, 12541, 0, 2, 9, 0, 12587, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Troll Patrol: The Alchemists Apprentice' if player has quest Troll patrol'."), +(20, 0, 12541, 0, 2, 9, 0, 12587, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Troll Patrol: The Alchemists Apprentice' if player has quest Troll patrol'."), +(19, 0, 12509, 0, 0, 9, 0, 12501, 0, 0, 0, 0, 0, '', "Show quest mark 12509 'Troll Patrol: Intestinal Fortitude' if player has quest Troll patrol'."), +(20, 0, 12509, 0, 0, 9, 0, 12501, 0, 0, 0, 0, 0, '', "Show quest mark 12509 'Troll Patrol: Intestinal Fortitude' if player has quest Troll patrol'."), +(19, 0, 12519, 0, 0, 9, 0, 12501, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Troll Patrol: Whatdya Want, a Medal?' if player has quest Troll patrol'."), +(20, 0, 12519, 0, 0, 9, 0, 12501, 0, 0, 0, 0, 0, '', "Show quest mark 12604 'Troll Patrol: Whatdya Want, a Medal?' if player has quest Troll patrol'."), +(19, 0, 12502, 0, 0, 9, 0, 12501, 0, 0, 0, 0, 0, '', "Show quest mark 12502 'Troll Patrol: High Standards' if player has quest Troll patrol'."), +(20, 0, 12502, 0, 0, 9, 0, 12501, 0, 0, 0, 0, 0, '', "Show quest mark 12502 'Troll Patrol: High Standards' if player has quest Troll patrol'."), +(19, 0, 12564, 0, 0, 9, 0, 12563, 0, 0, 0, 0, 0, '', "Show quest mark 12564 'Troll Patrol: Something for the Pain' if player has quest Troll patrol'."), +(20, 0, 12564, 0, 0, 9, 0, 12563, 0, 0, 0, 0, 0, '', "Show quest mark 12564 'Troll Patrol: Something for the Pain' if player has quest Troll patrol'."), +(19, 0, 12568, 0, 0, 9, 0, 12563, 0, 0, 0, 0, 0, '', "Show quest mark 12568 'Troll Patrol: Done to Death' if player has quest Troll patrol'."), +(20, 0, 12568, 0, 0, 9, 0, 12563, 0, 0, 0, 0, 0, '', "Show quest mark 12558 'Troll Patrol: Done to Death' if player has quest Troll patrol'."), +(19, 0, 12585, 0, 0, 9, 0, 12563, 0, 0, 0, 0, 0, '', "Show quest mark 12585 'Troll Patrol: Creature Comforts' if player has quest Troll patrol'."), +(20, 0, 12585, 0, 0, 9, 0, 12563, 0, 0, 0, 0, 0, '', "Show quest mark 12585 'Troll Patrol: Creature Comforts' if player has quest Troll patrol'."), +(19, 0, 12588, 0, 0, 9, 0, 12587, 0, 0, 0, 0, 0, '', "Show quest mark 12588 'Troll Patrol: Can You Dig It?' if player has quest Troll patrol'."), +(20, 0, 12588, 0, 0, 9, 0, 12587, 0, 0, 0, 0, 0, '', "Show quest mark 12588 'Troll Patrol: Can You Dig It?' if player has quest Troll patrol'."), +(19, 0, 12591, 0, 0, 9, 0, 12587, 0, 0, 0, 0, 0, '', "Show quest mark 12591 'Troll Patrol: Throwing Down' if player has quest Troll patrol'."), +(20, 0, 12591, 0, 0, 9, 0, 12587, 0, 0, 0, 0, 0, '', "Show quest mark 12591 'Troll Patrol: Throwing Down' if player has quest Troll patrol'."), +(19, 0, 12594, 0, 0, 9, 0, 12587, 0, 0, 0, 0, 0, '', "Show quest mark 12594 'Troll Patrol: Couldn't Care Less' if player has quest Troll patrol'."), +(20, 0, 12594, 0, 0, 9, 0, 12587, 0, 0, 0, 0, 0, '', "Show quest mark 12594 'Troll Patrol: Couldn't Care Less' if player has quest Troll patrol'."), +(19, 0, 12557, 0, 0, 9, 0, 12596, 0, 0, 0, 0, 0, '', "Show quest mark 12557 'Lab Work' if player has quest Pa'Troll'."), +(20, 0, 12557, 0, 0, 9, 0, 12596, 0, 0, 0, 0, 0, '', "Show quest mark 12557 'Lab Work' if player has quest Pa'Troll'."), +(19, 0, 12597, 0, 0, 9, 0, 12596, 0, 0, 0, 0, 0, '', "Show quest mark 12597 'Something for the Pain' if player has quest Pa'Troll'."), +(20, 0, 12597, 0, 0, 9, 0, 12596, 0, 0, 0, 0, 0, '', "Show quest mark 12597 'Something for the Pain' if player has quest Pa'Troll'."), +(19, 0, 12598, 0, 0, 9, 0, 12596, 0, 0, 0, 0, 0, '', "Show quest mark 12598 'Throwing Down' if player has quest Pa'Troll'."), +(20, 0, 12598, 0, 0, 9, 0, 12596, 0, 0, 0, 0, 0, '', "Show quest mark 12598 'Throwing Down' if player has quest Pa'Troll'."), +(19, 0, 12599, 0, 0, 9, 0, 12596, 0, 0, 0, 0, 0, '', "Show quest mark 12599 'Creature Comforts' if player has quest Pa'Troll'."), +(20, 0, 12599, 0, 0, 9, 0, 12596, 0, 0, 0, 0, 0, '', "Show quest mark 12599 'Creature Comforts' if player has quest Pa'Troll'."); + +UPDATE `creature_template` SET `AIName`='SmartAI', `ScriptName`='' WHERE `entry` =28039; +DELETE FROM `smart_scripts` WHERE `entryorguid` =28039 AND `source_type`=0; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28039, 0, 0, 1, 19, 0, 100, 0, 12596, 0, 0, 0, 85, 51506, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Pa''Troll - Invoker Cast Clear Patrol Quests'), +(28039, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 85, 51509, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Pa''Troll - Invoker Cast Clear Patrol Quests II'), +(28039, 0, 2, 5, 19, 0, 100, 0, 12587, 0, 0, 0, 85, 51573, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Troll Patrol - Invoker Cast On Patrol'), +(28039, 0, 3, 5, 19, 0, 100, 0, 12501, 0, 0, 0, 85, 51573, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Troll Patrol - Invoker Cast On Patrol'), +(28039, 0, 4, 5, 19, 0, 100, 0, 12563, 0, 0, 0, 85, 51573, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Troll Patrol - Invoker Cast On Patrol'), +(28039, 0, 5, 6, 61, 0, 100, 0, 0, 0, 0, 0, 85, 53712, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Troll Patrol - Invoker Cast Clear DAILY Patrol SUBQuests 00'), +(28039, 0, 6, 7, 61, 0, 100, 0, 0, 0, 0, 0, 85, 53713, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Troll Patrol - Invoker Cast Clear DAILY Patrol SUBQuests 01'), +(28039, 0, 7, 8, 61, 0, 100, 0, 0, 0, 0, 0, 85, 53715, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Troll Patrol - Invoker Cast Clear DAILY Patrol SUBQuests 02'), +(28039, 0, 8, 9, 61, 0, 100, 0, 0, 0, 0, 0, 85, 53716, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Troll Patrol - Invoker Cast Clear DAILY Patrol SUBQuests 03'), +(28039, 0, 9, 0, 61, 0, 100, 0, 0, 0, 0, 0, 85, 53707, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Accept Troll Patrol - Invoker Cast On Patrol Heartbeat Script'), +(28039, 0, 10, 0, 20, 0, 100, 0, 12587, 0, 0, 0, 28, 51573, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Reward Congratulations - Remove Aura On Patrol'), +(28039, 0, 11, 0, 20, 0, 100, 0, 12563, 0, 0, 0, 28, 53707, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Reward Troll Patrol - Remove Aura On Patrol Heartbeat Script'), +(28039, 0, 12, 0, 20, 0, 100, 0, 12501, 0, 0, 0, 28, 53707, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Reward Troll Patrol - Remove Aura On Patrol Heartbeat Script'), +(28039, 0, 13, 0, 20, 0, 100, 0, 12604, 0, 0, 0, 28, 53707, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Commander Kunz - On Quest Reward Troll Patrol - Remove Aura On Patrol Heartbeat Script'); + +UPDATE `quest_template_addon` SET `ExclusiveGroup`=12587 WHERE `ID` IN(12501,12563,12587); + +DELETE FROM `pool_quest` WHERE `pool_entry` IN (@Pool); + +INSERT INTO `pool_quest` (`entry`, `pool_entry`, `description`) VALUES +(12587, @Pool, 'Troll Patrol'), +(12501, @Pool, 'Troll Patrol'), +(12563, @Pool, 'Troll Patrol'); + +DELETE FROM `pool_template` WHERE `entry` IN (@Pool); + +INSERT INTO `pool_template` (`entry`, `max_limit`, `description`) VALUES +(@Pool, 1, 'Troll Patrol Daily Quests'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_02_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_02_00_world_335.sql new file mode 100644 index 00000000000..e7a9f60e790 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_02_00_world_335.sql @@ -0,0 +1,3 @@ +-- +-- Only for 3.3.5! +UPDATE `conditions` SET `ConditionTypeOrReference`=42 WHERE `ConditionTypeOrReference`=41; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_03_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_03_00_world.sql new file mode 100644 index 00000000000..473bac4708a --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_03_00_world.sql @@ -0,0 +1,93 @@ +SET @CGUID := 91749; +SET @OGUID := 62179; + +UPDATE `creature_template` SET `npcflag`=16777216 WHERE `entry`=28162; + +DELETE FROM `npc_spellclick_spells` WHERE `npc_entry`=28162; +INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES +(28162, 51026, 1, 0); +DELETE FROM `smart_scripts` WHERE `entryorguid`IN(28162,28330,28156) AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`IN(2833000,2833001,2833002) AND `source_type`=9; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28162, 0, 0, 1, 8, 0, 100, 1, 51026, 0, 0, 0, 11, 61286, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Drakkari Corpse - On Spellhit Create Drakkari Medallion Cover - Cast World Generic Dismount/Cancel Shapeshift'), +(28162, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 11, 50737, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Drakkari Corpse - On Spellhit Create Drakkari Medallion Cover - Cast Create Drakkari Medallion'), +(28162, 0, 2, 3, 61, 0, 100, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Drakkari Corpse - On Spellhit Create Drakkari Medallion Cover - Cast Create Drakkari Medallion'), +(28162, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 41, 3000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Drakkari Corpse - On Spellhit Create Drakkari Medallion Cover - Despawn'), +(28162, 0, 4, 0, 25, 0, 100, 0, 0, 0, 0, 0, 81, 16777216, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Drakkari Corpse - On Respawn - Set NPC Flags'), +(28330, 0, 0, 1, 8, 0, 100, 0, 51333, 0, 120000, 120000, 33, 28330, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Ancient Dirt KC Bunny - On Spell Hit - Give Quest Credit'), +(28330, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 70, 120, 0, 0, 0, 0, 0, 20, 190550, 0, 0, 0, 0, 0, 0, 'Ancient Dirt KC Bunny - On Spell Hit - Despawn GO'), +(28330, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 87, 2833000, 2833001, 2833002, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ancient Dirt KC Bunny - On Spell Hit - Run Random Script'), +(28156, 0, 0, 1, 8, 0, 100, 1, 51276, 0, 0, 0, 11, 59216, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Defeated Argent Footman - On Spellhit \'Incinerate Corpse\' - Cast \'Burning Corpse\''), +(28156, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 11, 51279, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Defeated Argent Footman - On Spellhit - Cast \'Defeated Argent Footman KC\''), +(28156, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 41, 10000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Defeated Argent Footman - On Spellhit - Despawn'), +(2833000, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 51345, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ancient Dirt KC Bunny - Script 1 - Cast Summon Ancient Drakkari Chest'), +(2833001, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 51357, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ancient Dirt KC Bunny - Script 2 - Cast Summon Spider'), +(2833002, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 51370, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ancient Dirt KC Bunny - Script 3 - Cast Summon Drakkari Spectre'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=18 AND `SourceGroup`=28162; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(18, 28162, 51026, 0, 0, 9, 0, 12519, 0, 0, 0, 0, 0, '', 'Required quest active for spellclick'); + +DELETE FROM `gameobject_template` WHERE `entry`=190552; +INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `faction`, `flags`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES +(190552, 3, 2450, 'Ancient Drakkari Chest', '', '', '', 94, 0, 1, 1691, 27240, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 14007); + +DELETE FROM `gameobject_loot_template` WHERE `Entry`=27240; +INSERT INTO `gameobject_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(27240, 46369, 0, 52, 0, 1, 1, 1, 1, NULL), +(27240, 46368, 0, 47, 0, 1, 1, 1, 1, NULL), +(27240, 43851, 0, 15, 0, 1, 2, 1, 1, NULL), +(27240, 43852, 0, 14, 0, 1, 2, 1, 1, NULL), +(27240, 33470, 0, 14, 0, 1, 3, 1, 4, NULL); + +DELETE FROM `creature` WHERE `id`=28330; +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES +(@CGUID+0, 28330, 571, 1, 1, 4994.237, -2934.52, 289.698, 4.502949, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+1, 28330, 571, 1, 1, 4928.283, -2954.844, 289.4258, 0.3665192, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+2, 28330, 571, 1, 1, 4971.499, -2967.053, 290.4032, 6.021386, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+3, 28330, 571, 1, 1, 4934.217, -2988.888, 290.1517, 3.316126, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+4, 28330, 571, 1, 1, 4901.642, -3020.357, 290.4903, 3.577925, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+5, 28330, 571, 1, 1, 4936.192, -2911.305, 289.9935, 3.804818, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+6, 28330, 571, 1, 1, 4904.635, -2938.013, 290.041, 2.792527, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+7, 28330, 571, 1, 1, 4959.712, -2882.519, 290.1794, 2.495821, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+8, 28330, 571, 1, 1, 4903.988, -2988.983, 289.8607, 6.073746, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+9, 28330, 571, 1, 1, 4884.578, -2949.397, 291.4635, 6.248279, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+10, 28330, 571, 1, 1, 4867.053, -3032.317, 290.2768, 0.01745329, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+11, 28330, 571, 1, 1, 4875.137, -2981.573, 289.6624, 3.769911, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+12, 28330, 571, 1, 1, 4948.37, -2845.009, 289.9186, 0.2094395, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+13, 28330, 571, 1, 1, 4900.262, -2870.288, 290.5846, 2.879793, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+14, 28330, 571, 1, 1, 4889.488, -2826.498, 291.2368, 6.213372, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+15, 28330, 571, 1, 1, 4865.896, -2879.65, 291.2252, 3.124139, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+16, 28330, 571, 1, 1, 4847.792, -2933.366, 290.7986, 1.954769, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+17, 28330, 571, 1, 1, 4838.494, -2962.302, 290.7893, 5.096361, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+18, 28330, 571, 1, 1, 4834.676, -3024.518, 290.9732, 5.77704, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+19, 28330, 571, 1, 1, 4834.516, -3055.432, 292.7168, 4.223697, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+20, 28330, 571, 1, 1, 4833.344, -3086.806, 290.7325, 5.183628, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+21, 28330, 571, 1, 1, 4811.373, -3122.263, 290.908, 3.787364, 120, 0, 0), -- 28330 (Area: 66) +(@CGUID+22, 28330, 571, 1, 1, 4774.604, -3146.782, 293.9535, 4.886922, 120, 0, 0); -- 28330 (Area: 66) + +DELETE FROM `gameobject` WHERE `id`=190550; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +(@OGUID+0, 190550, 571, 1, 1, 4947.931, -2845.012, 289.6788, 3.141593, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 4278) +(@OGUID+1, 190550, 571, 1, 1, 4994.241, -2934.715, 289.4844, 3.036838, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+2, 190550, 571, 1, 1, 4959.522, -2882.375, 289.9583, -0.2268925, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+3, 190550, 571, 1, 1, 4935.69, -2910.847, 289.8739, 0.4712385, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+4, 190550, 571, 1, 1, 4904.143, -2988.849, 289.7597, -2.879789, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+5, 190550, 571, 1, 1, 4901.818, -3020.541, 290.4142, 2.862335, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+6, 190550, 571, 1, 1, 4847.445, -2933.018, 290.703, 2.91469, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+7, 190550, 571, 1, 1, 4889.123, -2826.122, 291.1009, -2.670348, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+8, 190550, 571, 1, 1, 4959.522, -2882.375, 289.9583, -0.2268925, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+9, 190550, 571, 1, 1, 4904.084, -2937.728, 289.9795, -0.9250239, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+10, 190550, 571, 1, 1, 4865.544, -2879.292, 291.0988, 0.8377574, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+11, 190550, 571, 1, 1, 4935.69, -2910.847, 289.8739, 0.4712385, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+12, 190550, 571, 1, 1, 4934.223, -2988.802, 290.0577, 1.727875, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+13, 190550, 571, 1, 1, 4874.853, -2981.499, 289.5772, 5.183629, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+14, 190550, 571, 1, 1, 4837.822, -2961.738, 290.6022, 2.565632, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+15, 190550, 571, 1, 1, 4834.372, -3055.432, 292.4856, 4.799657, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+16, 190550, 571, 1, 1, 4928.226, -2954.833, 289.3405, 2.129301, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 4279) +(@OGUID+17, 190550, 571, 1, 1, 4900.326, -2870.361, 290.4038, 1.431168, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 0) +(@OGUID+18, 190550, 571, 1, 1, 4971.439, -2966.859, 290.2518, 4.520406, 0, 0, 0, 1, 120, 255, 1), -- 190550 (Area: 4278) +(@OGUID+19, 190550, 571, 1, 1, 4928.226, -2954.833, 289.3405, 2.129301, 0, 0, 0, 1, 120, 255, 1); -- 190550 (Area: 0) + +DELETE FROM `event_scripts` WHERE `id`=4845 AND `delay`=0 AND `command`=9 AND `datalong`=21207 AND `datalong2`=66 AND `dataint`=0 AND `x`=0 AND `y`=0 AND `z`=0 AND `o`=0 LIMIT 1; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_03_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_03_01_world.sql new file mode 100644 index 00000000000..a242d26efe1 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_03_01_world.sql @@ -0,0 +1,57 @@ +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=28330; + +-- Ghostwing needs spell 59091 in relation to Crusader Olakin Sainrith in phase 64 +DELETE FROM `npc_spellclick_spells` WHERE `npc_entry`= 31432 AND `spell_id`= 59091; + +INSERT INTO `npc_spellclick_spells` (`npc_entry`,`spell_id`,`cast_flags`,`user_type`) VALUES +(31432, 59091, 1, 0); + +DELETE FROM `vehicle_template_accessory` WHERE `entry`=31432 AND `seat_id`=0; + +DELETE FROM `creature` WHERE `guid`=145119; + +DELETE FROM `spell_area` WHERE `spell`=58139 AND `area`IN(4588); +INSERT INTO `spell_area` (`spell`, `area`, `quest_start`, `quest_end`, `aura_spell`, `racemask`, `gender`, `autocast`, `quest_start_status`, `quest_end_status`) VALUES +(58139, 4588, 13144, 0, 0, 0, 2, 1, 64, 11); -- Blackwatch after Killing two scourge with one skeleton +UPDATE `creature` SET `phaseMask`=65 WHERE `guid`=123657; + +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`IN(30631,31432); + +DELETE FROM `smart_scripts` WHERE `entryorguid`IN(30631,31432) AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`IN(31428) AND `source_type`=0 AND `id`>4; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(30631, 0, 0, 1, 20, 0, 100, 0, 13144, 0, 0, 0, 12, 31432, 1, 90000, 0, 0, 0, 8, 0, 0, 0, 6588.43, 3278.2, 818.203, 5.044, 'Darkrider Arly - On Quest Reward - Summon Ghostwing'), +(30631, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 12, 31428, 1, 90000, 0, 0, 0, 8, 0, 0, 0, 6648.77, 3217.7, 810.501, 1.55334, 'Darkrider Arly - On Quest Reward - Summon Crusader Olakin Sainrith'), +(31428, 0, 5, 6, 54, 0, 100, 0, 0, 0, 0, 0, 71, 0, 0, 40598, 42543, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Crusader Olakin Sainrith - On Just Summoned - Equip Items'), +(31428, 0, 6, 7, 61, 0, 100, 0, 0, 0, 0, 0, 44, 64, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Crusader Olakin Sainrith - On Just Summoned - Set Ingame Phase 64'), +(31428, 0, 7, 8, 61, 0, 100, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Crusader Olakin Sainrith - On Just Summoned - Dismount'), +(31428, 0, 8, 0, 61, 0, 100, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Crusader Olakin Sainrith - On Just Summoned - Say Line 1'), +(31428, 0, 9, 0, 38, 0, 100, 0, 2, 2, 0, 0, 11, 59091, 2, 0, 0, 0, 0, 19, 31432, 0, 0, 0, 0, 0, 0, 'Crusader Olakin Sainrith - On Data Set - Cast Ride Ghostwing'), +(31432, 0, 0, 1, 54, 0, 100, 0, 0, 0, 0, 0, 44, 64, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ghostwing - On Just Summoned - Set Ingame Phase 64'), +(31432, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ghostwing - On Just Summoned - Start WP'), +(31432, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 53, 1, 31432, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ghostwing - On Just Summoned - Set Active'), +(31432, 0, 3, 4, 40, 0, 100, 0, 1, 31432, 0, 0, 54, 3000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ghostwing - On Reached WP1 - Pause WP'), +(31432, 0, 4, 5, 61, 0, 100, 0, 0, 0, 0, 0, 45, 2, 2, 0, 0, 0, 0, 19, 31428, 0, 0, 0, 0, 0, 0, 'Ghostwing - On Reached WP1 - Set Data on Crusader Olakin Sainrith'), +(31432, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ghostwing - On Reached WP1 - Say Line 0'), +(31432, 0, 6, 7, 40, 0, 100, 0, 2, 31432, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 30631, 0, 0, 0, 0, 0, 0, 'Ghostwing - On Reached WP2 - Say Line 0 on Darkrider Arly'), +(31432, 0, 7, 8, 61, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 19, 31432, 0, 0, 0, 0, 0, 0, 'Ghostwing - On Reached WP2 - Despawn Crusader Olakin Sainrith'), +(31432, 0, 8, 0, 61, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ghostwing - On Reached WP2 - Despawn '); + +DELETE FROM `creature_text` WHERE `entry` IN(30631,31432); +DELETE FROM `creature_text` WHERE `entry` IN(31428) AND `groupid`=1; + + +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `comment`) VALUES +(30631, 0, 0, 'Damn it, Olakin, get your arse back here! There''s work to be done!', 12, 0, 100, 5, 0, 0, 32195, 'Darkrider Arly to Crusader Olakin Sainrith'), +(31428, 1, 0, 'Look! What''s a frostwyrm doing here? It''s coming straight for us.', 12, 0, 100, 25, 0, 0, 32173, 'Crusader Olakin Sainrith to Player'), +(31432, 0, 0, 'Destroy our raw materials, will you? Well, the master has a special plan in mind for you... ', 12, 0, 100, 460, 0, 0, 32171, 'Ghostwing to Player'); + +DELETE FROM `waypoints` WHERE `entry`=31432; +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES +(31432, 1, 6644.43, 3222.912, 823.0705, 'Ghostwing'), +(31432, 2, 6690.65, 3177.279, 860.5705, 'Ghostwing'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=59091; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 1, 59091, 0, 0, 31, 0, 3, 31432, 0, 0, 0, 0, '', 'Ride Ghostwing'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_00_world.sql new file mode 100644 index 00000000000..f338d6d0043 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_00_world.sql @@ -0,0 +1,32 @@ +/* Sunken Temple - Support for quest 3447: Secret of the Circle */ +SET @GO_GUID := 5521; +SET @ALTAR := 148836; +SET @LIGHT := 148883; +SET @ATAL_ALARION := 8580; +SET @ATALAI_IDOL := 148838; + +-- Altar of Hakkar +UPDATE `gossip_menu_option` SET `action_menu_id`=1302 WHERE `menu_id`=1288; +-- SAI: Add Pattern of lights +UPDATE `gameobject_template` SET `AIName`='SmartGameObjectAI' WHERE `entry`=@ALTAR; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ALTAR AND `source_type`=1 AND `id`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ALTAR*100 AND `source_type`=9 AND `id` BETWEEN 0 AND 5; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ALTAR,1,0,0,62,0,100,0,1288,0,0,0,80,@ALTAR*100,0,0,0,0,0,1,0,0,0,0,0,0,0, 'On gossip option select run script'), +(@ALTAR*100,9,0,0,1,0,100,0,0,0,0,0,50,@LIGHT,3,0,0,0,0,8,0,0,0,-515.553,95.25821,-148.7401,-1.500983, 'Script - Summon Temp GO'), +(@ALTAR*100,9,1,0,1,0,100,0,3000,3000,0,0,50,@LIGHT,3,0,0,0,0,8,0,0,0,-419.8487,94.48368,-148.7401,-1.500983, 'Script - Summon Temp GO'), +(@ALTAR*100,9,2,0,1,0,100,0,3000,3000,0,0,50,@LIGHT,3,0,0,0,0,8,0,0,0,-491.4003,135.9698,-148.7401,-1.500983, 'Script - Summon Temp GO'), +(@ALTAR*100,9,3,0,1,0,100,0,3000,3000,0,0,50,@LIGHT,3,0,0,0,0,8,0,0,0,-491.4909,53.48179,-148.7401,-1.500983, 'Script - Summon Temp GO'), +(@ALTAR*100,9,4,0,1,0,100,0,3000,3000,0,0,50,@LIGHT,3,0,0,0,0,8,0,0,0,-443.8549,136.1007,-148.7401,-1.500983, 'Script - Summon Temp GO'), +(@ALTAR*100,9,5,0,1,0,100,0,3000,3000,0,0,50,@LIGHT,3,0,0,0,0,8,0,0,0,-443.4171,53.83124,-148.7401,-1.500983, 'Script - Summon Temp GO'); + +-- Mini-boss Atal'alarion <Guardian of the Idol> and GameObject Idol of Hakkar +DELETE FROM `creature` WHERE `guid`=34521 AND `id`=@ATAL_ALARION; -- spawned by script + +DELETE FROM `gameobject` WHERE `guid`=@GO_GUID AND `id`=@ATALAI_IDOL; -- spawned but hidden until creature die +INSERT INTO `gameobject` (`guid`,`id`,`map`,`zoneid`,`areaid`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`,`VerifiedBuild`) VALUES +(@GO_GUID,@ATALAI_IDOL,109,0,0,3,1,-476.2693,94.41199,-189.7297,1.588249,0,0,0,1,-1,255,1,12340); + +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ATAL_ALARION AND `source_type`=0 AND `id`=7; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ATAL_ALARION,0,7,0,6,0,100,0,0,0,0,0,70,7200,0,0,0,0,0,14,@GO_GUID,@ATALAI_IDOL,0,0,0,0,0, 'Atal''alarion - On Just Died - Respawn Idol of Hakkar'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_01_world.sql new file mode 100644 index 00000000000..b02c2eb4e79 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_01_world.sql @@ -0,0 +1,2 @@ +-- +UPDATE `gameobject` SET `spawnMask`=1 WHERE `guid`=5521; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_02_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_02_world_335.sql new file mode 100644 index 00000000000..db8ca3a9178 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_02_world_335.sql @@ -0,0 +1,20 @@ +-- new gossip_menu_option entries for Quest 6566 What The Wind Carries +DELETE FROM `gossip_menu_option` WHERE `menu_id` IN (3664,3665,3666,3667,3668,3669,3670); +INSERT INTO `gossip_menu_option` (`menu_id`,`id`,`option_icon`,`option_text`,`OptionBroadcastTextID`,`option_id`,`npc_option_npcflag`,`action_menu_id`,`action_poi_id`,`box_coded`,`box_money`,`box_text`,`BoxBroadcastTextID`) VALUES +(3664,0,0,'Please share your wisdom with me, Warchief.',8308,1,1,3665,0,0,0,'',0), +(3665,0,0,'What discoveries?',8310,1,1,3666,0,0,0,'',0), +(3666,0,0,'Usurper?',8312,1,1,3667,0,0,0,'',0), +(3667,0,0,'With all due respect, Warchief - why not allow them to be destroyed? Does this not strengthen our position?',8314,1,1,3668,0,0,0,'',0), +(3668,0,0,'I... I did not think of it that way, Warchief.',8316,1,1,3669,0,0,0,'',0), +(3669,0,0,'I live only to serve, Warchief! My life is empty and meaningless without your guidance.',8318,1,1,3670,0,0,0,'',0), +(3670,0,0,'Of course, Warchief!',8320,1,1,3664,0,0,0,'',0); + +-- link gossip_menu_option menu_id to npc_text ID via gossip_menu (3664,4477 already exists) +DELETE FROM `gossip_menu` WHERE `entry` IN (3665,3666,3667,3668,3669,3670); +INSERT INTO `gossip_menu` (`entry`,`text_id`) VALUES +(3665,5733), +(3666,5734), +(3667,5735), +(3668,5736), +(3669,5737), +(3670,5738); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_03_world.sql new file mode 100644 index 00000000000..4d148adde55 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_04_03_world.sql @@ -0,0 +1,4 @@ +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=18 AND `SourceEntry` IN (63989,63997,63998); +DELETE FROM `npc_spellclick_spells` WHERE `npc_entry`=34072; +INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES +(34072, 51347, 3, 0); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_05_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_05_00_world.sql new file mode 100644 index 00000000000..8dde060140d --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_05_00_world.sql @@ -0,0 +1,34 @@ +UPDATE `creature_template` SET `AIName`='SmartAI',`InhabitType`=4,`VehicleId`=113 WHERE `entry`=32292; + +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(32236,32292) AND `source_type`=0 ; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(3229200) AND `source_type`=9 ; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(32292, 0, 0, 1, 54, 0, 100, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Aldur''thar Sentry - On Just Summoned - Store target'), +(32292, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 19, 32236, 0, 0, 0, 0, 0, 0, 'Aldur''thar Sentry - On Just Summoned - Move to Target'), +(32292, 0, 2, 0, 1, 0, 100, 1, 1500, 1500, 0, 0, 45, 1, 1, 0, 0, 0, 0, 19, 32236, 0, 0, 0, 0, 0, 0, 'Aldur''thar Sentry - OOC - Set Data on target'), +(32292, 0, 3, 0, 8, 0, 100, 1, 46598, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 19, 23837, 0, 0, 0, 0, 0, 0, 'Aldur''thar Sentry - On Spellhit - Move to Target'), +(32292, 0, 4, 0, 75, 0, 100, 1, 0, 23837, 2, 15000, 80, 3229200, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Aldur''thar Sentry - On Creature in Range - Run Script'), +(32236, 0, 0, 0, 0, 0, 100, 0, 0, 0, 3000, 5000, 11, 32000, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - IC - Cast Mind Seer'), +(32236, 0, 1, 0, 0, 0, 100, 0, 0, 3000, 5000, 6000, 11, 32026, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - IC - Cast Pain Spike'), +(32236, 0, 2, 3, 8, 0, 100, 0, 5513, 0, 60000, 60000, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - On Spellhit Orb of Illusion - Store Targetlist'), +(32236, 0, 3, 4,61, 0, 100, 0, 0, 0, 0, 0, 11, 4329, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - On Spellhit Orb of Illusion - Cast Drag and Drop: Dark Subjugator Transform'), +(32236, 0, 4, 5,61, 0, 100, 0, 0, 0, 0, 0, 4, 15131, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - Linked with Previous Event - Play Sound'), +(32236, 0, 5, 6,61, 0, 100, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - Linked with Previous Event - Turn random movement off'), +(32236, 0, 6, 7,61, 0, 100, 0, 0, 0, 0, 0, 18, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - Linked with Previous Event - Set immune'), +(32236, 0, 7, 8,61, 0, 100, 0, 0, 0, 0, 0, 11, 4328, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - Linked with Previous Event - Cast Drag and Drop: Summon Aldur''thar Sentry'), +(32236, 0, 8, 9,61, 0, 100, 0, 0, 0, 0, 0, 1, 0, 3000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - On Spellhit - Say'), +(32236, 0, 9, 10,61, 0, 100, 0, 0, 0, 0, 0, 33, 32229, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - Linked with Previous Event - Kill Credit'), +(32236, 0, 10, 0,61, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - Linked with Previous Event - Evade'), +(32236, 0, 11, 0,8, 0, 100, 0, 46598, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - On Spellhit - Say'), +(32236, 0, 12, 13,38, 0, 100, 0, 2, 2, 0, 0, 4, 15128, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - On Data Set - Play Sound'), +(32236, 0, 13, 0,61, 0, 100, 0, 2, 2, 0, 0, 41, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - On Data Set - Despawn After 5 seconds'), +(32236, 0, 14, 0,38, 0, 100, 0, 1, 1, 0, 0, 11, 46598, 0, 0, 0, 0, 0, 19, 32292, 0, 0, 0, 0, 0, 0, 'Dark Subjugator - On Data Set - Cast Ride Vehicle Hardcoded'), +(3229200, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 46, 20, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Aldur''thar Sentry - Script - Move forward'), +(3229200, 9, 1, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 11, 50630, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Aldur''thar Sentry - On reached WP2 - Cast Eject All Passengers'), +(3229200, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 45, 2, 2, 0, 0, 0, 0, 19, 32236, 0, 0, 0, 0, 0, 0, 'Aldur''thar Sentry - On reached WP2 - Set Data'), +(3229200, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Aldur''thar Sentry - On reached WP2 - Despawn After 5 seconds'); + +DELETE FROM `npc_spellclick_spells` WHERE `npc_entry`= 32292; +INSERT INTO `npc_spellclick_spells` (`npc_entry`,`spell_id`,`cast_flags`,`user_type`) VALUES +(32292, 46598, 1, 0); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_06_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_06_00_world.sql new file mode 100644 index 00000000000..e991023e514 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_06_00_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `gameobject` WHERE `guid` IN(62187,62190,62198); +UPDATE `smart_scripts` SET `target_type`=7 WHERE `entryorguid`=11448 AND `source_type`=0 AND `id`=2 AND `link`=0; +UPDATE `gameobject` SET `phaseMask`=64 WHERE `guid`IN(16974,16976,99723); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_06_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_06_01_world.sql new file mode 100644 index 00000000000..183121d6735 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_06_01_world.sql @@ -0,0 +1,7 @@ +UPDATE `smart_scripts` SET `link`=1 WHERE `entryorguid`IN (28064,28304,28305) AND `source_type`=0 AND `id`=0 AND `link`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`IN (28064,28304,28305) AND `source_type`=0 AND `id`=1; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28064, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 11, 51249, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Drakkari Pedestal 01 - On Spellhit \'Place Banner\' - Cast Summon Agent Crusade Banner'), +(28304, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 11, 51249, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Drakkari Pedestal 02 - On Spellhit \'Place Banner\' - Cast Summon Agent Crusade Banner'), +(28305, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 11, 51249, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Drakkari Pedestal 02 - On Spellhit \'Place Banner\' - Cast Summon Agent Crusade Banner'); +UPDATE `creature` SET `spawndist`=0, `MovementType`=0 WHERE `guid` IN(109153,109501,110958); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_07_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_07_00_world.sql new file mode 100644 index 00000000000..b9df4d07bb9 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_07_00_world.sql @@ -0,0 +1,10 @@ +-- +UPDATE `gameobject` SET `spawntimesecs`= 2 WHERE `guid` IN +(9175, -- Deserter Propaganda +40667, -- The Book of Ur +40774, -- Tool Kit +40775, -- Damaged Diving Gear +66308, -- New Avalon Patrol Schedule +66377, -- Empty Cauldron +66378, -- Iron Chain +66384); -- New Avalon Registry diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_07_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_07_01_world.sql new file mode 100644 index 00000000000..d74f4296903 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_07_01_world.sql @@ -0,0 +1,112 @@ +-- +-- Spelling, grammar and typo corrections, `trinity_string`, branch 3.3.5: +-- +UPDATE `trinity_string` SET `content_default`= "The command %s uses the following subcommands:%s" WHERE `entry`= 8; +UPDATE `trinity_string` SET `content_default`= "The following GMs are active on this server:" WHERE `entry`= 16; +UPDATE `trinity_string` SET `content_default`= "%s's flying command failed." WHERE `entry`= 21; +UPDATE `trinity_string` SET `content_default`= "Up to %u expansions are allowed now." WHERE `entry`= 61; +UPDATE `trinity_string` SET `content_default`= "One or more parameters contain incorrect values." WHERE `entry`= 62; +UPDATE `trinity_string` SET `content_default`= "Wrong parameter, id: %u does not exist." WHERE `entry`= 63; +UPDATE `trinity_string` SET `content_default`= "%s is appearing at your location." WHERE `entry`= 114; +UPDATE `trinity_string` SET `content_default`= "GUID %i, faction is %i, flags is %i, npcflag is %i, dynflag is %i." WHERE `entry`= 128; +UPDATE `trinity_string` SET `content_default`= "You changed GUID=%i's Faction to %i, flags to %i, npcflag to %i, dynflag to %i." WHERE `entry`= 130; +UPDATE `trinity_string` SET `content_default`= "You set all speeds of %s from normal to %2.2f." WHERE `entry`= 137; +UPDATE `trinity_string` SET `content_default`= "%s set all your speeds from normal to %2.2f." WHERE `entry`= 138; +UPDATE `trinity_string` SET `content_default`= "You set the speed of %s from normal to %2.2f." WHERE `entry`= 139; +UPDATE `trinity_string` SET `content_default`= "%s set your speed from normal to %2.2f." WHERE `entry`= 140; +UPDATE `trinity_string` SET `content_default`= "You set the swim speed of %s from normal to %2.2f." WHERE `entry`= 141; +UPDATE `trinity_string` SET `content_default`= "%s set your swim speed from normal to %2.2f." WHERE `entry`= 142; +UPDATE `trinity_string` SET `content_default`= "You set the backwards run speed of %s from normal to %2.2f." WHERE `entry`= 143; +UPDATE `trinity_string` SET `content_default`= "%s set your backwards run speed from normal to %2.2f." WHERE `entry`= 144; +UPDATE `trinity_string` SET `content_default`= "You set the fly speed of %s from normal to %2.2f." WHERE `entry`= 145; +UPDATE `trinity_string` SET `content_default`= "%s set your fly speed from normal to %2.2f." WHERE `entry`= 146; +UPDATE `trinity_string` SET `content_default`= "You set the size of %s to %2.2f." WHERE `entry`= 147; +UPDATE `trinity_string` SET `content_default`= "You take all the copper from %s." WHERE `entry`= 153; +UPDATE `trinity_string` SET `content_default`= "You play the sound %u." WHERE `entry`= 159; +UPDATE `trinity_string` SET `content_default`= "The following locations were found:\n%s" WHERE `entry`= 168; +UPDATE `trinity_string` SET `content_default`= "You tried to play the sound %u, but it does not exist." WHERE `entry`= 170; +UPDATE `trinity_string` SET `content_default`= "You can't teleport yourself to yourself!" WHERE `entry`= 171; +UPDATE `trinity_string` SET `content_default`= "You changed the runic power of %s to %i/%i." WHERE `entry`= 173; +UPDATE `trinity_string` SET `content_default`= "Error, a name can only contain the characters A-Z and a-z." WHERE `entry`= 203; +UPDATE `trinity_string` SET `content_default`= "Item '%u' (with extended cost %u) is already in the vendor list." WHERE `entry`= 210; +UPDATE `trinity_string` SET `content_default`= "Spells will be reset for all players at login. Relogging is strongly recommended!" WHERE `entry`= 218; +UPDATE `trinity_string` SET `content_default`= "Talents will be reset for all players at login. Relogging is strongly recommended!" WHERE `entry`= 219; +UPDATE `trinity_string` SET `content_default`= "No waypoints found in the database." WHERE `entry`= 239; +UPDATE `trinity_string` SET `content_default`= "Warning: Could not delete WP with ID: %d from the world" WHERE `entry`= 242; +UPDATE `trinity_string` SET `content_default`= "Invalid target map or coordinates (X: %f Y: %f MapId: %u)" WHERE `entry`= 263; +UPDATE `trinity_string` SET `content_default`= "Invalid zone coordinates (X: %f Y: %f AreaId: %u)" WHERE `entry`= 264; +UPDATE `trinity_string` SET `content_default`= "Game Object (GUID: %u) is referenced by nonexistent creature %u in GO list, can't be deleted." WHERE `entry`= 274; +UPDATE `trinity_string` SET `content_default`= "You can't kick yourself, log out instead." WHERE `entry`= 281; +UPDATE `trinity_string` SET `content_default`= "Show new ticket: ON" WHERE `entry`= 291; +UPDATE `trinity_string` SET `content_default`= "Show new ticket: OFF" WHERE `entry`= 292; +UPDATE `trinity_string` SET `content_default`= "%s's honor points were set to %u." WHERE `entry`= 299; +UPDATE `trinity_string` SET `content_default`= "Extended item cost %u does not exist." WHERE `entry`= 331; +UPDATE `trinity_string` SET `content_default`= "You repair all of %s's items." WHERE `entry`= 336; +UPDATE `trinity_string` SET `content_default`= "All your items were repaired by %s." WHERE `entry`= 337; +UPDATE `trinity_string` SET `content_default`= "Game Object (Entry: %u) contains invalid data and can't be spawned." WHERE `entry`= 348; +UPDATE `trinity_string` SET `content_default`= "Title %u (%s) set as current selected title for player %s." WHERE `entry`= 355; +UPDATE `trinity_string` SET `content_default`= "Current selected title for player %s is now reset to not known." WHERE `entry`= 356; +UPDATE `trinity_string` SET `content_default`= "Security level of account %s changed to %i." WHERE `entry`= 401; +UPDATE `trinity_string` SET `content_default`= "Your security level is too low for this action." WHERE `entry`= 403; +UPDATE `trinity_string` SET `content_default`= "Account %s does not exist." WHERE `entry`= 413; +UPDATE `trinity_string` SET `content_default`= "Account %s has never been banned." WHERE `entry`= 416; +UPDATE `trinity_string` SET `content_default`= "You learned all crafts, skills and recipes." WHERE `entry`= 433; +UPDATE `trinity_string` SET `content_default`= "Graveyard #%u is already linked to zone #%u (current)." WHERE `entry`= 450; +UPDATE `trinity_string` SET `content_default`= "Graveyard #%u can not be linked to subzone or nonexistent zone #%u (internal error)." WHERE `entry`= 452; +UPDATE `trinity_string` SET `content_default`= "No faction found in Graveyard with id= #%u, please update your database." WHERE `entry`= 454; +UPDATE `trinity_string` SET `content_default`= "Invalid team, please update your database." WHERE `entry`= 455; +UPDATE `trinity_string` SET `content_default`= "Quest %u is started from an item. Add the item to your inventory and start the quest normally: .additem %u" WHERE `entry`= 472; +UPDATE `trinity_string` SET `content_default`= "Player %s must have the skill %u (%s) before using this command." WHERE `entry`= 485; +UPDATE `trinity_string` SET `content_default`= "Target(%s) already knows that spell." WHERE `entry`= 489; +UPDATE `trinity_string` SET `content_default`= "You have already unlearnt that spell." WHERE `entry`= 491; +UPDATE `trinity_string` SET `content_default`= "That player is already in a guild." WHERE `entry`= 500; +UPDATE `trinity_string` SET `content_default`= "The guild was NOT created. Check if that guild already exists." WHERE `entry`= 501; +UPDATE `trinity_string` SET `content_default`= "No items from the itemset '%u' were found." WHERE `entry`= 502; +UPDATE `trinity_string` SET `content_default`= "Item '%i' '%s' added to slot %i." WHERE `entry`= 506; +UPDATE `trinity_string` SET `content_default`= "NPC currently selected by player:\nDB GUID: %u, current GUID: %u.\nFaction: %u.\nnpcFlags: %u.\nEntry: %u.\nDisplayID: %u (Native: %u)." WHERE `entry`= 539; +UPDATE `trinity_string` SET `content_default`= "%s no longer has any explored zones." WHERE `entry`= 552; +UPDATE `trinity_string` SET `content_default`= "Found nearby creatures (distance %f): %u" WHERE `entry`= 556; +UPDATE `trinity_string` SET `content_default`= "%s leveled you up to (%i)." WHERE `entry`= 557; +UPDATE `trinity_string` SET `content_default`= "%s leveled you down to (%i)." WHERE `entry`= 558; +UPDATE `trinity_string` SET `content_default`= "%s has reset your level progress." WHERE `entry`= 559; +UPDATE `trinity_string` SET `content_default`= "The value index %u is too big for %u (count: %u)." WHERE `entry`= 564; +UPDATE `trinity_string` SET `content_default`= "The selected player or creature does not have a victim." WHERE `entry`= 579; +UPDATE `trinity_string` SET `content_default`= "Player %s has learned all default spells for race/class and spell rewards from completed quests." WHERE `entry`= 580; +UPDATE `trinity_string` SET `content_default`= "Found nearby gameobjects (distance %f): %u" WHERE `entry`= 581; +UPDATE `trinity_string` SET `content_default`= "SpawnTime: Full:%s Remaining:%s" WHERE `entry`= 582; +UPDATE `trinity_string` SET `content_default`= "No event found." WHERE `entry`= 584; +UPDATE `trinity_string` SET `content_default`= "The event does not exist." WHERE `entry`= 585; +UPDATE `trinity_string` SET `content_default`= "The event %u is already active." WHERE `entry`= 587; +UPDATE `trinity_string` SET `content_default`= "The event %u is not active." WHERE `entry`= 588; +UPDATE `trinity_string` SET `content_default`= "You have learned all spells from the craft: %s" WHERE `entry`= 592; +UPDATE `trinity_string` SET `content_default`= "Item(s) can not be equipped or stored in the inventory due to a problem." WHERE `entry`= 706; +UPDATE `trinity_string` SET `content_default`= "An email address is required to change your password." WHERE `entry`= 881; +UPDATE `trinity_string` SET `content_default`= "The account %s was NOT deleted (the SQL file format was probably updated)." WHERE `entry`= 1002; +UPDATE `trinity_string` SET `content_default`= "The account %s was NOT deleted (unknown error)." WHERE `entry`= 1003; +UPDATE `trinity_string` SET `content_default`= "An account name can NOT be longer than 16 characters (client limit). The account was NOT created." WHERE `entry`= 1005; +UPDATE `trinity_string` SET `content_default`= "An account with this name already exists!" WHERE `entry`= 1006; +UPDATE `trinity_string` SET `content_default`= "The account %s was NOT created (the SQL file format was probably updated)." WHERE `entry`= 1007; +UPDATE `trinity_string` SET `content_default`= "The account %s was NOT created (unknown error)." WHERE `entry`= 1008; +UPDATE `trinity_string` SET `content_default`= "The character '%s' (GUID: %u Account %u) can NOT be restored: The account does not exist!" WHERE `entry`= 1023; +UPDATE `trinity_string` SET `content_default`= "The character '%s' (GUID: %u Account %u) can NOT be restored: The account character list is full!" WHERE `entry`= 1024; +UPDATE `trinity_string` SET `content_default`= "The character '%s' (GUID: %u Account %u) can NOT be restored: The name is already in use!" WHERE `entry`= 1025; +UPDATE `trinity_string` SET `content_default`= "The account %s (Id: %u) is allowed to use up to %u expansion(s) now." WHERE `entry`= 1100; +UPDATE `trinity_string` SET `content_default`= "The account %s (%u) has reached maximum amount of allowed characters (client limitation)." WHERE `entry`= 1113; +UPDATE `trinity_string` SET `content_default`= "The dump file contains damaged data!" WHERE `entry`= 1114; +UPDATE `trinity_string` SET `content_default`= "The character guid %u is already in use!" WHERE `entry`= 1117; +UPDATE `trinity_string` SET `content_default`= "You changed the gender of %s to %s." WHERE `entry`= 1120; +UPDATE `trinity_string` SET `content_default`= "Your gender was changed to %s by %s." WHERE `entry`= 1121; +UPDATE `trinity_string` SET `content_default`= "No pet found." WHERE `entry`= 1123; +UPDATE `trinity_string` SET `content_default`= "Wrong pet type." WHERE `entry`= 1124; +UPDATE `trinity_string` SET `content_default`= "Your pet has learned all talents." WHERE `entry`= 1125; +UPDATE `trinity_string` SET `content_default`= "The talents of %s's pet were reset." WHERE `entry`= 1127; +UPDATE `trinity_string` SET `content_default`= "Unable to dump deleted characters, aborting." WHERE `entry`= 1130; +UPDATE `trinity_string` SET `content_default`= "All configs are reloaded from the configuration file(s)." WHERE `entry`= 1157; +UPDATE `trinity_string` SET `content_default`= "Invalid name specified. The name must be a name of an online Game Master." WHERE `entry`= 2012; +UPDATE `trinity_string` SET `content_default`= "You cannot unassign tickets from staff members with a higher security level than yourself." WHERE `entry`= 2015; +UPDATE `trinity_string` SET `content_default`= "It might be amusing, but no... you cant freeze yourself." WHERE `entry`= 5001; +UPDATE `trinity_string` SET `content_default`= "Invalid input, check the name of the target." WHERE `entry`= 5002; +UPDATE `trinity_string` SET `content_default`= "You can't teleport yourself to yourself!" WHERE `entry`= 5011; +UPDATE `trinity_string` SET `content_default`= "No reason given." WHERE `entry`= 5035; +UPDATE `trinity_string` SET `content_default`= "You are outdoors." WHERE `entry`= 5042; +UPDATE `trinity_string` SET `content_default`= "You are indoors." WHERE `entry`= 5043; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_09_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_09_00_world.sql new file mode 100644 index 00000000000..d3ebf1af0ff --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_09_00_world.sql @@ -0,0 +1,38 @@ +UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` IN(4968,23704); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(4968,23704) AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(2370400) AND `source_type`=9; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(4968, 0, 0, 1, 62, 0, 100, 0, 2465, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Gossip Select - Close Gossip'), +(4968, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 1, 6, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Gossip Select - Say Line 6'), +(4968, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 11, 23122, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Gossip Select - Cast Jaina''s Autograph'), +(4968, 0, 3, 4, 20, 0, 100, 0, 11142, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Quest Reward (Survey Alcaz Island - Face player'), +(4968, 0, 4, 5, 61, 0, 100, 0, 0, 0, 0, 0, 1, 0, 5000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Quest Reward (Survey Alcaz Island - Say Line 0'), -- 04:20:13.000 +(4968, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Quest Reward (Survey Alcaz Island - Set NPC Flags'), +(4968, 0, 6, 0, 52, 0, 100, 0, 0, 4968, 0, 0, 1, 1, 7000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Text Over Line 0 - Say Line 1'), -- 04:20:18.000 +(4968, 0, 7, 0, 52, 0, 100, 0, 1, 4968, 0, 0, 1, 2, 6000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Text Over Line 1 - Say Line 2'), -- 04:20:25.000 +(4968, 0, 8, 0, 52, 0, 100, 0, 2, 4968, 0, 0, 1, 3, 7000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Text Over Line 2 - Say Line 3'), -- 04:20:31.000 +(4968, 0, 9, 0, 52, 0, 100, 0, 3, 4968, 0, 0, 1, 4, 6000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Text Over Line 3 - Say Line 4'), -- 04:20:38.000 +(4968, 0, 10, 0, 52, 0, 100, 0, 4, 4968, 0, 0, 1, 5, 5000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Text Over Line 4 - Say Line 5'), -- 04:20:44.000 +(4968, 0, 11, 12, 52, 0, 100, 0, 5, 4968, 0, 0, 81, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Text Over Line 5 - Set Npc Flag'), +(4968, 0, 12, 0, 61, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Lady Jaina Proudmoore - On Text Over Line 5 - Evade'), +(23704, 0, 0, 1, 62, 0, 100, 0, 8782, 0, 0, 0, 11, 42295, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Cassa Crimsonwing - On Gossip Option 0 Selected - Cast Spell 42295'), +(23704, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Cassa Crimsonwing - On Linked Actions - Close Gossip'); + +DELETE FROM `gossip_menu_option` WHERE `menu_id`=2465; +INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`, `BoxBroadcastTextID`) VALUES +(2465, 0, 0, 'Lady Jaina, this may sound like an odd request... but I have a young ward who is quite shy. You are a hero to him, and he asked me to get your autograph.', 9663, 1, 1, 0, 0, 0, 0, '', 0); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=2465; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(15, 2465, 0, 0, 0, 9, 0, 558, 0, 0, 0, 0, 0, '', 'Lady Jaina Proudmoore Shows gossip option 2465 if player has quest Jaina''s Autograph'); + +DELETE FROM `creature_text` WHERE `entry`=4968; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextID`, `comment`) VALUES +(4968, 0, 0, 'Perhaps I should explain...', 12, 0, 100, 1, 0, 0, 33092, 'Lady Jaina Proudmoore to Player'), +(4968, 1, 0, 'I had arranged for a secret summit between Warchief Thrall and King Wrynn, here in Theramore.', 12, 0, 100, 1, 0, 0, 33093, 'Lady Jaina Proudmoore to Player'), +(4968, 2, 0, 'The king was to travel here by ship, in secret. But the ship never arrived, and King Wrynn disappeared.', 12, 0, 100, 1, 0, 0, 33094, 'Lady Jaina Proudmoore to Player'), +(4968, 3, 0, 'Your help enabled us to connect the Defias to the mastermind behind the abduction, Onyxia, who was posing as a member of the royal court.', 12, 0, 100, 1, 0, 0, 33095, 'Lady Jaina Proudmoore to Player'), +(4968, 4, 0, 'Meanwhile, the king managed to escape his captors, and returned to Stormwind to deal with Onyxia.', 12, 0, 100, 1, 0, 0, 33096, 'Lady Jaina Proudmoore to Player'), +(4968, 5, 0, 'I will send word that you have discovered the link to the Defias. I was a fool to think them broken with the defeat of Edwin Van Cleef, and King Wrynn will want to make an example of all who remain.', 12, 0, 100, 1, 0, 0, 33097, 'Lady Jaina Proudmoore to Player'), +(4968, 6, 0, 'Why... that is very sweet of you. I gather that you are volunteering time for Children''s Week, yes $c? Well, you are to be commended. It is imperative that we remember those less fortunate - especially the children.$B$BI''d be happy to sign an autograph. Here you go.', 12, 0, 100, 1, 0, 0, 9665, 'Lady Jaina Proudmoore to Player'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_10_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_10_00_world.sql new file mode 100644 index 00000000000..e3170b27499 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_10_00_world.sql @@ -0,0 +1,4 @@ +DELETE FROM `creature_text` WHERE `entry`=4968 AND `groupid`=6 AND `id`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`=4968 AND `source_type`=0 AND `id` IN(1,2); +UPDATE `smart_scripts` SET `link`=0 WHERE `entryorguid`=4968 AND `source_type`=0 AND `id`=0 AND `link`=1; +UPDATE `gossip_menu_option` SET `action_menu_id`=5850 WHERE `menu_id`=2465 AND `id`=0; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_10_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_10_01_world.sql new file mode 100644 index 00000000000..80b23be82c2 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_10_01_world.sql @@ -0,0 +1,4 @@ +DELETE FROM `spell_area` WHERE `spell`=42316 AND `area`=2079 AND `quest_start`=11142 AND `aura_spell`=0 AND `racemask`=1101 AND `gender`=2; +DELETE FROM `spell_linked_spell` WHERE `spell_trigger` = -42385; +INSERT INTO `spell_linked_spell` (`spell_trigger`,`spell_effect`,`type`,`comment`) VALUES +(-42385, 42316, 0, 'On remove Alcaz Survey Aura - cast Alcaz Survey Credit'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_12_2015_11_14_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_12_2015_11_14_00_world.sql new file mode 100644 index 00000000000..b3e49eb1114 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_12_2015_11_14_00_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `trinity_string` WHERE `entry`=186; +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES +(186, 'TransMapID: %u TransOffsetX: %f TransOffsetY: %f TransOffsetZ: %f TransOffsetO: %f (Transport ID: %u %s)'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_13_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_13_00_world.sql new file mode 100644 index 00000000000..0c45636d945 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_13_00_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_sindragosa_ice_tomb_target'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(69712, 'spell_sindragosa_ice_tomb_target'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_13_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_13_01_world.sql new file mode 100644 index 00000000000..12bc205f125 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_13_01_world.sql @@ -0,0 +1,106 @@ +-- Fix quests Incense for the Festival Scorchlings and Incense for the Summer Scorchlings +DELETE FROM `creature_queststarter` WHERE `quest`=11964; +-- SAI for Festival Talespinner +UPDATE `creature_template` SET `AIName`= 'SmartAI' WHERE `entry`=16818; +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`=16818; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(16818,0,0,0,19,0,100,0,11966,0,0,0,11,46826,0,0,0,0,0,7,0,0,0,0,0,0,0,'Festival Talespinner - On target quest accepted - Cast Flame Keeper Breadcrumb'); +-- SAI for Festival Loremaster +UPDATE `creature_template` SET `AIName`= 'SmartAI' WHERE `entry`=16817; +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`=16817; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(16817,0,0,0,19,0,100,0,11964,0,0,0,11,46825,0,0,0,0,0,7,0,0,0,0,0,0,0,'Festival Loremaster - On target quest accepted - Cast Flame Warden Breadcrumb'); +-- Whisp of Ragnaros flag not selectable +UPDATE `creature_template` SET `unit_flags`=33554432 WHERE `entry`=26502; +-- SAI for Festival Schorchling +UPDATE `creature_template` SET `AIName`= 'SmartAI' WHERE `entry`=26520; +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`=26520; +DELETE FROM `smart_scripts` WHERE `source_type`=9 AND `entryorguid`=2652000; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(26520,0,0,0,8,0,100,0,47104,0,0,0,80,2652000,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - On spell hit - Run script '), +(2652000,9,1,0,0,0,100,0,0,0,0,0,1,0,2000,0,0,0,0,21,3,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 0'), +(2652000,9,2,0,0,0,100,0,1000,1000,0,0,1,1,1000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 1'), +(2652000,9,3,0,0,0,100,0,2000,2000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Cast grow'), +(2652000,9,4,0,0,0,100,0,0,0,0,0,1,2,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 2'), +(2652000,9,5,0,0,0,100,0,3000,3000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Cast grow'), +(2652000,9,6,0,0,0,100,0,0,0,0,0,1,3,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 3'), +(2652000,9,7,0,0,0,100,0,3000,3000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Cast grow'), +(2652000,9,8,0,0,0,100,0,0,0,0,0,1,4,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 4'), +(2652000,9,9,0,0,0,100,0,1000,1000,0,0,1,5,1000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 5'), +(2652000,9,10,0,0,0,100,0,2000,2000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Cast grow'), +(2652000,9,11,0,0,0,100,0,0,0,0,0,1,6,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 6'), +(2652000,9,12,0,0,0,100,0,3000,3000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Cast grow'), +(2652000,9,13,0,0,0,100,0,0,0,0,0,1,7,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 7'), +(2652000,9,14,0,0,0,100,0,0,0,0,0,11,47120,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Summon Whisp of Ragnaros'), +(2652000,9,15,0,0,0,100,0,0,0,0,0,75,45889,0,0,0,0,0,11,26502,10,0,0,0,0,0,'Festival Scorchling - Action list - Aura Scorchling Blast'), +(2652000,9,16,0,0,0,100,0,3000,3000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Cast grow'), +(2652000,9,17,0,0,0,100,0,0,0,0,0,41,0,0,0,0,0,0,11,26502,10,0,0,0,0,0,'Festival Scorchling - Action list - Despawn Whisp of Ragnaros '), +(2652000,9,18,0,0,0,100,0,0,0,0,0,1,8,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 8'), +(2652000,9,19,0,0,0,100,0,0,0,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Cast grow'), +(2652000,9,20,0,0,0,100,0,0,0,0,0,1,9,1000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 9'), +(2652000,9,21,0,0,0,100,0,1000,1000,0,0,11,46660,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Cast Extinguished'), +(2652000,9,22,0,0,0,100,0,0,0,0,0,28,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Remove aura from grow'), +(2652000,9,23,0,0,0,100,0,3000,3000,0,0,1,10,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Festival Scorchling - Action list - Say text 10'); +-- Festival Scorchling texts +DELETE FROM `creature_text` WHERE `entry`= 26520; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`,`BroadcastTextId`) VALUES +(26520,0,0,'Thank you again, $n, for this delectable incense.',12,0,100,1,1000,0,'Festival Scorchling',25699), +(26520,1,0,'%s devours the incense. It\'s ravenous!',16,0,100,1,1000,0,'Festival Scorchling',25717), +(26520,2,0,'So good! So packed with energy!',12,0,100,1,1000,0,'Festival Scorchling',25718), +(26520,3,0,'It has everything a growing scorchling needs!',12,0,100,1,1000,0,'Festival Scorchling',25719), +(26520,4,0,'I can feel the power SURGING within me!',12,0,100,1,1000,0,'Festival Scorchling',25730), +(26520,5,0,'%s bellows with laughter!',16,0,100,1,1000,0,'Festival Scorchling',25720), +(26520,6,0,'Now! Finally! Our plans can take effect!',12,0,100,1,1000,0,'Festival Scorchling',25721), +(26520,7,0,'KNEEL, LITTLE MORTAL! KNEEL BEFORE THE MIGHT OF THE HERALD OF RAGNAROS!',12,0,100,1,1000,0,'Festival Scorchling',25722), +(26520,8,0,'YOU WILL ALL PERISH IN FLAMES!',12,0,100,1,1000,0,'Festival Scorchling',25723), +(26520,9,0,'%s blinks...',16,0,100,1,1000,0,'Festival Scorchling',25724), +(26520,10,0,'Ah. I was merely jesting...',12,0,100,1,1000,0,'Festival Scorchling',25725); +-- SAI for Summer Schorchling +UPDATE `creature_template` SET `AIName`= 'SmartAI' WHERE `entry`=26401; +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`=26401; +DELETE FROM `smart_scripts` WHERE `source_type`=9 AND `entryorguid`=2640100; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(26401,0,0,0,8,0,100,0,47104,0,0,0,80,2640100,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - On spell hit - Start script'), +(2640100,9,1,0,0,0,100,0,0,0,0,0,1,0,2000,0,0,0,0,21,3,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 0'), +(2640100,9,2,0,0,0,100,0,1000,1000,0,0,1,1,1000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 1'), +(2640100,9,3,0,0,0,100,0,2000,2000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Cast grow'), +(2640100,9,4,0,0,0,100,0,0,0,0,0,1,2,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 2'), +(2640100,9,5,0,0,0,100,0,3000,3000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Actionlist - Action 5 - Cast grow'), +(2640100,9,6,0,0,0,100,0,0,0,0,0,1,3,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 3'), +(2640100,9,7,0,0,0,100,0,3000,3000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Cast grow'), +(2640100,9,8,0,0,0,100,0,0,0,0,0,1,4,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 4'), +(2640100,9,9,0,0,0,100,0,1000,1000,0,0,1,5,1000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 5'), +(2640100,9,10,0,0,0,100,0,2000,2000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Cast grow'), +(2640100,9,11,0,0,0,100,0,0,0,0,0,1,6,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 6'), +(2640100,9,12,0,0,0,100,0,3000,3000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Cast grow'), +(2640100,9,13,0,0,0,100,0,0,0,0,0,1,7,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 7'), +(2640100,9,14,0,0,0,100,0,0,0,0,0,11,47120,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Summon Whisp of Ragnaros'), +(2640100,9,15,0,0,0,100,0,0,0,0,0,75,45889,0,0,0,0,0,11,26502,10,0,0,0,0,0,'Summer Scorchling - Action list - Aura Scorchling Blast'), +(2640100,9,16,0,0,0,100,0,3000,3000,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Cast grow'), +(2640100,9,17,0,0,0,100,0,0,0,0,0,41,0,0,0,0,0,0,11,26502,10,0,0,0,0,0,'Summer Scorchling - Action list - Despawn Whisp of Ragnaros '), +(2640100,9,18,0,0,0,100,0,0,0,0,0,1,8,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 8'), +(2640100,9,19,0,0,0,100,0,0,0,0,0,11,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Cast grow'), +(2640100,9,20,0,0,0,100,0,0,0,0,0,1,9,1000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 9'), +(2640100,9,21,0,0,0,100,0,1000,1000,0,0,11,46660,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Cast Extinguished'), +(2640100,9,22,0,0,0,100,0,0,0,0,0,28,47114,0,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Remove aura from grow'), +(2640100,9,23,0,0,0,100,0,3000,3000,0,0,1,10,2000,0,0,0,0,1,0,0,0,0,0,0,0,'Summer Scorchling - Action list - Say text 10'); +-- Summer Scorchling texts +DELETE FROM `creature_text` WHERE `entry`= 26401; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`,`BroadcastTextId`) VALUES +(26401,0,0,'Thank you again, $n, for this delectable incense.',12,0,100,1,1000,0,'Summer Scorchling',25699), +(26401,1,0,'%s devours the incense. It\'s ravenous!',16,0,100,1,1000,0,'Summer Scorchling',25717), +(26401,2,0,'So good! So packed with energy!',12,0,100,1,1000,0,'Summer Scorchling',25718), +(26401,3,0,'It has everything a growing scorchling needs!',12,0,100,1,1000,0,'Summer Scorchling',25719), +(26401,4,0,'I can feel the power SURGING within me!',12,0,100,1,1000,0,'Summer Scorchling',25730), +(26401,5,0,'%s bellows with laughter!',16,0,100,1,1000,0,'Summer Scorchling',25720), +(26401,6,0,'Now! Finally! Our plans can take effect!',12,0,100,1,1000,0,'Summer Scorchling',25721), +(26401,7,0,'KNEEL, LITTLE MORTAL! KNEEL BEFORE THE MIGHT OF THE HERALD OF RAGNAROS!',12,0,100,1,1000,0,'Summer Scorchling',25722), +(26401,8,0,'YOU WILL ALL PERISH IN FLAMES!',12,0,100,1,1000,0,'Summer Scorchling',25723), +(26401,9,0,'%s blinks...',16,0,100,1,1000,0,'Summer Scorchling',25724), +(26401,10,0,'Ah. I was merely jesting...',12,0,100,1,1000,0,'Summer Scorchling',25725); + +-- Add conditions for spell Scorchling Gets Incense +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=47104; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition` ,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(13,1,47104,0,1,31,0,3,26520,0,0,0,'','Scorchling gets incense can hit Festival Scorchling'), +(13,1,47104,0,2,31,0,3,26401,0,0,0,'','Scorchling gets incense can hit Summer Scorchling'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_15_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_15_00_world.sql new file mode 100644 index 00000000000..69e2e3a873b --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_15_00_world.sql @@ -0,0 +1,4 @@ +SET @ENTRY := 62266; +DELETE FROM `disables` WHERE `sourceType`=0 AND `entry` = @ENTRY; +INSERT INTO `disables` (`sourceType`, `entry`, `flags`, `params_0`, `params_1`, `comment`) VALUES +(0,@ENTRY,64,0,0,'Disable LOS for Spell Trigger 3 adds'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_19_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_19_00_world.sql new file mode 100644 index 00000000000..ce96286d585 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_19_00_world.sql @@ -0,0 +1,66 @@ +UPDATE `smart_scripts` SET `target_type`=7 WHERE `entryorguid`=19227 AND `source_type`=0 AND `id`=1 AND `link`=0; + +UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` IN(20232); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(20232,20206) AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(2020600,2020601,2020602) AND `source_type`=9; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(20232, 0, 0, 0, 20, 0, 100, 0, 10344, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Wing Commander Gryphongar - On quest reward (Wing Commander Gryphongar) - Say'), +(20206, 0, 0, 1, 20, 0, 100, 0, 10919, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On Quest \'Fei Fei\'s Treat\' Finished - Set Active'), +(20206, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On Quest \'Fei Fei\'s Treat\' Finished - Set NPC Flags'), +(20206, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 53, 0, 20206, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On Quest \'Fei Fei\'s Treat\' Finished - Start Waypoints'), +(20206, 0, 3, 4, 40, 0, 100, 0, 1, 20206, 0, 0, 54, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP1 - Pause WP'), +(20206, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 80, 2020600, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP1 - Run Script 1'), +(20206, 0, 5, 6, 40, 0, 100, 0, 12, 20206, 0, 0, 54, 1000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP12 - Pause WP'), +(20206, 0, 6, 0, 61, 0, 100, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP12 - Say Line 3'), +(20206, 0, 7, 8, 40, 0, 100, 0, 8, 20206, 0, 0, 54, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP8 - Pause WP'), +(20206, 0, 8, 0, 61, 0, 100, 0, 0, 0, 0, 0, 80, 2020600, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP8 - Run Script 2'), +(20206, 0, 9, 10, 40, 0, 100, 0, 14, 20206, 0, 0, 54, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP14 - Pause WP'), +(20206, 0, 10, 0, 61, 0, 100, 0, 0, 0, 0, 0, 80, 2020601, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP14 - Run Script 3'), +(20206, 0, 11, 12, 40, 0, 100, 0, 16, 20206, 0, 0, 81, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP16 - Set NPC Flags'), +(20206, 0, 12, 13, 61, 0, 100, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 2.22254, 'Fei Fei - On reached WP16 - Set Orientation'), +(20206, 0, 13, 0, 61, 0, 100, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - On reached WP16 - Set Active Off'), + + +(2020600, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - Script 1 - Say Line 1'), -- 22:32:01.531 +(2020600, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 5, 35, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - Script 1 - Play Emote 35'), -- 22:32:02.625 +(2020600, 9, 2, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 11, 39216, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - Script 1 - Cast Create Fei Fei Stash'), -- 22:32:03.812 +(2020600, 9, 3, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - Script 1 - Say Line 2'), -- 22:32:05.156 + +(2020601, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - Script 3 - Say Line 1'), -- 22:32:43.656 +(2020601, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 5, 35, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - Script 3 - Play Emote 35'), -- 22:32:45.062 +(2020601, 9, 2, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fei Fei - Script 3 - Say Line 4'); -- 22:32:46.484 + +DELETE FROM `creature_text` WHERE `entry` IN(20232,20206); +DELETE FROM `creature_text` WHERE `entry` IN(19308) AND `groupid`=0 AND `id`=3; + +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(20232, 0, 0, 'Welcome to Shatter Point, $n! I hope you survive the experience!', 12, 0, 100, 1, 0, 0, 18272, 0, 'Wing Commander Gryphongar'), +(19308, 0, 3, 'I regret to inform you all that we sent home another ten soldiers today - in body bags.', 12, 7, 100, 1, 0, 0, 16455, 0, 'Marshal Isildor'), +(20206, 0, 0, '%s digs in the dirt...', 16, 0, 100, 35, 0, 0, 20312, 0, 'Fei Fei to Fei Fei Stash Bunny'), +(20206, 1, 0, '%s sniffs around, unsatisfied with this hiding spot.', 16, 0, 100, 0, 0, 0, 20315, 0,'Fei Fei to Fei Fei Stash Bunny'), +(20206, 2, 0, '%s looks for a hiding spot...', 16, 0, 100, 0, 0, 0, 20316, 0,'Fei Fei to Fei Fei Stash Bunny'), +(20206, 3, 0, '%s buries his treat!', 16, 0, 100, 0, 0, 0, 20313, 0,'Fei Fei to Fei Fei Stash Bunny'); + +DELETE FROM `waypoints` WHERE `entry`=20206; +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES +(20206, 1, -689.1158, 2630.12, 89.82688, 'Fei Fei'), +(20206, 2,-690.6677 ,2634.433 ,90.20647, 'Fei Fei'), +(20206, 3,-689.6677 ,2656.183 ,92.45647, 'Fei Fei'), +(20206, 4,-686.1677 ,2679.433 ,92.20647, 'Fei Fei'), +(20206, 5,-678.6677 ,2699.683 ,94.95647, 'Fei Fei'), +(20206, 6,-671.6677 ,2710.683 ,94.70647, 'Fei Fei'), +(20206, 7,-667.1677 ,2725.933 ,94.20647, 'Fei Fei'), +(20206, 8,-666.6677 ,2729.433 ,93.95647, 'Fei Fei'), +(20206, 9,-671.9177 ,2732.183 ,93.95647, 'Fei Fei'), +(20206, 10,-680.6677 ,2732.683 ,93.95647, 'Fei Fei'), +(20206, 11,-685.9177 ,2734.933 ,94.20647, 'Fei Fei'), +(20206, 12,-686.4177 ,2742.183 ,93.95647, 'Fei Fei'), +(20206, 13,-690.9177 ,2746.683 ,93.95647, 'Fei Fei'), +(20206, 14,-698.7195, 2743.245, 94.08604, 'Fei Fei'), +(20206, 15,-669.3355, 2727.604, 94.01691, 'Fei Fei'), +(20206, 16,-684.603, 2626.44, 89.1955, 'Fei Fei'); + +DELETE FROM `gameobject` WHERE `id` =185302; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +(28524, 185302, 530, 1, 1, -699.4442, 2742.403, 94.18588, -0.5759573, 0, 0, 0, 1, 120, 255, 1); -- 185302 (Area: 0) diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_19_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_19_01_world.sql new file mode 100644 index 00000000000..79452fdf43c --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_19_01_world.sql @@ -0,0 +1,64 @@ +UPDATE `gameobject_template` SET `AIName`='SmartGameObjectAI', scriptname='' WHERE `entry` IN (177243, 177365, 177366, 177367, 177368, 177369, 177397, 177398, 177399, 177400); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (177243, 177365, 177366, 177367, 177368, 177369, 177397, 177398, 177399, 177400) AND `source_type`=1; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (17724300, 17736500, 17736600, 17736700, 17736800, 17736900, 17739700, 17739800, 17739900, 17740000) AND `source_type`=9; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES + +(177243,1,0,0,70,0,100,0,2,0,0,0,80,17724300,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17724300, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17724300, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17724300, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17724300, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'), + +(177365,1,0,0,70,0,100,0,2,0,0,0,80,17736500,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17736500, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17736500, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736500, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736500, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'), + +(177366,1,0,0,70,0,100,0,2,0,0,0,80,17736600,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17736600, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17736600, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736600, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736600, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'), + +(177367,1,0,0,70,0,100,0,2,0,0,0,80,17736700,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17736700, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17736700, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736700, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736700, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'), + +(177368,1,0,0,70,0,100,0,2,0,0,0,80,17736800,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17736800, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17736800, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736800, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736800, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'), + +(177369,1,0,0,70,0,100,0,2,0,0,0,80,17736900,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17736900, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17736900, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736900, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17736900, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'), + +(177397,1,0,0,70,0,100,0,2,0,0,0,80,17739700,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17739700, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17739700, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17739700, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17739700, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'), + +(177398,1,0,0,70,0,100,0,2,0,0,0,80,17739800,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17739800, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17739800, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17739800, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17739800, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'), + +(177399,1,0,0,70,0,100,0,2,0,0,0,80,17739900,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17739900, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17739900, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17739900, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17739900, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'), + +(177400,1,0,0,70,0,100,0,2,0,0,0,80,17740000,2,0,0,0,0,1,0,0,0,0,0,0,0,'demon portal - on state change - Call Timed ActionList'), +(17740000, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 11937, 3, 60000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - summon'), +(17740000, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17740000, 9, 2, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 70, 300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - despawn'), +(17740000, 9, 3, 0, 0, 0, 100, 0, 30000, 30000, 0, 0, 99, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,0,'demon portal - ActionList - Reset'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_19_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_19_02_world.sql new file mode 100644 index 00000000000..a0a6ff3619c --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_19_02_world.sql @@ -0,0 +1,16 @@ +UPDATE `smart_scripts` SET `event_type`=75, `event_param1`=0, `event_param2`=16878, `event_param3`=4000, `event_param4`=4000, `action_param2`=1, `target_type`=1, `target_param1`=0, `target_param2`=0, `comment`='Anchorite Relic Bunny - On Shattered Hand Berserker in range - Cast \'Anchorite Contrition\' (No Repeat)' WHERE `entryorguid`=22444 AND `source_type`=0 AND `id`=1 AND `link`=0; +UPDATE `gameobject_template` SET `AIName`='' WHERE `entry`=185298; + +UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` IN(22454); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(22454) AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`=185298 AND `source_type`=1; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(22454, 0, 0, 0, 54, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 21, 30, 0, 0, 0, 0, 0, 0, 'Fel Spirit - On Just Summoned - Attack'), +(22454, 0, 1, 0, 4, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Fel Spirit - On Agro - Attack'); + +DELETE FROM `creature_text` WHERE `entry`=22454; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `comment`) VALUES +(22454, 0, 0, 'Vengeance will not be yours, $n!', 12, 0, 100, 15, 0, 0, 20301, 'Fel Spirit to Player'); + +UPDATE `gameobject_template` SET `flags` = 16 WHERE `entry` = 185298; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_20_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_20_00_world.sql new file mode 100644 index 00000000000..8120f1be86f --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_20_00_world.sql @@ -0,0 +1,13 @@ +-- +UPDATE `creature_template` SET `InhabitType`=4 WHERE `Entry` IN (33377, 33779); +UPDATE `creature` SET `MovementType`=0, `spawndist`=0 WHERE `id`=33377; +DELETE FROM `creature` WHERE `id`=33167; +DELETE FROM `creature` WHERE `guid` IN (136266,136265); +UPDATE `creature` SET `position_x`=-733.608, `position_y`=-131.445, `position_z`=429.842, `orientation`= 4.15265 WHERE `guid`=136271; + +SET @ENTRY1 := -136528; +SET @ENTRY2 := -136525; +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid` IN (@ENTRY1, @ENTRY2); +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY1,0,0,0,1,0,100,0,2000,2000,0,0,11,48310,0,0,0,0,0,10,137508,33779,0,0,0,0,0,'Kirin Tor Battle-Mage - OOC - cast Transitus Shield Beam'), +(@ENTRY2,0,0,0,1,0,100,0,2000,2000,0,0,11,48310,0,0,0,0,0,10,137507,33779,0,0,0,0,0,'Kirin Tor Battle-Mage - OOC - cast Transitus Shield Beam'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_20_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_20_01_world.sql new file mode 100644 index 00000000000..f59710f1e32 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_20_01_world.sql @@ -0,0 +1,62 @@ +UPDATE `spell_dbc` SET `Effect1`=28, `EffectMiscValueB1`=64 WHERE `Id`=33903; + +DELETE FROM `smart_scripts` WHERE `entryorguid`=19188 AND `source_type`=0 AND `id`>3; +DELETE FROM `smart_scripts` WHERE `entryorguid`=21504 AND `source_type`=0 AND `id`>0; +DELETE FROM `smart_scripts` WHERE `entryorguid`=19305 AND `source_type`=0 AND `id`>5; +DELETE FROM `smart_scripts` WHERE `entryorguid`=19419 AND `source_type`=0 AND `id`>1; + +UPDATE `smart_scripts` SET `event_param2`=1,`target_type`=21, `target_param1`=100 WHERE `entryorguid`=19294 AND `source_type`=0 AND `id`=0 AND `link`=0; +UPDATE `smart_scripts` SET `event_param2`=2 WHERE `entryorguid`=19294 AND `source_type`=0 AND `id`=3 AND `link`=0; +UPDATE `smart_scripts` SET `action_param2`=1 WHERE `entryorguid`=19293 AND `source_type`=0 AND `id`=0 AND `link`=0; +UPDATE `smart_scripts` SET `action_param2`=2 WHERE `entryorguid`=20599 AND `source_type`=0 AND `id`=0 AND `link`=0; + +UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` IN(20781,20617); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(20781,20617) AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(2078100,2150400) AND `source_type`=9; + +DELETE FROM `smart_scripts` WHERE `entryorguid`=1929400 AND `source_type`=9 AND `id`>8; +DELETE FROM `event_scripts` WHERE `id`=13256; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(19188, 0, 4, 0, 2, 0, 100, 1, 0, 75, 0, 0, 11, 33903, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Raging Colossus - At 75% HP - Cast Summon Crystalhide Rageling (No Repeat)'), +(19188, 0, 5, 0, 2, 0, 100, 1, 0, 50, 0, 0, 11, 33903, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Raging Colossus - At 50% HP - Cast Summon Crystalhide Rageling (No Repeat)'), +(1929400, 9, 9, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 11, 31401, 2, 0, 0, 0, 0, 19, 20599, 0, 0, 0, 0, 0, 0, 'Earthbinder Galandria Nightbreeze - On Script - Cast Moonfire'), +(1929400, 9, 10, 0, 0, 0, 100, 0, 3000, 3000, 0, 0, 11, 33844, 2, 0, 0, 0, 0, 19, 20599, 0, 0, 0, 0, 0, 0, 'Earthbinder Galandria Nightbreeze - On Script - Cast Entangling Roots'), +(20781, 0, 0, 0, 8, 0, 100, 0, 35413, 0, 180000, 180000, 80, 2078100, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seed of Revitalization Target Trigger - On Spellhit (Seed of Revitalization) - Run Script'), -- 15:12:53.391 +(20617, 0, 0, 0, 38, 0, 100, 0, 1, 1, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - On Data Set - Set Phase 1'), +(20617, 0, 1, 0, 38, 0, 100, 0, 2, 2, 0, 0, 11, 35468, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - On Data Set - Cast Seed of Revitalization Entangling Roots Visual'), +(20617, 0, 2, 0, 38, 0, 100, 0, 3, 3, 0, 0, 28, 35468, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - On Data Set - Remove Seed of Revitalization Entangling Roots Visual'), +(20617, 0, 3, 0, 38, 0, 100, 0, 4, 4, 0, 0, 22, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - On Data Set - Set Phase 0'), +(20617, 0, 4, 0, 1, 1, 100, 0, 0, 0, 3000, 3000, 11, 35487, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - OOC (Phase 1) - Cast Seed of Revitalization Lightning Cloud Visual'), +(20617, 0, 5, 0, 1, 2, 100, 1, 0, 0, 0, 0, 11, 35471, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - OOC (Phase 2) - Cast Seed of Revitalization Giant Insect Swarm Visual'), +(20617, 0, 6, 0, 38, 0, 100, 0, 5, 5, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - On Data Set - Set Phase 2'), +(20617, 0, 7, 8, 38, 0, 100, 0, 6, 6, 0, 0, 22, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - On Data Set - Set Phase 0'), +(20617, 0, 8, 9, 61, 0, 100, 0, 0, 0, 0, 0, 28, 35468, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - On Data Set - Set Phase 0'), +(20617, 0, 9, 0, 61, 0, 100, 0, 0, 0, 0, 0, 28, 35471, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Red Crystal Trigger - On Data Set - Set Phase 0'), +(19305, 0, 6, 7, 54, 0, 100, 0, 0, 0, 0, 0, 11, 7741, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Goliathon - On Just Summoned - Cast Summoned Demon'), +(19305, 0, 7, 0, 61, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 21, 100, 0, 0, 0, 0, 0, 0, 'Goliathon - On Just Summoned - Start Combat'), +(21504, 0, 1, 0, 38, 0, 100, 0, 2, 2, 0, 0, 80, 2150400, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Pathaleon the Calculator\'s Image - On Data Set 2 2 - Run Script'), +(19419, 0, 2, 3, 54, 0, 100, 0, 0, 0, 0, 0, 11, 24240, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Raging Shardling - On Just Summoned - Cast Spawn - Red Lightning'), +(19419, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 21, 50, 0, 0, 0, 0, 0, 0, 'Raging Shardling - On Just Summoned - Attack'), +(2150400, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 34427, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Pathaleon the Calculator\'s Image - Script - Cast Ethereal Teleport'), -- 15:13:04.266 +(2150400, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 33900, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Pathaleon the Calculator\'s Image - Script - Cast Shroud of Death'), -- 15:13:04.266 +(2150400, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 1, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Pathaleon the Calculator\'s Image - Script - Say Line 9'), -- 15:13:06.453 +(2150400, 9, 3, 0, 0, 0, 100, 0, 12000, 12000, 0, 0, 1, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Pathaleon the Calculator\'s Image - Script - Say Line 10'), -- 15:13:18.578 +(2150400, 9, 4, 0, 0, 0, 100, 0, 12000, 12000, 0, 0, 11, 23017, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Pathaleon the Calculator\'s Image - Cast Arcane Channeling'), -- 15:13:30.547 +(2150400, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 11, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Pathaleon the Calculator\'s Image - Script - Say Line 11'), -- 15:13:30.687 +(2150400, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 19305, 6, 60000, 0, 0, 0, 8, 0, 0, 0, 107.4091, 4839.756, 78.9819, 6.118358, 'Pathaleon the Calculator\'s Image - Script - Summon Goliathon'), -- 15:13:30.687 +(2150400, 9, 7, 0, 0, 0, 100, 0, 12000, 12000, 0, 0, 1, 12, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Pathaleon the Calculator\'s Image - Script - Say Line 12'), -- 15:13:42.828 +(2150400, 9, 8, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Pathaleon the Calculator\'s Image - Script - Despawn'), -- 15:13:42.828 +(2078100, 9, 0, 0, 0, 0, 100, 0, 3000, 3000, 0, 0, 45, 1, 1, 0, 0, 0, 0, 9, 20617, 0, 100, 0, 0, 0, 0, 'Seed of Revitalization Target Trigger - Script - Set Data on Red Crystal Trigger'), -- 15:12:56.781 +(2078100, 9, 1, 0, 0, 0, 100, 0, 8000, 8000, 0, 0, 45, 2, 2, 0, 0, 0, 0, 10, 72893, 20617, 0, 0, 0, 0, 0, 'Seed of Revitalization Target Trigger - Script - Set Data on Red Crystal Trigger'), -- 15:13:04.266 +(2078100, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 12, 21504, 1, 60000, 0, 0, 0, 8, 0, 0, 0, 129.1348, 4834.785, 76.19424, 0.06981317, 'Seed of Revitalization Target Trigger - Script - Summon Pathaleon the Calculators Image'), -- 15:13:04.266 +(2078100, 9, 3, 0, 0, 0, 100, 0, 250, 250, 0, 0, 45, 2, 2, 0, 0, 0, 0, 19, 21504, 0, 0, 0, 0, 0, 0, 'Seed of Revitalization Target Trigger - Script - Set Data on Pathaleon the Calculators Image'), +(2078100, 9, 4, 0, 0, 0, 100, 0, 10000, 10000, 0, 0, 45, 5, 5, 0, 0, 0, 0, 9, 20617, 0, 100, 0, 0, 0, 0, 'Seed of Revitalization Target Trigger - Script - Set Data on Red Crystal Trigger'), -- 15:12:56.781 +(2078100, 9, 5, 0, 0, 0, 100, 0, 26000, 26000, 0, 0, 45, 6, 6, 0, 0, 0, 0, 9, 20617, 0, 100, 0, 0, 0, 0, 'Seed of Revitalization Target Trigger - Script - Set Data on Red Crystal Trigger'); -- 15:12:56.781 + +DELETE FROM `creature_text` WHERE `entry`=21504 AND `groupid`>8; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(21504, 9, 0, 'And just what do you think you are doing? You dare to interfere with my master''s experiment?', 12, 0, 100, 25, 0, 0, 18369, 0, 'Pathaleon the Calculators Image'), +(21504, 10, 0, 'Do you like what we''ve done here? Perhaps we will drop these crystals from the sky all over Outland.', 12, 0, 100, 6, 0, 0, 18370, 0, 'Pathaleon the Calculators Image'), +(21504, 11, 0, 'I grow bored with your attempt to heal the land and quell the energies summoning and driving the colossi mad. Goliathon, King of the Colossi, Prince Kael''thas and I demand that you defend the crystal!', 12, 0, 100, 0, 0, 0, 18371, 0, 'Pathaleon the Calculators Image'), +(21504, 12, 0, 'We will meet again soon.', 12, 0, 100, 1, 0, 0, 18372, 0, 'Pathaleon the Calculators Image'); + diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_20_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_20_02_world.sql new file mode 100644 index 00000000000..9b03a9cdea3 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_20_02_world.sql @@ -0,0 +1,40 @@ +-- Charscale Invoker SAI +SET @ENTRY := 40417; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,0,0,100,0,6000,6000,8000,8000,11,75419,0,0,0,0,0,2,0,0,0,0,0,0,0,"Charscale Invoker - In Combat - Cast 'Scorch'"), +(@ENTRY,0,1,0,0,0,100,0,10000,10000,20000,20000,11,75413,0,0,0,0,0,1,0,0,0,0,0,0,0,"Charscale Invoker - In Combat - Cast 'Flame Wave'"); + +-- Charscale Assaulter SAI +SET @ENTRY := 40419; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,0,0,100,0,6000,6000,7000,7000,11,15284,0,0,0,0,0,2,0,0,0,0,0,0,0,"Charscale Assaulter - In Combat - Cast 'Cleave'"), +(@ENTRY,0,1,0,0,0,100,0,14000,14000,14000,14000,11,75418,0,0,0,0,0,1,0,0,0,0,0,0,0,"Charscale Assaulter - In Combat - Cast 'Shockwave'"); + +-- Charscale Commander SAI +SET @ENTRY := 40423; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,1,0,0,100,0,8000,8000,40000,40000,11,75414,0,0,0,0,0,1,0,0,0,0,0,0,0,"Charscale Commander - In Combat - Cast 'Rallying Shout'"), +(@ENTRY,0,1,0,61,0,100,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Charscale Commander - In Combat - Say Line 0"), +(@ENTRY,0,2,0,0,0,100,0,15000,15000,14000,14000,11,13737,0,0,0,0,0,2,0,0,0,0,0,0,0,"Charscale Commander - In Combat - Cast 'Mortal Strike'"); + +-- Charscale Commander Text +DELETE FROM `creature_text` WHERE `entry`=@ENTRY; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `comment`) VALUES +(@ENTRY, 0, 0, '%s rallies the other combatants with a battle roar!', 41, 0, 100, 0, 0, 0, 40420, 'Charscale Commander'); + +-- Charscale Elite SAI +SET @ENTRY := 40421; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,0,0,100,0,12000,12000,11000,11000,11,15621,0,0,0,0,0,2,0,0,0,0,0,0,0,"Charscale Elite - In Combat - Cast 'Skull Crack'"); + +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_ruby_sanctum_rallying_shout'; +INSERT INTO `spell_script_names` VALUE +(75415, 'spell_ruby_sanctum_rallying_shout'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_21_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_21_00_world.sql new file mode 100644 index 00000000000..55f6cceaed8 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_21_00_world.sql @@ -0,0 +1,80 @@ +SET @OGUID := 63491; + +UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` IN(16834,16833,19766,19763,19764,16915,18827,18828,19408); +UPDATE `gameobject_template` SET `AIName`='SmartGameObjectAI' WHERE `entry`IN(183941,183936,183940); + +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(16834,16833,19766,19763,19764,16915,18827,18828,19408) AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(1976600,1976300,1976400) AND `source_type`=9; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(183941,183936,183940) AND `source_type`=1; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(18828, 0, 0, 0, 1, 0, 100, 0, 30000, 60000, 30000, 60000, 11, 33016, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Camera Shaker - OOC - Cast Internal Shake Camera'), +(19408, 0, 0, 0, 14, 0, 100, 0, 1000, 30, 45000, 60000, 11, 34086, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Maiden of Grief - On Friendly Heath Deficit - Whipped Frenzy'), +(19408, 0, 1, 0, 9, 0, 100, 0, 0, 5, 10000, 15000, 11, 15968, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Maiden of Grief - On Range - Cast Lash of Pain'), +(18827, 0, 0, 1, 2, 0, 100, 1, 0, 15, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gan''arg Sapper - On 15% - Say Line 0'), +(18827, 0, 1, 0, 61, 0, 100, 1, 0, 0, 0, 0, 11, 33974, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Gan''arg Sapper - On 15% - Cast Power Burn'), +(18827, 0, 2, 0, 0, 0, 100, 0, 0, 2000, 45000, 60000, 11, 33895, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Gan''arg Sapper - IC - Cast Set Charge'), +(16915, 0, 0, 0, 1, 0, 100, 0, 30000, 60000, 30000, 60000, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Foreman Razelcraz - OOC - Say Line 0'), +(16915, 0, 1, 0, 1, 0, 100, 0, 45000, 90000, 45000, 90000, 11, 34396, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Foreman Razelcraz - OOC - Cast Zap'), +(16915, 0, 2, 0, 1, 0, 100, 0, 20000, 40000, 20000, 40000, 5, 60, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Foreman Razelcraz - OOC - Play emote oneshotkick'), +(16834, 0, 0, 0, 20, 0, 100, 0, 9423, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Anchorite Obadei - On Quest Reward (Return to Obadei) - Say Line 0'), +(16833, 0, 0, 1, 20, 0, 100, 0, 9424, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 19, 16834, 11000, 0, 0, 0, 0, 0, 'Makuru - On Quest Reward (Makurus Vengeance) - Say Line 1 on Anchorite Obadei'), +(16833, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 0, 19, 16834, 0, 0, 0, 0, 0, 0, 'Makuru - On Quest Reward (Makurus Vengeance) - Face Anchorite Obadei'), +(16833, 0, 2, 3, 52, 0, 100, 0, 1, 16834, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Makuru - On Text Over (Line 1 on Anchorite Obadei) - Say Line 0'), +(16833, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 19, 16834, 0, 0, 0, 0, 0, 0, 'Makuru - On Text Over Line 0 - Say Line 2 on Anchorite Obadei'), +(183941, 1, 0, 0, 70, 0, 100, 0, 2, 0, 0, 0, 45, 0, 1, 0, 0, 0, 0, 19, 19766, 0, 0, 0, 0, 0, 0, 'Jakks Cage - On Gameobject State Changed - Set Data 0 1'), +(19766, 0, 1, 0, 38, 0, 100, 0, 0, 1, 0, 0, 80, 1976600, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jakk - On Data Set 0 1 - Run Script (Phase 1)'), +(1976600, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jakk - On Script - Set Data 0 0'), +(1976600, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 46, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jakk - On Script - Move Forward 10 Yards'), +(1976600, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jakk - On Script - Say Line 0'), +(1976600, 9, 3, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 32, 0, 0, 0, 0, 0, 0, 20, 183941, 0, 0, 0, 0, 0, 0, 'Jakk - On Script - Reset GO'), +(1976600, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jakk - On Script - Despawn Instant'), +(183936, 1, 0, 0, 70, 0, 100, 0, 2, 0, 0, 0, 45, 0, 1, 0, 0, 0, 0, 19, 19763, 0, 0, 0, 0, 0, 0, 'Mannis Cage - On Gameobject State Changed - Set Data 0 1'), +(19763, 0, 1, 0, 38, 0, 100, 0, 0, 1, 0, 0, 80, 1976300, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Manni - On Data Set 0 1 - Run Script (Phase 1)'), +(1976300, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Manni - On Script - Set Data 0 0'), +(1976300, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 46, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Manni - On Script - Move Forward 10 Yards'), +(1976300, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Manni - On Script - Say Line 0'), +(1976300, 9, 3, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 32, 0, 0, 0, 0, 0, 0, 20, 183936, 0, 0, 0, 0, 0, 0, 'Manni - On Script - Reset GO'), +(1976300, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Manni - On Script - Despawn Instant'), +(183940, 1, 0, 0, 70, 0, 100, 0, 2, 0, 0, 0, 45, 0, 1, 0, 0, 0, 0, 19, 19764, 0, 0, 0, 0, 0, 0, 'Mohs Cage - On Gameobject State Changed - Set Data 0 1'), +(19764, 0, 1, 0, 38, 0, 100, 0, 0, 1, 0, 0, 80, 1976400, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Moh - On Data Set 0 1 - Run Script (Phase 1)'), +(1976400, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Moh - On Script - Set Data 0 0'), +(1976400, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 46, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Moh - On Script - Move Forward 10 Yards'), +(1976400, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Moh - On Script - Say Line 0'), +(1976400, 9, 3, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 32, 0, 0, 0, 0, 0, 0, 20, 183940, 0, 0, 0, 0, 0, 0, 'Moh - On Script - Reset GO'), +(1976400, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Moh - On Script - Despawn Instant'); + +DELETE FROM `creature_text` WHERE `entry`in(16834,16833,19766,19763,19764,16915,18827); + +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(16915, 0, 0, 'I''ll get you working yet, you bucket of junk.', 12, 0, 100, 1, 0, 0, 17798, 0, 'Foreman Razelcraz'), +(16915, 0, 1, 'What?! You don''t think I can do it? I''ll show you...once I get my parts, that is.', 12, 0, 100, 1, 0, 0, 17802, 0, 'Foreman Razelcraz'), +(16915, 0, 2, 'It moved! I swear, I saw it move!', 12, 0, 100, 0, 0, 0, 17804, 0, 'Foreman Razelcraz'), +(16915, 0, 3, 'Ouch! That''s not right.', 12, 0, 100, 0, 0, 0, 17805, 0, 'Foreman Razelcraz'), +(16915, 0, 4, 'Oh yeah, it''s real funny isn''t it?', 12, 0, 100, 1, 0, 0, 17803, 0, 'Foreman Razelcraz'), +(16834, 0, 0, 'No! Not... Sedai! The orcs must pay!', 12, 0, 100, 1, 0, 0, 13997, 0, 'Anchorite Obadei'), +(16834, 1, 0, 'What have you done, Makuru?! These are not our ways!', 12, 0, 100, 0, 0, 0, 13991, 0, 'Anchorite Obadei'), +(16834, 2, 0, 'I understand how you feel Makuru. Sedai was my brother after all. Yet we can''t disgrace his memory by going against his very ideals.', 12, 0, 100, 0, 0, 0, 13992, 0, 'Makuru'), +(16833, 1, 0, 'The orcs hate us, Obadei! They''ve killed many of us before! They deserve death and worse.', 12, 0, 100, 0, 0, 0, 13996, 0, 'Makuru'), +(19766, 0, 0, 'I don''t know which is worse, getting eaten by fel orcs or working for that slave master Razelcraz! Oh well, thanks anyways!', 12, 0, 100, 66, 0, 0, 17410, 0, 'Jakk'), +(19763, 0, 0, 'Thank goodness you got here, it was almost dinner time!', 12, 0, 100, 3, 0, 0, 17407, 0, 'Manni'), +(19764, 0, 0, 'I thought I was a goner for sure.', 12, 0, 100, 4, 0, 0, 17409, 0, 'Moh'), +(18827, 0, 0, '%s''s eyes glow red as he begins to cackle madly!.', 16, 7, 100, 0, 0, 0, 16771, 0, 'Gan''arg Sapper'); + + +DELETE FROM gameobject WHERE `id` =183934; +INSERT INTO gameobject (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `VerifiedBuild`) VALUES +(@OGUID+0, 183934, 530, 0, 0, 1, 1, 9.587782, 3181.049, 9.555613, 2.111848, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+1, 183934, 530, 0, 0, 1, 1, -15.59028, 3096.009, 0.048549, 2.862335, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+2, 183934, 530, 0, 0, 1, 1, 74.26378, 3039.501, -0.616187, 4.415683, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+3, 183934, 530, 0, 0, 1, 1, 185.5247, 3007.743, -0.824237, 2.652894, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+4, 183934, 530, 0, 0, 1, 1, 193.6588, 3062.065, -0.588734, 2.042035, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+5, 183934, 530, 0, 0, 1, 1, 263.3892, 3016.845, -0.839023, 6.003934, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+6, 183934, 530, 0, 0, 1, 1, 44.87815, 3077.427, -1.222514, 0.05235888, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+7, 183934, 530, 0, 0, 1, 1, 22.71669, 3097.806, -0.868156, 5.567601, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+8, 183934, 530, 0, 0, 1, 1, 20.05642, 3070.531, -0.681531, 5.969027, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+9, 183934, 530, 0, 0, 1, 1, 26.94727, 3130.273, -0.856446, 4.76475, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+10, 183934, 530, 0, 0, 1, 1, 101.7286, 3043.015, -1.222528, 5.480334, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+11, 183934, 530, 0, 0, 1, 1, 174.7734, 3039.325, -0.794917, 0.6806767, 0, 0, 0, 1, 120, 255, 1, 20886), -- 183934 (Area: 0) +(@OGUID+12, 183934, 530, 0, 0, 1, 1, 263.3892, 3016.845, -0.839023, 6.003934, 0, 0, 0, 1, 120, 255, 1, 20886); -- 183934 (Area: 0) + diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_23_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_23_00_world.sql new file mode 100644 index 00000000000..9195b652288 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_23_00_world.sql @@ -0,0 +1,164 @@ +-- Naxxramas instance cleanup +SET @OGUID = 5517; -- gameobject GUID (1 object) used for everything except heigan + +-- ======== -- +-- Faerlina -- +-- ======== -- +-- Move probability of SAY_SLAY to DB +UPDATE `creature_text` SET `probability`=16 WHERE `entry`=15953 and `groupid`=2; + +-- ================== -- +-- Heigan the Unclean -- +-- ================== -- +-- Completely re-do eruption fissure spawns +SET @OGUID2 = 84980; -- gameobject GUID (76 objects); needs to match the constant in boss_heigan.cpp +DELETE FROM `gameobject` WHERE `id` between 181510 and 181552; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`,`VerifiedBuild`) VALUES + (@OGUID2+0,181510,533,3,1,2787.255000,-3654.130000,274.316700,3.534301,0.000000,0.000000,-0.980784,0.195095,0,0,1,15354), + (@OGUID2+1,181526,533,3,1,2781.556000,-3670.999000,274.351800,3.153633,0.000000,0.000000,-0.999982,0.006020,0,0,1,15354), + (@OGUID2+2,181511,533,3,1,2782.403000,-3660.402000,274.314800,2.110888,0.000000,0.000000,0.870119,0.492841,0,0,1,15354), + (@OGUID2+3,181517,533,3,1,2793.238000,-3664.132000,274.316700,0.635802,0.000000,0.000000,0.312573,0.949894,0,0,1,15354), + (@OGUID2+4,181518,533,3,1,2802.508000,-3664.726000,274.316700,0.635802,0.000000,0.000000,0.312573,0.949894,0,0,1,15354), + (@OGUID2+5,181523,533,3,1,2795.809000,-3677.562000,274.072800,2.853153,0.000000,0.000000,0.989618,0.143721,0,0,1,15354), + (@OGUID2+6,181519,533,3,1,2811.998000,-3671.979000,274.072800,5.809874,0.000000,0.000000,-0.234453,0.972127,0,0,1,15354), + (@OGUID2+7,181524,533,3,1,2792.327000,-3684.134000,274.316700,4.976158,0.000000,0.000000,-0.607980,0.793952,0,0,1,15354), + (@OGUID2+8,181520,533,3,1,2810.557000,-3680.581000,274.316700,3.186728,0.000000,0.000000,-0.999745,0.022566,0,0,1,15354), + (@OGUID2+9,181521,533,3,1,2800.146000,-3682.706000,274.351800,1.038823,0.000000,0.000000,0.496369,0.868111,0,0,1,15354), + (@OGUID2+10,181523,533,3,1,2795.809000,-3677.562000,274.072800,2.853153,0.000000,0.000000,0.989618,0.143721,0,0,1,15354), + (@OGUID2+11,181524,533,3,1,2792.327000,-3684.134000,274.316700,4.976158,0.000000,0.000000,-0.607980,0.793952,0,0,1,15354), + (@OGUID2+12,181520,533,3,1,2810.557000,-3680.581000,274.316700,3.186728,0.000000,0.000000,-0.999745,0.022566,0,0,1,15354), + (@OGUID2+13,181521,533,3,1,2800.146000,-3682.706000,274.351800,1.038823,0.000000,0.000000,0.496369,0.868111,0,0,1,15354), + (@OGUID2+14,181522,533,3,1,2805.961000,-3691.666000,274.316700,4.434372,0.000000,0.000000,-0.798264,0.602308,0,0,1,15354), + + (@OGUID2+15,181515,533,3,1,2755.239000,-3649.898000,274.316700,3.396841,0.000000,0.000000,-0.991867,0.127278,0,0,1,15354), + (@OGUID2+16,181516,533,3,1,2763.548000,-3654.044000,274.316700,3.399228,0.000000,0.000000,-0.991715,0.128462,0,0,1,15354), + (@OGUID2+17,181531,533,3,1,2749.335000,-3662.211000,274.351800,3.636871,0.000000,0.000000,-0.969494,0.245116,0,0,1,15354), + (@OGUID2+18,181514,533,3,1,2757.844000,-3659.562000,274.316700,1.971156,0.000000,0.000000,0.833592,0.552381,0,0,1,15354), + (@OGUID2+19,181512,533,3,1,2778.426000,-3651.314000,274.316700,3.540596,0.000000,0.000000,-0.980166,0.198181,0,0,1,15354), + (@OGUID2+20,181516,533,3,1,2763.548000,-3654.044000,274.316700,3.399228,0.000000,0.000000,-0.991715,0.128462,0,0,1,15354), + (@OGUID2+21,181530,533,3,1,2758.163000,-3667.129000,274.351800,3.138830,0.000000,0.000000,0.999999,0.001381,0,0,1,15354), + (@OGUID2+22,181514,533,3,1,2757.844000,-3659.562000,274.316700,1.971156,0.000000,0.000000,0.833592,0.552381,0,0,1,15354), + (@OGUID2+23,181512,533,3,1,2778.426000,-3651.314000,274.316700,3.540596,0.000000,0.000000,-0.980166,0.198181,0,0,1,15354), + (@OGUID2+24,181529,533,3,1,2763.326000,-3680.528000,274.351800,3.146377,0.000000,0.000000,-0.999997,0.002392,0,0,1,15354), + (@OGUID2+25,181513,533,3,1,2774.297000,-3660.655000,274.316700,6.099252,0.000000,0.000000,-0.091837,0.995774,0,0,1,15354), + (@OGUID2+26,181528,533,3,1,2769.250000,-3671.420000,274.422200,5.859179,0.000000,0.000000,-0.210419,0.977611,0,0,1,15354), + (@OGUID2+27,181527,533,3,1,2777.413000,-3677.635000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354), + (@OGUID2+28,181527,533,3,1,2777.413000,-3677.635000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354), + (@OGUID2+29,181529,533,3,1,2763.326000,-3680.528000,274.351800,3.146377,0.000000,0.000000,-0.999997,0.002392,0,0,1,15354), + (@OGUID2+30,181525,533,3,1,2783.359000,-3688.357000,274.385100,3.161319,0.000000,0.000000,-0.999951,0.009863,0,0,1,15354), + (@OGUID2+31,181528,533,3,1,2769.250000,-3671.420000,274.422200,5.859179,0.000000,0.000000,-0.210419,0.977611,0,0,1,15354), + (@OGUID2+32,181528,533,3,1,2769.250000,-3671.420000,274.422200,5.859179,0.000000,0.000000,-0.210419,0.977611,0,0,1,15354), + (@OGUID2+33,181529,533,3,1,2763.326000,-3680.528000,274.351800,3.146377,0.000000,0.000000,-0.999997,0.002392,0,0,1,15354), + (@OGUID2+34,181516,533,3,1,2763.548000,-3654.044000,274.316700,3.399228,0.000000,0.000000,-0.991715,0.128462,0,0,1,15354), + (@OGUID2+35,181530,533,3,1,2758.163000,-3667.129000,274.351800,3.138830,0.000000,0.000000,0.999999,0.001381,0,0,1,15354), + (@OGUID2+36,181514,533,3,1,2757.844000,-3659.562000,274.316700,1.971156,0.000000,0.000000,0.833592,0.552381,0,0,1,15354), + (@OGUID2+37,181515,533,3,1,2755.239000,-3649.898000,274.316700,3.396841,0.000000,0.000000,-0.991867,0.127278,0,0,1,15354), + (@OGUID2+38,181531,533,3,1,2749.335000,-3662.211000,274.351800,3.636871,0.000000,0.000000,-0.969494,0.245116,0,0,1,15354), + (@OGUID2+39,181512,533,3,1,2778.426000,-3651.314000,274.316700,3.540596,0.000000,0.000000,-0.980166,0.198181,0,0,1,15354), + + (@OGUID2+40,181532,533,3,1,2743.089000,-3671.320000,274.316700,2.464252,0.000000,0.000000,0.943197,0.332233,0,0,1,15354), + (@OGUID2+41,181534,533,3,1,2737.166000,-3675.165000,274.316700,4.369651,0.000000,0.000000,-0.817333,0.576165,0,0,1,15354), + (@OGUID2+42,181532,533,3,1,2743.089000,-3671.320000,274.316700,2.464252,0.000000,0.000000,0.943197,0.332233,0,0,1,15354), + (@OGUID2+43,181533,533,3,1,2754.007000,-3673.770000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354), + (@OGUID2+44,181534,533,3,1,2737.166000,-3675.165000,274.316700,4.369651,0.000000,0.000000,-0.817333,0.576165,0,0,1,15354), + (@OGUID2+45,181536,533,3,1,2740.491000,-3692.128000,274.387000,0.792787,0.000000,0.000000,0.386094,0.922459,0,0,1,15354), + (@OGUID2+46,181533,533,3,1,2754.007000,-3673.770000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354), + (@OGUID2+47,181535,533,3,1,2747.132000,-3684.353000,274.351800,3.132432,0.000000,0.000000,0.999989,0.004580,0,0,1,15354), + (@OGUID2+48,181541,533,3,1,2760.581000,-3688.306000,274.387000,0.412781,0.000000,0.000000,0.204928,0.978777,0,0,1,15354), + (@OGUID2+49,181533,533,3,1,2754.007000,-3673.770000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354), + (@OGUID2+50,181532,533,3,1,2743.089000,-3671.320000,274.316700,2.464252,0.000000,0.000000,0.943197,0.332233,0,0,1,15354), + (@OGUID2+51,181544,533,3,1,2774.958000,-3701.132000,274.316700,0.523547,0.000000,0.000000,0.258794,0.965933,0,0,1,15354), + (@OGUID2+52,181543,533,3,1,2772.080000,-3692.152000,274.351800,5.018846,0.000000,0.000000,-0.590897,0.806747,0,0,1,15354), + (@OGUID2+53,181543,533,3,1,2772.080000,-3692.152000,274.351800,5.018846,0.000000,0.000000,-0.590897,0.806747,0,0,1,15354), + (@OGUID2+54,181544,533,3,1,2774.958000,-3701.132000,274.316700,0.523547,0.000000,0.000000,0.258794,0.965933,0,0,1,15354), + (@OGUID2+55,181542,533,3,1,2764.288000,-3698.094000,274.422200,5.490798,0.000000,0.000000,-0.385910,0.922536,0,0,1,15354), + (@OGUID2+56,181541,533,3,1,2760.581000,-3688.306000,274.387000,0.412781,0.000000,0.000000,0.204928,0.978777,0,0,1,15354), + (@OGUID2+57,181533,533,3,1,2754.007000,-3673.770000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354), + (@OGUID2+58,181540,533,3,1,2752.924000,-3693.020000,274.316700,4.099892,0.000000,0.000000,-0.887387,0.461025,0,0,1,15354), + (@OGUID2+59,181536,533,3,1,2740.491000,-3692.128000,274.387000,0.792787,0.000000,0.000000,0.386094,0.922459,0,0,1,15354), + (@OGUID2+60,181532,533,3,1,2743.089000,-3671.320000,274.316700,2.464252,0.000000,0.000000,0.943197,0.332233,0,0,1,15354), + (@OGUID2+61,181534,533,3,1,2737.166000,-3675.165000,274.316700,4.369651,0.000000,0.000000,-0.817333,0.576165,0,0,1,15354), + (@OGUID2+62,181535,533,3,1,2747.132000,-3684.353000,274.351800,3.132432,0.000000,0.000000,0.999989,0.004580,0,0,1,15354), + + (@OGUID2+63,181552,533,3,1,2784.168000,-3724.730000,274.385100,1.050844,0.000000,0.000000,0.501578,0.865112,0,0,1,15354), + (@OGUID2+64,181552,533,3,1,2784.168000,-3724.730000,274.385100,1.050844,0.000000,0.000000,0.501578,0.865112,0,0,1,15354), + (@OGUID2+65,181545,533,3,1,2772.289000,-3711.435000,274.422200,6.022432,0.000000,0.000000,-0.130008,0.991513,0,0,1,15354), + (@OGUID2+66,181549,533,3,1,2776.160000,-3721.793000,274.387000,3.937367,0.000000,0.000000,-0.921882,0.387472,0,0,1,15354), + (@OGUID2+67,181551,533,3,1,2774.989000,-3731.793000,274.387000,3.927917,0.000000,0.000000,-0.923702,0.383111,0,0,1,15354), + (@OGUID2+68,181548,533,3,1,2765.765000,-3718.734000,274.316700,4.807982,0.000000,0.000000,-0.672515,0.740084,0,0,1,15354), + (@OGUID2+69,181546,533,3,1,2761.821000,-3711.915000,274.314800,3.961473,0.000000,0.000000,-0.917145,0.398554,0,0,1,15354), + (@OGUID2+70,181550,533,3,1,2765.327000,-3728.606000,274.314800,6.217947,0.000000,0.000000,-0.032614,0.999468,0,0,1,15354), + (@OGUID2+71,181547,533,3,1,2754.189000,-3718.121000,274.316700,5.370356,0.000000,0.000000,-0.440733,0.897638,0,0,1,15354), + (@OGUID2+72,181538,533,3,1,2752.927000,-3706.516000,274.316700,1.047839,0.000000,0.000000,0.500278,0.865865,0,0,1,15354), + (@OGUID2+73,181537,533,3,1,2738.396000,-3703.130000,274.385100,5.746106,0.000000,0.000000,-0.265324,0.964159,0,0,1,15354), + (@OGUID2+74,181539,533,3,1,2746.133000,-3700.192000,274.316700,5.493282,0.000000,0.000000,-0.384764,0.923015,0,0,1,15354), + (@OGUID2+75,181549,533,3,1,2776.160000,-3721.793000,274.387000,3.937367,0.000000,0.000000,-0.921882,0.387472,0,0,1,15354); + + + +-- ======= -- +-- Loatheb -- +-- ======= -- +-- Get rid of the superfluous aurascript for a dummy that's just there to make him talk +DELETE FROM `spell_script_names` WHERE `scriptname`="spell_loatheb_necrotic_aura_warning"; + +-- ======== -- +-- Thaddius -- +-- ======== -- +-- Move UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE (thaddius' base state) to creature_template instead of applying it in script +UPDATE `creature_template` SET `unit_flags`=33554688 WHERE `entry`=15928; +-- Move inactive aura to creature_template_addon +DELETE FROM `creature_template_addon` WHERE entry = 15928; +INSERT INTO `creature_template_addon` (`entry`,`auras`) VALUES (15928,"28160"); + +-- ==================== -- +-- Instructor Razuvious -- +-- ==================== -- +-- Razuvious has been informed that Rubik's Cubes become noticably easier to solve if you buy six-colored ones. +-- Thus, he will no longer take out his frustration on raid groups by throwing unsolved two-colored variants at them. +UPDATE `creature_equip_template` SET `itemid3`=29010 WHERE `creatureid`=16061; +DELETE FROM `spell_custom_attr` WHERE `entry`=55550; +INSERT INTO `spell_custom_attr` (`entry`,`attributes`) VALUES +(55550,524288); +-- Also, give his understudies actual weaponry. The poor sods. +DELETE FROM `creature_equip_template` WHERE `CreatureID`=16803; +INSERT INTO `creature_equip_template` (`CreatureID`,`ItemID1`,`ItemID2`,`VerifiedBuild`) VALUES +(16803,2180,23356,"15354"); + +-- ================= -- +-- The Four Horsemen -- +-- ================= -- +-- Wanna hear something fun? +-- On the current core, you can shackle, daze, stun (and some others) Baron Rivendare. +-- Yes, only Baron Rivendare. The other Horsemen are fine. Why? I have no idea. +-- Fixing that. +UPDATE `creature_template` SET `mechanic_immune_mask`=617299803 WHERE `entry` in (16063,16064,16065,30549); + +-- ========= -- +-- Sapphiron -- +-- ========= -- +DELETE FROM `spell_script_names` WHERE `spell_id` in (24780,28522,28524,28560); +INSERT INTO `spell_script_names` (`spell_id`,`scriptname`) VALUES +(24780,"spell_sapphiron_change_blizzard_target"), -- Periodic aura on the Blizzard npc that handles target switches +(28522,"spell_sapphiron_icebolt"), -- AuraScript for spawning ice block GO once the player has stopped moving +(28524,"spell_sapphiron_frost_breath"), -- We can't get rid of the LoS emulation "hack" on frost breath targeting (yet!), but at least moving it to a spellscript... +(28560,"spell_sapphiron_summon_blizzard"); -- Blizzard is now properly summoned! Yay! +-- DB target position for the anti-cheese frost explosion +DELETE FROM `spell_target_position` WHERE `ID`=29318; +INSERT INTO `spell_target_position` (`ID`,`EffectIndex`,`MapID`,`PositionX`,`PositionY`,`PositionZ`,`VerifiedBuild`) VALUES +(29318,0,533,3493.45,-5375.38,138.168,"15595"); +-- Wing Buffet trigger NPC +UPDATE `creature_template` SET `unit_flags`=33554944,`unit_flags2`=2048,`flags_extra`=128,`spell1`=29328,`BaseAttackTime`=1000,`ScriptName`="trigger_periodic" WHERE `entry`=17025; +-- Blizzard bunny NPC +UPDATE `creature_template` SET `speed_run`=0.42857142,`BaseAttackTime`=3000,`InhabitType`=1 WHERE `entry`=16474; +DELETE FROM `creature_template_addon` WHERE `entry`=16474; +INSERT INTO `creature_template_addon` (`entry`,`auras`) VALUES (16474,"24780"); +-- Spawn GO is now spawned by DB +DELETE FROM `gameobject` WHERE `guid` between @OGUID+0 and @OGUID+0; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`VerifiedBuild`) VALUES +(@OGUID+0, 181356, 533, 3, 1, 3522.565, -5236.76, 137.6257, 4.485497, 0, 0, -0.782608, 0.6225148,0,0); +UPDATE `gameobject_template` SET `ScriptName`="go_sapphiron_birth" WHERE `entry`=181356; +-- Turn off interactivity on ice blocks +UPDATE `gameobject_template` SET `type`=5,`data2`=0 WHERE `entry`=181247; +-- Text cleanup +UPDATE `creature_text` SET `language`=0, `emote`=0, `textrange`=3 WHERE `entry`=15989; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_24_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_24_00_world_335.sql new file mode 100644 index 00000000000..4d69d8fd3f2 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_24_00_world_335.sql @@ -0,0 +1,9 @@ +-- +UPDATE `creature` SET `MovementType`=0 WHERE `guid` IN (46414, 46416); +UPDATE `creature_addon` SET `path_id`=0 WHERE `guid` IN (46414, 46416); +DELETE FROM `waypoint_data` WHERE `id` IN (464140, 464160); +DELETE FROM `creature_formations` WHERE `leaderGUID`=46394; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(46394, 46394, 0, 0, 2, 0, 0), +(46394, 46414, 4, 260, 2, 1, 5), +(46394, 46416, 4, 100, 2, 1, 5); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_24_01_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_24_01_world_335.sql new file mode 100644 index 00000000000..01d7857519e --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_24_01_world_335.sql @@ -0,0 +1,9 @@ +-- +UPDATE `quest_template_addon` SET `AllowableClasses`=1 WHERE `id`=8316; +UPDATE `quest_template_addon` SET `AllowableClasses`=2 WHERE `id`=8376; +UPDATE `quest_template_addon` SET `AllowableClasses`=4 WHERE `id`=8377; +UPDATE `quest_template_addon` SET `AllowableClasses`=8 WHERE `id`=8378; +UPDATE `quest_template_addon` SET `AllowableClasses`=16 WHERE `id`=8379; +UPDATE `quest_template_addon` SET `AllowableClasses`=64 WHERE `id`=8380; +UPDATE `quest_template_addon` SET `AllowableClasses`=384 WHERE `id`=8381; +UPDATE `quest_template_addon` SET `AllowableClasses`=1024 WHERE `id`=8382; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_24_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_24_02_world.sql new file mode 100644 index 00000000000..199582eb4a0 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_24_02_world.sql @@ -0,0 +1,4 @@ +UPDATE `creature` SET `unit_flags`=832 WHERE `guid`IN(57890,57891) AND `id`=16831; +UPDATE `creature` SET `unit_flags`=33536 WHERE `guid`IN(57492) AND `id`=16580; +UPDATE `creature` SET `unit_flags`=768 WHERE `guid`IN(57542,57543) AND `id`=16582; +UPDATE `creature` SET `unit_flags`=768 WHERE `guid`IN(58137) AND `id`=16864; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_26_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_26_00_world.sql new file mode 100644 index 00000000000..58a42dc214d --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_26_00_world.sql @@ -0,0 +1,516 @@ +-- Fix moving phantom guest who should be sitting. +UPDATE `creature` SET `MovementType`=0 AND `spawndist`=0, `position_x`=-10997.400391, `position_y`=-1893.040039, `orientation`=3.572645 WHERE `guid`=135230; +UPDATE `creature_addon` SET `bytes1`=1, `bytes2`=5 WHERE `guid`=135230; + +SET @NPC := 135151; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10988.13,`position_y`=-2019.135,`position_z`=80.22357 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10988.13,-2019.135,80.22357,0,0,0,0,100,0), +(@PATH,2,-10987.89,-2011.348,80.22346,0,0,0,0,100,0), +(@PATH,3,-10984.39,-2008.848,80.22346,0,0,0,0,100,0), +(@PATH,4,-10981.26,-2006.71,80.22307,0,0,0,0,100,0), +(@PATH,5,-10972.16,-2002.439,80.22302,0,0,0,0,100,0), +(@PATH,6,-10979.17,-1997.218,80.22329,0,0,0,0,100,0), +(@PATH,7,-10980.42,-1997.218,80.22329,0,0,0,0,100,0), +(@PATH,8,-10981.42,-1997.218,80.22329,0,0,0,0,100,0), +(@PATH,9,-10985.26,-1997.161,80.22356,0,0,0,0,100,0), +(@PATH,10,-10984.12,-1987.489,80.22325,0,0,0,0,100,0), +(@PATH,11,-10979.12,-1986.239,80.22325,0,0,0,0,100,0), +(@PATH,12,-10973.73,-1984.487,80.22291,0,0,0,0,100,0), +(@PATH,13,-10967.48,-1974.487,80.22291,0,0,0,0,100,0), +(@PATH,14,-10966.55,-1973.238,80.22318,0,0,0,0,100,0), +(@PATH,15,-10962.55,-1970.488,80.22318,0,0,0,0,100,0), +(@PATH,16,-10957.55,-1966.988,80.22318,0,0,0,0,100,0), +(@PATH,17,-10955.99,-1967.212,80.2233,0,0,0,0,100,0), +(@PATH,18,-10952.45,-1968.359,80.22365,0,0,0,0,100,0), +(@PATH,19,-10951.29,-1984.542,80.22362,0,0,0,0,100,0), +(@PATH,20,-10953.64,-1990.575,80.22345,0,0,0,0,100,0), +(@PATH,21,-10954.39,-1991.575,80.22345,0,0,0,0,100,0), +(@PATH,22,-10956.89,-1995.075,80.22345,0,0,0,0,100,0), +(@PATH,23,-10961.48,-2000.67,80.2235,0,0,0,0,100,0), +(@PATH,24,-10961.23,-2004.42,80.2235,0,0,0,0,100,0), +(@PATH,25,-10961.32,-2013.403,80.22313,0,0,0,0,100,0), +(@PATH,26,-10964.57,-2015.653,80.22313,0,0,0,0,100,0), +(@PATH,27,-10972.57,-2021.653,80.22313,0,0,0,0,100,0), +(@PATH,28,-10974.32,-2022.653,80.22313,0,0,0,0,100,0), +(@PATH,29,-10976.85,-2024.267,80.22278,0,0,0,0,100,0), +(@PATH,30,-10984.28,-2022.546,80.22318,0,0,0,0,100,0), +(@PATH,31,-10986.03,-2021.296,80.22318,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00021939B3 .go -10988.13 -2019.135 80.22357 + +SET @NPC := 135153; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-11067.45,`position_y`=-1954.224,`position_z`=77.52905 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11067.45,-1954.224,77.52905,0,0,0,0,100,0), +(@PATH,2,-11066.2,-1960.974,77.52905,0,0,0,0,100,0), +(@PATH,3,-11065.75,-1963.135,77.51662,0,0,0,0,100,0), +(@PATH,4,-11065.75,-1967.135,77.51662,0,0,0,0,100,0), +(@PATH,5,-11065.79,-1972.166,77.51814,0,0,0,0,100,0), +(@PATH,6,-11066.38,-1980.533,77.51814,0,0,0,0,100,0), +(@PATH,7,-11066.62,-1984.77,77.51814,0,0,0,0,100,0), +(@PATH,8,-11069.65,-1987.687,77.51814,0,0,0,0,100,0), +(@PATH,9,-11070.65,-1989.187,77.51814,0,0,0,0,100,0), +(@PATH,10,-11071.15,-1989.937,77.51814,0,0,0,0,100,0), +(@PATH,11,-11070.94,-1998.072,77.51814,0,0,0,0,100,0), +(@PATH,12,-11070.44,-1998.822,77.51814,0,0,0,0,100,0), +(@PATH,13,-11068.2,-2002.879,77.51814,0,0,0,0,100,0), +(@PATH,14,-11065.7,-2003.629,77.51814,0,0,0,0,100,0), +(@PATH,15,-11063.57,-2004.327,77.51814,0,0,0,0,100,0), +(@PATH,16,-11061.32,-2005.077,77.51814,0,0,0,0,100,0), +(@PATH,17,-11055.32,-2003.327,77.51814,0,0,0,0,100,0), +(@PATH,18,-11054.66,-2002.821,77.55538,0,0,0,0,100,0), +(@PATH,19,-11054.31,-1995.887,77.51814,0,0,0,0,100,0), +(@PATH,20,-11055.06,-1993.137,77.51814,0,0,0,0,100,0), +(@PATH,21,-11055.91,-1986.87,77.51814,0,0,0,0,100,0), +(@PATH,22,-11054.91,-1981.87,77.51814,0,0,0,0,100,0), +(@PATH,23,-11054.66,-1978.87,77.51814,0,0,0,0,100,0), +(@PATH,24,-11054.28,-1978.515,77.51814,0,0,0,0,100,0), +(@PATH,25,-11054.03,-1977.265,77.51814,0,0,0,0,100,0), +(@PATH,26,-11053.78,-1974.765,77.51814,0,0,0,0,100,0), +(@PATH,27,-11051.89,-1965.272,77.51814,0,0,0,0,100,0), +(@PATH,28,-11048.71,-1950.098,77.51814,0,0,0,0,100,0), +(@PATH,29,-11048.46,-1946.348,77.51814,0,0,0,0,100,0), +(@PATH,30,-11047.88,-1941.905,77.51763,0,0,0,0,100,0), +(@PATH,31,-11047.38,-1933.655,77.51763,0,0,0,0,100,0), +(@PATH,32,-11047.21,-1931.985,77.51714,0,0,0,0,100,0), +(@PATH,33,-11047.59,-1921.692,77.51558,0,0,0,0,100,0), +(@PATH,34,-11057.2,-1924.383,77.51465,0,0,0,0,100,0), +(@PATH,35,-11058.45,-1924.383,77.51465,0,0,0,0,100,0), +(@PATH,36,-11063.45,-1924.133,77.51465,0,0,0,0,100,0), +(@PATH,37,-11068.15,-1924.406,77.51405,0,0,0,0,100,0), +(@PATH,38,-11067.4,-1927.406,77.51405,0,0,0,0,100,0), +(@PATH,39,-11067.21,-1928.737,77.51527,0,0,0,0,100,0), +(@PATH,40,-11066.71,-1930.737,77.51527,0,0,0,0,100,0), +(@PATH,41,-11067.95,-1936.832,77.515,0,0,0,0,100,0), +(@PATH,42,-11068.2,-1939.332,77.515,0,0,0,0,100,0), +(@PATH,43,-11068.68,-1942.693,77.51746,0,0,0,0,100,0), +(@PATH,44,-11068.93,-1945.193,77.51746,0,0,0,0,100,0), +(@PATH,45,-11068.48,-1949.942,77.51735,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00029939B3 .go -11067.45 -1954.224 77.52905 + +SET @NPC := 135160; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10901.4,`position_y`=-1937.891,`position_z`=92.465 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10901.4,-1937.891,92.465,0,0,0,0,100,0), +(@PATH,2,-10900.29,-1929.272,92.4336,0,0,0,0,100,0), +(@PATH,3,-10901.91,-1923.966,92.44674,0,0,0,0,100,0), +(@PATH,4,-10929.68,-1920.51,94.00494,0,0,0,0,100,0), +(@PATH,5,-10931.06,-1919.155,94.07338,0,0,0,0,100,0), +(@PATH,6,-10943.3,-1903.568,94.07179,0,0,0,0,100,0), +(@PATH,7,-10944.89,-1920.322,94.07281,0,0,0,0,100,0), +(@PATH,8,-10942.7,-1925.781,94.07328,0,0,0,0,100,0), +(@PATH,9,-10938.01,-1929.625,94.00285,0,0,0,0,100,0), +(@PATH,10,-10916.58,-1931.924,92.45416,0,0,0,0,100,0), +(@PATH,11,-10913.29,-1936.26,92.45316,0,0,0,0,100,0), +(@PATH,12,-10914.17,-1940.8,92.45174,0,0,0,0,100,0), +(@PATH,13,-10916.33,-1945.966,92.44943,0,0,0,0,100,0), +(@PATH,14,-10918.42,-1951.383,92.44786,0,0,0,0,100,0), +(@PATH,15,-10915.9,-1954.492,92.43726,0,0,0,0,100,0), +(@PATH,16,-10918.41,-1959.593,92.43956,0,0,0,0,100,0), +(@PATH,17,-10925.46,-1968.512,92.43243,0,0,0,0,100,0), +(@PATH,18,-10929.36,-1971.48,92.43213,0,0,0,0,100,0), +(@PATH,19,-10930.33,-1974.389,92.43208,0,0,0,0,100,0), +(@PATH,20,-10921.77,-1991.525,92.43311,0,0,0,0,100,0), +(@PATH,21,-10917.44,-1995.525,92.43374,0,0,0,0,100,0), +(@PATH,22,-10909.94,-1997.982,92.43427,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00031939B3 .go -10901.4 -1937.891 92.465 + +SET @NPC := 135165; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10939.02,`position_y`=-1978.883,`position_z`=93.82455 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10939.02,-1978.883,93.82455,0,0,0,0,100,0), +(@PATH,2,-10937.05,-1980.987,94.02183,0,0,0,0,100,0), +(@PATH,3,-10936.1,-1981.984,93.75357,0,0,0,0,100,0), +(@PATH,4,-10935.1,-1982.984,93.00357,0,0,0,0,100,0), +(@PATH,5,-10933.3,-1984.661,92.40492,0,0,0,0,100,0), +(@PATH,6,-10931.4,-1988.728,92.43253,0,0,0,0,100,0), +(@PATH,7,-10929.84,-1993.005,92.43249,0,0,0,0,100,0), +(@PATH,8,-10929.33,-1998.021,92.43246,0,0,0,0,100,0), +(@PATH,9,-10927.59,-1998.024,92.4326,0,0,0,0,100,0), +(@PATH,10,-10926.84,-1997.024,92.4326,0,0,0,0,100,0), +(@PATH,11,-10923.82,-1993.655,92.43284,0,0,0,0,100,0), +(@PATH,12,-10920.28,-1992.615,92.43314,0,0,0,0,100,0), +(@PATH,13,-10916.69,-1991.384,92.43354,0,0,0,0,100,0), +(@PATH,14,-10912.31,-1989.809,92.43417,0,0,0,0,100,0), +(@PATH,15,-10907.22,-1987.487,92.43446,0,0,0,0,100,0), +(@PATH,16,-10907.61,-1983.417,92.43436,0,0,0,0,100,0), +(@PATH,17,-10911.33,-1980.017,92.43408,0,0,0,0,100,0), +(@PATH,18,-10913.89,-1977.515,92.43388,0,0,0,0,100,0), +(@PATH,19,-10915.35,-1974.443,92.43365,0,0,0,0,100,0), +(@PATH,20,-10917.08,-1969.858,92.43343,0,0,0,0,100,0), +(@PATH,21,-10918.56,-1962.168,92.43033,0,0,0,0,100,0), +(@PATH,22,-10917.81,-1960.168,92.43033,0,0,0,0,100,0), +(@PATH,23,-10917.31,-1957.168,92.43033,0,0,0,0,100,0), +(@PATH,24,-10916.8,-1956.043,92.44185,0,0,0,0,100,0), +(@PATH,25,-10913.85,-1945.233,92.44743,0,0,0,0,100,0), +(@PATH,26,-10913.63,-1940.582,92.45272,0,0,0,0,100,0), +(@PATH,27,-10913.35,-1935.01,92.45383,0,0,0,0,100,0), +(@PATH,28,-10917.51,-1933.436,92.45338,0,0,0,0,100,0), +(@PATH,29,-10922.4,-1936.293,92.4428,0,0,0,0,100,0), +(@PATH,30,-10925.65,-1937.793,92.4428,0,0,0,0,100,0), +(@PATH,31,-10926.53,-1938.423,92.52744,0,0,0,0,100,0), +(@PATH,32,-10929.78,-1939.673,92.52744,0,0,0,0,100,0), +(@PATH,33,-10930.73,-1940.091,93.50311,0,0,0,0,100,0), +(@PATH,34,-10930.98,-1938.091,93.75311,0,0,0,0,100,0), +(@PATH,35,-10930.98,-1935.091,94.00311,0,0,0,0,100,0), +(@PATH,36,-10932.33,-1925.829,94.07312,0,0,0,0,100,0), +(@PATH,37,-10934.22,-1919.477,94.07236,0,0,0,0,100,0), +(@PATH,38,-10936.83,-1914.139,94.07259,0,0,0,0,100,0), +(@PATH,39,-10940.94,-1913.56,94.07243,0,0,0,0,100,0), +(@PATH,40,-10943.83,-1916.909,94.07263,0,0,0,0,100,0), +(@PATH,41,-10945.09,-1924.069,94.07304,0,0,0,0,100,0), +(@PATH,42,-10945.81,-1929.354,94.07185,0,0,0,0,100,0), +(@PATH,43,-10946.08,-1934.29,94.07332,0,0,0,0,100,0), +(@PATH,44,-10945.36,-1938.052,94.06967,0,0,0,0,100,0), +(@PATH,45,-10944.86,-1940.302,94.06967,0,0,0,0,100,0), +(@PATH,46,-10943.61,-1941.302,94.06967,0,0,0,0,100,0), +(@PATH,47,-10942.36,-1942.552,94.06967,0,0,0,0,100,0), +(@PATH,48,-10941.18,-1943.745,94.07132,0,0,0,0,100,0), +(@PATH,49,-10938.37,-1950.035,94.06915,0,0,0,0,100,0), +(@PATH,50,-10938.62,-1951.785,94.06915,0,0,0,0,100,0), +(@PATH,51,-10938.97,-1960.17,94.07024,0,0,0,0,100,0), +(@PATH,52,-10939.53,-1967.704,94.07249,0,0,0,0,100,0), +(@PATH,53,-10939.97,-1974.155,94.07382,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00039939B3 .go -10939.02 -1978.883 93.82455 + +SET @NPC := 135162; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10946.03,`position_y`=-2018.407,`position_z`=80.01561 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10946.03,-2018.407,80.01561,0,0,0,0,100,0), +(@PATH,2,-10938.18,-2019.209,80.42243,0,0,0,0,100,0), +(@PATH,3,-10936.18,-2020.459,80.42243,0,0,0,0,100,0), +(@PATH,4,-10937.69,-2035.067,86.25978,0,0,0,0,100,0), +(@PATH,5,-10937,-2040.216,86.32371,0,0,0,0,100,0), +(@PATH,6,-10933.3,-2043.247,86.32394,0,0,0,0,100,0), +(@PATH,7,-10928.26,-2043.84,86.32447,0,0,0,0,100,0), +(@PATH,8,-10923.09,-2042.638,86.32227,0,0,0,0,100,0), +(@PATH,9,-10920.8,-2037.279,86.56629,0,0,0,0,100,0), +(@PATH,10,-10916.75,-2002.508,92.43436,0,0,0,0,100,0), +(@PATH,11,-10911.1,-2000.068,92.43423,0,0,0,0,100,0), +(@PATH,12,-10907.79,-1994.801,92.43451,0,0,0,0,100,0), +(@PATH,13,-10903.67,-1963.204,92.42834,0,0,0,0,100,0), +(@PATH,14,-10888.27,-1964.728,92.42189,0,0,0,0,100,0), +(@PATH,15,-10903.75,-1963.212,92.4287,0,0,0,0,100,0), +(@PATH,16,-10907.83,-1994.959,92.43437,0,0,0,0,100,0), +(@PATH,17,-10911.13,-1999.935,92.43394,0,0,0,0,100,0), +(@PATH,18,-10916.75,-2002.692,92.43467,0,0,0,0,100,0), +(@PATH,19,-10920.86,-2037.652,86.46838,0,0,0,0,100,0), +(@PATH,20,-10923.34,-2042.72,86.32289,0,0,0,0,100,0), +(@PATH,21,-10927.59,-2043.72,86.32289,0,0,0,0,100,0), +(@PATH,22,-10933.56,-2043.322,86.32355,0,0,0,0,100,0), +(@PATH,23,-10937.03,-2040.081,86.32348,0,0,0,0,100,0), +(@PATH,24,-10937.61,-2035.351,86.17421,0,0,0,0,100,0), +(@PATH,25,-10935.98,-2020.486,80.32269,0,0,0,0,100,0), +(@PATH,26,-10938.22,-2019.048,80.224,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00041939B3 .go -10946.03 -2018.407 80.01561 + +SET @NPC := 135163; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10955.42,`position_y`=-1963.914,`position_z`=80.2235 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10955.42,-1963.914,80.2235,0,0,0,0,100,0), +(@PATH,2,-10954.92,-1963.914,80.2235,0,0,0,0,100,0), +(@PATH,3,-10953.17,-1964.164,80.2235,0,0,0,0,100,0), +(@PATH,4,-10951.67,-1964.164,80.2235,0,0,0,0,100,0), +(@PATH,5,-10948.86,-1964.864,80.22345,0,0,0,0,100,0), +(@PATH,6,-10950.26,-1979.561,80.22365,0,0,0,0,100,0), +(@PATH,7,-10951.19,-1990.361,80.22372,0,0,0,0,100,0), +(@PATH,8,-10951.69,-1996.111,80.22372,0,0,0,0,100,0), +(@PATH,9,-10952.35,-2001.243,80.22384,0,0,0,0,100,0), +(@PATH,10,-10952.85,-2007.493,80.22384,0,0,0,0,100,0), +(@PATH,11,-10953.4,-2011.886,80.22395,0,0,0,0,100,0), +(@PATH,12,-10954.68,-2022.679,80.224,0,0,0,0,100,0), +(@PATH,13,-10954.93,-2024.179,80.224,0,0,0,0,100,0), +(@PATH,14,-10955.48,-2028.294,80.22382,0,0,0,0,100,0), +(@PATH,15,-10957.73,-2030.747,80.22321,0,0,0,0,100,0), +(@PATH,16,-10962.98,-2030.497,80.22321,0,0,0,0,100,0), +(@PATH,17,-10972.18,-2030.008,80.22282,0,0,0,0,100,0), +(@PATH,18,-10983.17,-2027.766,80.22281,0,0,0,0,100,0), +(@PATH,19,-10988.94,-2024.042,80.22321,0,0,0,0,100,0), +(@PATH,20,-10988.37,-2013.056,80.22353,0,0,0,0,100,0), +(@PATH,21,-10988.54,-2013.409,79.97359,0,0,0,0,100,0), +(@PATH,22,-10988.46,-2013.481,80.22325,0,0,0,0,100,0), +(@PATH,23,-10988.71,-2023.731,80.22325,0,0,0,0,100,0), +(@PATH,24,-10988.75,-2023.836,80.22316,0,0,0,0,100,0), +(@PATH,25,-10988.75,-2024.336,80.22316,0,0,0,0,100,0), +(@PATH,26,-10982.8,-2028.037,80.22272,0,0,0,0,100,0), +(@PATH,27,-10971.73,-2030.244,80.22316,0,0,0,0,100,0), +(@PATH,28,-10962.98,-2030.494,80.22316,0,0,0,0,100,0), +(@PATH,29,-10957.72,-2030.729,80.22354,0,0,0,0,100,0), +(@PATH,30,-10955.97,-2028.979,80.22354,0,0,0,0,100,0), +(@PATH,31,-10955.48,-2028.02,80.22393,0,0,0,0,100,0), +(@PATH,32,-10954.98,-2024.27,80.22393,0,0,0,0,100,0), +(@PATH,33,-10954.72,-2023.956,80.22394,0,0,0,0,100,0), +(@PATH,34,-10954.47,-2022.456,80.22394,0,0,0,0,100,0), +(@PATH,35,-10953.16,-2011.596,80.22389,0,0,0,0,100,0), +(@PATH,36,-10953.16,-2007.846,80.22389,0,0,0,0,100,0), +(@PATH,37,-10952.21,-2001.05,80.22374,0,0,0,0,100,0), +(@PATH,38,-10951.96,-1996.3,80.22374,0,0,0,0,100,0), +(@PATH,39,-10951.04,-1990.129,80.22367,0,0,0,0,100,0), +(@PATH,40,-10949.86,-1979.275,80.22361,0,0,0,0,100,0), +(@PATH,41,-10948.86,-1965.775,80.22361,0,0,0,0,100,0), +(@PATH,42,-10948.85,-1965.412,80.22345,0,0,0,0,100,0), +(@PATH,43,-10951.85,-1964.412,80.22345,0,0,0,0,100,0), +(@PATH,44,-10953.1,-1964.162,80.22345,0,0,0,0,100,0), +(@PATH,45,-10955.14,-1963.792,80.22339,0,0,0,0,100,0), +(@PATH,46,-10960.14,-1963.292,80.22339,0,0,0,0,100,0), +(@PATH,47,-10965.23,-1962.463,80.2235,0,0,0,0,100,0), +(@PATH,48,-10965.14,-1962.785,79.97355,0,0,0,0,100,0), +(@PATH,49,-10960.49,-1963.204,80.22346,0,0,0,0,100,0), +(@PATH,50,-10955.74,-1963.704,80.22346,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00049939B3 .go -10955.42 -1963.914 80.2235 + +SET @NPC := 135164; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10966.42,`position_y`=-1982.83,`position_z`=80.22289 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10966.42,-1982.83,80.22289,0,0,0,0,100,0), +(@PATH,2,-10966.24,-1994.689,80.22308,0,0,0,0,100,0), +(@PATH,3,-10964.49,-1996.189,80.22308,0,0,0,0,100,0), +(@PATH,4,-10960.91,-2000.212,80.22343,0,0,0,0,100,0), +(@PATH,5,-10960.91,-2004.462,80.22343,0,0,0,0,100,0), +(@PATH,6,-10960.92,-2011.736,80.22325,0,0,0,0,100,0), +(@PATH,7,-10964.42,-2015.986,80.22325,0,0,0,0,100,0), +(@PATH,8,-10970.53,-2022.625,80.22308,0,0,0,0,100,0), +(@PATH,9,-10972.53,-2020.375,80.22308,0,0,0,0,100,0), +(@PATH,10,-10972.61,-2018.252,80.22304,0,0,0,0,100,0), +(@PATH,11,-10977.02,-2015.768,80.22273,0,0,0,0,100,0), +(@PATH,12,-10973.18,-2002.99,80.22287,0,0,0,0,100,0), +(@PATH,13,-10975.69,-1994.738,80.22289,0,0,0,0,100,0), +(@PATH,14,-10973.55,-1987.507,80.22292,0,0,0,0,100,0), +(@PATH,15,-10973.07,-1975.399,80.22276,0,0,0,0,100,0), +(@PATH,16,-10967.98,-1974.459,80.22279,0,0,0,0,100,0), +(@PATH,17,-10967.48,-1973.709,80.22279,0,0,0,0,100,0), +(@PATH,18,-10964.03,-1970.752,80.22292,0,0,0,0,100,0), +(@PATH,19,-10959.04,-1970.99,80.22316,0,0,0,0,100,0), +(@PATH,20,-10957.93,-1975.517,80.22319,0,0,0,0,100,0), +(@PATH,21,-10959.64,-1979.725,80.22298,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00051939B3 .go -10966.42 -1982.83 80.22289 + +SET @NPC := 135152; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10993.07,`position_y`=-2027.777,`position_z`=79.97364 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10993.07,-2027.777,79.97364,0,0,0,0,100,0), +(@PATH,2,-10954.54,-2031.941,80.22369,0,0,0,0,100,0), +(@PATH,3,-10945.95,-1963.57,80.2234,0,0,0,0,100,0), +(@PATH,4,-10964.31,-1961.222,80.22327,0,0,0,0,100,0), +(@PATH,5,-10945.95,-1963.57,80.2234,0,0,0,0,100,0), +(@PATH,6,-10954.54,-2031.941,80.22369,0,0,0,0,100,0), +(@PATH,7,-10993.07,-2027.777,79.97364,0,0,0,0,100,0), +(@PATH,8,-10990.63,-2007.031,80.22373,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00059939B3 .go -10993.07 -2027.777 79.97364 + +SET @NPC := 135161; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10940.92,`position_y`=-1998.817,`position_z`=93.95387 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10936.96,-1999.992,92.54521,0,0,0,0,100,0), +(@PATH,2,-10940.92,-1998.817,93.95387,0,0,0,0,100,0), +(@PATH,3,-10946.22,-2042.642,94.07538,0,0,0,0,100,0), +(@PATH,4,-11002.46,-2037.389,94.07399,0,0,0,0,100,0), +(@PATH,5,-10997.76,-1988.969,94.08043,0,0,0,0,100,0), +(@PATH,6,-11001.04,-1986.668,94.07949,0,0,0,0,100,0), +(@PATH,7,-11019.84,-1984.078,94.08058,0,0,0,0,100,0), +(@PATH,8,-11021.94,-1979.799,94.07922,0,0,0,0,100,0), +(@PATH,9,-11021.18,-1971.51,94.07477,0,0,0,0,100,0), +(@PATH,10,-11021.94,-1979.799,94.07922,0,0,0,0,100,0), +(@PATH,11,-11019.84,-1984.078,94.08058,0,0,0,0,100,0), +(@PATH,12,-11001.04,-1986.668,94.07949,0,0,0,0,100,0), +(@PATH,13,-10997.76,-1988.969,94.08043,0,0,0,0,100,0), +(@PATH,14,-11002.46,-2037.389,94.07399,0,0,0,0,100,0), +(@PATH,15,-10946.22,-2042.642,94.07538,0,0,0,0,100,0), +(@PATH,16,-10940.92,-1998.817,93.95387,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00061939B3 .go -10936.96 -1999.992 92.54521 + +SET @NPC := 135166; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-11018.67,`position_y`=-1948.95,`position_z`=94.11409 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11018.67,-1948.95,94.11409,0,0,0,0,100,0), +(@PATH,2,-11019.33,-1955.598,94.06949,0,0,0,0,100,0), +(@PATH,3,-11017.58,-1958.348,94.06949,0,0,0,0,100,0), +(@PATH,4,-11015.82,-1960.591,94.07437,0,0,0,0,100,0), +(@PATH,5,-11010.95,-1961.954,94.07813,0,0,0,0,100,0), +(@PATH,6,-11005.31,-1962.993,94.07982,0,0,0,0,100,0), +(@PATH,7,-11000.51,-1962.511,94.08182,0,0,0,0,100,0), +(@PATH,8,-10997.26,-1960.511,94.08182,0,0,0,0,100,0), +(@PATH,9,-10997.06,-1960.231,94.07545,0,0,0,0,100,0), +(@PATH,10,-10993.45,-1956.026,94.0743,0,0,0,0,100,0), +(@PATH,11,-10992.71,-1952.289,94.06744,0,0,0,0,100,0), +(@PATH,12,-10992.46,-1951.039,94.06744,0,0,0,0,100,0), +(@PATH,13,-10989.33,-1951.245,94.06941,0,0,0,0,100,0), +(@PATH,14,-10989.58,-1952.745,94.06941,0,0,0,0,100,0), +(@PATH,15,-10990.44,-1956.788,94.07174,0,0,0,0,100,0), +(@PATH,16,-10992.64,-1960.311,94.07793,0,0,0,0,100,0), +(@PATH,17,-10999.8,-1964.796,94.08316,0,0,0,0,100,0), +(@PATH,18,-11003.42,-1967.318,94.08348,0,0,0,0,100,0), +(@PATH,19,-11005.92,-1969.318,94.08348,0,0,0,0,100,0), +(@PATH,20,-11009.72,-1972.45,94.08435,0,0,0,0,100,0), +(@PATH,21,-11006.94,-1976.569,94.08415,0,0,0,0,100,0), +(@PATH,22,-11005.19,-1978.569,94.08415,0,0,0,0,100,0), +(@PATH,23,-11002.7,-1981.706,94.08524,0,0,0,0,100,0), +(@PATH,24,-10996.71,-1985.477,94.08297,0,0,0,0,100,0), +(@PATH,25,-10993.34,-1986.766,94.08041,0,0,0,0,100,0), +(@PATH,26,-10998.21,-2033.577,94.07561,0,0,0,0,100,0), +(@PATH,27,-10949.22,-2039.019,94.07603,0,0,0,0,100,0), +(@PATH,28,-10941.91,-1976.454,94.07447,0,0,0,0,100,0), +(@PATH,29,-10941.03,-1973.073,94.07249,0,0,0,0,100,0), +(@PATH,30,-10941.03,-1970.573,94.07249,0,0,0,0,100,0), +(@PATH,31,-10938.04,-1944.34,94.0692,0,0,0,0,100,0), +(@PATH,32,-10944.45,-1938.374,94.06937,0,0,0,0,100,0), +(@PATH,33,-10945.51,-1937.203,94.07327,0,0,0,0,100,0), +(@PATH,34,-10942.28,-1905.302,93.82167,0,0,0,0,100,0), +(@PATH,35,-10945.63,-1937.244,94.0717,0,0,0,0,100,0), +(@PATH,36,-10944.63,-1938.244,94.0717,0,0,0,0,100,0), +(@PATH,37,-10938.18,-1944.174,94.06793,0,0,0,0,100,0), +(@PATH,38,-10940.76,-1970.675,94.07205,0,0,0,0,100,0), +(@PATH,39,-10941.05,-1973.169,94.07341,0,0,0,0,100,0), +(@PATH,40,-10942.1,-1976.591,94.07454,0,0,0,0,100,0), +(@PATH,41,-10949.38,-2038.871,94.07526,0,0,0,0,100,0), +(@PATH,42,-10998.12,-2033.78,94.07454,0,0,0,0,100,0), +(@PATH,43,-10993.17,-1986.922,94.08283,0,0,0,0,100,0), +(@PATH,44,-10996.42,-1985.672,94.08283,0,0,0,0,100,0), +(@PATH,45,-11002.46,-1981.708,94.08536,0,0,0,0,100,0), +(@PATH,46,-11005.32,-1978.522,94.08371,0,0,0,0,100,0), +(@PATH,47,-11007.07,-1976.272,94.08371,0,0,0,0,100,0), +(@PATH,48,-11009.86,-1972.258,94.08409,0,0,0,0,100,0), +(@PATH,49,-11006.01,-1968.957,94.08367,0,0,0,0,100,0), +(@PATH,50,-11003.51,-1967.457,94.08367,0,0,0,0,100,0), +(@PATH,51,-10999.68,-1964.603,94.08018,0,0,0,0,100,0), +(@PATH,52,-10992.57,-1960.071,94.07755,0,0,0,0,100,0), +(@PATH,53,-10990.57,-1957.071,94.07755,0,0,0,0,100,0), +(@PATH,54,-10989.64,-1952.785,94.06929,0,0,0,0,100,0), +(@PATH,55,-10989.41,-1951.198,94.06895,0,0,0,0,100,0), +(@PATH,56,-10992.41,-1950.948,94.06895,0,0,0,0,100,0), +(@PATH,57,-10992.66,-1952.448,94.06895,0,0,0,0,100,0), +(@PATH,58,-10993.41,-1956.079,94.07048,0,0,0,0,100,0), +(@PATH,59,-10997.04,-1960.266,94.07538,0,0,0,0,100,0), +(@PATH,60,-11000.84,-1962.545,94.08139,0,0,0,0,100,0), +(@PATH,61,-11005.54,-1962.94,94.07911,0,0,0,0,100,0), +(@PATH,62,-11011.18,-1961.785,94.07573,0,0,0,0,100,0), +(@PATH,63,-11015.9,-1960.729,94.07407,0,0,0,0,100,0), +(@PATH,64,-11017.4,-1958.479,94.07407,0,0,0,0,100,0), +(@PATH,65,-11019.35,-1955.508,94.06929,0,0,0,0,100,0); +-- 0x1C310842801005C00053CE00069939B3 .go -11018.67 -1948.95 94.11409 + +SET @NPC := 135308; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10979.41,`position_y`=-1917.581,`position_z`=79.1259 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10979.41,-1917.581,79.1259,0,0,0,0,100,0), +(@PATH,2,-10998.85,-1915.525,79.12059,0,0,0,0,100,0), +(@PATH,3,-11004.85,-1917.525,79.12059,0,0,0,0,100,0), +(@PATH,4,-11006.42,-1919.255,79.13147,0,0,0,0,100,0), +(@PATH,5,-11009.31,-1923.276,79.13788,0,0,0,0,100,0), +(@PATH,6,-11014.77,-1924.695,79.11803,0,0,0,0,100,0), +(@PATH,7,-11025.74,-1923.575,79.06779,0,0,0,0,100,0), +(@PATH,8,-11039.73,-1922.107,77.51696,0,0,0,0,100,0), +(@PATH,9,-11050.26,-1923.549,77.51479,0,0,0,0,100,0), +(@PATH,10,-11062.01,-1926.049,77.51479,0,0,0,0,100,0), +(@PATH,11,-11068.23,-1927.658,77.51482,0,0,0,0,100,0), +(@PATH,12,-11050.19,-1925.471,77.51665,0,0,0,0,100,0), +(@PATH,13,-11039.85,-1924.404,77.56751,0,0,0,0,100,0), +(@PATH,14,-11025.49,-1925.841,79.11525,0,0,0,0,100,0), +(@PATH,15,-11014.73,-1927.159,79.11803,0,0,0,0,100,0), +(@PATH,16,-11010.48,-1927.909,79.11803,0,0,0,0,100,0), +(@PATH,17,-11008.93,-1928.397,79.11803,0,0,0,0,100,0), +(@PATH,18,-11007.43,-1929.897,79.11803,0,0,0,0,100,0), +(@PATH,19,-11004.79,-1932.291,79.11801,0,0,0,0,100,0), +(@PATH,20,-10995.54,-1934.041,79.11801,0,0,0,0,100,0), +(@PATH,21,-10970.88,-1936.847,79.11803,0,0,0,0,100,0), +(@PATH,22,-10965.63,-1935.597,79.11803,0,0,0,0,100,0), +(@PATH,23,-10963.02,-1932.276,79.11803,0,0,0,0,100,0), +(@PATH,24,-10960.78,-1928.736,79.11803,0,0,0,0,100,0), +(@PATH,25,-10962.28,-1925.236,79.11803,0,0,0,0,100,0), +(@PATH,26,-10963.28,-1922.127,79.1109,0,0,0,0,100,0), +(@PATH,27,-10968.51,-1919.033,79.11447,0,0,0,0,100,0); +-- 0x1C310842801007C00053CE00001939B3 .go -10979.41 -1917.581 79.1259 + +SET @NPC := 135311; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-10967.35,`position_y`=-1910.074,`position_z`=79.13056 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-10967.35,-1910.074,79.13056,0,0,0,0,100,0), +(@PATH,2,-10973.81,-1909.259,79.13441,0,0,0,0,100,0), +(@PATH,3,-10978.96,-1902.012,79.11913,0,0,0,0,100,0), +(@PATH,4,-10993.51,-1900.544,79.10841,0,0,0,0,100,0), +(@PATH,5,-10998.31,-1904.632,79.0873,0,0,0,0,100,0), +(@PATH,6,-11008.63,-1904.277,79.12164,0,0,0,0,100,0), +(@PATH,7,-11016.06,-1902.035,79.11803,0,0,0,0,100,0), +(@PATH,8,-11018.93,-1894.202,79.11803,0,0,0,0,100,0), +(@PATH,9,-11013.55,-1888.369,79.11407,0,0,0,0,100,0), +(@PATH,10,-11005.47,-1887.72,79.09593,0,0,0,0,100,0), +(@PATH,11,-10997.97,-1889.47,79.09593,0,0,0,0,100,0), +(@PATH,12,-10993.66,-1894.292,79.0679,0,0,0,0,100,0), +(@PATH,13,-10993.11,-1896.752,79.08858,0,0,0,0,100,0), +(@PATH,14,-10978.52,-1899.429,79.14062,0,0,0,0,100,0), +(@PATH,15,-10971.52,-1891.436,79.14864,0,0,0,0,100,0), +(@PATH,16,-10968.58,-1890.591,79.14295,0,0,0,0,100,0), +(@PATH,17,-10964.36,-1890.848,79.12196,0,0,0,0,100,0), +(@PATH,18,-10958.21,-1891.544,78.85779,0,0,0,0,100,0), +(@PATH,19,-10953.68,-1895.616,79.11803,0,0,0,0,100,0), +(@PATH,20,-10951.67,-1902.097,79.12449,0,0,0,0,100,0), +(@PATH,21,-10954.11,-1907.472,79.1279,0,0,0,0,100,0), +(@PATH,22,-10957.36,-1910.472,79.1279,0,0,0,0,100,0); +-- 0x1C310842801007C00053CE00009939B3 .go -10967.35 -1910.074 79.13056 + +SET @NPC := 135307; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-11097.81,`position_y`=-1933.661,`position_z`=50.14211 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11097.81,-1933.661,50.14211,0,0,0,0,100,0), +(@PATH,2,-11102.14,-1941.538,50.13525,0,0,0,0,100,0), +(@PATH,3,-11110.07,-1946.739,50.13507,0,0,0,0,100,0), +(@PATH,4,-11116.22,-1949.221,50.13885,0,0,0,0,100,0), +(@PATH,5,-11127.4,-1949.477,50.13752,0,0,0,0,100,0), +(@PATH,6,-11137.96,-1945.1,50.13647,0,0,0,0,100,0), +(@PATH,7,-11127.29,-1949.459,50.13817,0,0,0,0,100,0), +(@PATH,8,-11116.23,-1949.254,50.13683,0,0,0,0,100,0), +(@PATH,9,-11110.07,-1946.739,50.13507,0,0,0,0,100,0), +(@PATH,10,-11102.14,-1941.538,50.13525,0,0,0,0,100,0); +-- 0x1C310842800FC7C00053CE00001939B3 .go -11097.81 -1933.661 50.14211 diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_27_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_27_00_world.sql new file mode 100644 index 00000000000..9421881c88a --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_27_00_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_gen_clear_debuffs'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(34098, 'spell_gen_clear_debuffs'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_28_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_28_00_world.sql new file mode 100644 index 00000000000..b4a7e2d5a36 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_28_00_world.sql @@ -0,0 +1,2 @@ +-- +UPDATE `creature` SET `spawndist`=0 WHERE `guid`=135230; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_28_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_28_01_world.sql new file mode 100644 index 00000000000..b4a24b011b3 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_28_01_world.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName = "npc_pet_gen_baby_blizzard_bear" WHERE entry = 32841; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_03_29_00_world_335.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_29_00_world_335.sql new file mode 100644 index 00000000000..e3851e59c8e --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_03_29_00_world_335.sql @@ -0,0 +1,11 @@ +-- +UPDATE `game_event` SET `start_time`='2016-06-21 00:01:00' WHERE `eventEntry`=1; +UPDATE `game_event` SET `start_time`='2016-12-15 06:00:00' WHERE `eventEntry`=2; +UPDATE `game_event` SET `start_time`='2016-03-27 00:01:00' WHERE `eventEntry`=9; +UPDATE `game_event` SET `start_time`='2016-05-02 00:01:00' WHERE `eventEntry`=10; +UPDATE `game_event` SET `start_time`='2016-09-09 00:01:00' WHERE `eventEntry`=11; +UPDATE `game_event` SET `start_time`='2016-10-18 01:00:00' WHERE `eventEntry`=12; +UPDATE `game_event` SET `start_time`='2016-09-20 00:01:00' WHERE `eventEntry`=24; +UPDATE `game_event` SET `start_time`='2016-11-21 01:00:00' WHERE `eventEntry`=26; +UPDATE `game_event` SET `start_time`='2016-09-19 00:01:00' WHERE `eventEntry`=50; +UPDATE `game_event` SET `start_time`='2016-11-01 01:00:00' WHERE `eventEntry`=51; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_01_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_01_00_world.sql new file mode 100644 index 00000000000..024bbb6fa5a --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_01_00_world.sql @@ -0,0 +1,89 @@ +DELETE FROM `creature_text` WHERE `entry` in(25317,25220,25222); +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `comment`) VALUES +(25317, 0, 0, 'What''s the matter, $c? Think you''re too good to stand in line with the rest of us?', 12, 0, 100, 0, 0, 0, 24758, 'Civilian Recruit to Player'), +(25220, 0, 0, 'Miner.', 12, 7, 100, 66, 0, 0, 24377, 'Civilian Recruit to Generic Quest Trigger - LAB'), +(25220, 0, 1, 'Farmhand, sir.', 12, 7, 100, 66, 0, 0, 24373, 'Civilian Recruit to Generic Quest Trigger - LAB'), +(25220, 0, 2, 'Tailor.', 12, 7, 100, 66, 0, 0, 24374, 'Civilian Recruit to Generic Quest Trigger - LAB'), +(25220, 0, 3, 'Blacksmith.', 12, 7, 100, 66, 0, 0, 24375, 'Civilian Recruit to Generic Quest Trigger - LAB'), +(25220, 0, 4, 'Carpenter.', 12, 7, 100, 66, 0, 0, 24371, 'Civilian Recruit to Generic Quest Trigger - LAB'), +(25220, 0, 5, 'Shipwright.', 12, 7, 100, 66, 0, 0, 24372, 'Civilian Recruit to Generic Quest Trigger - LAB'), +(25220, 0, 6, 'Mason, sir.', 12, 7, 100, 66, 0, 0, 24376, 'Civilian Recruit to Generic Quest Trigger - LAB'), +(25220, 0, 7, 'Cook.', 12, 7, 100, 66, 0, 0, 24378, 'Civilian Recruit to Generic Quest Trigger - LAB'), +(25222, 0, 0, 'What did you do before you came to Northrend, then?', 12, 7, 100, 0, 0, 0, 24386, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 0, 1, 'State your profession.', 12, 7, 100, 0, 0, 0, 24382, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 0, 2, 'Yes, then. What is your trade?', 12, 7, 100, 0, 0, 0, 24383, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 0, 3, 'Your previous line of work, recruit?', 12, 7, 100, 0, 0, 0, 24385, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 0, 4, 'Your profession?', 12, 7, 100, 0, 0, 0, 24384, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 1, 0, 'Yes, you''re well seasoned in your field of work. Report to the civilian liaison at once, we need more like you!', 12, 7, 100, 273, 0, 0, 24361, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 1, 1, 'I thought we had enough in your line of work, but it looks like we have some openings. Report to the civilian liaison.', 12, 7, 100, 273, 0, 0, 24360, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 1, 2, 'I do have some openings in your line of work. Report to the civilian liaison.', 12, 7, 100, 273, 0, 0, 24359, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 1, 3, 'Yeah. We could use some more of you. Report to the civilian liaison for work assignment.', 12, 7, 100, 273, 0, 0, 24358, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 2, 0, 'Not anymore! Here''s your sword. Report to the barracks for duty!', 12, 7, 100, 397, 0, 0, 24363, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 2, 1, 'Afraid not, friend. Here''s your sword and shield. Report to the barracks for duty.', 12, 7, 100, 397, 0, 0, 24365, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 2, 2, 'You''re breaking my heart - I''ve quotas to fill, you know? Can you wield a sword? Off to the barracks.', 12, 7, 100, 397, 0, 0, 24367, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 2, 3, 'With a sword arm like that? I''m afraid we need you in the front lines, my friend. Report to the barracks.', 12, 7, 100, 397, 0, 0, 24366, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 2, 4, 'Looks like we have room for one more... no, my mistake. That''s a seven not a one. Hope you''re good with a sword - report to the barracks.', 12, 7, 100, 397, 0, 0, 24368, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 3, 0, 'Next, please!', 12, 7, 100, 22, 0, 0, 24370, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 3, 1, 'Keep it moving, people.', 12, 7, 100, 22, 0, 0, 24369, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'), +(25222, 3, 2, 'Next!', 12, 7, 100, 22, 0, 0, 24357, 'Recruitment Officer Carven to Generic Quest Trigger - LAB'); + +DELETE FROM `waypoints` WHERE `entry`=25220; +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES +(25220, 1, 2253.644, 5195.469, 11.40062, 'Civilian Recruit'), +(25220, 2, 2254.098, 5196.36, 11.40062, 'Civilian Recruit'), +(25220, 3, 2277.823, 5238.724, 11.45096, 'Civilian Recruit'), +(25220, 4, 2279.217, 5241.407, 11.45096, 'Civilian Recruit'), +(25220, 5, 2280.84, 5244.218, 11.45719, 'Civilian Recruit'), +(25220, 6, 2282.603, 5245.736, 11.36353, 'Civilian Recruit'), +(25220, 7, 2284.867, 5246.299, 11.45096, 'Civilian Recruit'), +(25220, 8, 2287.469, 5245.929, 11.45096, 'Civilian Recruit'), +(25220, 9, 2289.469, 5244.898, 11.45096, 'Civilian Recruit'), +(25220, 10, 2291.772, 5243.933, 11.45096, 'Civilian Recruit'), +(25220, 11, 2294.129, 5242.708, 11.45096, 'Civilian Recruit'), +(25220, 12, 2298.062, 5241.932, 12.3176, 'Civilian Recruit'), +(25220, 13, 2303.019, 5253.306, 11.50584, 'Civilian Recruit'), +(25220, 14, 2308.73, 5256.926, 11.50584, 'Civilian Recruit'), +(25220, 15, 2320.826, 5259.258, 11.25584, 'Civilian Recruit'); + +DELETE FROM `creature` WHERE `guid` IN(108008,108007,108006,108005,108004,108003,108002,108001,108000); + +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`IN(24959,25220,25307); +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`IN(-107575,-107574); +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`IN(25220,25307); +DELETE FROM `smart_scripts` WHERE `source_type`=9 AND `entryorguid`IN(2522000,2522001); + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(-107575, 0, 0, 0, 11, 0, 100, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Generic Quest Trigger - LAB - On Spawn - Set Active'), +(-107575, 0, 1, 0, 1, 0, 100, 0, 0, 0, 22000, 23000, 12, 25220, 8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Generic Quest Trigger - LAB - OOC - Cast Borean Tundra - Valiance Keep Flavor - Summon Recruit'), +(-107574, 0, 1, 0, 1, 0, 100, 0, 0, 0, 22000, 23000, 11, 45307, 8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Generic Quest Trigger - LAB - OOC - Cast Borean Tundra - Valiance Keep Flavor - Queue Global Ping'), +(25307, 0, 0, 0, 19, 0, 100, 0, 11672, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 25317, 0, 0, 0, 0, 0, 0, 'Recruitment Officer Blythe - On Quest Accepted (Enlistment Day) - Say'), +(25220, 0, 0, 1, 54, 0, 100, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Just Summoned - Set Active'), +(25220, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 53, 0, 25220, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Just Summoned - Start WP'), +(25220, 0, 2, 0, 8, 0, 100, 0, 45313, 0, 0, 0, 54, 22000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Spellhit - Anchor Here - Pause WP'), +(25220, 0, 3, 0, 8, 0, 100, 0, 45307, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Spellhit - Borean Tundra - Valiance Keep Flavor - Queue Global Ping - Resume WP'), +(25220, 0, 4, 0, 40, 0, 100, 0, 3, 25220, 0, 0, 11, 45313, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP3 - Cast Anchor Here'), +(25220, 0, 5, 0, 40, 0, 100, 0, 4, 25220, 0, 0, 11, 45313, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP4 - Cast Anchor Here'), +(25220, 0, 6, 0, 40, 0, 100, 0, 5, 25220, 0, 0, 11, 45313, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP5 - Cast Anchor Here'), +(25220, 0, 7, 0, 40, 0, 100, 0, 6, 25220, 0, 0, 11, 45313, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP6 - Cast Anchor Here'), +(25220, 0, 8, 0, 40, 0, 100, 0, 7, 25220, 0, 0, 11, 45313, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP7 - Cast Anchor Here'), +(25220, 0, 9, 0, 40, 0, 100, 0, 8, 25220, 0, 0, 11, 45313, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP8 - Cast Anchor Here'), +(25220, 0, 10, 0, 40, 0, 100, 0, 9, 25220, 0, 0, 11, 45313, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP9 - Cast Anchor Here'), +(25220, 0, 11, 0, 40, 0, 100, 0, 10, 25220, 0, 0, 11, 45313, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP10 - Cast Anchor Here'), +(25220, 0, 12, 0, 40, 0, 100, 0, 11, 25220, 0, 0, 11, 45313, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP11 - Cast Anchor Here'), +(25220, 0, 13, 14, 40, 0, 100, 0, 12, 25220, 0, 0, 54, 18000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP11 - Cast Anchor Here'), +(25220, 0, 14, 0, 61, 0, 100, 0, 0, 0, 0, 0, 87, 2522000, 2522001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP11 - Run Script'), +(25220, 0, 15, 0, 40, 0, 100, 0, 15, 25220, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - On Reached WP15 - Despawn'), +(2522000, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 25222, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 1 - Say'), +(2522000, 9, 1, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Scrip 2 - Say'), +(2522000, 9, 2, 0, 0, 0, 100, 0, 6000, 7000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 19, 25222, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 2 - Say'), +(2522000, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 2 - Equip Items'), +(2522000, 9, 4, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 65, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 2 - Resume WP'), +(2522000, 9, 5, 0, 0, 0, 100, 0, 4000, 5000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 19, 25222, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 2 - Say'), +(2522001, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 25222, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 1 - Say'), +(2522001, 9, 1, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Scrip 2 - Say'), +(2522001, 9, 2, 0, 0, 0, 100, 0, 6000, 7000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 19, 25222, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 3 - Say'), +(2522001, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 71, 0, 0, 2178, 143, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 3 - Equip Items'), +(2522001, 9, 4, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 65, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 3 - Resume WP'), +(2522001, 9, 5, 0, 0, 0, 100, 0, 4000, 5000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 19, 25222, 0, 0, 0, 0, 0, 0, 'Civilian Recruit - Script 2 - Say'); + + diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_01_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_01_01_world.sql new file mode 100644 index 00000000000..38a13f0ea84 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_01_01_world.sql @@ -0,0 +1,67 @@ +UPDATE `smart_scripts` SET `event_chance`=100 WHERE `entryorguid`=26417 AND `source_type`=0 AND `id`=2 AND `link`=3; +UPDATE `smart_scripts` SET `event_chance`=100, `action_type`=87, `action_param2`=2641701, `action_param3`=2641701, `action_param4`=2641701 WHERE `entryorguid`=26417 AND `source_type`=0 AND `id`=3 AND `link`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`=2641701 AND `source_type`=9 AND `id`=0 AND `link`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`=26417 AND `source_type`=0 AND `id`>3; +DELETE FROM `smart_scripts` WHERE `entryorguid`=26261 AND `source_type`=0 AND `id`=3 AND `link`=0; +UPDATE `gameobject_template` SET `AIName`='SmartGameObjectAI' WHERE `entry`IN(188264,188288,188289); +DELETE FROM `smart_scripts` WHERE `source_type`=1 AND `entryorguid`IN(188264,188288,188289); +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`IN(26445); +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`IN(26445); + +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(-109925,-109919,-109926,-109911,-109912,-109910,-109908,-109920,-109913,-109921,-109923,-109909,-109922); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceGroup`=1 AND `SourceEntry`=46820; +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceGroup`=1 AND `SourceEntry`=47320; + +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 1, 46820, 0, 1, 31, 0, 3, 26264, 0, 0, 0, 0,'', 'Toss Tree - only targets Dummy'), +(13, 1, 47320, 0, 1, 31, 0, 3, 26261, 0, 0, 0, 0,'', 'Toss Boulder 2 - only targets Runed Giant'); + +UPDATE`smart_scripts` SET `action_param1`=47320,`comment`='Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder 2\'' WHERE `entryorguid`=26261 AND `source_type`=0 AND `id`=2 AND `link`=0; +UPDATE `smart_scripts` SET `event_param3`=12000, `event_param4`=21000 WHERE `entryorguid`=26261 AND `source_type`=0 AND `id`=2 AND `link`=0; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2641701, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 36, 26872, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Runed Giant - On Script 2 - Change entry to Weakened Giant'), +(26417, 0, 4, 0, 75, 0, 100, 0, 0, 26261, 30, 0, 49, 0, 0, 0, 0, 0, 0, 19, 26261, 0, 0, 0, 0, 0, 0, 'Runed Giant - On Grizzly Hills Giant within 20 yards - Attack Grizzly Hills Giant'), +(26261, 0, 3, 0, 75, 0, 100, 0, 0, 26417, 30, 0, 49, 0, 0, 0, 0, 0, 0, 19, 26417, 0, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - On Runed Giant in Range - Attack Runed Giant'), +(188264, 1, 0, 1, 70, 0, 100, 0, 2, 0, 0, 0, 12, 26445, 1, 1000, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'First Rune Plate - On Gossip Hello - Summon Rune Plate'), +(188264, 1, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 19, 26445, 0, 0, 0, 0, 0, 0, 'First Rune Plate - On Gossip Hello - Set Data on Rune Plate'), +(188288, 1, 0, 1, 70, 0, 100, 0, 2, 0, 0, 0, 12, 26445, 1, 1000, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Second Rune Plate - On Gossip Hello - Summon Rune Plate'), +(188288, 1, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 45, 2, 2, 0, 0, 0, 0, 19, 26445, 0, 0, 0, 0, 0, 0, 'Second Rune Plate - On Gossip Hello - Set Data on Rune Plate'), +(188289, 1, 0, 1, 70, 0, 100, 0, 2, 0, 0, 0, 12, 26445, 1, 1000, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Third Rune Plate - On Gossip Hello - Summon Rune Plate'), +(188289, 1, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 45, 3, 3, 0, 0, 0, 0, 19, 26445, 0, 0, 0, 0, 0, 0, 'Third Rune Plate - On Gossip Hello - Set Data on Rune Plate'), +(26445, 0, 0, 0, 38, 0, 100, 0, 1, 1, 0, 0, 84, 0, 0, 0, 0, 0, 0, 21, 10, 0, 0, 0, 0, 0, 0, 'Rune Plate - On Data Set - Simple Talk Group 0'), +(26445, 0, 1, 0, 38, 0, 100, 0, 2, 2, 0, 0, 84, 1, 0, 0, 0, 0, 0, 21, 10, 0, 0, 0, 0, 0, 0, 'Rune Plate - On Data Set - Simple Talk Group 1'), +(26445, 0, 2, 0, 38, 0, 100, 0, 3, 3, 0, 0, 84, 2, 0, 0, 0, 0, 0, 21, 10, 0, 0, 0, 0, 0, 0, 'Rune Plate - On Data Set - Simple Talk Group 2'), +(-109925, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109925, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109919, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109919, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109926, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109926, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109911, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109911, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109912, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109912, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109910, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109910, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109908, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109908, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109920, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109920, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109913, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109913, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109921, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109921, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109923, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109923, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109909, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109909, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''), +(-109922, 0, 0, 0, 1, 0, 100, 0, 2000, 5000, 5000, 8000, 11, 46815, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Boulder\''), +(-109922, 0, 1, 0, 1, 0, 100, 0, 8000, 20000, 10000, 28000, 11, 46820, 0, 0, 0, 0, 0, 19, 26264, 85, 0, 0, 0, 0, 0, 'Grizzly Hills Giant - Out of Combat - Cast \'Toss Tree\''); + +DELETE FROM `creature_text` WHERE `entry` in(26445); +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `comment`) VALUES +(26445, 0, 0, 'Shall return to the cradle of iron and stone.', 12, 0, 100, 0, 0, 0, 25686, 'Rune Plate'), +(26445, 1, 0, 'Return to Ulduar, nestled in the embrace of the storm.', 12, 0, 100, 0, 0, 0, 25688, 'Rune Plate'), +(26445, 2, 0, 'Greatest of the Maker''s children, arise and claim your birthright.', 12, 0, 100, 0, 0, 0, 25690, 'Rune Plate'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_02_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_02_00_world.sql new file mode 100644 index 00000000000..dc8f4375da0 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_02_00_world.sql @@ -0,0 +1,14 @@ +DELETE FROM `creature_addon` WHERE `guid` IN(106613,106612,106611,106879,106509); +INSERT INTO `creature_addon` (`guid`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(106613, 0, 0, 0, 4097, 0, '29266'), +(106612, 0, 0, 0, 4097, 0, '29266'), +(106611, 0, 0, 0, 4097, 0, '29266'), +(106879, 0, 0, 0, 4097, 0, '29266'), +(106509, 0, 0, 0, 4097, 0, '29266'); + + +UPDATE `creature` SET `unit_flags`=570721024 WHERE `guid` IN(106613,106612,106611,106879,106509); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry`=23666; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(22, 4, 23666, 0, 0, 1, 1, 29266, 0, 0, 1, 0, 0, '', 'Winterskorn Berserker only run SAI if Winterskorn Berserker does not have aura Permanent Feign Death'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_02_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_02_01_world.sql new file mode 100644 index 00000000000..4bcca1d6250 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_02_01_world.sql @@ -0,0 +1,17 @@ +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(9297,9521,9526,9527) AND `source_type`=0 AND `id`=1; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(9297, 0, 1, 0, 0, 0, 100, 0, 15000, 15000, 12000, 15000, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Enraged Wyvern - OOC - Despawn'), +(9521, 0, 1, 0, 0, 0, 100, 0, 15000, 15000, 12000, 15000, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Enraged Felbat - OOC - Despawn'), +(9526, 0, 1, 0, 0, 0, 100, 0, 15000, 15000, 15000, 15000, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Enraged Gryphon - OOC - Despawn'), +(9527, 0, 1, 0, 0, 0, 100, 0, 15000, 15000, 12000, 15000, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Enraged Hippogryph - OOC - Despawn'); + +-- Demon Portal Guardian SAI +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=11937; +DELETE FROM `smart_scripts` WHERE `entryorguid`=11937 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(11937, 0, 0, 0, 54, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 21, 30, 0, 0, 0, 0, 0, 0, 'Demon Portal Guardian - On Just Summoned - Attack'), +(11937, 0, 1, 0, 4, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Demon Portal Guardian - On Agro - Attack'), +(11937, 0, 2, 0, 1, 0, 100, 1, 30000, 30000, 30000, 30000, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Demon Portal Guardian - Out of Combat - Despawn'); + +-- set correct broadcast_text ID for Vim'gol the Vile's aggro text in creature_text +UPDATE `creature_text` SET `BroadcastTextId`= 20773 WHERE `BroadcastTextId`= 20733 AND `entry`= 22911; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_02_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_02_02_world.sql new file mode 100644 index 00000000000..89b8032be10 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_02_02_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=63277; +INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES +(63277,65269,2,'General Vezax - Shadow Crash - Haste and reduced mana cost'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_03_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_03_00_world.sql new file mode 100644 index 00000000000..8344df664f2 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_03_00_world.sql @@ -0,0 +1,2 @@ +-- Remove duplicate spawn of "Big Roy" (24785) +DELETE FROM `creature` WHERE `guid`=203496 AND `id`=24785; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_03_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_03_01_world.sql new file mode 100644 index 00000000000..a150fe2d69e --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_03_01_world.sql @@ -0,0 +1,36 @@ +DELETE FROM `smart_scripts` WHERE `entryorguid`=24713 AND `source_type`=0 AND `id`>1; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(24713, 0, 2, 3, 62, 0, 100, 0, 9335, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, '"Crowleg" Dan - On Gossip Option Select - Close Gossip'), +(24713, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, '"Crowleg" Dan - On Gossip Option Select - Start Attack'); + +DELETE FROM `gossip_menu_option` WHERE `menu_id`=9335; +INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`, `BoxBroadcastTextID`) VALUES +(9335, 0, 0, 'Ummm... the frog says you''re a traitor, "matey."', 25738, 1, 1, 0, 0, 0, 0, NULL, 0); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=9335; + +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(15, 9335, 0, 0, 0, 9, 0, 11479, 0, 0, 0, 0, 0, '', 'Crowleg" Dan - Only show Gossip if player is on quest'); + +UPDATE `gameobject_template` SET `AIName`='SmartGameObjectAI', scriptname='' WHERE `entry` =186944; +DELETE FROM `smart_scripts` WHERE `entryorguid` =186944 AND `source_type`=1; + + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(186944, 1, 0, 1, 70, 0, 100, 0, 2, 0, 0, 0, 105, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dirt Mound - On State Changed - Add Go Flag '), +(186944, 1, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 12, 24790, 1, 120000, 1, 0, 0, 8, 0, 0, 0, 688.9122, -3377.737, 67.87585, 1.291544, 'Dirt Mound - On State Changed - Summon Black Conrads Ghost'), +(186944, 1, 2, 3, 61, 0, 100, 0, 0, 0, 0, 0, 12, 24796, 1, 120000, 1, 0, 0, 8, 0, 0, 0, 691.5706, -3375.863, 68.09953, 1.308997, 'Dirt Mound - On State Changed - Summon Spectral Sailor'), +(186944, 1, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 12, 24796, 1, 120000, 1, 0, 0, 8, 0, 0, 0, 687.27, -3374.881, 67.92136, 1.047198, 'Dirt Mound - On State Changed - Summon Spectral Sailor'); + +DELETE FROM `creature` WHERE `guid`=116177; +UPDATE `gameobject` SET `spawntimesecs`=120 WHERE `guid`=5842; + +DELETE FROM `smart_scripts` WHERE `entryorguid`=23777 AND `source_type`=0 AND `id`IN(6,7); + +UPDATE `smart_scripts` SET `link`=6 WHERE `entryorguid`=23777 AND `source_type`=0 AND `id`=1 AND `link`=0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(23777, 0, 6, 7, 61, 0, 100, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake Egg - On Reset - Set Passive'), +(23777, 0, 7, 0, 61, 0, 100, 0, 0, 0, 0, 0, 94, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake Egg - On Reset - Set Dynamic Flags'); + + +UPDATE `creature_template` SET `unit_flags`=0 WHERE `entry`=23777; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_03_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_03_02_world.sql new file mode 100644 index 00000000000..1a408d3ec6a --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_03_02_world.sql @@ -0,0 +1,2 @@ +-- Fix respawn time for quest loot GO "Daggerfen Poison Manual" +UPDATE `gameobject` SET `spawntimesecs`=2 WHERE `guid`=22662; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_04_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_04_00_world.sql new file mode 100644 index 00000000000..69da8a7d699 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_04_00_world.sql @@ -0,0 +1,149 @@ +UPDATE `quest_template_addon` SET `RequiredMinRepValue`=9000 WHERE `ID`=9729; + +DELETE FROM `creature_text` WHERE `entry`=17877; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(17877, 0, 0, 'Fhwoor go now, $n. Get ark, come back.', 12, 0, 100, 0, 0, 0, 16439, 0, 'Fhwoor'), +(17877, 1, 0, 'Take moment... get ready.', 12, 0, 100, 0, 0, 0, 16440, 0, 'Fhwoor'), +(17877, 2, 0, 'We go!', 12, 0, 100, 0, 0, 0, 16441, 0, 'Fhwoor'), +(17877, 3, 0, '%s lifts the Ark of Ssslith with ease.', 16, 0, 100, 0, 0, 0, 16442, 0, 'Fhwoor'), +(17877, 4, 0, 'Uh oh...', 12, 0, 100, 0, 0, 0, 16443, 0, 'Fhwoor'), +(17877, 5, 0, 'Ha ha, squishy naga!', 12, 0, 100, 0, 0, 0, 16444, 0, 'Fhwoor'), +(17877, 6, 0, '%s places the Ark of Ssslith on the ground.', 16, 0, 100, 0, 0, 0, 16445, 0, 'Fhwoor'), +(17877, 7, 0, 'Fhwoor do good!', 16, 0, 100, 0, 0, 0, 16446, 0, 'Fhwoor'); + +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`IN(18154,17877); + +DELETE FROM `smart_scripts` WHERE `entryorguid`IN(17877,18154) AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`IN(1787700,1787701) AND `source_type`=9; +DELETE FROM `smart_scripts` WHERE `entryorguid`=18089 AND `source_type`=0 AND `id`>0; +DELETE FROM `smart_scripts` WHERE `entryorguid`=18088 AND `source_type`=0 AND `id`>1; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(18154, 0, 0, 0, 54, 0, 100, 0, 0, 0, 0, 0, 53, 0, 18154, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 'Ssslith - On Just Summoned - Start WP'), +(18088, 0, 2, 0, 54, 0, 100, 0, 0, 0, 0, 0, 53, 0, 18088, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 'Bloodscale Enchantress - On Just Summoned - Start WP'), +(18089, 0, 1, 0, 54, 0, 100, 0, 0, 0, 0, 0, 53, 0, 18089, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 'Bloodscale Slavedriver - On Just Summoned - Start WP'), +(18154, 0, 1, 0, 40, 0, 100, 0, 12, 18154, 0, 0, 66, 0, 0, 0, 0, 0, 0, 19, 17877, 0, 0, 0, 0, 0, 0, 'Ssslith - On Reached WP12 - Face Fhwoor'), +(18088, 0, 3, 0, 40, 0, 100, 0, 6, 18088, 0, 0, 66, 0, 0, 0, 0, 0, 0, 19, 17877, 0, 0, 0, 0, 0, 0, 'Bloodscale Enchantress - On Reached WP12 - Face Fhwoor'), +(18089, 0, 2, 0, 40, 0, 100, 0, 8, 18089, 0, 0, 66, 0, 0, 0, 0, 0, 0, 19, 17877, 0, 0, 0, 0, 0, 0, 'Bloodscale Slavedriver - On Reached WP12 - Face Fhwoor'), +(17877, 0, 0, 1, 19, 0, 100, 0, 9729, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Quest Accept (Fhwoor Smash) - Store Targetlist'), +(17877, 0, 1, 18, 61, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Quest Accept (Fhwoor Smash) - Say Line 0'), +(17877, 0, 2, 0, 6, 0, 100, 0, 0, 0, 0, 0, 6, 9729, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Death - Fail Quest Fhwoor Smash'), +(17877, 0, 3, 4, 40, 0, 100, 0, 11, 17877, 0, 0, 1, 1, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP11 - Say Line 1'), +(17877, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 54, 20000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP11 - Pause WP (20 seconds)'), +(17877, 0, 5, 0, 40, 0, 100, 0, 12, 17877, 0, 0, 1, 2, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP12 - Say Line 2'), +(17877, 0, 6, 7, 40, 0, 100, 0, 27, 17877, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP27 - Say Line 3'), +(17877, 0, 7, 8, 61, 0, 100, 0, 0, 0, 0, 0, 54, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP27 - Pause WP (5 seconds)'), +(17877, 0, 8, 0, 61, 0, 100, 0, 0, 0, 0, 0, 70, 120, 0, 0, 0, 0, 0, 20, 182082, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP27 - Despawn The Ark of Ssslith'), +(17877, 0, 9, 10, 40, 0, 100, 0, 43, 17877, 0, 0, 1, 4, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP43 - Say Line 4'), +(17877, 0, 10, 11, 61, 0, 100, 0, 0, 0, 0, 0, 54, 20000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP43 - Pause WP (20 seconds)'), +(17877, 0, 11, 12, 61, 0, 100, 0, 0, 0, 0, 0, 12, 18154, 1, 300000, 0, 0, 0, 8, 0, 0, 0, 168.5472, 8207.521, 22.9772, 4.467648, 'Fhwoor - On Reached WP43 - Summon Ssslith'), +(17877, 0, 12, 13, 61, 0, 100, 0, 0, 0, 0, 0, 12, 18088, 1, 300000, 0, 0, 0, 8, 0, 0, 0, 172.8663, 8214.886, 22.31137, 4.198237, 'Fhwoor - On Reached WP43 - Summon Bloodscale Enchantress'), +(17877, 0, 13, 0, 61, 0, 100, 0, 0, 0, 0, 0, 12, 18089, 1, 300000, 0, 0, 0, 8, 0, 0, 0, 166.7656, 8215.018, 22.63307, 4.604752, 'Fhwoor - On Reached WP43 - Summon Bloodscale Slavedriver'), +(17877, 0, 14, 0, 11, 0, 100, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Spawn Set Active'), +(17877, 0, 15, 0, 40, 0, 100, 0, 44, 17877, 0, 0, 1, 5, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP44 - Say Line 5'), +(17877, 0, 16, 0, 40, 0, 100, 0, 45, 17877, 0, 0, 59, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP45 - Set Run On'), +(17877, 0, 17, 0, 40, 0, 100, 0, 60, 17877, 0, 0, 80, 1787701, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP60 - Run Script 2'), +(17877, 0, 18, 0, 61, 0, 100, 0, 0, 0, 0, 0, 80, 1787700, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Quest Accept - Run Script 1'), +(17877, 0, 19, 20, 40, 0, 100, 0, 61, 17877, 0, 0, 66, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 2.042035, 'Fhwoor - On Reached WP61 - Set Orientation'), +(17877, 0, 20, 21, 61, 0, 100, 0, 0, 0, 0, 0, 81, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP61 - Set Npc Flags'), +(17877, 0, 21, 22, 61, 0, 100, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP61 - Turn Run Off'), +(17877, 0, 22, 23, 61, 0, 100, 0, 0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP61 - Say Line 7'), +(17877, 0, 23, 24, 61, 0, 100, 0, 0, 0, 0, 0, 2, 1709, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP61 - Set Faction'), +(17877, 0, 24, 0, 61, 0, 100, 0, 0, 0, 0, 0, 15, 9729, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Reached WP61 - Complete Quest'), +(17877, 0, 25, 0, 9, 0, 100, 0, 0, 10, 20000, 30000, 11, 31277, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - On Range - Cast Stomp'), +(1787700, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - Script - Set NPC Flags'), +(1787700, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 2, 250, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - Script - Set Faction'), +(1787700, 9, 2, 0, 0, 0, 100, 0, 10000, 10000, 0, 0, 53, 0, 17877, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - Script - Start WP'), +(1787701, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 54, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - Script 2 - Pause WP (5 Seconds)'), +(1787701, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 6, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fhwoor - Script 2 - Say Line 6'), +(1787701, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 50, 182082, 180, 0, 0, 0, 0, 8, 0, 0, 0, 249.717, 8482.185, 22.96521, 3.159062, 'Fhwoor - Script 2 - Summon The Ark of Ssslith'); + +DELETE FROM `waypoints` WHERE `entry`IN(17877,18154,18088,18089); +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES +(17877, 1, 213.6417, 8469.281, 23.52778, 'Fhwoor'), +(17877, 2, 194.8211, 8448.552, 24.48719, 'Fhwoor'), +(17877, 3, 181.9171, 8416.949, 23.39253, 'Fhwoor'), +(17877, 4, 162.9771, 8387.255, 22.28007, 'Fhwoor'), +(17877, 5, 169.1168, 8353.966, 21.07829, 'Fhwoor'), +(17877, 6, 179.16, 8325.873, 20.83087, 'Fhwoor'), +(17877, 7, 170.3557, 8302.857, 21.0235, 'Fhwoor'), +(17877, 8, 182.7192, 8270.847, 18.91084, 'Fhwoor'), +(17877, 9, 220.4595, 8241.914, 20.72861, 'Fhwoor'), +(17877, 10, 248.3627, 8210.217, 19.54621, 'Fhwoor'), +(17877, 11, 283.827, 8203.188, 22.15056, 'Fhwoor'), +(17877, 12, 299.8667, 8188.261, 21.42571, 'Fhwoor'), +(17877, 13, 318.4961, 8184.514, 18.0551, 'Fhwoor'), +(17877, 14, 333.9666, 8178.852, 17.66307, 'Fhwoor'), +(17877, 15, 349.5377, 8179.188, 18.45091, 'Fhwoor'), +(17877, 16, 366.4365, 8187.577, 21.90989, 'Fhwoor'), +(17877, 17, 378.7538, 8190.383, 23.30309, 'Fhwoor'), +(17877, 18, 396.7187, 8184.856, 19.38158, 'Fhwoor'), +(17877, 19, 416.5232, 8164.166, 18.35449, 'Fhwoor'), +(17877, 20, 436.7097, 8153.245, 21.59639, 'Fhwoor'), +(17877, 21, 451.9413, 8151.88, 23.76729, 'Fhwoor'), +(17877, 22, 467.4153, 8152.104, 22.10491, 'Fhwoor'), +(17877, 23, 485.0933, 8148.362, 20.20708, 'Fhwoor'), +(17877, 24, 500.4597, 8146.723, 20.18372, 'Fhwoor'), +(17877, 25, 517.5106, 8156.078, 22.14917, 'Fhwoor'), +(17877, 26, 536.4334, 8157.974, 23.6155, 'Fhwoor'), +(17877, 27, 558.9749, 8159.831, 23.83816, 'Fhwoor'), +(17877, 28, 522.1965, 8135.454, 21.15369, 'Fhwoor'), +(17877, 29, 498.0764, 8136.04, 20.90411, 'Fhwoor'), +(17877, 30, 477.8418, 8127.26, 22.5633, 'Fhwoor'), +(17877, 31, 450.433, 8131.167, 21.50137, 'Fhwoor'), +(17877, 32, 431.7549, 8121.7, 18.242, 'Fhwoor'), +(17877, 33, 416.2102, 8120.498, 17.59649, 'Fhwoor'), +(17877, 34, 394.6256, 8120.143, 17.94713, 'Fhwoor'), +(17877, 35, 379.7412, 8113.295, 17.7740, 'Fhwoor'), +(17877, 36, 364.4443, 8105.485, 18.17426, 'Fhwoor'), +(17877, 37, 350.215, 8106.762, 17.74799, 'Fhwoor'), +(17877, 38, 335.0946, 8119.199, 17.49909, 'Fhwoor'), +(17877, 39, 328.1111, 8135.518, 18.31635, 'Fhwoor'), +(17877, 40, 305.7509, 8149.812, 20.04914, 'Fhwoor'), +(17877, 41, 275.4078, 8161.027, 17.7491, 'Fhwoor'), +(17877, 42, 247.4046, 8177.393, 17.72273, 'Fhwoor'), +(17877, 43, 220.5886, 8180.784, 19.78761, 'Fhwoor'), +(17877, 44, 205.7915, 8183.323, 23.08216, 'Fhwoor'), +(17877, 45, 203.9108, 8206.521, 22.37668, 'Fhwoor'), +(17877, 46, 200.2505, 8229.313, 24.96921, 'Fhwoor'), +(17877, 47, 201.1895, 8251.09, 21.10947, 'Fhwoor'), +(17877, 48, 190.4957, 8267.601, 18.47761, 'Fhwoor'), +(17877, 49, 175.0741, 8288.405, 18.58564, 'Fhwoor'), +(17877, 50, 182.4148, 8311.77, 21.29364, 'Fhwoor'), +(17877, 51, 182.5205, 8333.074, 19.87689, 'Fhwoor'), +(17877, 52, 175.5308, 8357.185, 18.46842, 'Fhwoor'), +(17877, 53, 183.5543, 8381.03, 16.24468, 'Fhwoor'), +(17877, 54, 195.2988, 8399.357, 16.50945, 'Fhwoor'), +(17877, 55, 208.5941, 8413.654, 18.89419, 'Fhwoor'), +(17877, 56, 221.3398, 8432.104, 20.17568, 'Fhwoor'), +(17877, 57, 230.968, 8446.415, 21.99157, 'Fhwoor'), +(17877, 58, 227.1291, 8465.446, 19.64525, 'Fhwoor'), +(17877, 59, 231.5279, 8479.356, 17.87813, 'Fhwoor'), +(17877, 60, 246.9482, 8481.803, 22.1418, 'Fhwoor'), +(17877, 61, 231.4028, 8479.942, 18.03377, 'Fhwoor'), +(18154, 1, 169.4304, 8210.07, 22.51478, 'Ssslith'), +(18154, 2, 169.5868, 8209.083, 22.51478, 'Ssslith'), +(18154, 3, 168.75, 8208.333, 22.80278, 'Ssslith'), +(18154, 4, 168.0234, 8205.424, 23.42778, 'Ssslith'), +(18154, 5, 167.709, 8204.166, 23.80278, 'Ssslith'), +(18154, 6, 167.709, 8202.083, 23.80278, 'Ssslith'), +(18154, 7, 167.709, 8200, 23.60022, 'Ssslith'), +(18154, 8, 170.3105, 8196.961, 22.97522, 'Ssslith'), +(18154, 9, 170.834, 8196.354, 22.85022, 'Ssslith'), +(18154, 10, 171.2306, 8194.351, 22.48486, 'Ssslith'), +(18154, 11, 182.8383, 8183.431, 23.90405, 'Ssslith'), +(18154, 12, 188.6353, 8182.512, 23.86377, 'Ssslith'), +(18088, 1, 172.8497, 8215.886, 22.30278, 'Bloodscale Enchantress'), +(18088, 2, 172.8672, 8214.886, 22.30278, 'Bloodscale Enchantress'), +(18088, 3, 172.0461, 8213.434, 22.35161, 'Bloodscale Enchantress'), +(18088, 4, 176.9391, 8193.834, 23.09314, 'Bloodscale Enchantress'), +(18088, 5, 181.4677, 8187.228, 23.00415, 'Bloodscale Enchantress'), +(18088, 6, 185.6965, 8186.558, 23.32629, 'Bloodscale Enchantress'), +(18089, 1, 166.6959, 8216.016, 22.55278, 'Bloodscale Slavedriver'), +(18089, 2, 166.7656, 8215.018, 22.55278, 'Bloodscale Slavedriver'), +(18089, 3, 165.9063, 8207.064, 23.10177, 'Bloodscale Slavedriver'), +(18089, 4, 165.6914, 8205.076, 23.72677, 'Bloodscale Slavedriver'), +(18089, 5, 164.922, 8197.819, 23.50668, 'Bloodscale Slavedriver'), +(18089, 6, 172.0933, 8188.685, 22.47522, 'Bloodscale Slavedriver'), +(18089, 7, 180.3612, 8180.244, 24.05603, 'Bloodscale Slavedriver'), +(18089, 8, 184.59, 8179.574, 24.47522, 'Bloodscale Slavedriver'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_05_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_05_00_world.sql new file mode 100644 index 00000000000..f59e70ddb34 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_05_00_world.sql @@ -0,0 +1,2 @@ +UPDATE `quest_template_addon` SET `RequiredMinRepValue`=42000 WHERE `ID`=9729; +DELETE FROM `smart_scripts` WHERE `entryorguid`=11937 AND `source_type`=0 AND `id`=1 AND `link`=0; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_05_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_05_01_world.sql new file mode 100644 index 00000000000..eb2609af74d --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_05_01_world.sql @@ -0,0 +1,2 @@ +-- +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceGroup`=1 AND `SourceEntry`=47320; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_08_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_08_00_world.sql new file mode 100644 index 00000000000..930e599396f --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_08_00_world.sql @@ -0,0 +1,133 @@ +SET @CGUID := 78642; + +DELETE FROM `creature` WHERE `id` IN(17417,17418,17404,17405); +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES +(@CGUID+0, 17417, 530, 1, 1, 214.6568, 4122.551, 79.8511, 2.251475, 120, 0, 0), -- 17417 (Area: 0) (possible waypoints or random movement) +(@CGUID+1, 17417, 530, 1, 1, 216.0346, 4125.61, 80.22345, 2.251475, 120, 0, 0), -- 17417 (Area: 0) (possible waypoints or random movement) +(@CGUID+2, 17404, 530, 1, 1, 211.6765, 4126.361, 79.04578, 2.391101, 120, 0, 0), -- 17404 (Area: 0) (possible waypoints or random movement) +(@CGUID+3, 17418, 530, 1, 1, 261.5179, 4106.813, 93.315, 2.663978, 120, 0, 0), -- 17418 (Area: 0) +(@CGUID+4, 17418, 530, 1, 1, 260.6302, 4103.529, 93.33371, 2.60972, 120, 0, 0), -- 17418 (Area: 0) +(@CGUID+5, 17405, 530, 1, 1, 230.5075, 4118.714, 83.56195, 2.949606, 120, 0, 0); -- 17405 (Area: 0) (possible waypoints or random movement) + +UPDATE `creature` SET `equipment_id`=1 WHERE `id` IN(17417,17418,17404,17405); + +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`IN(17413,17417,17404,17418,17405); + +DELETE FROM `smart_scripts` WHERE `entryorguid`IN(17413,17417,17404,17418,17405) AND `source_type`=0; + +DELETE FROM `smart_scripts` WHERE `entryorguid`IN(1740400,1740500) AND `source_type`=9; + + +DELETE FROM `smart_scripts` WHERE `entryorguid`IN(-@CGUID-0,-@CGUID-1,-@CGUID-2,-@CGUID-3,-@CGUID-4,-@CGUID-5) AND `source_type`=0; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(-@CGUID-0, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 18, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (1) - On Respawn - Set Immune'), +(-@CGUID-0, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (1) - On Respawn - Set Invisible'), +(-@CGUID-0, 0, 1, 2, 38, 0, 100, 1, 1, 1, 0, 0, 19, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (1) - On Data Set - Set Immune'), +(-@CGUID-0, 0, 2, 3, 61, 0, 100, 0, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (1) - On Data Set - Set visible'), +(-@CGUID-0, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 53, 0, 1741700, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (1) - On Respawn - Start WP'), +(-@CGUID-0, 0, 4, 5, 40, 0, 100, 0, 2, 1741700, 0, 0, 54, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (1) - On Reached WP3 - Pause WP'), +(-@CGUID-0, 0, 5, 6, 61, 0, 100, 0, 0, 0, 0, 0, 11, 30460, 2, 0, 0, 0, 0, 19, 17404, 0, 0, 0, 0, 0, 0, 'Mag har Escort (1) - On Reached WP3 - Cast Kick'), +(-@CGUID-0, 0, 6, 0, 61, 0, 100, 0, 0, 0, 0, 0, 45, 2, 2, 0, 0, 0, 0, 19, 17404, 0, 0, 0, 0, 0, 0, 'Mag har Escort (1) - On Reached WP3 - Set Data on Sedei'), +(-@CGUID-0, 0, 7, 8, 40, 0, 100, 0, 5, 1741700, 0, 0, 45, 3, 3, 0, 0, 0, 0, 10, @CGUID+3, 17418, 0, 0, 0, 0, 0, 'Mag har Escort (1) - On Reached WP6 - Start Attack'), +(-@CGUID-0, 0, 8, 0, 61, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 10, @CGUID+3, 17418, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Reached WP12 - Start Attack'), +(-@CGUID-0, 0, 9, 0, 0, 0, 100, 1, 3000, 3000, 0, 0, 45, 4, 4, 0, 0, 0, 0, 10, @CGUID+3, 17418, 0, 0, 0, 0, 0, 'Mag har Escort (2) - IC - Set Data'), + +(-@CGUID-1, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 18, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Respawn - Set Immune'), +(-@CGUID-1, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Respawn - Set Invisible'), +(-@CGUID-1, 0, 1, 2, 38, 0, 100, 1, 1, 1, 0, 0, 19, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Data Set - Set Immune'), +(-@CGUID-1, 0, 2, 3, 61, 0, 100, 0, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Data Set - Set visible'), +(-@CGUID-1, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 53, 0, 1741701, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Respawn - Start WP'), +(-@CGUID-1, 0, 4, 5, 40, 0, 100, 0, 3, 1741701, 0, 0, 54, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Reached WP9 - Pause WP'), +(-@CGUID-1, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Reached WP9 - Say'), +(-@CGUID-1, 0, 6, 7, 40, 0, 100, 0, 10, 1741701, 0, 0, 45, 3, 3, 0, 0, 0, 0, 10, @CGUID+4, 17418, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Reached WP12 - Start Attack'), +(-@CGUID-1, 0, 7, 0, 61, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 10, @CGUID+4, 17418, 0, 0, 0, 0, 0, 'Mag har Escort (2) - On Reached WP12 - Start Attack'), +(-@CGUID-1, 0, 8, 0, 0, 0, 100, 1, 3000, 3000, 0, 0, 45, 4, 4, 0, 0, 0, 0, 10, @CGUID+4, 17418, 0, 0, 0, 0, 0, 'Mag har Escort (2) - IC - Set Data'), + +(-@CGUID-2, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 18, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - On Respawn - Set Immune'), +(-@CGUID-2, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - On Respawn - Set Invisible'), +(-@CGUID-2, 0, 1, 2, 38, 0, 100, 1, 1, 1, 0, 0, 19, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - On Data Set - Set Immune'), +(-@CGUID-2, 0, 2, 3, 61, 0, 100, 0, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - On Data Set - Set visible'), +(-@CGUID-2, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 53, 0, 17404, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - On Respawn - Start WP'), +(-@CGUID-2, 0, 4, 0, 38, 0, 100, 0, 2, 2, 0, 0, 80, 1740400, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - On Data Set - Run Script'), +(-@CGUID-2, 0, 5, 0, 40, 0, 100, 0, 3, 17404, 0, 0, 54, 21000, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - On Reached WP3 - Pause WP'), +(-@CGUID-2, 0, 6, 0, 40, 0, 100, 0, 5, 17404, 0, 0, 54, 18000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - On Reached WP5 - Pause WP'), + +(-@CGUID-3, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 18, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (1) - On Respawn - Set Immune'), +(-@CGUID-3, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (1) - On Respawn - Set Invisible'), +(-@CGUID-3, 0, 2, 3, 38, 0, 100, 1, 1, 1, 0, 0, 19, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (1) - On Data Set - Set Immune'), +(-@CGUID-3, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (1) - On Data Set - Set visible'), +(-@CGUID-3, 0, 5, 0, 38, 0, 100, 0, 3, 3, 0, 0, 49, 0, 0, 0, 0, 0, 0, 19, 17417, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (1) - On Data Set - Start Attack'), + +(-@CGUID-4, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 18, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (2) - On Respawn - Set Immune'), +(-@CGUID-4, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (2) - On Respawn - Set Invisible'), +(-@CGUID-4, 0, 2, 3, 38, 0, 100, 1, 1, 1, 0, 0, 19, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (2) - On Data Set - Set Immune'), +(-@CGUID-4, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (2) - On Data Set - Set visible'), +(-@CGUID-4, 0, 5, 0, 38, 0, 100, 0, 3, 3, 0, 0, 49, 0, 0, 0, 0, 0, 0, 19, 17417, 0, 0, 0, 0, 0, 0, 'Laughing Skull Ambusher (2) - On Data Set - Start Attack'), + +(-@CGUID-5, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 18, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Krun Spinebreaker - On Respawn - Set Immune'), +(-@CGUID-5, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Krun Spinebreaker - On Respawn - Set Invisible'), +(-@CGUID-5, 0, 1, 2, 38, 0, 100, 1, 1, 1, 0, 0, 19, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Krun Spinebreaker - On Data Set - Set Immune'), +(-@CGUID-5, 0, 2, 3, 61, 0, 100, 0, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Krun Spinebreaker - On Data Set - Set visible'), +(-@CGUID-5, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 53, 1, 17405, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Krun Spinebreaker - On Respawn - Start WP'), +(-@CGUID-5, 0, 4, 0, 40, 0, 100, 0, 3, 17405, 0, 0, 80, 1740500, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Krun Spinebreaker - On Reached WP3 - Run Script'), + +(1740400, 9, 0, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 45, 1, 1, 0, 0, 0, 0, 10, @CGUID+3, 17418, 0, 0, 0, 0, 0, 'Vindicator Sedai - Script - Set Data'), +(1740400, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 10, @CGUID+4, 17418, 0, 0, 0, 0, 0, 'Vindicator Sedai - Script - Say'), +(1740400, 9, 2, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - Script - Say'), +(1740400, 9, 3, 0, 0, 0, 100, 0, 15000, 15000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - Script - Say'), +(1740400, 9, 4, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - Script - Say'), +(1740400, 9, 5, 0, 0, 0, 100, 0, 18000, 18000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Vindicator Sedai - Script - Say'), +(1740400, 9, 6, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 45, 1, 1, 0, 0, 0, 0, 10, @CGUID+5, 17405, 0, 0, 0, 0, 0, 'Vindicator Sedai - Script - Say'), + +(1740500, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 30462, 2, 0, 0, 0, 0, 19, 17404, 0, 0, 0, 0, 0, 0, 'Krun Spinebreaker - Script - Cast Execute Sedei'), +(1740500, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Krun Spinebreaker - Script - Say'), +(1740500, 9, 2, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 41, 0, 0, 0, 0, 0, 0, 10, @CGUID+0, 17417, 0, 0, 0, 0, 0, 'Krun Spinebreaker - Script - Despawn Mag har Escort'), +(1740500, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 10, @CGUID+1, 17417, 0, 0, 0, 0, 0, 'Krun Spinebreaker - Script - Despawn Mag har Escort'), +(1740500, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 10, @CGUID+2, 17404, 0, 0, 0, 0, 0, 'Krun Spinebreaker - Script - Despawn Vindicator Sedai'), +(1740500, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 10, @CGUID+3, 17418, 0, 0, 0, 0, 0, 'Krun Spinebreaker - Script - Despawn Laughing Skull Ambusher'), +(1740500, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 10, @CGUID+4, 17418, 0, 0, 0, 0, 0, 'Krun Spinebreaker - Script - Despawn'), +(1740500, 9, 7, 0, 0, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Krun Spinebreaker - Script - Despawn'), + +(17413, 0, 0, 1, 54, 0, 100, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 10, @CGUID+0, 17417, 0, 0, 0, 0, 0, 'Sedai Quest Credit Marker - On Just Summoned - Set Data on Mag har Escort'), +(17413, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 10, @CGUID+1, 17417, 0, 0, 0, 0, 0, 'Sedai Quest Credit Marker - On Just Summoned - Set Data on Mag har Escort'), +(17413, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 10, @CGUID+2, 17404, 0, 0, 0, 0, 0, 'Sedai Quest Credit Marker - On Just Summoned - Set Data on Vindicator Sedei'); + + +DELETE FROM `waypoints` WHERE `entry`IN(17404,17405,1741700,1741701,1741800,1741801); +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES +(1741700, 1, 206.7916, 4132.612, 77.49819, 'Mag har Escort (1)'), +(1741700, 2, 199.061, 4142.329, 75.17587, 'Mag har Escort (1)'), -- Kick +(1741700, 3, 203.75, 4134.571, 76.52649, 'Mag har Escort (1)'), +(1741700, 4, 211.582, 4128.351, 79.12319, 'Mag har Escort (1)'), +(1741700, 5, 219.5054, 4125.231, 80.99819, 'Mag har Escort (1)'), +(1741701, 1, 206.2685, 4128.42, 77.62319, 'Mag har Escort (2)'), +(1741701, 2, 200.5664, 4136.248, 75.65149, 'Mag har Escort (2)'), +(1741701, 3, 196.179, 4141.198, 74.30087, 'Mag har Escort (2)'), -- say +(1741701, 4, 203.9766, 4138.813, 76.40149, 'Mag har Escort (2)'), +(1741701, 5, 206.5171, 4135.979, 77.40149, 'Mag har Escort (2)'), +(1741701, 6, 209.2334, 4134.047, 78.15149, 'Mag har Escort (2)'), +(1741701, 7, 209.2334, 4134.047, 78.15149, 'Mag har Escort (2)'), +(1741701, 8, 211.4904, 4132.254, 79.12319, 'Mag har Escort (2)'), +(1741701, 9, 214.5568, 4129.819, 79.74819, 'Mag har Escort (2)'), +(1741701, 10, 219.3728, 4128.506, 81.12319, 'Mag har Escort (2)'), +(17404, 1, 204.9158, 4134.23, 76.90149, 'Vindicator Sedai'), +(17404, 2, 200.7516, 4138.94, 75.52649, 'Vindicator Sedai'), +(17404, 3, 196.6698, 4143.903, 74.30087, 'Vindicator Sedai'), -- Event +(17404, 4, 201.4514, 4139.023, 75.90149, 'Vindicator Sedai'), +(17404, 5, 202.2026, 4138.024, 76.15149, 'Vindicator Sedai'), +(17404, 6, 198.0219, 4143.623, 74.92587, 'Vindicator Sedai'), +(17404, 7, 192.3438, 4150.61, 73.67587, 'Vindicator Sedai'), +(17405, 1, 213.5774, 4129.949, 79.74819, 'Krun Spinebreaker'), +(17405, 2, 203.9323, 4137.877, 76.40149, 'Krun Spinebreaker'), +(17405, 3, 193.1504, 4149.705, 73.80087, 'Krun Spinebreaker'); -- Assasinate + + +DELETE FROM `creature_text` WHERE `entry`IN(17417,17404,17405); +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(17417, 0, 0, 'Do not return, draenei scum. Next time we won''t spare your life, unarmed or not!', 12, 0, 100, 0, 0, 0, 13986, 0, 'Mag har Escort'), -- 21:04:49.000 +(17404, 0, 0, 'I''ve failed... peace is impossible.', 12, 0, 100, 0, 0, 0, 13982, 0, 'Vindicator Sedai'), -- 21:04:58.000 +(17404, 1, 0, 'What in the Light''s name...?', 12, 0, 100, 0, 0, 0, 13983, 0, 'Vindicator Sedai'), -- 21:05:13.000 +(17404, 2, 0, 'Fel orcs!', 12, 0, 100, 0, 0, 0, 13984, 0, 'Vindicator Sedai'), -- 21:05:18.000 +(17404, 3, 0, 'The cycle of bloodshed is unending... Is there nothing I can do?', 12, 0, 100, 0, 0, 0, 13985, 0, 'Vindicator Sedai'), -- 21:05:36.000 +(17405, 0, 0, 'You can die!', 12, 0, 100, 0, 0, 0, 13988, 0, 'Krun Spinebreaer'); -- 21:05:48.000 diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_00_world_2016_03_28_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_00_world_2016_03_28_00_world.sql new file mode 100644 index 00000000000..0fc505965a3 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_00_world_2016_03_28_00_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `trinity_string` WHERE `entry`=1030; +INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES +(1030,'Account name cannot contain ''@'' character.'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_01_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_01_world.sql new file mode 100644 index 00000000000..0c01492d746 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_01_world.sql @@ -0,0 +1,2 @@ +-- +DELETE FROM `creature_addon` WHERE `guid`=203496; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_02_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_02_world.sql new file mode 100644 index 00000000000..60ae64d1715 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_02_world.sql @@ -0,0 +1,44 @@ +-- +/* Spell Bonus Data */ +-- Enchants +DELETE FROM `spell_bonus_data` WHERE `entry` IN (6297,13897,13907,20004,20006,20007,28005,44525,44578,46579,64442,64569); +INSERT INTO `spell_bonus_data` (`entry`,`direct_bonus`,`dot_bonus`,`ap_bonus`,`ap_dot_bonus`,`comments`) VALUES +( 6297, 0, 0, -1, -1, 'Fiery Blaze'), +(13897, 0, 0, -1, -1, 'Fiery Weapon - Fiery Weapon'), +(13907, 0, 0, -1, -1, 'Demonslaying - Smite Demon'), +(20004, 0, 0, -1, -1, 'Lifestealing - Life Steal'), +(20006, 0, 0, -1, -1, 'Unholy Weapon - Unholy Curse'), +(20007, 0, 0, -1, -1, 'Crusader - Holy Strength'), +(28005, 0, 0, -1, -1, 'Battlemaster - Battlemaster'), +(44525, 0, 0, -1, -1, 'Icebreaker - Icebreaker'), +(44578, 0, 0, -1, -1, 'Lifeward - Lifeward'), +(46579, 0, 0, -1, -1, 'Deathfrost - Deathfrost'), +(64442, 0, 0, -1, -1, 'Blade Warding - Blade Warding'), +(64569, 0, 0, -1, -1, 'Blood Draining - Blood Reserve'); + +-- Items +DELETE FROM `spell_bonus_data` WHERE `entry` IN (7712,7714,10577,16614,17484,18798,21992,27655,28788,38395,40972,55756,60526,67714,67760); +INSERT INTO `spell_bonus_data` (`entry`,`direct_bonus`,`dot_bonus`,`ap_bonus`,`ap_dot_bonus`,`comments`) VALUES +( 7712, 0, 0, -1, -1, 'Blazefury Medallion & Fiery Retributer (Fire Strike)'), +( 7714, 0, 0, -1, -1, 'Fiery Plate Gauntlets (Fire Strike)'), +(10577, 0, 0, -1, -1, 'Gauntlets of the Sea (Heal)'), +(16614, 0, 0, -1, -1, 'Storm Gauntlets (Lightning Strike)'), +(17484, 0, 0, -1, -1, 'Skullforge Reaver - Skullforge Brand'), +(18798, 0, 0, -1, -1, 'Freezing Band (Freeze)'), +(21992, 0, 0, -1, -1, 'Thunderfury'), +(27655, 0, 0, -1, -1, 'Heart of Wyrmthalak (Flame Lash)'), +(28788, 0, 0, -1, -1, 'Paladin T3 (8)'), +(38395, 0, 0, -1, -1, 'Warlock - Siphon Essence - T6 2P proc'), +(40972, 0, 0, -1, -1, 'Crystal Spire of Karabor - heal effect'), +(55756, 0, 0, -1, -1, 'Brunnhildar weapons (Chilling Blow)'), +(60526, 0, 0, -1, -1, 'Living Ice Crystals - heal effect'), +(67714, 0, 0, -1, -1, 'Pillar of Flame (Normal)'), +(67760, 0, 0, -1, -1, 'Pillar of Flame (Heroic)'); + +-- Consumables +DELETE FROM `spell_bonus_data` WHERE `entry` IN (28715,38616,43731,43733); +INSERT INTO `spell_bonus_data` (`entry`,`direct_bonus`,`dot_bonus`,`ap_bonus`,`ap_dot_bonus`,`comments`) VALUES +(28715, 0, 0, -1, -1, 'Consumable - Flamecap (Flamecap Fire)'), +(38616, 0, 0, -1, -1, 'Poison - Bloodboil Poison'), +(43731, 0, 0, -1, -1, 'Consumable - Stormchops (Lightning Zap)'), +(43733, 0, 0, -1, -1, 'Consumable - Stormchops (Lightning Zap)'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_03_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_03_world.sql new file mode 100644 index 00000000000..732e3d83ee5 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_03_world.sql @@ -0,0 +1,5 @@ +-- +DELETE FROM `player_factionchange_reputations` WHERE `alliance_id`= 589; +INSERT INTO `player_factionchange_reputations` (`alliance_id`, `horde_id`) VALUES +(589, 1137); +UPDATE `creature` SET `equipment_id`=0 WHERE `id` IN(17404); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_04_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_04_world.sql new file mode 100644 index 00000000000..01154d2070a --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_04_world.sql @@ -0,0 +1,9 @@ +-- +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=17 AND `SourceEntry` IN (44550, 44610, 44609); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(17, 0, 44550, 0, 0, 29, 0, 24820, 5, 0, 0, 0, 0, '', 'Allow spell Collect Data only on Iron Dwarf Relic 24820'), +(17, 0, 44610, 0, 0, 29, 0, 24824, 5, 0, 0, 0, 0, '', 'Allow spell Collect Data only on Iron Dwarf Relics'), +(17, 0, 44609, 0, 0, 29, 0, 24271, 10, 0, 0, 0, 0, '', 'Allow spell Bluff only on Iron Dwarf'), +(17, 0, 44609, 0, 1, 29, 0, 23673, 10, 0, 0, 0, 0, '', 'Allow spell Bluff only on Iron Dwarf'), +(17, 0, 44609, 0, 2, 29, 0, 23672, 10, 0, 0, 0, 0, '', 'Allow spell Bluff only on Iron Dwarf'), +(17, 0, 44609, 0, 3, 29, 0, 23675, 10, 0, 0, 0, 0, '', 'Allow spell Bluff only on Iron Dwarf'); diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_05_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_05_world.sql new file mode 100644 index 00000000000..815540ecef1 --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_09_05_world.sql @@ -0,0 +1,41 @@ +-- +SET @Oguid:=65714; + +DELETE FROM `gameobject` WHERE `guid` BETWEEN @OGUID+0 AND @OGUID+29; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +(@OGUID+0, 195256, 530, 1, 1, 1021.34, 7392.52, 36.3235, -2.79252, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+1, 195256, 530, 1, 1, 971.367, 7408.7, 29.5432, -1.25664, 0, 0, 0, 1, 180, 255, 1 ), +(@OGUID+2, 195256, 530, 1, 1, 957.729, 7355.67, 29.1519, 0.436332, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+3, 195256, 530, 1, 1, 1006.33, 7322.55, 41.0474, -1.15192, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+4, 195256, 530, 1, 1, 1003.33, 7430, 28.0768, -0.925024, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+5, 195256, 530, 1, 1, 201.985, 8489.73, 24.4459, 0.645772, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+6, 195256, 530, 1, 1, 265.287, 8514.35, 23.5299, -2.60053, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+7, 195256, 530, 1, 1, 258.263, 8495.36, 23.4081, 2.16421, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+8, 195256, 530, 1, 1, 276.203, 6122.65, 142.509, -0.95993, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+9, 195256, 530, 1, 1, -208.633, 5388.65, 22.9273, -1.72787, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+10,195256, 530, 1, 1, -87.5959, 5535.55, 22.807, 0.575957, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+11,195256, 530, 1, 1, -192.623, 5531.5, 29.4519, -2.51327, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+12,195256, 530, 1, 1, -702.011, 2676.55, 93.484, 1.72787, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+13,195256, 530, 1, 1, -684.19, 2664.04, 90.9786, 0.506145, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+14,195256, 530, 1, 1, -708.662, 2640.04, 91.8499, -2.14675, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+15,195256, 530, 1, 1, -714.397, 2671.54, 93.9279, 2.23402, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+16,195256, 530, 1, 1, -696.738, 4172.8, 58.3883, 1.90241, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+17,195256, 530, 1, 1, -646.139, 4161.18, 66.1437, -2.58308, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+18,195256, 530, 1, 1, -597.076, 4097.25, 91.2013, 2.40855, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+19,195256, 530, 1, 1, -594.825, 4161.75, 65.7298, 2.47837, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+20,195256, 530, 1, 1, -661.823, 4157.85, 66.0003, -0.506145, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+21,195256, 530, 1, 1, -614.866, 4105.14, 90.6122, -0.453785, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+22,195256, 530, 1, 1, -685.76, 4176.18, 57.4531, 1.93731, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+23,195256, 530, 1, 1, -597.71, 4154.32, 65.3473, 2.65289, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+24,195256, 530, 1, 1, -2024.57, 5470.97, 3.92836, -0.296705, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+25,195256, 530, 1, 1, -1809.99, 5404.19, -12.5532, 1.95477, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+26,195256, 530, 1, 1, -2001.4, 5370.28, -8.0344, -2.32129, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+27,195256, 530, 1, 1, -1994.43, 5356.16, -8.06764, -2.93214, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+28,195256, 530, 1, 1, -1896.71, 5355.26, -12.4279, 1.01229, 0, 0, 0, 1, 180, 255, 1), +(@OGUID+29,195256, 530, 1, 1, -1942.76, 5448.9, -12.428, 0.034906, 0, 0, 0, 1, 180, 255, 1); + +DELETE FROM `game_event_gameobject` WHERE `guid` BETWEEN 80000 AND 80029 AND `eventEntry`=24; + +SET @Event:=24; +DELETE FROM `game_event_gameobject` WHERE `guid` BETWEEN @OGUID+0 AND @OGUID+29 AND `eventEntry`=24; +INSERT INTO `game_event_gameobject` SELECT @Event, gameobject.guid FROM `gameobject` WHERE gameobject.guid BETWEEN @OGUID+0 AND @OGUID+29; diff --git a/sql/old/3.3.5a/world/60_2016_04_11/2016_04_10_00_world.sql b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_10_00_world.sql new file mode 100644 index 00000000000..d5c24c4a65d --- /dev/null +++ b/sql/old/3.3.5a/world/60_2016_04_11/2016_04_10_00_world.sql @@ -0,0 +1,20 @@ +UPDATE `creature` SET `unit_flags`=33587968 WHERE `guid`IN(53208,53209,53210,53617,53586,53229,53711,53230,53710); + +DELETE FROM `creature_addon` WHERE `guid` IN(53208,53209,53210,53210,53617,53586,53229,53711,53230,53710); +INSERT INTO `creature_addon` (`guid`, `mount`, `bytes1`, `bytes2`, `auras`) VALUES +(53208, 0, 0x7, 0x1, ''), -- 23232 - 41290 - 41290 +(53209, 0, 0x7, 0x1, ''), -- 23232 - 41290 - 41290 +(53210, 0, 0x7, 0x1, ''), -- 23232 - 41290 - 41290 +(53617, 0, 0x7, 0x1, ''), -- 23236 +(53586, 0, 0x7, 0x1, ''), -- 23236 +(53229, 0, 0x7, 0x1, ''), -- 23235 +(53711, 0, 0x7, 0x1, ''), -- 23237 +(53230, 0, 0x7, 0x1, ''), -- 23235 +(53710, 0, 0x7, 0x1, ''); -- 23237 + +UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` IN(23232); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN(23232) AND `source_type`=0; + +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(23232, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 11, 41290, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mutant War Hound - On Reset - Cast Disease Cloud'), +(23232, 0, 1, 0, 6, 0, 100, 0, 0, 0, 0, 0, 11, 41193, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Mutant War Hound - On Death - Cast Cloud of Disease'); diff --git a/sql/updates/auth/2016_04_11_00_auth.sql b/sql/updates/auth/2016_04_11_00_auth.sql new file mode 100644 index 00000000000..be8a4d21b66 --- /dev/null +++ b/sql/updates/auth/2016_04_11_00_auth.sql @@ -0,0 +1 @@ +UPDATE `updates` SET `state`='ARCHIVED'; diff --git a/sql/updates/characters/2016_04_11_00_characters.sql b/sql/updates/characters/2016_04_11_00_characters.sql new file mode 100644 index 00000000000..be8a4d21b66 --- /dev/null +++ b/sql/updates/characters/2016_04_11_00_characters.sql @@ -0,0 +1 @@ +UPDATE `updates` SET `state`='ARCHIVED'; diff --git a/sql/updates/world/2016_04_11_00_world.sql b/sql/updates/world/2016_04_11_00_world.sql new file mode 100644 index 00000000000..2f8d539fe43 --- /dev/null +++ b/sql/updates/world/2016_04_11_00_world.sql @@ -0,0 +1,3 @@ +UPDATE `version` SET `db_version`='TDB 335.61', `cache_id`=61 LIMIT 1; + +UPDATE `updates` SET `state`='ARCHIVED'; diff --git a/sql/updates/world/2016_04_11_01_world_335.sql b/sql/updates/world/2016_04_11_01_world_335.sql new file mode 100644 index 00000000000..a432307d0b1 --- /dev/null +++ b/sql/updates/world/2016_04_11_01_world_335.sql @@ -0,0 +1,2 @@ +-- +UPDATE `gameobject` SET `spawntimesecs` = 5 WHERE `guid` IN (45719, 45720, 45721); diff --git a/sql/updates/world/2016_04_11_02_world_335.sql b/sql/updates/world/2016_04_11_02_world_335.sql new file mode 100644 index 00000000000..93b6000554c --- /dev/null +++ b/sql/updates/world/2016_04_11_02_world_335.sql @@ -0,0 +1,2 @@ +-- +UPDATE `spell_group` SET `spell_id`=56112 WHERE `id`=1061 and`spell_id`=46910; diff --git a/sql/updates/world/2016_04_15_03_world_335.sql b/sql/updates/world/2016_04_15_03_world_335.sql new file mode 100644 index 00000000000..afbe3b3ab63 --- /dev/null +++ b/sql/updates/world/2016_04_15_03_world_335.sql @@ -0,0 +1,2 @@ +-- +UPDATE `smart_scripts` SET `action_type`=51, `action_param1`=0 WHERE `entryorguid`=193100 AND `source_type`=9 AND `id`=7; diff --git a/sql/updates/world/2016_04_16_00_world.sql b/sql/updates/world/2016_04_16_00_world.sql new file mode 100644 index 00000000000..9219a4ef316 --- /dev/null +++ b/sql/updates/world/2016_04_16_00_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_baron_geddon_inferno'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(19695, 'spell_baron_geddon_inferno'); diff --git a/sql/updates/world/2016_04_16_01_world.sql b/sql/updates/world/2016_04_16_01_world.sql new file mode 100644 index 00000000000..95a8f0934ad --- /dev/null +++ b/sql/updates/world/2016_04_16_01_world.sql @@ -0,0 +1,307 @@ +SET @OGUID := 78735; -- 20 free guids required +SET @CGUID := 84148; -- 9 free guids required + +SET @NPC := @CGUID+1; +SET @PATH := @NPC * 10; + +UPDATE `creature_template` SET `difficulty_entry_1`=0 WHERE `entry` IN (25740,25755,25756,25865); +UPDATE `creature_template` SET `minlevel`=82,`maxlevel`=82, `mechanic_immune_mask`=617299839, `ScriptName`='boss_ahune' WHERE `entry`=25740; -- Ahune +UPDATE `creature_template` SET `minlevel`=80,`maxlevel`=80, `AIName`='SmartAI' WHERE `entry`=25755; -- Ahunite Hailstone +UPDATE `creature_template` SET `minlevel`=80,`maxlevel`=80, `AIName`='SmartAI' WHERE `entry`=25756; -- Ahunite Coldwave +UPDATE `creature_template` SET `minlevel`=80,`maxlevel`=80, `AIName`='SmartAI' WHERE `entry`=25757; -- Ahunite Frostwind +UPDATE `creature_template` SET `minlevel`=80,`maxlevel`=80, `flags_extra`=`flags_extra`|0x40000000, `mechanic_immune_mask`=617299839, `ScriptName`='npc_frozen_core' WHERE `entry`=25865; -- Frozen Core +UPDATE `creature_template` SET `ScriptName`='npc_ahune_bunny' WHERE `entry`=25745; +UPDATE `creature_template` SET `ScriptName`='npc_earthen_ring_flamecaller' WHERE `entry`=25754; +UPDATE `creature_template` SET `unit_flags`=33554432, `MovementType`=2 WHERE `entry` IN (25964,25965,25966); -- Shaman beam bunny +UPDATE `creature_template` SET `unit_flags`=33554432 WHERE `entry`=26239; -- Ghost of Ahune +UPDATE `creature_template` SET `flags_extra`=128 WHERE `entry`=25985; -- Ahune Ice Spear Bunny +UPDATE `gameobject_template` SET `ScriptName`='go_ahune_ice_stone' WHERE `entry`=187882; +UPDATE `creature` SET `orientation`=2.408554 WHERE `guid`=202734; -- Luma +UPDATE `creature` SET `orientation`=3.804818 WHERE `guid`=202737; -- Flamecaller +UPDATE `creature_template` SET `HealthModifier`=94.5, `unit_flags`=33554688 WHERE `entry`=25865; +UPDATE `creature_template` SET `HealthModifier`=18.8 WHERE `entry`=25755; +UPDATE `creature_template` SET `HealthModifier`=3.538 WHERE `entry`=25756; +UPDATE `creature_template` SET `HealthModifier`=1.5 WHERE `entry`=25757; +UPDATE `creature_template` SET `HealthModifier`=4 WHERE `entry`=40446; +UPDATE `creature_template` SET `InhabitType`=7 WHERE `entry` IN (25964,25965,25966,26190); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN +('spell_ahune_synch_health', +'spell_ice_spear_control_aura', +'spell_slippery_floor_periodic', +'spell_summon_ice_spear_delayer', +'spell_summoning_rhyme_aura', +'spell_ahune_spanky_hands', +'spell_ahune_minion_despawner', +'spell_ice_spear_target_picker', +'spell_ice_bombardment_dest_picker'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(46430, 'spell_ahune_synch_health'), +(46371, 'spell_ice_spear_control_aura'), +(46320, 'spell_slippery_floor_periodic'), +(46878, 'spell_summon_ice_spear_delayer'), +(45926, 'spell_summoning_rhyme_aura'), +(46146, 'spell_ahune_spanky_hands'), +(46843, 'spell_ahune_minion_despawner'), +(46372, 'spell_ice_spear_target_picker'), +(46398, 'spell_ice_bombardment_dest_picker'); + +DELETE FROM `creature_text` WHERE `entry` IN (25745,25754,25697,40446); +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(25745,0,0,'The Earthen Ring\'s Assault Begins.',41,0,100,0,0,0,24930,1,'Ahune Bunny- EMOTE_EARTHEN_ASSAULT'), +(25754,0,0,'Ahune Retreats. His defenses diminish.',41,0,100,0,0,0,24931,1,'Earthen Ring Flamecaller - EMOTE_RETREAT'), +(25754,1,0,'Ahune will soon resurface.',41,0,100,0,0,0,24932,1,'Earthen Ring Flamecaller - EMOTE_RESURFACE'), +(40446,0,0,'How DARE you! You will not stop the coming of Lord Ahune!',14,0,100,0,0,0,40437,0,'Skar\'this the Summoner'), +(25697,0,0,'The Ice Stone has melted!',14,0,100,0,0,0,24895,0,'Luma Skymother - SAY_PLAYER_1'), +(25697,1,0,'Ahune, your strength grows no more!',14,0,100,0,0,0,24893,0,'Luma Skymother - SAY_PLAYER_2'), +(25697,2,0,'Your frozen reign will not come to pass!',14,0,100,0,0,0,24894,0,'Luma Skymother - SAY_PLAYER_3'); + +DELETE FROM `gossip_menu` WHERE `entry`=11389; +INSERT INTO `gossip_menu` VALUES +(11389,15864); + +DELETE FROM `gossip_menu_option` WHERE `menu_id`=11389; +INSERT INTO `gossip_menu_option` (`menu_id`,`id`,`option_icon`,`option_text`,`OptionBroadcastTextID`,`option_id`,`npc_option_npcflag`,`action_menu_id`,`action_poi_id`,`box_coded`,`box_money`,`box_text`,`BoxBroadcastTextID`) VALUES +(11389,1,0,'Disturb the stone and summon Lord Ahune.',40443,1,1,0,0,0,0,NULL,0); + +DELETE FROM `creature_template_addon` WHERE `entry` IN (25740,25755,25865,25985,25952); +INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `auras`) VALUES +(25740, 0, 0, 9, 1, 61976), +(25755, 0, 0, 0, 0, 46542), +(25865, 0, 0, 0, 0, '46810 61976'), +(25985, 0, 0, 0, 0, '75498 46878'), +(25952, 0, 0, 0, 0, 46314); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry` IN (46603,46593,46735,45930,45941,46809,46843,46396,46398,46236); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,46603,0,0,31,0,3,26121,0,0,0,0,'',"Spell 'Force Wisp Flight Missile' can hit 'Wisp Source Bunny'"), +(13,1,46593,0,0,31,0,3,26120,0,0,0,0,'',"Spell 'Wisp Flight Missile and Beam' can hit 'Wisp Dest Bunny'"), +(13,1,46735,0,0,31,0,3,26190,0,0,0,0,'',"Spell 'Spank - Force Bunny To Knock You To' can hit '[PH] Spank Target Bunny'"), +(13,1,45930,0,1,31,0,3,25971,0,0,0,0,'',"Spell 'Ahune - Summoning Rhyme Spell, make bonfire' can hit 'Shaman Bonfire Bunny 000'"), +(13,1,45930,0,2,31,0,3,25972,0,0,0,0,'',"Spell 'Ahune - Summoning Rhyme Spell, make bonfire' can hit 'Shaman Bonfire Bunny 001'"), +(13,1,45930,0,3,31,0,3,25973,0,0,0,0,'',"Spell 'Ahune - Summoning Rhyme Spell, make bonfire' can hit 'Shaman Bonfire Bunny 002'"), +(13,1,45941,0,0,31,0,3,25746,0,0,0,0,'',"Spell 'Summon Ahune's Loot Missile' can hit '[PH] Ahune Loot Loc Bunny'"), +(13,1,46809,0,0,31,0,3,26239,0,0,0,0,'',"Spell 'Make Ahune's Ghost Burst' can hit 'Ghost of Ahune"), +(13,1,46843,0,1,31,0,3,25756,0,0,0,0,'',"Spell 'Minion Despawner' can hit 'Ahunite Coldwave'"), +(13,1,46843,0,2,31,0,3,25757,0,0,0,0,'',"Spell 'Minion Despawner' can hit 'Ahunite Frostwind'"), +(13,1,46843,0,3,31,0,3,25755,0,0,0,0,'',"Spell 'Minion Despawner' can hit 'Ahunite Hailstone'"), +(13,1,46398,0,0,31,0,3,25972,0,0,0,0,'',"Spell 'Ice Bombardment Dest Picker' can hit 'Shaman Bonfire Bunny'"), +(13,1,46396,0,0,31,0,3,25972,0,0,0,0,'',"Spell 'Ice Bombardment' can hit 'Shaman Bonfire Bunny'"), +(13,1,46236,0,1,31,0,3,25971,0,0,0,0,'',"Spell 'Close opening Visual' can hit 'Shaman Bonfire Bunny 000'"), +(13,1,46236,0,2,31,0,3,25972,0,0,0,0,'',"Spell 'Close opening Visual' can hit 'Shaman Bonfire Bunny 001'"), +(13,1,46236,0,3,31,0,3,25973,0,0,0,0,'',"Spell 'Close opening Visual' can hit 'Shaman Bonfire Bunny 002'"); + +DELETE FROM `disables` WHERE `sourceType`=0 AND `entry` IN (46314,46603,46593,46422); +INSERT INTO `disables` (`sourceType`, `entry`, `flags`, `params_0`, `params_1`, `comment`) VALUES +(0,46314,64,0,0,'Disable LOS for spell Ahune - Slippery Floor Ambient'), +(0,46603,64,0,0,'Disable LOS for spell Force Whisp to Flight'), +(0,46593,64,0,0,'Disable LOS for spell Whisp Flight Missile and Beam'), +(0,46422,64,0,0,'Disable LOS for spell Shamans Look for Opening'); + +DELETE FROM `spell_linked_spell` WHERE `spell_trigger` IN (45947,-45964,45964); +INSERT INTO `spell_linked_spell` (`spell_trigger`,`spell_effect`,`type`,`comment`) VALUES +(45947,45946,2,''), +(-45964,-46333,0,''), +(45964,46333,0,''); + +-- Skar'this the Summoner +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=40446; +DELETE FROM `smart_scripts` WHERE `entryorguid`=40446 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(40446,0,0,0,1,0,100,1,0,0,0,0,11,75427,0,0,0,0,0,1,0,0,0,0,0,0,0,'Skar\'this the Summoner - OOC - Cast \'Frost Channelling\''), +(40446,0,1,0,4,0,100,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,'Skar\'this the Summoner - On agro - say'), +(40446,0,2,0,0,0,100,0,5000,5000,15000,15000,11,55909,1,0,0,0,0,2,0,0,0,0,0,0,0,'Skar\'this the Summoner - IC - Cast Crashing Wave'), +(40446,0,3,0,0,0,100,0,10000,10000,20000,20000,11,11831,1,0,0,0,0,2,0,0,0,0,0,0,0,'Skar\'this the Summoner - IC - Cast Frost Nova'), +(40446,0,4,0,0,0,100,0,7000,7000,9000,9000,11,15043,0,0,0,0,0,2,0,0,0,0,0,0,0,'Skar\'this the Summoner - IC - Cast Frostbolt'); + +-- Summon Loot Bunny SAI +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=25746; +DELETE FROM `smart_scripts` WHERE `entryorguid`=25746 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(25746,0,0,0,8,0,100,0,45941,0,0,0,11,46891,0,0,0,0,0,1,0,0,0,0,0,0,0,'[PH] Ahune Loot Loc Bunny - On SpellHit - Cast \'Summon Loot\''); + +-- [PH] Spank Target Bunny SAI +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=26190; +DELETE FROM `smart_scripts` WHERE `entryorguid`=26190 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(26190,0,0,0,8,0,100,0,46735,0,0,0,11,46734,0,0,0,0,0,7,0,0,0,0,0,0,0,'[PH] Spank Target Bunny - On SpellHit \'Spank - Force Bunny To Knock You To\' - Cast \'Knock To\''); + +-- Ghost of Ahune +UPDATE `creature_template` SET `AIName`='SmartAI', `flags_extra`='2' WHERE `entry`=26239; +DELETE FROM `smart_scripts` WHERE `entryorguid`=26239 AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`=2623900 AND `source_type`=9; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(26239,0,0,0,25,0,100,0,0,0,0,0,3,0,11686,0,0,0,0,1,0,0,0,0,0,0,0,'Ghost of Ahune - On Reset - Morph to Model 11686'), +(26239,0,1,0,8,0,100,0,46809,0,4000,4000,80,2623900,2,0,0,0,0,1,0,0,0,0,0,0,0,'Ghost of Ahune - On SpellHit \'Make Ahune\'s Ghost Burst\' - Call Timed ActionList'), +(2623900,9,0,0,0,0,100,0,0,0,0,0,3,0,23707,0,0,0,0,1,0,0,0,0,0,0,0,'Ghost of Ahune - Timed ActionList - Morph to Model 23707'), +(2623900,9,1,0,0,0,100,0,0,0,0,0,11,46786,0,0,0,0,0,1,0,0,0,0,0,0,0,'Ghost of Ahune - Timed ActionList - Cast \'Ahune\'s Ghost Disguise\''), +(2623900,9,2,0,0,0,100,0,2400,2400,0,0,47,0,0,0,0,0,0,1,0,0,0,0,0,0,0,'Ghost of Ahune - Timed ActionList - Set Visibility Off'), +(2623900,9,3,0,0,0,100,0,500,500,0,0,3,0,11686,0,0,0,0,1,0,0,0,0,0,0,0,'Ghost of Ahune - Timed ActionList - Morph to Model 11686'), +(2623900,9,4,0,0,0,100,0,0,0,0,0,47,1,0,0,0,0,0,1,0,0,0,0,0,0,0,'Ghost of Ahune - Timed ActionList - Set Visibility On'); + +-- Wisp Source Bunny SAI +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=26121; +DELETE FROM `smart_scripts` WHERE `entryorguid`=26121 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(26121,0,0,1,8,0,100,0,46603,0,0,0,11,46593,0,0,0,0,0,11,26120,100,0,0,0,0,0,'Wisp Source Bunny - On SpellHit \'Force Wisp Flight Missile\' - Cast \'Wisp Flight Missile and Beam\''), +(26121,0,1,0,61,0,100,0,0,0,0,0,41,9000,0,0,0,0,0,1,0,0,0,0,0,0,0,'Wisp Source Bunny - On SpellHit \'Force Wisp Flight Missile\' - Despawn in 9s'); + +-- Wisp Dest Bunny SAI +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=26120; +DELETE FROM `smart_scripts` WHERE `entryorguid`=26120 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(26120,0,0,0,8,0,100,0,46593,0,0,0,41,9000,0,0,0,0,0,1,0,0,0,0,0,0,0,'Wisp Dest Bunny - On SpellHit \'Wisp Flight Missile and Beam\' - Despawn in 9s'); + +-- Shaman Beam Bunny SAI +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry` IN (25971,25972,25973); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (25971,25972,25973) AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(25971,0,0,0,8,0,100,0,45930,0,0,0,11,46339,0,0,0,0,0,1,0,0,0,0,0,0,0,'Shaman Beam Bunny 000 - On SpellHit - Cast \'Bonfire Disguise\''), +(25972,0,0,0,8,0,100,0,45930,0,0,0,11,46339,0,0,0,0,0,1,0,0,0,0,0,0,0,'Shaman Beam Bunny 001 - On SpellHit - Cast \'Bonfire Disguise\''), +(25973,0,0,0,8,0,100,0,45930,0,0,0,11,46339,0,0,0,0,0,1,0,0,0,0,0,0,0,'Shaman Beam Bunny 002 - On SpellHit - Cast \'Bonfire Disguise\''); + +-- Ahunite Hailstone SAI +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=25755; +DELETE FROM `smart_scripts` WHERE `entryorguid`=25755 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(25755,0,0,0,0,0,100,0,6000,8000,6000,8000,11,2676,0,0,0,0,0,2,0,0,0,0,0,0,0,'Ahunite Hailstone - In Combat - Cast \'Pulverize\''); + +-- Ahunite Coldwave SAI +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=25756; +DELETE FROM `smart_scripts` WHERE `entryorguid`=25756 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(25756,0,0,0,0,0,100,0,5000,7000,6000,8000,11,46406,0,0,0,0,0,2,0,0,0,0,0,0,0,'Ahunite Coldwave - In Combat - Cast \'Bitter Blast\''); + +-- Ahunite Frostwind SAI +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=25757; +DELETE FROM `smart_scripts` WHERE `entryorguid`=25757 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(25757,0,0,0,54,0,100,0,0,0,0,0,11,12550,0,0,0,0,0,1,0,0,0,0,0,0,0,'Ahunite Frostwind - On Just Summoned - Cast \'Lightning Shield\''), +(25757,0,1,0,0,0,100,0,2000,2000,5000,7000,11,46568,0,0,0,0,0,18,120,0,0,0,0,0,0,'Ahunite Frostwind - In Combat - Cast \'Wind Buffet\''); + +DELETE FROM `item_loot_template` WHERE `entry`=35512; +INSERT INTO `item_loot_template` (`Entry`,`Item`,`Reference`,`Chance`,`QuestRequired`,`LootMode`,`GroupId`,`MinCount`,`MaxCount`,`Comment`) VALUES +(35512,17202,0,100,0,1,0,2,5,NULL); + +DELETE FROM `item_loot_template` WHERE `Entry`=54536; +INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`) VALUES +(54536, 54806, 0, 3, 0, 1, 0, 1, 1), +(54536, 23247, 0, 100, 0, 1, 1, 5, 10), +(54536, 53641, 0, 3, 0, 1, 0, 1, 1); + +DELETE FROM `creature` WHERE `guid` BETWEEN @CGUID AND @CGUID+8; +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`MovementType`,`npcflag`,`unit_flags`,`dynamicflags`) VALUES +(@CGUID,25745,547,1,1,0,0,-96.64146,-230.8864,4.780959,1.413717,300,0,0,1,1,0,0,0,0), -- [PH] Ahune Summon Loc Bunny +(@CGUID+1,25964,547,1,1,0,0,-90.00211,-224.9285,-1.378754,2.956095,300,0,0,1,1,2,0,0,0), -- Shaman Beam Bunny 000 +(@CGUID+2,25965,547,1,1,0,0,-97.39627,-223.761,-1.494899,0.9130945,300,0,0,1,1,2,0,0,0), -- Shaman Beam Bunny 001 +(@CGUID+3,25966,547,1,1,0,0,-103.3054,-224.0149,0.5259815,5.676991,300,0,0,1,1,2,0,0,0), -- Shaman Beam Bunny 002 +(@CGUID+4,26190,547,1,1,0,0,-95.33572,-207.4834,16.28742,4.904375,300,0,0,1,1,0,0,0,0), -- [PH] Spank Target Bunny +(@CGUID+5,25952,547,1,1,0,0,-96.64146,-230.8864,4.780959,1.413717,300,0,0,1,1,0,0,0,0), -- Slippery Floor Bunny +(@CGUID+6,25952,547,1,1,0,0,-69.83901,-162.474,-2.303646,2.513274,300,0,0,1,1,0,0,0,0), -- Slippery Floor Bunny +(@CGUID+7,26239,547,1,1,0,0,-99.10214,-233.1872,-1.22297,1.466077,300,0,0,1,1,0,0,0,0), -- Ghost of Ahune +(@CGUID+8,25746,547,1,1,0,0,-96.8723,-212.8425,-1.149142,4.153883,300,0,0,1,1,0,0,0,0); -- [PH] Ahune Loot Loc Bunny + +DELETE FROM `gameobject` WHERE `guid` BETWEEN @OGUID AND @OGUID+19; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `VerifiedBuild`) VALUES +(@OGUID+0, 187882, 547, 0, 0, 1, 1, -69.90455, -162.2449, -2.366563, 2.426008, 0, 0, 0.9366722, 0.3502074, 120, 255, 1,0), -- Icestone +(@OGUID+1, 188067, 547, 0, 0, 1, 1,-79.397, -219.7025, -4.042892, -2.199115, 0, 0, -0.8910065, 0.4539906, 120, 255, 1, 0), -- Ice Block +(@OGUID+2, 188067, 547, 0, 0, 1, 1, -115.5985, -162.7724, -1.924025, -0.5585039, 0, 0, -0.2756367, 0.9612619, 120, 255, 1, 0), -- Ice Block +(@OGUID+3, 188067, 547, 0, 0, 1, 1, -71.89625, -145.4974, -1.551813, -1.954766, 0, 0, -0.8290367, 0.5591941, 120, 255, 1, 0), -- Ice Block +(@OGUID+4, 188067, 547, 0, 0, 1, 1, -49.27251, -168.9859, -1.898811, 2.007128, 0, 0, 0.8433914, 0.5372996, 120, 255, 1, 0), -- Ice Block +(@OGUID+5, 188067, 547, 0, 0, 1, 1, -75.95139, -182.771, -4.882017, -1.151916, 0, 0, -0.5446386, 0.8386708, 120, 255, 1, 0), -- Ice Block +(@OGUID+6, 188067, 547, 0, 0, 1, 1, -83.52528, -172.1806, -3.816522, 0.01745246, 0, 0, 0.00872612, 0.9999619, 120, 255, 1, 0), -- Ice Block +(@OGUID+7, 188067, 547, 0, 0, 1, 1, -83.52528, -217.3293, -3.0728, -0.4886912, 0, 0, -0.2419214, 0.9702958, 120, 255, 1, 0), -- Ice Block +(@OGUID+8, 188072, 547, 0, 0, 1, 1, -71.48915, -160.7316, -4.18569, -0.4188786, 0, 0, -0.2079115, 0.9781476, 120, 255, 1, 0), -- Ice Stone Mount +(@OGUID+9, 188072, 547, 0, 0, 1, 1, -69.21773, -163.491, -2.044773, 2.967041, 0, 0, 0.9961939, 0.08716504, 120, 255, 1, 0), -- Ice Stone Mount +(@OGUID+10, 188072, 547, 0, 0, 1, 1, -71.82486, -164.475, -3.962982, -0.9250239, 0, 0, -0.4461975, 0.8949345, 120, 255, 1, 0), -- Ice Stone Mount +(@OGUID+11, 188072, 547, 0, 0, 1, 1, -69.20837, -160.345, -4.25643, 1.850049, 0, 0, 0.7986355, 0.601815, 120, 255, 1, 0), -- Ice Stone Mount +(@OGUID+12, 188073, 547, 0, 0, 1, 1, -89.75205, -113.5002, -2.709442, 0.453785, 0, 0, 0.2249508, 0.9743701, 120, 255, 1, 0), -- Ahune Bonfire +(@OGUID+13, 188073, 547, 0, 0, 1, 1,-114.9574, -117.3017, -2.71, 2.007128, 0, 0, 0.8433914, 0.5372996, 120, 255, 1, 0), -- Ahune Bonfire +(@OGUID+14, 188142, 547, 0, 0, 1, 1, -74.65959, -243.8125, -2.735999, 2.216565, 0, 0, 0.8949337, 0.4461992, 120, 255, 1, 0), -- Ice Block, Big +(@OGUID+15, 188142, 547, 0, 0, 1, 1, -72.75314, -185.1547, -4.930593, 0.157079, 0, 0, 0.07845879, 0.9969174, 120, 255, 1, 0), -- Ice Block, Big +(@OGUID+16, 188142, 547, 0, 0, 1, 1, -103.7134, -245.5041, -1.377881, -1.291542, 0, 0, -0.6018143, 0.7986361, 120, 255, 1, 0), -- Ice Block, Big +(@OGUID+17, 188142, 547, 0, 0, 1, 1, -118.9196, -204.8023, -1.504161, 1.919862, 0, 0, 0.8191519, 0.5735767, 120, 255, 1, 0), -- Ice Block, Big +(@OGUID+18, 188142, 547, 0, 0, 1, 1, -117.3857, -165.9649, -2.018646, 0.5585039, 0, 0, 0.2756367, 0.9612619, 120, 255, 1, 0), -- Ice Block, Big +(@OGUID+19, 188142, 547, 0, 0, 1, 1, -75.42784, -221.16, -2.882941, 0.4886912, 0, 0, 0.2419214, 0.9702958, 120, 255, 1, 0); -- Ice Block, Big + +DELETE FROM `creature_addon` WHERE `guid` IN (@NPC,@NPC+1,@NPC+2); +INSERT INTO `creature_addon` (`guid`,`path_id`) VALUES +(@NPC,@PATH), +(@NPC+1,@PATH+10), +(@NPC+2,@PATH+20); + +DELETE FROM `waypoint_data` WHERE `id` IN (@PATH,@PATH+10,@PATH+20); +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-107.1537,-233.7247,27.1834,0,0,0,100,0), +(@PATH,2,-109.4618,-232.0907,25.12787,0,0,0,100,0), +(@PATH,3,-109.4792,-229.4328,20.98899,0,0,0,100,0), +(@PATH,4,-105.9522,-226.8887,17.26674,0,0,0,100,0), +(@PATH,5,-101.0044,-224.8914,16.04452,0,0,0,100,0), +(@PATH,6,-96.82773,-225.9608,15.73896,0,0,0,100,0), +(@PATH,7,-92.59879,-227.0505,15.54452,0,0,0,100,0), +(@PATH,8,-90.07465,-229.0938,16.58224,0,0,0,100,0), +(@PATH,9,-88.24558,-231.7715,22.47455,0,0,0,100,0), +(@PATH,10,-91.0969,-232.6422,24.65563,0,0,0,100,0), +(@PATH,11,-97.20647,-234.4709,28.46118,0,0,0,100,0), +(@PATH,12,-101.5825,-234.9054,29.35008,0,0,0,100,0), + +(@PATH+10,1,-109.4618,-232.0907,25.12787,0,0,0,100,0), +(@PATH+10,2,-109.4792,-229.4328,20.98899,0,0,0,100,0), +(@PATH+10,3,-105.9522,-226.8887,17.26674,0,0,0,100,0), +(@PATH+10,4,-101.0044,-224.8914,16.04452,0,0,0,100,0), +(@PATH+10,5,-96.82773,-225.9608,15.73896,0,0,0,100,0), +(@PATH+10,6,-92.59879,-227.0505,15.54452,0,0,0,100,0), +(@PATH+10,7,-90.07465,-229.0938,16.58224,0,0,0,100,0), +(@PATH+10,8,-88.24558,-231.7715,22.47455,0,0,0,100,0), +(@PATH+10,9,-91.0969,-232.6422,24.65563,0,0,0,100,0), +(@PATH+10,10,-97.20647,-234.4709,28.46118,0,0,0,100,0), +(@PATH+10,11,-101.5825,-234.9054,29.35008,0,0,0,100,0), +(@PATH+10,12,-107.1537,-233.7247,27.1834,0,0,0,100,0), + +(@PATH+20,1,-97.20647,-234.4709,28.46118,0,0,0,100,0), +(@PATH+20,2,-101.5825,-234.9054,29.35008,0,0,0,100,0), +(@PATH+20,3,-107.1537,-233.7247,27.1834,0,0,0,100,0), +(@PATH+20,4,-109.4618,-232.0907,25.12787,0,0,0,100,0), +(@PATH+20,5,-109.4792,-229.4328,20.98899,0,0,0,100,0), +(@PATH+20,6,-105.9522,-226.8887,17.26674,0,0,0,100,0), +(@PATH+20,7,-101.0044,-224.8914,16.04452,0,0,0,100,0), +(@PATH+20,8,-96.82773,-225.9608,15.73896,0,0,0,100,0), +(@PATH+20,9,-92.59879,-227.0505,15.54452,0,0,0,100,0), +(@PATH+20,10,-90.07465,-229.0938,16.58224,0,0,0,100,0), +(@PATH+20,11,-88.24558,-231.7715,22.47455,0,0,0,100,0), +(@PATH+20,12,-91.0969,-232.6422,24.65563,0,0,0,100,0); + +DELETE FROM `game_event_creature` WHERE `guid` BETWEEN @CGUID AND @CGUID+8 AND `eventEntry`=1; +INSERT INTO `game_event_creature` (`eventEntry`,`guid`) VALUES +(1,@CGUID), +(1,@CGUID+1), +(1,@CGUID+2), +(1,@CGUID+3), +(1,@CGUID+4), +(1,@CGUID+5), +(1,@CGUID+6), +(1,@CGUID+7), +(1,@CGUID+8); + +DELETE FROM `game_event_gameobject` WHERE `guid` BETWEEN @OGUID AND @OGUID+19 AND `eventEntry`=1; +INSERT INTO `game_event_gameobject` (`eventEntry`,`guid`) VALUES +(1,@OGUID), +(1,@OGUID+1), +(1,@OGUID+2), +(1,@OGUID+3), +(1,@OGUID+4), +(1,@OGUID+5), +(1,@OGUID+6), +(1,@OGUID+7), +(1,@OGUID+8), +(1,@OGUID+9), +(1,@OGUID+10), +(1,@OGUID+11), +(1,@OGUID+12), +(1,@OGUID+13), +(1,@OGUID+14), +(1,@OGUID+15), +(1,@OGUID+16), +(1,@OGUID+17), +(1,@OGUID+18), +(1,@OGUID+19); diff --git a/sql/updates/world/dummy b/sql/updates/world/dummy new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sql/updates/world/dummy diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 8dee99c65e7..0428738f2dd 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -8,42 +8,33 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -if( USE_COREPCH ) - include_directories(${CMAKE_CURRENT_BINARY_DIR}) -endif() - -file(GLOB_RECURSE sources_Common Common.cpp Common.h) -file(GLOB_RECURSE sources_Collision Collision/*.cpp Collision/*.h) -file(GLOB_RECURSE sources_Threading Threading/*.cpp Threading/*.h) -file(GLOB_RECURSE sources_Utilities Utilities/*.cpp Utilities/*.h) -file(GLOB_RECURSE sources_Configuration Configuration/*.cpp Configuration/*.h) -file(GLOB_RECURSE sources_Logging Logging/*.cpp Logging/*.h) -if (SERVERS) - file(GLOB_RECURSE sources_Cryptography Cryptography/*.cpp Cryptography/*.h) -endif (SERVERS) +CollectSourceFiles( + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE_SOURCES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/Debugging + ${CMAKE_CURRENT_SOURCE_DIR}/Platform + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) # Manually set sources for Debugging directory as we don't want to include WheatyExceptionReport in common project # It needs to be included both in authserver and worldserver for the static global variable to be properly initialized # and to handle crash logs on windows -set(sources_Debugging Debugging/Errors.cpp Debugging/Errors.h) -file(GLOB sources_localdir *.cpp *.h) +list(APPEND PRIVATE_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/Debugging/Errors.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Debugging/Errors.h) if (USE_COREPCH) - set(common_STAT_PCH_HDR PrecompiledHeaders/commonPCH.h) - set(common_STAT_PCH_SRC PrecompiledHeaders/commonPCH.cpp) + set(PRIVATE_PCH_HEADER PrecompiledHeaders/commonPCH.h) + set(PRIVATE_PCH_SOURCE PrecompiledHeaders/commonPCH.cpp) endif (USE_COREPCH) -set(common_STAT_SRCS - ${common_STAT_SRCS} - ${sources_Common} - ${sources_Collision} - ${sources_Threading} - ${sources_Utilities} - ${sources_Debugging} - ${sources_Configuration} - ${sources_Logging} - ${sources_Cryptography} - ${sources_localdir} +GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) + +add_definitions(-DTRINITY_API_EXPORT_COMMON) + +add_library(common + ${PRIVATE_PCH_SOURCE} + ${PRIVATE_SOURCES} ) # Do NOT add any extra include directory here, as we don't want the common @@ -55,37 +46,55 @@ set(common_STAT_SRCS # linkage (enums, defines...) it is discouraged to do so unless necessary, as it will pullute # include_directories leading to further unnoticed dependency aditions # Linker Depencency requirements: none -include_directories( - ${CMAKE_BINARY_DIR} +CollectIncludeDirectories( ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/Collision - ${CMAKE_CURRENT_SOURCE_DIR}/Collision/Management - ${CMAKE_CURRENT_SOURCE_DIR}/Collision/Maps - ${CMAKE_CURRENT_SOURCE_DIR}/Collision/Models - ${CMAKE_CURRENT_SOURCE_DIR}/Configuration - ${CMAKE_CURRENT_SOURCE_DIR}/Cryptography - ${CMAKE_CURRENT_SOURCE_DIR}/Debugging - ${CMAKE_CURRENT_SOURCE_DIR}/Logging - ${CMAKE_CURRENT_SOURCE_DIR}/Utilities - ${CMAKE_SOURCE_DIR}/dep/cppformat - ${CMAKE_SOURCE_DIR}/dep/g3dlite/include - ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include - ${CMAKE_SOURCE_DIR}/dep/SFMT - ${CMAKE_SOURCE_DIR}/dep/utf8cpp - ${OPENSSL_INCLUDE_DIR} - ${VALGRIND_INCLUDE_DIR} -) + PUBLIC_INCLUDES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) -GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(common + PUBLIC + # Provide the binary dir for all child targets + ${CMAKE_BINARY_DIR} + ${PUBLIC_INCLUDES} + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) -add_library(common STATIC - ${common_STAT_SRCS} - ${common_STAT_PCH_SRC} -) +target_link_libraries(common + PUBLIC + boost + cppformat + g3dlib + Detour + sfmt + utf8cpp + openssl + valgrind + threads + jemalloc + PRIVATE + process) add_dependencies(common revision_data.h) +set_target_properties(common + PROPERTIES + FOLDER + "server") + +if( BUILD_SHARED_LIBS ) + if( UNIX ) + install(TARGETS common + LIBRARY + DESTINATION lib) + elseif( WIN32 ) + install(TARGETS common + RUNTIME + DESTINATION "${CMAKE_INSTALL_PREFIX}") + endif() +endif() + # Generate precompiled header if (USE_COREPCH) - add_cxx_pch(common ${common_STAT_PCH_HDR} ${common_STAT_PCH_SRC}) + add_cxx_pch(common ${PRIVATE_PCH_HEADER} ${PRIVATE_PCH_SOURCE}) endif () diff --git a/src/common/Collision/BoundingIntervalHierarchy.h b/src/common/Collision/BoundingIntervalHierarchy.h index 0b15bd2d92f..eb0a102806f 100644 --- a/src/common/Collision/BoundingIntervalHierarchy.h +++ b/src/common/Collision/BoundingIntervalHierarchy.h @@ -67,7 +67,7 @@ struct AABound Copyright (c) 2003-2007 Christopher Kulla */ -class BIH +class TC_COMMON_API BIH { private: void init_empty() diff --git a/src/common/Collision/DynamicTree.h b/src/common/Collision/DynamicTree.h index 0f18bb265f8..85707efebd2 100644 --- a/src/common/Collision/DynamicTree.h +++ b/src/common/Collision/DynamicTree.h @@ -31,7 +31,7 @@ namespace G3D class GameObjectModel; struct DynTreeImpl; -class DynamicMapTree +class TC_COMMON_API DynamicMapTree { DynTreeImpl *impl; diff --git a/src/common/Collision/Management/IVMapManager.h b/src/common/Collision/Management/IVMapManager.h index 1e64551956c..35437b7b816 100644 --- a/src/common/Collision/Management/IVMapManager.h +++ b/src/common/Collision/Management/IVMapManager.h @@ -42,7 +42,7 @@ namespace VMAP #define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case //=========================================================== - class IVMapManager + class TC_COMMON_API IVMapManager { private: bool iEnableLineOfSightCalc; diff --git a/src/common/Collision/Management/MMapFactory.h b/src/common/Collision/Management/MMapFactory.h index edd074fc93d..6dda7a40a22 100644 --- a/src/common/Collision/Management/MMapFactory.h +++ b/src/common/Collision/Management/MMapFactory.h @@ -38,7 +38,7 @@ namespace MMAP // static class // holds all mmap global data // access point to MMapManager singleton - class MMapFactory + class TC_COMMON_API MMapFactory { public: static MMapManager* createOrGetMMapManager(); diff --git a/src/common/Collision/Management/MMapManager.h b/src/common/Collision/Management/MMapManager.h index 1a502a916dd..a8d792296bb 100644 --- a/src/common/Collision/Management/MMapManager.h +++ b/src/common/Collision/Management/MMapManager.h @@ -58,7 +58,7 @@ namespace MMAP // singleton class // holds all all access to mmap loading unloading and meshes - class MMapManager + class TC_COMMON_API MMapManager { public: MMapManager() : loadedTiles(0), thread_safe_environment(true) {} @@ -75,7 +75,7 @@ namespace MMAP dtNavMesh const* GetNavMesh(uint32 mapId); uint32 getLoadedTilesCount() const { return loadedTiles; } - uint32 getLoadedMapsCount() const { return loadedMMaps.size(); } + uint32 getLoadedMapsCount() const { return uint32(loadedMMaps.size()); } private: bool loadMapData(uint32 mapId); uint32 packTileID(int32 x, int32 y); diff --git a/src/common/Collision/Management/VMapFactory.h b/src/common/Collision/Management/VMapFactory.h index 1a45bd5094b..a730fa12ef2 100644 --- a/src/common/Collision/Management/VMapFactory.h +++ b/src/common/Collision/Management/VMapFactory.h @@ -29,7 +29,7 @@ namespace VMAP { //=========================================================== - class VMapFactory + class TC_COMMON_API VMapFactory { public: static IVMapManager* createOrGetVMapManager(); diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h index 722ac4935c6..61c5025e41f 100644 --- a/src/common/Collision/Management/VMapManager2.h +++ b/src/common/Collision/Management/VMapManager2.h @@ -51,7 +51,7 @@ namespace VMAP class StaticMapTree; class WorldModel; - class ManagedModel + class TC_COMMON_API ManagedModel { public: ManagedModel() : iModel(nullptr), iRefCount(0) { } @@ -75,7 +75,7 @@ namespace VMAP VMAP_DISABLE_LIQUIDSTATUS = 0x8 }; - class VMapManager2 : public IVMapManager + class TC_COMMON_API VMapManager2 : public IVMapManager { protected: // Tree to check collision diff --git a/src/common/Collision/Maps/MapTree.h b/src/common/Collision/Maps/MapTree.h index 63d542754c1..c6a283cac4d 100644 --- a/src/common/Collision/Maps/MapTree.h +++ b/src/common/Collision/Maps/MapTree.h @@ -29,7 +29,7 @@ namespace VMAP class GroupModel; class VMapManager2; - struct LocationInfo + struct TC_COMMON_API LocationInfo { LocationInfo(): hitInstance(nullptr), hitModel(nullptr), ground_Z(-G3D::finf()) { } const ModelInstance* hitInstance; @@ -37,7 +37,7 @@ namespace VMAP float ground_Z; }; - class StaticMapTree + class TC_COMMON_API StaticMapTree { typedef std::unordered_map<uint32, bool> loadedTileMap; typedef std::unordered_map<uint32, uint32> loadedSpawnMap; @@ -87,7 +87,7 @@ namespace VMAP StaticMapTree& operator=(StaticMapTree const& right) = delete; }; - struct AreaInfo + struct TC_COMMON_API AreaInfo { AreaInfo(): result(false), ground_Z(-G3D::finf()), flags(0), adtId(0), rootId(0), groupId(0) { } diff --git a/src/common/Collision/Maps/TileAssembler.h b/src/common/Collision/Maps/TileAssembler.h index 1e2dc1924f1..74111f69910 100644 --- a/src/common/Collision/Maps/TileAssembler.h +++ b/src/common/Collision/Maps/TileAssembler.h @@ -35,7 +35,7 @@ namespace VMAP */ //=============================================== - class ModelPosition + class TC_COMMON_API ModelPosition { private: G3D::Matrix3 iRotation; @@ -55,7 +55,7 @@ namespace VMAP typedef std::map<uint32, ModelSpawn> UniqueEntryMap; typedef std::multimap<uint32, uint32> TileMap; - struct MapSpawns + struct TC_COMMON_API MapSpawns { UniqueEntryMap UniqueEntries; TileMap TileEntries; @@ -64,7 +64,7 @@ namespace VMAP typedef std::map<uint32, MapSpawns*> MapData; //=============================================== - struct GroupModel_Raw + struct TC_COMMON_API GroupModel_Raw { uint32 mogpflags; uint32 GroupWMOID; @@ -82,7 +82,7 @@ namespace VMAP bool Read(FILE* f); }; - struct WorldModel_Raw + struct TC_COMMON_API WorldModel_Raw { uint32 RootWMOID; std::vector<GroupModel_Raw> groupsArray; @@ -90,7 +90,7 @@ namespace VMAP bool Read(const char * path); }; - class TileAssembler + class TC_COMMON_API TileAssembler { private: std::string iDestDir; diff --git a/src/common/Collision/Models/GameObjectModel.h b/src/common/Collision/Models/GameObjectModel.h index 9d8687233c1..37f11af20ac 100644 --- a/src/common/Collision/Models/GameObjectModel.h +++ b/src/common/Collision/Models/GameObjectModel.h @@ -35,7 +35,7 @@ namespace VMAP class GameObject; struct GameObjectDisplayInfoEntry; -class GameObjectModelOwnerBase +class TC_COMMON_API GameObjectModelOwnerBase { public: virtual bool IsSpawned() const { return false; } @@ -47,7 +47,7 @@ public: virtual void DebugVisualizeCorner(G3D::Vector3 const& /*corner*/) const { } }; -class GameObjectModel /*, public Intersectable*/ +class TC_COMMON_API GameObjectModel /*, public Intersectable*/ { GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(NULL) { } public: @@ -84,4 +84,6 @@ private: std::unique_ptr<GameObjectModelOwnerBase> owner; }; +TC_COMMON_API void LoadGameObjectModelList(std::string const& dataPath); + #endif // _GAMEOBJECT_MODEL_H diff --git a/src/common/Collision/Models/ModelInstance.h b/src/common/Collision/Models/ModelInstance.h index d101630d1e9..84a41b15ce6 100644 --- a/src/common/Collision/Models/ModelInstance.h +++ b/src/common/Collision/Models/ModelInstance.h @@ -39,7 +39,7 @@ namespace VMAP MOD_HAS_BOUND = 1<<2 }; - class ModelSpawn + class TC_COMMON_API ModelSpawn { public: //mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name @@ -60,7 +60,7 @@ namespace VMAP static bool writeToFile(FILE* rw, const ModelSpawn &spawn); }; - class ModelInstance: public ModelSpawn + class TC_COMMON_API ModelInstance: public ModelSpawn { public: ModelInstance(): iInvScale(0.0f), iModel(nullptr) { } diff --git a/src/common/Collision/Models/WorldModel.h b/src/common/Collision/Models/WorldModel.h index 39787f6c664..bfc0367627f 100644 --- a/src/common/Collision/Models/WorldModel.h +++ b/src/common/Collision/Models/WorldModel.h @@ -33,7 +33,7 @@ namespace VMAP struct AreaInfo; struct LocationInfo; - class MeshTriangle + class TC_COMMON_API MeshTriangle { public: MeshTriangle() : idx0(0), idx1(0), idx2(0) { } @@ -44,7 +44,7 @@ namespace VMAP uint32 idx2; }; - class WmoLiquid + class TC_COMMON_API WmoLiquid { public: WmoLiquid(uint32 width, uint32 height, const G3D::Vector3 &corner, uint32 type); @@ -70,7 +70,7 @@ namespace VMAP }; /*! holding additional info for WMO group files */ - class GroupModel + class TC_COMMON_API GroupModel { public: GroupModel() : iBound(), iMogpFlags(0), iGroupWMOID(0), iLiquid(NULL) { } @@ -103,7 +103,7 @@ namespace VMAP }; /*! Holds a model (converted M2 or WMO) in its original coordinate space */ - class WorldModel + class TC_COMMON_API WorldModel { public: WorldModel(): RootWMOID(0) { } diff --git a/src/common/Collision/RegularGrid.h b/src/common/Collision/RegularGrid.h index 6a2a07968ad..563cf516406 100644 --- a/src/common/Collision/RegularGrid.h +++ b/src/common/Collision/RegularGrid.h @@ -20,7 +20,7 @@ class NodeCreatorFunc = NodeCreator<Node>, /*class BoundsFunc = BoundsTrait<T>,*/ class PositionFunc = PositionTrait<T> > -class RegularGrid2D +class TC_COMMON_API RegularGrid2D { public: diff --git a/src/common/Common.h b/src/common/Common.h index e8adc55d20d..aa04abacd30 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -21,28 +21,31 @@ #include "Define.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <cmath> -#include <errno.h> -#include <signal.h> -#include <assert.h> - -#include <set> -#include <unordered_set> +#include <algorithm> +#include <array> +#include <exception> #include <list> -#include <string> #include <map> -#include <unordered_map> +#include <memory> #include <queue> +#include <set> #include <sstream> -#include <algorithm> -#include <memory> +#include <string> +#include <type_traits> +#include <unordered_map> +#include <unordered_set> #include <vector> -#include <array> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <ctime> +#include <cerrno> +#include <csignal> + +#include <boost/optional.hpp> +#include <boost/utility/in_place_factory.hpp> #include <boost/functional/hash.hpp> #include "Debugging/Errors.h" @@ -130,9 +133,9 @@ enum LocaleConstant #define MAX_LOCALES 8 #define MAX_ACCOUNT_TUTORIAL_VALUES 8 -extern char const* localeNames[TOTAL_LOCALES]; +TC_COMMON_API extern char const* localeNames[TOTAL_LOCALES]; -LocaleConstant GetLocaleByName(const std::string& name); +TC_COMMON_API LocaleConstant GetLocaleByName(const std::string& name); typedef std::vector<std::string> StringVector; @@ -151,6 +154,10 @@ typedef std::vector<std::string> StringVector; #define MAX_QUERY_LEN 32*1024 +//! Optional helper class to wrap optional values within. +template <typename T> +using Optional = boost::optional<T>; + namespace Trinity { //! std::make_unique implementation (TODO: remove this once C++14 is supported) diff --git a/src/common/Configuration/BuiltInConfig.h b/src/common/Configuration/BuiltInConfig.h index 4ae4ed40189..0ffa059bc41 100644 --- a/src/common/Configuration/BuiltInConfig.h +++ b/src/common/Configuration/BuiltInConfig.h @@ -19,6 +19,7 @@ #define BUILT_IN_CONFIG_H #include <string> +#include "Define.h" /// Provides helper functions to access built-in values /// which can be overwritten in config @@ -26,16 +27,16 @@ namespace BuiltInConfig { /// Returns the CMake command when any is specified in the config, /// returns the built-in path otherwise - std::string GetCMakeCommand(); + TC_COMMON_API std::string GetCMakeCommand(); /// Returns the build directory path when any is specified in the config, /// returns the built-in one otherwise - std::string GetBuildDirectory(); + TC_COMMON_API std::string GetBuildDirectory(); /// Returns the source directory path when any is specified in the config, /// returns the built-in one otherwise - std::string GetSourceDirectory(); + TC_COMMON_API std::string GetSourceDirectory(); /// Returns the path to the mysql executable (`mysql`) when any is specified /// in the config, returns the built-in one otherwise - std::string GetMySQLExecutable(); + TC_COMMON_API std::string GetMySQLExecutable(); } // namespace BuiltInConfig diff --git a/src/common/Configuration/Config.cpp b/src/common/Configuration/Config.cpp index 5db333c8aff..ddaab7dee61 100644 --- a/src/common/Configuration/Config.cpp +++ b/src/common/Configuration/Config.cpp @@ -21,6 +21,7 @@ #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ini_parser.hpp> #include "Config.h" +#include "Log.h" using namespace boost::property_tree; @@ -56,42 +57,81 @@ bool ConfigMgr::LoadInitial(std::string const& file, std::string& error) return true; } +ConfigMgr* ConfigMgr::instance() +{ + static ConfigMgr instance; + return &instance; +} + bool ConfigMgr::Reload(std::string& error) { return LoadInitial(_filename, error); } -std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def) const +template<class T> +T ConfigMgr::GetValueDefault(std::string const& name, T def) const { - std::string value = _config.get<std::string>(ptree::path_type(name, '/'), def); - - value.erase(std::remove(value.begin(), value.end(), '"'), value.end()); + try + { + return _config.get<T>(ptree::path_type(name, '/')); + } + catch (boost::property_tree::ptree_bad_path) + { + TC_LOG_WARN("server.loading", "Missing name %s in config file %s, add \"%s = %s\" to this file", + name.c_str(), _filename.c_str(), name.c_str(), std::to_string(def).c_str()); + } + catch (boost::property_tree::ptree_bad_data) + { + TC_LOG_ERROR("server.loading", "Bad value defined for name %s in config file %s, going to use %s instead", + name.c_str(), _filename.c_str(), std::to_string(def).c_str()); + } - return value; + return def; } -bool ConfigMgr::GetBoolDefault(std::string const& name, bool def) const +template<> +std::string ConfigMgr::GetValueDefault<std::string>(std::string const& name, std::string def) const { try { - std::string val = _config.get<std::string>(ptree::path_type(name, '/')); - val.erase(std::remove(val.begin(), val.end(), '"'), val.end()); - return (val == "true" || val == "TRUE" || val == "yes" || val == "YES" || val == "1"); + return _config.get<std::string>(ptree::path_type(name, '/')); + } + catch (boost::property_tree::ptree_bad_path) + { + TC_LOG_WARN("server.loading", "Missing name %s in config file %s, add \"%s = %s\" to this file", + name.c_str(), _filename.c_str(), name.c_str(), def.c_str()); } - catch (std::exception const& /*ex*/) + catch (boost::property_tree::ptree_bad_data) { - return def; + TC_LOG_ERROR("server.loading", "Bad value defined for name %s in config file %s, going to use %s instead", + name.c_str(), _filename.c_str(), def.c_str()); } + + return def; +} + +std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def) const +{ + std::string val = GetValueDefault(name, def); + val.erase(std::remove(val.begin(), val.end(), '"'), val.end()); + return val; +} + +bool ConfigMgr::GetBoolDefault(std::string const& name, bool def) const +{ + std::string val = GetValueDefault(name, std::string(def ? "1" : "0")); + val.erase(std::remove(val.begin(), val.end(), '"'), val.end()); + return (val == "1" || val == "true" || val == "TRUE" || val == "yes" || val == "YES"); } int ConfigMgr::GetIntDefault(std::string const& name, int def) const { - return _config.get<int>(ptree::path_type(name, '/'), def); + return GetValueDefault(name, def); } float ConfigMgr::GetFloatDefault(std::string const& name, float def) const { - return _config.get<float>(ptree::path_type(name, '/'), def); + return GetValueDefault(name, def); } std::string const& ConfigMgr::GetFilename() diff --git a/src/common/Configuration/Config.h b/src/common/Configuration/Config.h index ada910d8fcc..10113cd88d3 100644 --- a/src/common/Configuration/Config.h +++ b/src/common/Configuration/Config.h @@ -19,25 +19,25 @@ #ifndef CONFIG_H #define CONFIG_H +#include "Define.h" + #include <string> #include <list> #include <mutex> #include <boost/property_tree/ptree.hpp> -class ConfigMgr +class TC_COMMON_API ConfigMgr { - ConfigMgr() { } - ~ConfigMgr() { } + ConfigMgr() = default; + ConfigMgr(ConfigMgr const&) = delete; + ConfigMgr& operator=(ConfigMgr const&) = delete; + ~ConfigMgr() = default; public: /// Method used only for loading main configuration files (authserver.conf and worldserver.conf) bool LoadInitial(std::string const& file, std::string& error); - static ConfigMgr* instance() - { - static ConfigMgr instance; - return &instance; - } + static ConfigMgr* instance(); bool Reload(std::string& error); @@ -54,8 +54,8 @@ private: boost::property_tree::ptree _config; std::mutex _configLock; - ConfigMgr(ConfigMgr const&); - ConfigMgr& operator=(ConfigMgr const&); + template<class T> + T GetValueDefault(std::string const& name, T def) const; }; #define sConfigMgr ConfigMgr::instance() diff --git a/src/common/Cryptography/ARC4.h b/src/common/Cryptography/ARC4.h index f39e662e295..7e680176836 100644 --- a/src/common/Cryptography/ARC4.h +++ b/src/common/Cryptography/ARC4.h @@ -22,7 +22,7 @@ #include <openssl/evp.h> #include "Define.h" -class ARC4 +class TC_COMMON_API ARC4 { public: ARC4(uint8 len); diff --git a/src/common/Cryptography/Authentication/AuthCrypt.h b/src/common/Cryptography/Authentication/AuthCrypt.h index 878391e3ce8..db4de8a7bd1 100644 --- a/src/common/Cryptography/Authentication/AuthCrypt.h +++ b/src/common/Cryptography/Authentication/AuthCrypt.h @@ -23,7 +23,7 @@ class BigNumber; -class AuthCrypt +class TC_COMMON_API AuthCrypt { public: AuthCrypt(); diff --git a/src/common/Cryptography/BigNumber.h b/src/common/Cryptography/BigNumber.h index a5bda50dc72..1d21be1b431 100644 --- a/src/common/Cryptography/BigNumber.h +++ b/src/common/Cryptography/BigNumber.h @@ -24,7 +24,7 @@ struct bignum_st; -class BigNumber +class TC_COMMON_API BigNumber { public: BigNumber(); diff --git a/src/common/Cryptography/HMACSHA1.h b/src/common/Cryptography/HMACSHA1.h index 29a926d5b16..049847489a6 100644 --- a/src/common/Cryptography/HMACSHA1.h +++ b/src/common/Cryptography/HMACSHA1.h @@ -28,7 +28,7 @@ class BigNumber; #define SEED_KEY_SIZE 16 -class HmacHash +class TC_COMMON_API HmacHash { public: HmacHash(uint32 len, uint8 *seed); diff --git a/src/common/Cryptography/OpenSSLCrypto.h b/src/common/Cryptography/OpenSSLCrypto.h index df1b14b5eda..65155df9af8 100644 --- a/src/common/Cryptography/OpenSSLCrypto.h +++ b/src/common/Cryptography/OpenSSLCrypto.h @@ -18,6 +18,8 @@ #ifndef OPENSSL_CRYPTO_H #define OPENSSL_CRYPTO_H +#include "Define.h" + /** * A group of functions which setup openssl crypto module to work properly in multithreaded enviroment * If not setup properly - it will crash @@ -25,9 +27,9 @@ namespace OpenSSLCrypto { /// Needs to be called before threads using openssl are spawned - void threadsSetup(); + TC_COMMON_API void threadsSetup(); /// Needs to be called after threads using openssl are despawned - void threadsCleanup(); + TC_COMMON_API void threadsCleanup(); } -#endif
\ No newline at end of file +#endif diff --git a/src/common/Cryptography/SHA1.h b/src/common/Cryptography/SHA1.h index ffa02176a2d..970ab5c0cb9 100644 --- a/src/common/Cryptography/SHA1.h +++ b/src/common/Cryptography/SHA1.h @@ -25,7 +25,7 @@ class BigNumber; -class SHA1Hash +class TC_COMMON_API SHA1Hash { public: SHA1Hash(); diff --git a/src/common/Debugging/Errors.cpp b/src/common/Debugging/Errors.cpp index 1ec66ff6d59..2ce00229e53 100644 --- a/src/common/Debugging/Errors.cpp +++ b/src/common/Debugging/Errors.cpp @@ -96,4 +96,11 @@ void Abort(char const* file, int line, char const* function) exit(1); } +void AbortHandler(int /*sigval*/) +{ + // nothing useful to log here, no way to pass args + *((volatile int*)NULL) = 0; + exit(1); +} + } // namespace Trinity diff --git a/src/common/Debugging/Errors.h b/src/common/Debugging/Errors.h index 38e311a6b13..e4b3563ca96 100644 --- a/src/common/Debugging/Errors.h +++ b/src/common/Debugging/Errors.h @@ -23,16 +23,18 @@ namespace Trinity { - DECLSPEC_NORETURN void Assert(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; - DECLSPEC_NORETURN void Assert(char const* file, int line, char const* function, char const* message, char const* format, ...) ATTR_NORETURN ATTR_PRINTF(5, 6); + DECLSPEC_NORETURN TC_COMMON_API void Assert(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; + DECLSPEC_NORETURN TC_COMMON_API void Assert(char const* file, int line, char const* function, char const* message, char const* format, ...) ATTR_NORETURN ATTR_PRINTF(5, 6); - DECLSPEC_NORETURN void Fatal(char const* file, int line, char const* function, char const* message, ...) ATTR_NORETURN ATTR_PRINTF(4, 5); + DECLSPEC_NORETURN TC_COMMON_API void Fatal(char const* file, int line, char const* function, char const* message, ...) ATTR_NORETURN ATTR_PRINTF(4, 5); - DECLSPEC_NORETURN void Error(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; + DECLSPEC_NORETURN TC_COMMON_API void Error(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; - DECLSPEC_NORETURN void Abort(char const* file, int line, char const* function) ATTR_NORETURN; + DECLSPEC_NORETURN TC_COMMON_API void Abort(char const* file, int line, char const* function) ATTR_NORETURN; - void Warning(char const* file, int line, char const* function, char const* message); + TC_COMMON_API void Warning(char const* file, int line, char const* function, char const* message); + + DECLSPEC_NORETURN TC_COMMON_API void AbortHandler(int sigval) ATTR_NORETURN; } // namespace Trinity diff --git a/src/common/Define.h b/src/common/Define.h index b34edb6a549..d03d26ad780 100644 --- a/src/common/Define.h +++ b/src/common/Define.h @@ -95,6 +95,45 @@ #endif #endif //COMPILER == COMPILER_GNU +#ifdef TRINITY_API_USE_DYNAMIC_LINKING +# if COMPILER == COMPILER_MICROSOFT +# define TC_API_EXPORT __declspec(dllexport) +# define TC_API_IMPORT __declspec(dllimport) +# elif COMPILER == COMPILER_GNU +# define TC_API_EXPORT __attribute__((visibility("default"))) +# define TC_API_IMPORT +# else +# error compiler not supported! +# endif +#else +# define TC_API_EXPORT +# define TC_API_IMPORT +#endif + +#ifdef TRINITY_API_EXPORT_COMMON +# define TC_COMMON_API TC_API_EXPORT +#else +# define TC_COMMON_API TC_API_IMPORT +#endif + +#ifdef TRINITY_API_EXPORT_DATABASE +# define TC_DATABASE_API TC_API_EXPORT +#else +# define TC_DATABASE_API TC_API_IMPORT +#endif + +#ifdef TRINITY_API_EXPORT_SHARED +# define TC_SHARED_API TC_API_EXPORT +#else +# define TC_SHARED_API TC_API_IMPORT +#endif + +#ifdef TRINITY_API_EXPORT_GAME +# define TC_GAME_API TC_API_EXPORT +#else +# define TC_GAME_API TC_API_IMPORT +#endif + #define UI64FMTD "%" PRIu64 #define UI64LIT(N) UINT64_C(N) diff --git a/src/common/GitRevision.cpp b/src/common/GitRevision.cpp index 5343fbd6531..2162e36847f 100644 --- a/src/common/GitRevision.cpp +++ b/src/common/GitRevision.cpp @@ -1,5 +1,4 @@ #include "GitRevision.h" -#include "CompilerDefs.h" #include "revision_data.h" char const* GitRevision::GetHash() diff --git a/src/common/GitRevision.h b/src/common/GitRevision.h index 7fddcb7605a..aace8ad2076 100644 --- a/src/common/GitRevision.h +++ b/src/common/GitRevision.h @@ -19,22 +19,23 @@ #define __GITREVISION_H__ #include <string> +#include "Define.h" namespace GitRevision { - char const* GetHash(); - char const* GetDate(); - char const* GetBranch(); - char const* GetCMakeCommand(); - char const* GetBuildDirectory(); - char const* GetSourceDirectory(); - char const* GetMySQLExecutable(); - char const* GetFullDatabase(); - char const* GetFullVersion(); - char const* GetCompanyNameStr(); - char const* GetLegalCopyrightStr(); - char const* GetFileVersionStr(); - char const* GetProductVersionStr(); + TC_COMMON_API char const* GetHash(); + TC_COMMON_API char const* GetDate(); + TC_COMMON_API char const* GetBranch(); + TC_COMMON_API char const* GetCMakeCommand(); + TC_COMMON_API char const* GetBuildDirectory(); + TC_COMMON_API char const* GetSourceDirectory(); + TC_COMMON_API char const* GetMySQLExecutable(); + TC_COMMON_API char const* GetFullDatabase(); + TC_COMMON_API char const* GetFullVersion(); + TC_COMMON_API char const* GetCompanyNameStr(); + TC_COMMON_API char const* GetLegalCopyrightStr(); + TC_COMMON_API char const* GetFileVersionStr(); + TC_COMMON_API char const* GetProductVersionStr(); } #endif diff --git a/src/common/Logging/Appender.h b/src/common/Logging/Appender.h index f0bfe423a66..d24daa2b60d 100644 --- a/src/common/Logging/Appender.h +++ b/src/common/Logging/Appender.h @@ -41,7 +41,7 @@ enum LogLevel const uint8 MaxLogLevels = 6; -enum AppenderType +enum AppenderType : uint8 { APPENDER_NONE, APPENDER_CONSOLE, @@ -59,7 +59,7 @@ enum AppenderFlags APPENDER_FLAGS_MAKE_FILE_BACKUP = 0x10 // only used by FileAppender }; -struct LogMessage +struct TC_COMMON_API LogMessage { LogMessage(LogLevel _level, std::string const& _type, std::string&& _text) : level(_level), type(_type), text(std::forward<std::string>(_text)), mtime(time(NULL)) @@ -85,7 +85,7 @@ struct LogMessage } }; -class Appender +class TC_COMMON_API Appender { public: Appender(uint8 _id, std::string const& name, LogLevel level = LOG_LEVEL_DISABLED, AppenderFlags flags = APPENDER_FLAGS_NONE); @@ -123,7 +123,7 @@ Appender* CreateAppender(uint8 id, std::string const& name, LogLevel level, Appe return new AppenderImpl(id, name, level, flags, std::forward<ExtraAppenderArgs>(extraArgs)); } -class InvalidAppenderArgsException : public std::length_error +class TC_COMMON_API InvalidAppenderArgsException : public std::length_error { public: explicit InvalidAppenderArgsException(std::string const& message) : std::length_error(message) { } diff --git a/src/common/Logging/AppenderConsole.h b/src/common/Logging/AppenderConsole.h index 5d7eae36b40..96d17207158 100644 --- a/src/common/Logging/AppenderConsole.h +++ b/src/common/Logging/AppenderConsole.h @@ -42,7 +42,7 @@ enum ColorTypes const uint8 MaxColors = uint8(WHITE) + 1; -class AppenderConsole : public Appender +class TC_COMMON_API AppenderConsole : public Appender { public: typedef std::integral_constant<AppenderType, APPENDER_CONSOLE>::type TypeIndex; diff --git a/src/common/Logging/AppenderFile.h b/src/common/Logging/AppenderFile.h index 9ba5d59259c..956b7a70b93 100644 --- a/src/common/Logging/AppenderFile.h +++ b/src/common/Logging/AppenderFile.h @@ -21,7 +21,7 @@ #include <atomic> #include "Appender.h" -class AppenderFile : public Appender +class TC_COMMON_API AppenderFile : public Appender { public: typedef std::integral_constant<AppenderType, APPENDER_FILE>::type TypeIndex; diff --git a/src/common/Logging/Log.cpp b/src/common/Logging/Log.cpp index 4bd0487343d..f7a84fb8b47 100644 --- a/src/common/Logging/Log.cpp +++ b/src/common/Logging/Log.cpp @@ -214,13 +214,13 @@ void Log::ReadLoggersFromConfig() AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE, ExtraAppenderArgs()); appenders[appender->getId()] = appender; - Logger& logger = loggers[LOGGER_ROOT]; - logger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR); - logger.addAppender(appender->getId(), appender); + Logger& rootLogger = loggers[LOGGER_ROOT]; + rootLogger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR); + rootLogger.addAppender(appender->getId(), appender); - logger = loggers["server"]; - logger.Create("server", LOG_LEVEL_ERROR); - logger.addAppender(appender->getId(), appender); + Logger& serverLogger = loggers["server"]; + serverLogger.Create("server", LOG_LEVEL_INFO); + serverLogger.addAppender(appender->getId(), appender); } } @@ -320,6 +320,12 @@ void Log::Close() appenders.clear(); } +Log* Log::instance() +{ + static Log instance; + return &instance; +} + void Log::Initialize(boost::asio::io_service* ioService) { if (ioService) @@ -331,6 +337,13 @@ void Log::Initialize(boost::asio::io_service* ioService) LoadFromConfig(); } +void Log::SetSynchronous() +{ + delete _strand; + _strand = nullptr; + _ioService = nullptr; +} + void Log::LoadFromConfig() { Close(); diff --git a/src/common/Logging/Log.h b/src/common/Logging/Log.h index a90481ad5d2..6460e404c90 100644 --- a/src/common/Logging/Log.h +++ b/src/common/Logging/Log.h @@ -34,7 +34,7 @@ #define LOGGER_ROOT "root" -class Log +class TC_COMMON_API Log { typedef std::unordered_map<std::string, Logger> LoggerMap; @@ -44,13 +44,10 @@ class Log public: - static Log* instance() - { - static Log instance; - return &instance; - } + static Log* instance(); void Initialize(boost::asio::io_service* ioService); + void SetSynchronous(); // Not threadsafe - should only be called from main() after all threads are joined void LoadFromConfig(); void Close(); bool ShouldLog(std::string const& type, LogLevel level) const; diff --git a/src/common/Logging/LogOperation.h b/src/common/Logging/LogOperation.h index 618629b5423..56e2307d492 100644 --- a/src/common/Logging/LogOperation.h +++ b/src/common/Logging/LogOperation.h @@ -19,11 +19,12 @@ #define LOGOPERATION_H #include <memory> +#include "Define.h" class Logger; struct LogMessage; -class LogOperation +class TC_COMMON_API LogOperation { public: LogOperation(Logger const* _logger, std::unique_ptr<LogMessage>&& _msg) diff --git a/src/common/Logging/Logger.h b/src/common/Logging/Logger.h index 67eab4295a4..4ac2e4494cc 100644 --- a/src/common/Logging/Logger.h +++ b/src/common/Logging/Logger.h @@ -20,7 +20,7 @@ #include "Appender.h" -class Logger +class TC_COMMON_API Logger { public: Logger(); diff --git a/src/server/shared/Service/ServiceWin32.cpp b/src/common/Platform/ServiceWin32.cpp index b6a1682993b..3c34f3e322c 100644 --- a/src/server/shared/Service/ServiceWin32.cpp +++ b/src/common/Platform/ServiceWin32.cpp @@ -261,4 +261,3 @@ bool WinServiceRun() return true; } #endif - diff --git a/src/server/shared/Service/ServiceWin32.h b/src/common/Platform/ServiceWin32.h index 3d67bfe5445..b892ba4e3b6 100644 --- a/src/server/shared/Service/ServiceWin32.h +++ b/src/common/Platform/ServiceWin32.h @@ -26,4 +26,3 @@ bool WinServiceRun(); #endif // _WIN32_SERVICE_ #endif // _WIN32 - diff --git a/src/common/Threading/LockedQueue.h b/src/common/Threading/LockedQueue.h index c6faaaf81ca..21a29d7e53b 100644 --- a/src/common/Threading/LockedQueue.h +++ b/src/common/Threading/LockedQueue.h @@ -57,6 +57,14 @@ public: unlock(); } + //! Adds items back to front of the queue + template<class Iterator> + void readd(Iterator begin, Iterator end) + { + std::lock_guard<std::mutex> lock(_lock); + _queue.insert(_queue.begin(), begin, end); + } + //! Gets the next result in the queue, if any. bool next(T& result) { diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h index f3e9432ca4c..7c889068011 100644 --- a/src/common/Utilities/Containers.h +++ b/src/common/Utilities/Containers.h @@ -20,6 +20,7 @@ #include "Define.h" #include "Random.h" +#include "Util.h" #include <algorithm> #include <functional> #include <list> diff --git a/src/common/Utilities/EventMap.h b/src/common/Utilities/EventMap.h index a1aaa9af269..6a314a9e633 100644 --- a/src/common/Utilities/EventMap.h +++ b/src/common/Utilities/EventMap.h @@ -22,7 +22,7 @@ #include "Duration.h" #include "Util.h" -class EventMap +class TC_COMMON_API EventMap { /** * Internal storage type. @@ -122,7 +122,7 @@ public: */ void ScheduleEvent(uint32 eventId, Milliseconds const& time, uint32 group = 0, uint8 phase = 0) { - ScheduleEvent(eventId, time.count(), group, phase); + ScheduleEvent(eventId, uint32(time.count()), group, phase); } /** @@ -145,7 +145,7 @@ public: */ void RescheduleEvent(uint32 eventId, Milliseconds const& time, uint32 group = 0, uint8 phase = 0) { - RescheduleEvent(eventId, time.count(), group, phase); + RescheduleEvent(eventId, uint32(time.count()), group, phase); } /** @@ -169,7 +169,7 @@ public: */ void Repeat(Milliseconds const& time) { - Repeat(time.count()); + Repeat(uint32(time.count())); } /** @@ -190,7 +190,7 @@ public: */ void Repeat(Milliseconds const& minTime, Milliseconds const& maxTime) { - Repeat(minTime.count(), maxTime.count()); + Repeat(uint32(minTime.count()), uint32(maxTime.count())); } /** @@ -218,7 +218,7 @@ public: */ void DelayEvents(Milliseconds const& delay) { - DelayEvents(delay.count()); + DelayEvents(uint32(delay.count())); } /** @@ -239,7 +239,7 @@ public: */ void DelayEvents(Milliseconds const& delay, uint32 group) { - DelayEvents(delay.count(), group); + DelayEvents(uint32(delay.count()), group); } /** diff --git a/src/common/Utilities/EventProcessor.h b/src/common/Utilities/EventProcessor.h index e5eafed79b9..e10558e6a21 100644 --- a/src/common/Utilities/EventProcessor.h +++ b/src/common/Utilities/EventProcessor.h @@ -25,7 +25,7 @@ // Note. All times are in milliseconds here. -class BasicEvent +class TC_COMMON_API BasicEvent { public: BasicEvent() @@ -55,7 +55,7 @@ class BasicEvent typedef std::multimap<uint64, BasicEvent*> EventList; -class EventProcessor +class TC_COMMON_API EventProcessor { public: EventProcessor(); diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/common/Utilities/MessageBuffer.h index d68bee181b1..d08c4b25bab 100644 --- a/src/server/shared/Networking/MessageBuffer.h +++ b/src/common/Utilities/MessageBuffer.h @@ -20,6 +20,7 @@ #include "Define.h" #include <vector> +#include <cstring> class MessageBuffer { diff --git a/src/common/Utilities/Random.cpp b/src/common/Utilities/Random.cpp index cc013110b01..31318e8f52d 100644 --- a/src/common/Utilities/Random.cpp +++ b/src/common/Utilities/Random.cpp @@ -61,6 +61,14 @@ float frand(float min, float max) return float(GetRng()->Random() * (max - min) + min); } +Milliseconds randtime(Milliseconds const& min, Milliseconds const& max) +{ + long long diff = max.count() - min.count(); + ASSERT(diff >= 0); + ASSERT(diff <= (uint32)-1); + return min + Milliseconds(urand(0, diff)); +} + uint32 rand32() { return GetRng()->BRandom(); diff --git a/src/common/Utilities/Random.h b/src/common/Utilities/Random.h index 5610651a83b..b3ca00219ef 100644 --- a/src/common/Utilities/Random.h +++ b/src/common/Utilities/Random.h @@ -19,29 +19,33 @@ #define Random_h__ #include "Define.h" +#include "Duration.h" #include <limits> #include <random> /* Return a random number in the range min..max. */ -int32 irand(int32 min, int32 max); +TC_COMMON_API int32 irand(int32 min, int32 max); /* Return a random number in the range min..max (inclusive). */ -uint32 urand(uint32 min, uint32 max); +TC_COMMON_API uint32 urand(uint32 min, uint32 max); /* Return a random millisecond value between min and max seconds. Functionally equivalent to urand(min*IN_MILLISECONDS, max*IN_MILLISECONDS). */ -uint32 urandms(uint32 min, uint32 max); +TC_COMMON_API uint32 urandms(uint32 min, uint32 max); /* Return a random number in the range 0 .. UINT32_MAX. */ -uint32 rand32(); +TC_COMMON_API uint32 rand32(); + +/* Return a random time in the range min..max (up to millisecond precision). Only works for values where millisecond difference is a valid uint32. */ +TC_COMMON_API Milliseconds randtime(Milliseconds const& min, Milliseconds const& max); /* Return a random number in the range min..max */ -float frand(float min, float max); +TC_COMMON_API float frand(float min, float max); /* Return a random double from 0.0 to 1.0 (exclusive). */ -double rand_norm(); +TC_COMMON_API double rand_norm(); /* Return a random double from 0.0 to 100.0 (exclusive). */ -double rand_chance(); +TC_COMMON_API double rand_chance(); /* Return true if a random roll fits in the specified chance (range 0-100). */ inline bool roll_chance_f(float chance) @@ -58,7 +62,7 @@ inline bool roll_chance_i(int chance) /* * SFMT wrapper satisfying UniformRandomNumberGenerator concept for use in <random> algorithms */ -class SFMTEngine +class TC_COMMON_API SFMTEngine { public: typedef uint32 result_type; diff --git a/src/common/Utilities/StartProcess.cpp b/src/common/Utilities/StartProcess.cpp new file mode 100644 index 00000000000..c47c02bbe87 --- /dev/null +++ b/src/common/Utilities/StartProcess.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "StartProcess.h" + +#include <atomic> +#include <thread> +#include <functional> + +#include <boost/algorithm/string/join.hpp> +#include <boost/iostreams/stream.hpp> +#include <boost/iostreams/copy.hpp> +#include <boost/iostreams/concepts.hpp> +#include <boost/iostreams/device/file_descriptor.hpp> +#include <boost/process.hpp> +#include <boost/system/system_error.hpp> + +#include "Common.h" +#include "Log.h" + +using namespace boost::process; +using namespace boost::process::initializers; +using namespace boost::iostreams; + +namespace Trinity { + +template<typename T> +class TCLogSink +{ + T callback_; + +public: + typedef char char_type; + typedef sink_tag category; + + // Requires a callback type which has a void(std::string) signature + TCLogSink(T callback) + : callback_(std::move(callback)) { } + + std::streamsize write(const char* str, std::streamsize size) + { + callback_(std::string(str, size)); + return size; + } +}; + +template<typename T> +auto MakeTCLogSink(T&& callback) + -> TCLogSink<typename std::decay<T>::type> +{ + return { std::forward<T>(callback) }; +} + +template<typename T> +static int CreateChildProcess(T waiter, std::string const& executable, + std::vector<std::string> const& args, + std::string const& logger, std::string const& input, + bool secure) +{ + auto outPipe = create_pipe(); + auto errPipe = create_pipe(); + + Optional<file_descriptor_source> inputSource; + + if (!secure) + { + TC_LOG_TRACE(logger.c_str(), "Starting process \"%s\" with arguments: \"%s\".", + executable.c_str(), boost::algorithm::join(args, " ").c_str()); + } + + // Start the child process + child c = [&] + { + if (!input.empty()) + { + inputSource = file_descriptor_source(input); + + // With binding stdin + return execute(run_exe(boost::filesystem::absolute(executable)), + set_args(args), + bind_stdin(*inputSource), + bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)), + bind_stderr(file_descriptor_sink(errPipe.sink, close_handle))); + } + else + { + // Without binding stdin + return execute(run_exe(boost::filesystem::absolute(executable)), + set_args(args), + bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)), + bind_stderr(file_descriptor_sink(errPipe.sink, close_handle))); + } + }(); + + file_descriptor_source outFd(outPipe.source, close_handle); + file_descriptor_source errFd(errPipe.source, close_handle); + + auto outInfo = MakeTCLogSink([&](std::string msg) + { + TC_LOG_INFO(logger.c_str(), "%s", msg.c_str()); + }); + + auto outError = MakeTCLogSink([&](std::string msg) + { + TC_LOG_ERROR(logger.c_str(), "%s", msg.c_str()); + }); + + copy(outFd, outInfo); + copy(errFd, outError); + + // Call the waiter in the current scope to prevent + // the streams from closing too early on leaving the scope. + int const result = waiter(c); + + if (!secure) + { + TC_LOG_TRACE(logger.c_str(), ">> Process \"%s\" finished with return value %i.", + executable.c_str(), result); + } + + if (inputSource) + inputSource->close(); + + return result; +} + +int StartProcess(std::string const& executable, std::vector<std::string> const& args, + std::string const& logger, std::string input_file, bool secure) +{ + return CreateChildProcess([](child& c) -> int + { + try + { + return wait_for_exit(c); + } + catch (...) + { + return EXIT_FAILURE; + } + }, executable, args, logger, input_file, secure); +} + +class AsyncProcessResultImplementation + : public AsyncProcessResult +{ + std::string const executable; + std::vector<std::string> const args; + std::string const logger; + std::string const input_file; + bool const is_secure; + + std::atomic<bool> was_terminated; + + // Workaround for missing move support in boost < 1.57 + Optional<std::shared_ptr<std::future<int>>> result; + Optional<std::reference_wrapper<child>> my_child; + +public: + explicit AsyncProcessResultImplementation(std::string executable_, std::vector<std::string> args_, + std::string logger_, std::string input_file_, + bool secure) + : executable(std::move(executable_)), args(std::move(args_)), + logger(std::move(logger_)), input_file(input_file_), + is_secure(secure), was_terminated(false) { } + + AsyncProcessResultImplementation(AsyncProcessResultImplementation const&) = delete; + AsyncProcessResultImplementation& operator= (AsyncProcessResultImplementation const&) = delete; + AsyncProcessResultImplementation(AsyncProcessResultImplementation&&) = delete; + AsyncProcessResultImplementation& operator= (AsyncProcessResultImplementation&&) = delete; + + int StartProcess() + { + ASSERT(!my_child, "Process started already!"); + + return CreateChildProcess([&](child& c) -> int + { + int result; + my_child = std::reference_wrapper<child>(c); + + try + { + result = wait_for_exit(c); + } + catch (...) + { + result = EXIT_FAILURE; + } + + my_child.reset(); + return was_terminated ? EXIT_FAILURE : result; + + }, executable, args, logger, input_file, is_secure); + } + + void SetFuture(std::future<int> result_) + { + result = std::make_shared<std::future<int>>(std::move(result_)); + } + + /// Returns the future which contains the result of the process + /// as soon it is finished. + std::future<int>& GetFutureResult() override + { + ASSERT(*result, "The process wasn't started!"); + return **result; + } + + /// Tries to terminate the process + void Terminate() override + { + if (!my_child) + { + was_terminated = true; + try + { + terminate(my_child->get()); + } + catch(...) + { + // Do nothing + } + } + } +}; + +TC_COMMON_API std::shared_ptr<AsyncProcessResult> + StartAsyncProcess(std::string executable, std::vector<std::string> args, + std::string logger, std::string input_file, bool secure) +{ + auto handle = std::make_shared<AsyncProcessResultImplementation>( + std::move(executable), std::move(args), std::move(logger), std::move(input_file), secure); + + handle->SetFuture(std::async(std::launch::async, [handle] { return handle->StartProcess(); })); + return handle; +} + +Optional<std::string> SearchExecutableInPath(std::string const& filename) +{ + try + { + auto result = search_path(filename); + if (result.empty()) + return boost::none; + else + return result; + } + catch (...) + { + return boost::none; + } +} + +} // namespace Trinity diff --git a/src/common/Utilities/StartProcess.h b/src/common/Utilities/StartProcess.h new file mode 100644 index 00000000000..3b380bd4f4e --- /dev/null +++ b/src/common/Utilities/StartProcess.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef Process_h__ +#define Process_h__ + +#include <future> +#include <memory> +#include "Common.h" + +namespace Trinity { + +/// Starts a process with the given arguments and parameters and will block +/// until the process is finished. +/// When an input path is given, the file will be routed to the processes stdin. +/// When the process is marked as secure no arguments are leaked to logs. +/// Note that most executables expect it's name as the first argument. +TC_COMMON_API int StartProcess(std::string const& executable, std::vector<std::string> const& args, + std::string const& logger, std::string input_file = "", + bool secure = false); + +/// Platform and library independent representation +/// of asynchronous process results +class AsyncProcessResult +{ +public: + virtual ~AsyncProcessResult() { } + + /// Returns the future which contains the result of the process + /// as soon it is finished. + virtual std::future<int>& GetFutureResult() = 0; + + /// Tries to terminate the process + virtual void Terminate() = 0; +}; + +/// Starts a process asynchronously with the given arguments and parameters and +/// returns an AsyncProcessResult immediately which is set, when the process exits. +/// When an input path is given, the file will be routed to the processes stdin. +/// When the process is marked as secure no arguments are leaked to logs. +/// Note that most executables expect it's name as the first argument. +TC_COMMON_API std::shared_ptr<AsyncProcessResult> + StartAsyncProcess(std::string executable, std::vector<std::string> args, + std::string logger, std::string input_file = "", + bool secure = false); + +/// Searches for the given executable in the PATH variable +/// and returns a present optional when it was found. +TC_COMMON_API Optional<std::string> SearchExecutableInPath(std::string const& filename); + +} // namespace Trinity + +#endif // Process_h__ diff --git a/src/common/Utilities/StringFormat.h b/src/common/Utilities/StringFormat.h index d85523bc11f..e21b1024e87 100644 --- a/src/common/Utilities/StringFormat.h +++ b/src/common/Utilities/StringFormat.h @@ -19,7 +19,7 @@ #ifndef TRINITYCORE_STRING_FORMAT_H #define TRINITYCORE_STRING_FORMAT_H -#include "format.h" +#include "cppformat/format.h" namespace Trinity { diff --git a/src/common/Utilities/TaskScheduler.h b/src/common/Utilities/TaskScheduler.h index 8cf5d914128..6784c968683 100644 --- a/src/common/Utilities/TaskScheduler.h +++ b/src/common/Utilities/TaskScheduler.h @@ -46,7 +46,7 @@ class TaskContext; /// with the same duration or a new one. /// It also provides access to the repeat counter which is useful for task that repeat itself often /// but behave different every time (spoken event dialogs for example). -class TaskScheduler +class TC_COMMON_API TaskScheduler { friend class TaskContext; @@ -131,7 +131,7 @@ class TaskScheduler }; }; - class TaskQueue + class TC_COMMON_API TaskQueue { std::multiset<TaskContainer, Compare> container; @@ -401,14 +401,14 @@ private: auto const milli_max = std::chrono::duration_cast<std::chrono::milliseconds>(max); // TC specific: use SFMT URandom - return std::chrono::milliseconds(urand(milli_min.count(), milli_max.count())); + return std::chrono::milliseconds(urand(uint32(milli_min.count()), uint32(milli_max.count()))); } /// Dispatch remaining tasks void Dispatch(success_t const& callback); }; -class TaskContext +class TC_COMMON_API TaskContext { friend class TaskScheduler; diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index 1360253294f..3d8cda66d48 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -22,6 +22,7 @@ #include "utf8.h" #include "Errors.h" // for ASSERT #include <stdarg.h> +#include <boost/algorithm/string/case_conv.hpp> #if COMPILER == COMPILER_GNU #include <sys/socket.h> @@ -218,22 +219,29 @@ bool IsIPAddress(char const* ipaddress) } /// create PID file -uint32 CreatePIDFile(const std::string& filename) +uint32 CreatePIDFile(std::string const& filename) { - FILE* pid_file = fopen (filename.c_str(), "w" ); + FILE* pid_file = fopen(filename.c_str(), "w"); if (pid_file == NULL) return 0; + uint32 pid = GetPID(); + + fprintf(pid_file, "%u", pid); + fclose(pid_file); + + return pid; +} + +uint32 GetPID() +{ #ifdef _WIN32 DWORD pid = GetCurrentProcessId(); #else pid_t pid = getpid(); #endif - fprintf(pid_file, "%u", pid ); - fclose(pid_file); - - return (uint32)pid; + return uint32(pid); } size_t utf8length(std::string& utf8str) @@ -418,7 +426,7 @@ bool utf8ToConsole(const std::string& utf8str, std::string& conStr) return false; conStr.resize(wstr.size()); - CharToOemBuffW(&wstr[0], &conStr[0], wstr.size()); + CharToOemBuffW(&wstr[0], &conStr[0], uint32(wstr.size())); #else // not implemented yet conStr = utf8str; @@ -432,7 +440,7 @@ bool consoleToUtf8(const std::string& conStr, std::string& utf8str) #if PLATFORM == PLATFORM_WINDOWS std::wstring wstr; wstr.resize(conStr.size()); - OemToCharBuffW(&conStr[0], &wstr[0], conStr.size()); + OemToCharBuffW(&conStr[0], &wstr[0], uint32(conStr.size())); return WStrToUtf8(wstr, utf8str); #else @@ -450,7 +458,7 @@ bool Utf8FitTo(const std::string& str, std::wstring const& search) return false; // converting to lower case - wstrToLower( temp ); + wstrToLower(temp); if (temp.find(search) == std::wstring::npos) return false; @@ -469,10 +477,10 @@ void utf8printf(FILE* out, const char *str, ...) void vutf8printf(FILE* out, const char *str, va_list* ap) { #if PLATFORM == PLATFORM_WINDOWS - char temp_buf[32*1024]; - wchar_t wtemp_buf[32*1024]; + char temp_buf[32 * 1024]; + wchar_t wtemp_buf[32 * 1024]; - size_t temp_len = vsnprintf(temp_buf, 32*1024, str, *ap); + size_t temp_len = vsnprintf(temp_buf, 32 * 1024, str, *ap); //vsnprintf returns -1 if the buffer is too small if (temp_len == size_t(-1)) temp_len = 32*1024-1; @@ -480,13 +488,24 @@ void vutf8printf(FILE* out, const char *str, va_list* ap) size_t wtemp_len = 32*1024-1; Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len); - CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len+1); + CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], uint32(wtemp_len + 1)); fprintf(out, "%s", temp_buf); #else vfprintf(out, str, *ap); #endif } +bool Utf8ToUpperOnlyLatin(std::string& utf8String) +{ + std::wstring wstr; + if (!Utf8toWStr(utf8String, wstr)) + return false; + + std::transform(wstr.begin(), wstr.end(), wstr.begin(), wcharToUpperOnlyLatin); + + return WStrToUtf8(wstr, utf8String); +} + std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */) { int32 init = 0; @@ -510,3 +529,34 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse return ss.str(); } + +void HexStrToByteArray(std::string const& str, uint8* out, bool reverse /*= false*/) +{ + // string must have even number of characters + if (str.length() & 1) + return; + + int32 init = 0; + int32 end = int32(str.length()); + int8 op = 1; + + if (reverse) + { + init = int32(str.length() - 2); + end = -2; + op = -1; + } + + uint32 j = 0; + for (int32 i = init; i != end; i += 2 * op) + { + char buffer[3] = { str[i], str[i + 1], '\0' }; + out[j++] = uint8(strtoul(buffer, NULL, 16)); + } +} + +bool StringToBool(std::string const& str) +{ + std::string lowerStr = boost::algorithm::to_lower_copy(str); + return lowerStr == "1" || lowerStr == "true" || lowerStr == "yes"; +} diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index ab5cabca8d2..cc68f3b2237 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -40,7 +40,7 @@ template<typename T, class S> struct Finder bool operator()(const std::pair<int, S> &obj) { return obj.second.*idMember_ == val_; } }; -class Tokenizer +class TC_COMMON_API Tokenizer { public: typedef std::vector<char const*> StorageType; @@ -68,15 +68,15 @@ private: StorageType m_storage; }; -void stripLineInvisibleChars(std::string &src); +TC_COMMON_API void stripLineInvisibleChars(std::string &src); -int32 MoneyStringToMoney(const std::string& moneyString); +TC_COMMON_API int32 MoneyStringToMoney(const std::string& moneyString); -struct tm* localtime_r(const time_t* time, struct tm *result); +TC_COMMON_API struct tm* localtime_r(const time_t* time, struct tm *result); -std::string secsToTimeString(uint64 timeInSecs, bool shortText = false, bool hoursOnly = false); -uint32 TimeStringToSecs(const std::string& timestring); -std::string TimeToTimestampStr(time_t t); +TC_COMMON_API std::string secsToTimeString(uint64 timeInSecs, bool shortText = false, bool hoursOnly = false); +TC_COMMON_API uint32 TimeStringToSecs(const std::string& timestring); +TC_COMMON_API std::string TimeToTimestampStr(time_t t); inline void ApplyPercentModFloatVar(float& var, float val, bool apply) { @@ -111,20 +111,20 @@ inline T RoundToInterval(T& num, T floor, T ceil) } // UTF8 handling -bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr); +TC_COMMON_API bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr); // in wsize==max size of buffer, out wsize==real string size -bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize); +TC_COMMON_API bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize); inline bool Utf8toWStr(const std::string& utf8str, wchar_t* wstr, size_t& wsize) { return Utf8toWStr(utf8str.c_str(), utf8str.size(), wstr, wsize); } -bool WStrToUtf8(std::wstring const& wstr, std::string& utf8str); +TC_COMMON_API bool WStrToUtf8(std::wstring const& wstr, std::string& utf8str); // size==real string size -bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str); +TC_COMMON_API bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str); -size_t utf8length(std::string& utf8str); // set string to "" if invalid utf8 sequence -void utf8truncate(std::string& utf8str, size_t len); +TC_COMMON_API size_t utf8length(std::string& utf8str); // set string to "" if invalid utf8 sequence +TC_COMMON_API void utf8truncate(std::string& utf8str, size_t len); inline bool isBasicLatinCharacter(wchar_t wchar) { @@ -303,19 +303,24 @@ inline void wstrToLower(std::wstring& str) std::transform( str.begin(), str.end(), str.begin(), wcharToLower ); } -std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension); +TC_COMMON_API std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension); -bool utf8ToConsole(const std::string& utf8str, std::string& conStr); -bool consoleToUtf8(const std::string& conStr, std::string& utf8str); -bool Utf8FitTo(const std::string& str, std::wstring const& search); -void utf8printf(FILE* out, const char *str, ...); -void vutf8printf(FILE* out, const char *str, va_list* ap); +TC_COMMON_API bool utf8ToConsole(const std::string& utf8str, std::string& conStr); +TC_COMMON_API bool consoleToUtf8(const std::string& conStr, std::string& utf8str); +TC_COMMON_API bool Utf8FitTo(const std::string& str, std::wstring const& search); +TC_COMMON_API void utf8printf(FILE* out, const char *str, ...); +TC_COMMON_API void vutf8printf(FILE* out, const char *str, va_list* ap); +TC_COMMON_API bool Utf8ToUpperOnlyLatin(std::string& utf8String); -bool IsIPAddress(char const* ipaddress); +TC_COMMON_API bool IsIPAddress(char const* ipaddress); -uint32 CreatePIDFile(const std::string& filename); +TC_COMMON_API uint32 CreatePIDFile(std::string const& filename); +TC_COMMON_API uint32 GetPID(); -std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false); +TC_COMMON_API std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false); +TC_COMMON_API void HexStrToByteArray(std::string const& str, uint8* out, bool reverse = false); + +TC_COMMON_API bool StringToBool(std::string const& str); // simple class for not-modifyable list template <typename T> diff --git a/src/genrev/CMakeLists.txt b/src/genrev/CMakeLists.txt index 91a13609037..355e2043b51 100644 --- a/src/genrev/CMakeLists.txt +++ b/src/genrev/CMakeLists.txt @@ -13,3 +13,8 @@ add_custom_target(revision_data.h ALL COMMAND "${CMAKE_COMMAND}" -DBUILDDIR="${CMAKE_BINARY_DIR}" -P "${CMAKE_SOURCE_DIR}/cmake/genrev.cmake" "${CMAKE_BINARY_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) + +set_target_properties(revision_data.h + PROPERTIES + FOLDER + "server") diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 9a454696ca8..2c7a4773e88 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -12,16 +12,19 @@ # This to stop a few silly crashes that could have been avoided IF people # weren't doing some -O3 psychooptimizations etc. -find_package(MySQL REQUIRED) - if(CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW) add_definitions(-fno-delete-null-pointer-checks) endif() -set(sources_windows_Debugging - ${CMAKE_SOURCE_DIR}/src/common/Debugging/WheatyExceptionReport.cpp - ${CMAKE_SOURCE_DIR}/src/common/Debugging/WheatyExceptionReport.h -) +if(WIN32) + set(sources_windows + ${CMAKE_SOURCE_DIR}/src/common/Debugging/WheatyExceptionReport.cpp + ${CMAKE_SOURCE_DIR}/src/common/Debugging/WheatyExceptionReport.h + ${CMAKE_SOURCE_DIR}/src/common/Platform/ServiceWin32.cpp + ${CMAKE_SOURCE_DIR}/src/common/Platform/ServiceWin32.h + ) +endif(WIN32) + add_subdirectory(database) add_subdirectory(shared) add_subdirectory(game) diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index d87847d6740..d1f0e4460e9 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -10,66 +10,29 @@ ########### authserver ############### -file(GLOB_RECURSE sources_authentication Authentication/*.cpp Authentication/*.h) -file(GLOB_RECURSE sources_realms Realms/*.cpp Realms/*.h) -file(GLOB_RECURSE sources_server Server/*.cpp Server/*.h) -file(GLOB sources_localdir *.cpp *.h) - -if (USE_COREPCH) - set(authserver_PCH_HDR PrecompiledHeaders/authPCH.h) - set(authserver_PCH_SRC PrecompiledHeaders/authPCH.cpp) -endif() - -set(authserver_SRCS - ${authserver_SRCS} - ${sources_authentication} - ${sources_realms} - ${sources_server} - ${sources_localdir} -) +CollectSourceFiles( + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE_SOURCES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) if( WIN32 ) - set(authserver_SRCS - ${authserver_SRCS} - ${sources_windows_Debugging} - ) + list(APPEND PRIVATE_SOURCES ${sources_windows}) if ( MSVC ) - set(authserver_SRCS - ${authserver_SRCS} - authserver.rc - ) - endif () + list(APPEND PRIVATE_SOURCES authserver.rc) + endif() endif() -include_directories( - ${CMAKE_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/Authentication - ${CMAKE_CURRENT_SOURCE_DIR}/Realms - ${CMAKE_CURRENT_SOURCE_DIR}/Server - ${CMAKE_SOURCE_DIR}/dep/cppformat - ${CMAKE_SOURCE_DIR}/src/common/ - ${CMAKE_SOURCE_DIR}/src/common/Configuration - ${CMAKE_SOURCE_DIR}/src/common/Cryptography - ${CMAKE_SOURCE_DIR}/src/common/Debugging - ${CMAKE_SOURCE_DIR}/src/common/Logging - ${CMAKE_SOURCE_DIR}/src/common/Threading - ${CMAKE_SOURCE_DIR}/src/common/Utilities - ${CMAKE_SOURCE_DIR}/src/server/database - ${CMAKE_SOURCE_DIR}/src/server/database/Database - ${CMAKE_SOURCE_DIR}/src/server/database/Logging - ${CMAKE_SOURCE_DIR}/src/server/shared/Networking - ${CMAKE_SOURCE_DIR}/src/server/shared/Packets - ${CMAKE_SOURCE_DIR}/src/server/shared/Service - ${MYSQL_INCLUDE_DIR} - ${OPENSSL_INCLUDE_DIR} - ${VALGRIND_INCLUDE_DIR} -) +if (USE_COREPCH) + set(PRIVATE_PCH_HEADER PrecompiledHeaders/authPCH.h) + set(PRIVATE_PCH_SOURCE PrecompiledHeaders/authPCH.cpp) +endif() GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) add_executable(authserver - ${authserver_SRCS} - ${authserver_PCH_SRC} + ${PRIVATE_PCH_SOURCE} + ${PRIVATE_SOURCES} ) if( NOT WIN32 ) @@ -79,15 +42,25 @@ if( NOT WIN32 ) endif() target_link_libraries(authserver - shared - database - common - format - ${MYSQL_LIBRARY} - ${OPENSSL_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_LIBRARIES} -) + PUBLIC + shared) + +CollectIncludeDirectories( + ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC_INCLUDES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) + +target_include_directories(authserver + PUBLIC + ${PUBLIC_INCLUDES} + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) + +set_target_properties(authserver + PROPERTIES + FOLDER + "server") if( WIN32 ) if ( MSVC ) @@ -113,5 +86,5 @@ endif() # Generate precompiled header if (USE_COREPCH) - add_cxx_pch(authserver ${authserver_PCH_HDR} ${authserver_PCH_SRC}) + add_cxx_pch(authserver ${PRIVATE_PCH_HEADER} ${PRIVATE_PCH_SOURCE}) endif() diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 0618ec437b6..a53187ad737 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -76,10 +76,11 @@ boost::asio::deadline_timer* _dbPingTimer; uint32 _dbPingInterval; boost::asio::deadline_timer* _banExpiryCheckTimer; uint32 _banExpiryCheckInterval; -LoginDatabaseWorkerPool LoginDatabase; int main(int argc, char** argv) { + signal(SIGABRT, &Trinity::AbortHandler); + std::string configFile = _TRINITY_REALM_CONFIG; std::string configService; auto vm = GetConsoleArguments(argc, argv, configFile, configService); @@ -134,7 +135,7 @@ int main(int argc, char** argv) // Get the list of realms for the server sRealmList->Initialize(*_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); - if (sRealmList->size() == 0) + if (sRealmList->GetRealms().empty()) { TC_LOG_ERROR("server.authserver", "No valid realms specified."); StopDB(); @@ -194,6 +195,8 @@ int main(int argc, char** argv) sAuthSocketMgr.StopNetwork(); + sRealmList->Close(); + // Close the Database Pool and library StopDB(); diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h deleted file mode 100644 index cc5c88c01f2..00000000000 --- a/src/server/authserver/Realms/RealmList.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _REALMLIST_H -#define _REALMLIST_H - -#include <boost/asio/ip/address.hpp> -#include <boost/asio/ip/tcp.hpp> -#include <boost/asio/io_service.hpp> -#include "Common.h" - -using namespace boost::asio; - -enum RealmFlags -{ - REALM_FLAG_NONE = 0x00, - REALM_FLAG_INVALID = 0x01, - REALM_FLAG_OFFLINE = 0x02, - REALM_FLAG_SPECIFYBUILD = 0x04, - REALM_FLAG_UNK1 = 0x08, - REALM_FLAG_UNK2 = 0x10, - REALM_FLAG_RECOMMENDED = 0x20, - REALM_FLAG_NEW = 0x40, - REALM_FLAG_FULL = 0x80 -}; - -// Storage object for a realm -struct Realm -{ - ip::address ExternalAddress; - ip::address LocalAddress; - ip::address LocalSubnetMask; - uint16 port; - std::string name; - uint8 icon; - RealmFlags flag; - uint8 timezone; - uint32 m_ID; - AccountTypes allowedSecurityLevel; - float populationLevel; - uint32 gamebuild; -}; - -/// Storage object for the list of realms on the server -class RealmList -{ -public: - typedef std::map<std::string, Realm> RealmMap; - - static RealmList* instance() - { - static RealmList instance; - return &instance; - } - - ~RealmList(); - - void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); - - void UpdateIfNeed(); - - void AddRealm(const Realm& NewRealm) { m_realms[NewRealm.name] = NewRealm; } - - RealmMap::const_iterator begin() const { return m_realms.begin(); } - RealmMap::const_iterator end() const { return m_realms.end(); } - uint32 size() const { return m_realms.size(); } - -private: - RealmList(); - - void UpdateRealms(bool init = false); - void UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, - ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build); - - RealmMap m_realms; - uint32 m_UpdateInterval; - time_t m_NextUpdateTime; - boost::asio::ip::tcp::resolver* _resolver; -}; - -#define sRealmList RealmList::instance() -#endif diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 57e5d6682f2..f044e0cea94 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -146,6 +146,11 @@ void AccountInfo::LoadResult(Field* fields) IsBanned = fields[6].GetUInt64() != 0; IsPermanenetlyBanned = fields[7].GetUInt64() != 0; SecurityLevel = AccountTypes(fields[8].GetUInt8()); + + // Use our own uppercasing of the account name instead of using UPPER() in mysql query + // This is how the account was created in the first place and changing it now would result in breaking + // login for all accounts having accented characters in their name + Utf8ToUpperOnlyLatin(Login); } AuthSession::AuthSession(tcp::socket&& socket) : Socket(std::move(socket)), @@ -844,7 +849,7 @@ tcp::endpoint const GetAddressForClient(Realm const& realm, ip::address const& c realmIp = realm.ExternalAddress; } - tcp::endpoint endpoint(realmIp, realm.port); + tcp::endpoint endpoint(realmIp, realm.Port); // Return external IP return endpoint; @@ -880,22 +885,19 @@ void AuthSession::RealmListCallback(PreparedQueryResult result) } while (result->NextRow()); } - // Update realm list if need - sRealmList->UpdateIfNeed(); - // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) ByteBuffer pkt; size_t RealmListSize = 0; - for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) + for (RealmList::RealmMap::value_type const& i : sRealmList->GetRealms()) { - const Realm &realm = i->second; + const Realm &realm = i.second; // don't work with realms which not compatible with the client - bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.gamebuild)); + bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.Build == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.Build)); // No SQL injection. id of realm is controlled by the database. - uint32 flag = realm.flag; - RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); + uint32 flag = realm.Flags; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.Build); if (!okBuild) { if (!buildInfo) @@ -907,7 +909,7 @@ void AuthSession::RealmListCallback(PreparedQueryResult result) if (!buildInfo) flag &= ~REALM_FLAG_SPECIFYBUILD; - std::string name = i->first; + std::string name = realm.Name; if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) { std::ostringstream ss; @@ -915,19 +917,19 @@ void AuthSession::RealmListCallback(PreparedQueryResult result) name = ss.str(); } - uint8 lock = (realm.allowedSecurityLevel > _accountInfo.SecurityLevel) ? 1 : 0; + uint8 lock = (realm.AllowedSecurityLevel > _accountInfo.SecurityLevel) ? 1 : 0; - pkt << uint8(realm.icon); // realm type + pkt << uint8(realm.Type); // realm type if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients pkt << uint8(lock); // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; - pkt << boost::lexical_cast<std::string>(GetAddressForClient(realm, GetRemoteIpAddress())); - pkt << float(realm.populationLevel); - pkt << uint8(characterCounts[realm.m_ID]); - pkt << uint8(realm.timezone); // realm category + pkt << boost::lexical_cast<std::string>(realm.GetAddressForClient(GetRemoteIpAddress())); + pkt << float(realm.PopulationLevel); + pkt << uint8(characterCounts[realm.Id.Realm]); + pkt << uint8(realm.Timezone); // realm category if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - pkt << uint8(realm.m_ID); + pkt << uint8(realm.Id.Realm); else pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients diff --git a/src/server/authserver/Server/AuthSocketMgr.h b/src/server/authserver/Server/AuthSocketMgr.h index a16b7d405b9..9923f2b2f11 100644 --- a/src/server/authserver/Server/AuthSocketMgr.h +++ b/src/server/authserver/Server/AuthSocketMgr.h @@ -32,9 +32,9 @@ public: return instance; } - bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) override + bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port, int threadCount = 1) override { - if (!BaseSocketMgr::StartNetwork(service, bindIp, port)) + if (!BaseSocketMgr::StartNetwork(service, bindIp, port, threadCount)) return false; _acceptor->AsyncAcceptWithCallback<&AuthSocketMgr::OnSocketAccept>(); diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index a97d75b3f57..db60e3b3ece 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -184,6 +184,13 @@ LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth" LoginDatabase.WorkerThreads = 1 # +# LoginDatabase.SynchThreads +# Description: The amount of MySQL connections spawned to handle. +# Default: 1 - (LoginDatabase.WorkerThreads) + +LoginDatabase.SynchThreads = 1 + +# ################################################################################################### ################################################################################################### diff --git a/src/server/database/CMakeLists.txt b/src/server/database/CMakeLists.txt index 5a53899f4cb..bd2fa280ad6 100644 --- a/src/server/database/CMakeLists.txt +++ b/src/server/database/CMakeLists.txt @@ -8,34 +8,22 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -if (NOT MYSQL_FOUND) - message(SEND_ERROR "MySQL wasn't found on your system but it's required to build the servers!") -endif() - -if( USE_COREPCH ) - include_directories(${CMAKE_CURRENT_BINARY_DIR}) -endif() - -file(GLOB_RECURSE sources_Database Database/*.cpp Database/*.h) -file(GLOB_RECURSE sources_Logging Logging/*.cpp Logging/*.h) -file(GLOB_RECURSE sources_Updater Updater/*.cpp Updater/*.h) - -file(GLOB sources_localdir *.cpp *.h) - -# -# Build shared sourcelist -# +CollectSourceFiles( + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE_SOURCES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) if (USE_COREPCH) - set(database_STAT_PCH_HDR PrecompiledHeaders/databasePCH.h) - set(database_STAT_PCH_SRC PrecompiledHeaders/databasePCH.cpp) + set(PRIVATE_PCH_HEADER PrecompiledHeaders/databasePCH.h) + set(PRIVATE_PCH_SOURCE PrecompiledHeaders/databasePCH.cpp) endif() -set(database_STAT_SRCS - ${database_STAT_SRCS} - ${sources_Database} - ${sources_Logging} - ${sources_Updater} +GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) + +add_library(database + ${PRIVATE_PCH_SOURCE} + ${PRIVATE_SOURCES} ) # Do NOT add any extra include directory unless it does not create unneeded extra dependencies, @@ -47,31 +35,43 @@ set(database_STAT_SRCS # linkage (enums, defines...) it is discouraged to do so unless necessary, as it will pullute # include_directories leading to further unnoticed dependency aditions # Linker Depencency requirements: common -include_directories( +CollectIncludeDirectories( ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/Database - ${CMAKE_CURRENT_SOURCE_DIR}/Updater - ${CMAKE_SOURCE_DIR}/dep/cppformat - ${CMAKE_SOURCE_DIR}/dep/process - ${CMAKE_SOURCE_DIR}/src/common/ - ${CMAKE_SOURCE_DIR}/src/common/Configuration - ${CMAKE_SOURCE_DIR}/src/common/Debugging - ${CMAKE_SOURCE_DIR}/src/common/Logging - ${CMAKE_SOURCE_DIR}/src/common/Threading - ${CMAKE_SOURCE_DIR}/src/common/Utilities - ${MYSQL_INCLUDE_DIR} - ${OPENSSL_INCLUDE_DIR} - ${VALGRIND_INCLUDE_DIR} -) + PUBLIC_INCLUDES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) -GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(database + PUBLIC + ${PUBLIC_INCLUDES} + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) -add_library(database STATIC - ${database_STAT_SRCS} - ${database_STAT_PCH_SRC} -) +add_definitions(-DTRINITY_API_EXPORT_DATABASE) + +target_link_libraries(database + PUBLIC + common + mysql) + +set_target_properties(database + PROPERTIES + FOLDER + "server") + +if( BUILD_SHARED_LIBS ) + if( UNIX ) + install(TARGETS database + LIBRARY + DESTINATION lib) + elseif( WIN32 ) + install(TARGETS database + RUNTIME + DESTINATION "${CMAKE_INSTALL_PREFIX}") + endif() +endif() # Generate precompiled header if (USE_COREPCH) - add_cxx_pch(database ${database_STAT_PCH_HDR} ${database_STAT_PCH_SRC}) + add_cxx_pch(database ${PRIVATE_PCH_HEADER} ${PRIVATE_PCH_SOURCE}) endif () diff --git a/src/server/database/Database/AdhocStatement.h b/src/server/database/Database/AdhocStatement.h index ab85493a14e..9315038bce1 100644 --- a/src/server/database/Database/AdhocStatement.h +++ b/src/server/database/Database/AdhocStatement.h @@ -25,7 +25,7 @@ typedef std::future<QueryResult> QueryResultFuture; typedef std::promise<QueryResult> QueryResultPromise; /*! Raw, ad-hoc query. */ -class BasicStatementTask : public SQLOperation +class TC_DATABASE_API BasicStatementTask : public SQLOperation { public: BasicStatementTask(const char* sql, bool async = false); diff --git a/src/server/database/Database/DatabaseEnv.cpp b/src/server/database/Database/DatabaseEnv.cpp new file mode 100644 index 00000000000..3b2e632e4fb --- /dev/null +++ b/src/server/database/Database/DatabaseEnv.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "DatabaseEnv.h" + +WorldDatabaseWorkerPool WorldDatabase; +CharacterDatabaseWorkerPool CharacterDatabase; +LoginDatabaseWorkerPool LoginDatabase; diff --git a/src/server/database/Database/DatabaseEnv.h b/src/server/database/Database/DatabaseEnv.h index cc8355a1302..05a4d5aad75 100644 --- a/src/server/database/Database/DatabaseEnv.h +++ b/src/server/database/Database/DatabaseEnv.h @@ -38,9 +38,11 @@ #include "Implementation/CharacterDatabase.h" #include "Implementation/WorldDatabase.h" -extern WorldDatabaseWorkerPool WorldDatabase; -extern CharacterDatabaseWorkerPool CharacterDatabase; -extern LoginDatabaseWorkerPool LoginDatabase; +/// Accessor to the world database +TC_DATABASE_API extern WorldDatabaseWorkerPool WorldDatabase; +/// Accessor to the character database +TC_DATABASE_API extern CharacterDatabaseWorkerPool CharacterDatabase; +/// Accessor to the realm/login database +TC_DATABASE_API extern LoginDatabaseWorkerPool LoginDatabase; #endif - diff --git a/src/server/database/Database/DatabaseLoader.cpp b/src/server/database/Database/DatabaseLoader.cpp index 92d8730cd12..f358bdd54b4 100644 --- a/src/server/database/Database/DatabaseLoader.cpp +++ b/src/server/database/Database/DatabaseLoader.cpp @@ -32,7 +32,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st { bool const updatesEnabledForThis = DBUpdater<T>::IsEnabled(_updateFlags); - _open.push(std::make_pair([this, name, updatesEnabledForThis, &pool]() -> bool + _open.push([this, name, updatesEnabledForThis, &pool]() -> bool { std::string const dbString = sConfigMgr->GetStringDefault(name + "DatabaseInfo", ""); if (dbString.empty()) @@ -71,12 +71,13 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st return false; } } + // Add the close operation + _close.push([&pool] + { + pool.Close(); + }); return true; - }, - [&pool]() - { - pool.Close(); - })); + }); // Populate and update only if updates are enabled for this pool if (updatesEnabledForThis) @@ -137,38 +138,7 @@ bool DatabaseLoader::Load() bool DatabaseLoader::OpenDatabases() { - while (!_open.empty()) - { - std::pair<Predicate, std::function<void()>> const load = _open.top(); - if (load.first()) - _close.push(load.second); - else - { - // Close all loaded databases - while (!_close.empty()) - { - _close.top()(); - _close.pop(); - } - return false; - } - - _open.pop(); - } - return true; -} - -// Processes the elements of the given stack until a predicate returned false. -bool DatabaseLoader::Process(std::stack<Predicate>& stack) -{ - while (!stack.empty()) - { - if (!stack.top()()) - return false; - - stack.pop(); - } - return true; + return Process(_open); } bool DatabaseLoader::PopulateDatabases() @@ -186,9 +156,30 @@ bool DatabaseLoader::PrepareStatements() return Process(_prepare); } -template -DatabaseLoader& DatabaseLoader::AddDatabase<LoginDatabaseConnection>(DatabaseWorkerPool<LoginDatabaseConnection>& pool, std::string const& name); -template -DatabaseLoader& DatabaseLoader::AddDatabase<WorldDatabaseConnection>(DatabaseWorkerPool<WorldDatabaseConnection>& pool, std::string const& name); -template -DatabaseLoader& DatabaseLoader::AddDatabase<CharacterDatabaseConnection>(DatabaseWorkerPool<CharacterDatabaseConnection>& pool, std::string const& name); +bool DatabaseLoader::Process(std::queue<Predicate>& queue) +{ + while (!queue.empty()) + { + if (!queue.front()()) + { + // Close all open databases which have a registered close operation + while (!_close.empty()) + { + _close.top()(); + _close.pop(); + } + + return false; + } + + queue.pop(); + } + return true; +} + +template TC_DATABASE_API +DatabaseLoader& DatabaseLoader::AddDatabase<LoginDatabaseConnection>(LoginDatabaseWorkerPool&, std::string const&); +template TC_DATABASE_API +DatabaseLoader& DatabaseLoader::AddDatabase<CharacterDatabaseConnection>(CharacterDatabaseWorkerPool&, std::string const&); +template TC_DATABASE_API +DatabaseLoader& DatabaseLoader::AddDatabase<WorldDatabaseConnection>(WorldDatabaseWorkerPool&, std::string const&); diff --git a/src/server/database/Database/DatabaseLoader.h b/src/server/database/Database/DatabaseLoader.h index da92cf85a9f..647c1e113e3 100644 --- a/src/server/database/Database/DatabaseLoader.h +++ b/src/server/database/Database/DatabaseLoader.h @@ -19,14 +19,15 @@ #define DatabaseLoader_h__ #include "DatabaseWorkerPool.h" -#include "DatabaseEnv.h" +#include "DBUpdater.h" -#include <stack> #include <functional> +#include <stack> +#include <queue> // A helper class to initiate all database worker pools, // handles updating, delays preparing of statements and cleans up on failure. -class DatabaseLoader +class TC_DATABASE_API DatabaseLoader { public: DatabaseLoader(std::string const& logger, uint32 const defaultUpdateMask); @@ -56,16 +57,18 @@ private: bool PrepareStatements(); using Predicate = std::function<bool()>; + using Closer = std::function<void()>; - static bool Process(std::stack<Predicate>& stack); + // Invokes all functions in the given queue and closes the databases on errors. + // Returns false when there was an error. + bool Process(std::queue<Predicate>& queue); std::string const _logger; bool const _autoSetup; uint32 const _updateFlags; - std::stack<std::pair<Predicate, std::function<void()>>> _open; - std::stack<std::function<void()>> _close; - std::stack<Predicate> _populate, _update, _prepare; + std::queue<Predicate> _open, _populate, _update, _prepare; + std::stack<Closer> _close; }; #endif // DatabaseLoader_h__ diff --git a/src/server/database/Database/DatabaseWorker.h b/src/server/database/Database/DatabaseWorker.h index c21a3d2a343..d6b43943f7d 100644 --- a/src/server/database/Database/DatabaseWorker.h +++ b/src/server/database/Database/DatabaseWorker.h @@ -24,7 +24,7 @@ class MySQLConnection; class SQLOperation; -class DatabaseWorker +class TC_DATABASE_API DatabaseWorker { public: DatabaseWorker(ProducerConsumerQueue<SQLOperation*>* newQueue, MySQLConnection* connection); diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp new file mode 100644 index 00000000000..ba2a4256919 --- /dev/null +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "DatabaseWorkerPool.h" +#include "DatabaseEnv.h" + +#define MIN_MYSQL_SERVER_VERSION 50100u +#define MIN_MYSQL_CLIENT_VERSION 50100u + +template <class T> +DatabaseWorkerPool<T>::DatabaseWorkerPool() + : _queue(new ProducerConsumerQueue<SQLOperation*>()), + _async_threads(0), _synch_threads(0) +{ + WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe."); + WPFatal(mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "TrinityCore does not support MySQL versions below 5.1"); + WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s) does not match the version used to compile TrinityCore (%s).", + mysql_get_client_info(), MYSQL_SERVER_VERSION); +} + +template <class T> +void DatabaseWorkerPool<T>::SetConnectionInfo(std::string const& infoString, + uint8 const asyncThreads, uint8 const synchThreads) +{ + _connectionInfo = Trinity::make_unique<MySQLConnectionInfo>(infoString); + + _async_threads = asyncThreads; + _synch_threads = synchThreads; +} + +template <class T> +uint32 DatabaseWorkerPool<T>::Open() +{ + WPFatal(_connectionInfo.get(), "Connection info was not set!"); + + TC_LOG_INFO("sql.driver", "Opening DatabasePool '%s'. " + "Asynchronous connections: %u, synchronous connections: %u.", + GetDatabaseName(), _async_threads, _synch_threads); + + uint32 error = OpenConnections(IDX_ASYNC, _async_threads); + + if (error) + return error; + + error = OpenConnections(IDX_SYNCH, _synch_threads); + + if (!error) + { + TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. " SZFMTD + " total connections running.", GetDatabaseName(), + (_connections[IDX_SYNCH].size() + _connections[IDX_ASYNC].size())); + } + + return error; +} + +template <class T> +void DatabaseWorkerPool<T>::Close() +{ + TC_LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName()); + + //! Closes the actualy MySQL connection. + _connections[IDX_ASYNC].clear(); + + TC_LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. " + "Proceeding with synchronous connections.", + GetDatabaseName()); + + //! Shut down the synchronous connections + //! There's no need for locking the connection, because DatabaseWorkerPool<>::Close + //! should only be called after any other thread tasks in the core have exited, + //! meaning there can be no concurrent access at this point. + _connections[IDX_SYNCH].clear(); + + TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName()); +} + +template <class T> +bool DatabaseWorkerPool<T>::PrepareStatements() +{ + for (auto& connections : _connections) + for (auto& connection : connections) + { + connection->LockIfReady(); + if (!connection->PrepareStatements()) + { + connection->Unlock(); + Close(); + return false; + } + else + connection->Unlock(); + } + + return true; +} + +template <class T> +QueryResult DatabaseWorkerPool<T>::Query(const char* sql, T* connection /*= nullptr*/) +{ + if (!connection) + connection = GetFreeConnection(); + + ResultSet* result = connection->Query(sql); + connection->Unlock(); + if (!result || !result->GetRowCount() || !result->NextRow()) + { + delete result; + return QueryResult(NULL); + } + + return QueryResult(result); +} + +template <class T> +PreparedQueryResult DatabaseWorkerPool<T>::Query(PreparedStatement* stmt) +{ + auto connection = GetFreeConnection(); + PreparedResultSet* ret = connection->Query(stmt); + connection->Unlock(); + + //! Delete proxy-class. Not needed anymore + delete stmt; + + if (!ret || !ret->GetRowCount()) + { + delete ret; + return PreparedQueryResult(NULL); + } + + return PreparedQueryResult(ret); +} + +template <class T> +QueryResultFuture DatabaseWorkerPool<T>::AsyncQuery(const char* sql) +{ + BasicStatementTask* task = new BasicStatementTask(sql, true); + // Store future result before enqueueing - task might get already processed and deleted before returning from this method + QueryResultFuture result = task->GetFuture(); + Enqueue(task); + return result; +} + +template <class T> +PreparedQueryResultFuture DatabaseWorkerPool<T>::AsyncQuery(PreparedStatement* stmt) +{ + PreparedStatementTask* task = new PreparedStatementTask(stmt, true); + // Store future result before enqueueing - task might get already processed and deleted before returning from this method + PreparedQueryResultFuture result = task->GetFuture(); + Enqueue(task); + return result; +} + +template <class T> +QueryResultHolderFuture DatabaseWorkerPool<T>::DelayQueryHolder(SQLQueryHolder* holder) +{ + SQLQueryHolderTask* task = new SQLQueryHolderTask(holder); + // Store future result before enqueueing - task might get already processed and deleted before returning from this method + QueryResultHolderFuture result = task->GetFuture(); + Enqueue(task); + return result; +} + +template <class T> +void DatabaseWorkerPool<T>::CommitTransaction(SQLTransaction transaction) +{ +#ifdef TRINITY_DEBUG + //! Only analyze transaction weaknesses in Debug mode. + //! Ideally we catch the faults in Debug mode and then correct them, + //! so there's no need to waste these CPU cycles in Release mode. + switch (transaction->GetSize()) + { + case 0: + TC_LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing."); + return; + case 1: + TC_LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code."); + break; + default: + break; + } +#endif // TRINITY_DEBUG + + Enqueue(new TransactionTask(transaction)); +} + +template <class T> +void DatabaseWorkerPool<T>::DirectCommitTransaction(SQLTransaction& transaction) +{ + T* connection = GetFreeConnection(); + int errorCode = connection->ExecuteTransaction(transaction); + if (!errorCode) + { + connection->Unlock(); // OK, operation succesful + return; + } + + //! Handle MySQL Errno 1213 without extending deadlock to the core itself + /// @todo More elegant way + if (errorCode == ER_LOCK_DEADLOCK) + { + uint8 loopBreaker = 5; + for (uint8 i = 0; i < loopBreaker; ++i) + { + if (!connection->ExecuteTransaction(transaction)) + break; + } + } + + //! Clean up now. + transaction->Cleanup(); + + connection->Unlock(); +} + +template <class T> +void DatabaseWorkerPool<T>::EscapeString(std::string& str) +{ + if (str.empty()) + return; + + char* buf = new char[str.size() * 2 + 1]; + EscapeString(buf, str.c_str(), uint32(str.size())); + str = buf; + delete[] buf; +} + +template <class T> +void DatabaseWorkerPool<T>::KeepAlive() +{ + //! Ping synchronous connections + for (auto& connection : _connections[IDX_SYNCH]) + { + if (connection->LockIfReady()) + { + connection->Ping(); + connection->Unlock(); + } + } + + //! Assuming all worker threads are free, every worker thread will receive 1 ping operation request + //! If one or more worker threads are busy, the ping operations will not be split evenly, but this doesn't matter + //! as the sole purpose is to prevent connections from idling. + auto const count = _connections[IDX_ASYNC].size(); + for (uint8 i = 0; i < count; ++i) + Enqueue(new PingOperation); +} + +template <class T> +uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConnections) +{ + for (uint8 i = 0; i < numConnections; ++i) + { + // Create the connection + auto connection = [&] { + switch (type) + { + case IDX_ASYNC: + return Trinity::make_unique<T>(_queue.get(), *_connectionInfo); + case IDX_SYNCH: + return Trinity::make_unique<T>(*_connectionInfo); + default: + ABORT(); + } + }(); + + if (uint32 error = connection->Open()) + { + // Failed to open a connection or invalid version, abort and cleanup + _connections[type].clear(); + return error; + } + else if (mysql_get_server_version(connection->GetHandle()) < MIN_MYSQL_SERVER_VERSION) + { + TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1"); + return 1; + } + else + { + _connections[type].push_back(std::move(connection)); + } + } + + // Everything is fine + return 0; +} + +template <class T> +T* DatabaseWorkerPool<T>::GetFreeConnection() +{ + uint8 i = 0; + auto const num_cons = _connections[IDX_SYNCH].size(); + T* connection = nullptr; + //! Block forever until a connection is free + for (;;) + { + connection = _connections[IDX_SYNCH][++i % num_cons].get(); + //! Must be matched with t->Unlock() or you will get deadlocks + if (connection->LockIfReady()) + break; + } + + return connection; +} + +template class TC_DATABASE_API DatabaseWorkerPool<LoginDatabaseConnection>; +template class TC_DATABASE_API DatabaseWorkerPool<WorldDatabaseConnection>; +template class TC_DATABASE_API DatabaseWorkerPool<CharacterDatabaseConnection>; diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index d5a254647eb..d883366237f 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -32,9 +32,7 @@ #include <mysqld_error.h> #include <memory> - -#define MIN_MYSQL_SERVER_VERSION 50100u -#define MIN_MYSQL_CLIENT_VERSION 50100u +#include <array> class PingOperation : public SQLOperation { @@ -59,97 +57,21 @@ class DatabaseWorkerPool public: /* Activity state */ - DatabaseWorkerPool() : _queue(new ProducerConsumerQueue<SQLOperation*>()), - _async_threads(0), _synch_threads(0) - { - memset(_connectionCount, 0, sizeof(_connectionCount)); - _connections.resize(IDX_SIZE); - - WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe."); - WPFatal(mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "TrinityCore does not support MySQL versions below 5.1"); - WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s) does not match the version used to compile TrinityCore (%s).", - mysql_get_client_info(), MYSQL_SERVER_VERSION); - } + DatabaseWorkerPool(); ~DatabaseWorkerPool() { _queue->Cancel(); } - void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads) - { - _connectionInfo.reset(new MySQLConnectionInfo(infoString)); - - _async_threads = asyncThreads; - _synch_threads = synchThreads; - } - - uint32 Open() - { - WPFatal(_connectionInfo.get(), "Connection info was not set!"); - - TC_LOG_INFO("sql.driver", "Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.", - GetDatabaseName(), _async_threads, _synch_threads); - - uint32 error = OpenConnections(IDX_ASYNC, _async_threads); - - if (error) - return error; - - error = OpenConnections(IDX_SYNCH, _synch_threads); - - if (!error) - { - TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(), - (_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC])); - } - - return error; - } - - void Close() - { - TC_LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName()); + void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads); - for (uint8 i = 0; i < _connectionCount[IDX_ASYNC]; ++i) - { - T* t = _connections[IDX_ASYNC][i]; - t->Close(); //! Closes the actualy MySQL connection. - } + uint32 Open(); - TC_LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.", - GetDatabaseName()); - - //! Shut down the synchronous connections - //! There's no need for locking the connection, because DatabaseWorkerPool<>::Close - //! should only be called after any other thread tasks in the core have exited, - //! meaning there can be no concurrent access at this point. - for (uint8 i = 0; i < _connectionCount[IDX_SYNCH]; ++i) - _connections[IDX_SYNCH][i]->Close(); - - TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName()); - } + void Close(); //! Prepares all prepared statements - bool PrepareStatements() - { - for (uint8 i = 0; i < IDX_SIZE; ++i) - for (uint32 c = 0; c < _connectionCount[i]; ++c) - { - T* t = _connections[i][c]; - t->LockIfReady(); - if (!t->PrepareStatements()) - { - t->Unlock(); - Close(); - return false; - } - else - t->Unlock(); - } - - return true; - } + bool PrepareStatements(); inline MySQLConnectionInfo const* GetConnectionInfo() const { @@ -201,9 +123,9 @@ class DatabaseWorkerPool if (!sql) return; - T* t = GetFreeConnection(); - t->Execute(sql); - t->Unlock(); + T* connection = GetFreeConnection(); + connection->Execute(sql); + connection->Unlock(); } //! Directly executes a one-way SQL operation in string format -with variable args-, that will block the calling thread until finished. @@ -221,9 +143,9 @@ class DatabaseWorkerPool //! Statement must be prepared with the CONNECTION_SYNCH flag. void DirectExecute(PreparedStatement* stmt) { - T* t = GetFreeConnection(); - t->Execute(stmt); - t->Unlock(); + T* connection = GetFreeConnection(); + connection->Execute(stmt); + connection->Unlock(); //! Delete proxy-class. Not needed anymore delete stmt; @@ -235,21 +157,7 @@ class DatabaseWorkerPool //! Directly executes an SQL query in string format that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. - QueryResult Query(const char* sql, T* conn = nullptr) - { - if (!conn) - conn = GetFreeConnection(); - - ResultSet* result = conn->Query(sql); - conn->Unlock(); - if (!result || !result->GetRowCount() || !result->NextRow()) - { - delete result; - return QueryResult(NULL); - } - - return QueryResult(result); - } + QueryResult Query(const char* sql, T* connection = nullptr); //! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. @@ -276,23 +184,7 @@ class DatabaseWorkerPool //! Directly executes an SQL query in prepared format that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. //! Statement must be prepared with CONNECTION_SYNCH flag. - PreparedQueryResult Query(PreparedStatement* stmt) - { - T* t = GetFreeConnection(); - PreparedResultSet* ret = t->Query(stmt); - t->Unlock(); - - //! Delete proxy-class. Not needed anymore - delete stmt; - - if (!ret || !ret->GetRowCount()) - { - delete ret; - return PreparedQueryResult(NULL); - } - - return PreparedQueryResult(ret); - } + PreparedQueryResult Query(PreparedStatement* stmt); /** Asynchronous query (with resultset) methods. @@ -300,14 +192,7 @@ class DatabaseWorkerPool //! Enqueues a query in string format that will set the value of the QueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. - QueryResultFuture AsyncQuery(const char* sql) - { - BasicStatementTask* task = new BasicStatementTask(sql, true); - // Store future result before enqueueing - task might get already processed and deleted before returning from this method - QueryResultFuture result = task->GetFuture(); - Enqueue(task); - return result; - } + QueryResultFuture AsyncQuery(const char* sql); //! Enqueues a query in string format -with variable args- that will set the value of the QueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. @@ -320,27 +205,13 @@ class DatabaseWorkerPool //! Enqueues a query in prepared format that will set the value of the PreparedQueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. //! Statement must be prepared with CONNECTION_ASYNC flag. - PreparedQueryResultFuture AsyncQuery(PreparedStatement* stmt) - { - PreparedStatementTask* task = new PreparedStatementTask(stmt, true); - // Store future result before enqueueing - task might get already processed and deleted before returning from this method - PreparedQueryResultFuture result = task->GetFuture(); - Enqueue(task); - return result; - } + PreparedQueryResultFuture AsyncQuery(PreparedStatement* stmt); //! Enqueues a vector of SQL operations (can be both adhoc and prepared) that will set the value of the QueryResultHolderFuture //! return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. //! Any prepared statements added to this holder need to be prepared with the CONNECTION_ASYNC flag. - QueryResultHolderFuture DelayQueryHolder(SQLQueryHolder* holder) - { - SQLQueryHolderTask* task = new SQLQueryHolderTask(holder); - // Store future result before enqueueing - task might get already processed and deleted before returning from this method - QueryResultHolderFuture result = task->GetFuture(); - Enqueue(task); - return result; - } + QueryResultHolderFuture DelayQueryHolder(SQLQueryHolder* holder); /** Transaction context methods. @@ -354,57 +225,11 @@ class DatabaseWorkerPool //! Enqueues a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations //! were appended to the transaction will be respected during execution. - void CommitTransaction(SQLTransaction transaction) - { - #ifdef TRINITY_DEBUG - //! Only analyze transaction weaknesses in Debug mode. - //! Ideally we catch the faults in Debug mode and then correct them, - //! so there's no need to waste these CPU cycles in Release mode. - switch (transaction->GetSize()) - { - case 0: - TC_LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing."); - return; - case 1: - TC_LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code."); - break; - default: - break; - } - #endif // TRINITY_DEBUG - - Enqueue(new TransactionTask(transaction)); - } + void CommitTransaction(SQLTransaction transaction); //! Directly executes a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations //! were appended to the transaction will be respected during execution. - void DirectCommitTransaction(SQLTransaction& transaction) - { - T* con = GetFreeConnection(); - int errorCode = con->ExecuteTransaction(transaction); - if (!errorCode) - { - con->Unlock(); // OK, operation succesful - return; - } - - //! Handle MySQL Errno 1213 without extending deadlock to the core itself - /// @todo More elegant way - if (errorCode == ER_LOCK_DEADLOCK) - { - uint8 loopBreaker = 5; - for (uint8 i = 0; i < loopBreaker; ++i) - { - if (!con->ExecuteTransaction(transaction)) - break; - } - } - - //! Clean up now. - transaction->Cleanup(); - - con->Unlock(); - } + void DirectCommitTransaction(SQLTransaction& transaction); //! Method used to execute prepared statements in a diverse context. //! Will be wrapped in a transaction if valid object is present, otherwise executed standalone. @@ -441,90 +266,21 @@ class DatabaseWorkerPool } //! Apply escape string'ing for current collation. (utf8) - void EscapeString(std::string& str) - { - if (str.empty()) - return; - - char* buf = new char[str.size() * 2 + 1]; - EscapeString(buf, str.c_str(), str.size()); - str = buf; - delete[] buf; - } + void EscapeString(std::string& str); //! Keeps all our MySQL connections alive, prevent the server from disconnecting us. - void KeepAlive() - { - //! Ping synchronous connections - for (uint8 i = 0; i < _connectionCount[IDX_SYNCH]; ++i) - { - T* t = _connections[IDX_SYNCH][i]; - if (t->LockIfReady()) - { - t->Ping(); - t->Unlock(); - } - } - - //! Assuming all worker threads are free, every worker thread will receive 1 ping operation request - //! If one or more worker threads are busy, the ping operations will not be split evenly, but this doesn't matter - //! as the sole purpose is to prevent connections from idling. - for (size_t i = 0; i < _connections[IDX_ASYNC].size(); ++i) - Enqueue(new PingOperation); - } + void KeepAlive(); private: - uint32 OpenConnections(InternalIndex type, uint8 numConnections) - { - _connections[type].resize(numConnections); - for (uint8 i = 0; i < numConnections; ++i) - { - T* t; - - if (type == IDX_ASYNC) - t = new T(_queue.get(), *_connectionInfo); - else if (type == IDX_SYNCH) - t = new T(*_connectionInfo); - else - ABORT(); - - _connections[type][i] = t; - ++_connectionCount[type]; - - uint32 error = t->Open(); - - if (!error) - { - if (mysql_get_server_version(t->GetHandle()) < MIN_MYSQL_SERVER_VERSION) - { - TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1"); - error = 1; - } - } - - // Failed to open a connection or invalid version, abort and cleanup - if (error) - { - while (_connectionCount[type] != 0) - { - t = _connections[type][i--]; - delete t; - --_connectionCount[type]; - } - return error; - } - } - - // Everything is fine - return 0; - } + uint32 OpenConnections(InternalIndex type, uint8 numConnections); unsigned long EscapeString(char *to, const char *from, unsigned long length) { if (!to || !from || !length) return 0; - return mysql_real_escape_string(_connections[IDX_SYNCH][0]->GetHandle(), to, from, length); + return mysql_real_escape_string( + _connections[IDX_SYNCH].front()->GetHandle(), to, from, length); } void Enqueue(SQLOperation* op) @@ -534,22 +290,7 @@ class DatabaseWorkerPool //! Gets a free connection in the synchronous connection pool. //! Caller MUST call t->Unlock() after touching the MySQL context to prevent deadlocks. - T* GetFreeConnection() - { - uint8 i = 0; - size_t num_cons = _connectionCount[IDX_SYNCH]; - T* t = NULL; - //! Block forever until a connection is free - for (;;) - { - t = _connections[IDX_SYNCH][++i % num_cons]; - //! Must be matched with t->Unlock() or you will get deadlocks - if (t->LockIfReady()) - break; - } - - return t; - } + T* GetFreeConnection(); char const* GetDatabaseName() const { @@ -558,9 +299,7 @@ class DatabaseWorkerPool //! Queue shared by async worker threads. std::unique_ptr<ProducerConsumerQueue<SQLOperation*>> _queue; - std::vector<std::vector<T*>> _connections; - //! Counter of MySQL connections; - uint32 _connectionCount[IDX_SIZE]; + std::array<std::vector<std::unique_ptr<T>>, IDX_SIZE> _connections; std::unique_ptr<MySQLConnectionInfo> _connectionInfo; uint8 _async_threads, _synch_threads; }; diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h index ec9e626ee1b..123e25dbbf3 100644 --- a/src/server/database/Database/Field.h +++ b/src/server/database/Database/Field.h @@ -53,7 +53,7 @@ | SUM, AVG | DECIMAL | | COUNT | BIGINT | */ -class Field +class TC_DATABASE_API Field { friend class ResultSet; friend class PreparedResultSet; @@ -323,7 +323,7 @@ class Field data.value = NULL; } - static size_t SizeForType(MYSQL_FIELD* field) + static uint32 SizeForType(MYSQL_FIELD* field) { switch (field->type) { diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index ab68aca2a8c..ce01b0eb245 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -42,11 +42,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_MAIL_LIST_INFO, "SELECT id, sender, (SELECT name FROM characters WHERE guid = sender) AS sendername, receiver, (SELECT name FROM characters WHERE guid = receiver) AS receivername, " "subject, deliver_time, expire_time, money, has_items FROM mail WHERE receiver = ? ", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_MAIL_LIST_ITEMS, "SELECT itemEntry,count FROM item_instance WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_ENUM, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.playerBytes, c.playerBytes2, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " + PrepareStatement(CHAR_SEL_ENUM, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid " "FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? LEFT JOIN guild_member AS gm ON c.guid = gm.guid " "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL ORDER BY c.guid", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.playerBytes, c.playerBytes2, c.level, c.zone, c.map, " + PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, " "c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, " "cb.guid, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? " "LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid " @@ -64,7 +64,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, " + PrepareStatement(CHAR_SEL_CHARACTER, "SELECT guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, playerFlags, " "position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " "resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, " "arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk, " @@ -351,7 +351,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_LFG_DATA, "DELETE FROM lfg_data WHERE guid = ?", CONNECTION_ASYNC); // Player saving - PrepareStatement(CHAR_INS_CHARACTER, "INSERT INTO characters (guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, " + PrepareStatement(CHAR_INS_CHARACTER, "INSERT INTO characters (guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, playerFlags, " "map, instance_id, instance_mode_mask, position_x, position_y, position_z, orientation, trans_x, trans_y, trans_z, trans_o, transguid, " "taximask, cinematic, " "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, " @@ -359,8 +359,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() "death_expire_time, taxi_path, arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, " "todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk, health, power1, power2, power3, " "power4, power5, power6, power7, latency, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, ammoId, knownTitles, actionBars, grantableLevels) VALUES " - "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,playerBytes=?,playerBytes2=?,playerFlags=?," + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,skin=?,face=?,hairStyle=?,hairColor=?,facialStyle=?,bankSlots=?,restState=?,playerFlags=?," "map=?,instance_id=?,instance_mode_mask=?,position_x=?,position_y=?,position_z=?,orientation=?,trans_x=?,trans_y=?,trans_z=?,trans_o=?,transguid=?,taximask=?,cinematic=?,totaltime=?,leveltime=?,rest_bonus=?," "logout_time=?,is_logout_resting=?,resettalents_cost=?,resettalents_time=?,extra_flags=?,stable_slots=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?," "arenaPoints=?,totalHonorPoints=?,todayHonorPoints=?,yesterdayHonorPoints=?,totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?,knownCurrencies=?," @@ -407,7 +407,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID, "DELETE FROM character_instance WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_INSTANCE, "UPDATE character_instance SET instance = ?, permanent = ?, extendState = ? WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_INSTANCE, "INSERT INTO character_instance (guid, instance, permanent, extendState) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_GENDER_PLAYERBYTES, "UPDATE characters SET gender = ?, playerBytes = ?, playerBytes2 = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GENDER_AND_APPEARANCE, "UPDATE characters SET gender = ?, skin = ?, face = ?, hairStyle = ?, hairColor = ?, facialStyle = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_SKILL, "DELETE FROM character_skills WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ADD_CHARACTER_SOCIAL_FLAGS, "UPDATE character_social SET flags = flags | ? WHERE guid = ? AND friend = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_REM_CHARACTER_SOCIAL_FLAGS, "UPDATE character_social SET flags = flags & ~ ? WHERE guid = ? AND friend = ?", CONNECTION_ASYNC); @@ -440,7 +440,6 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHAR_OLD_CHARS, "SELECT guid, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID, "SELECT arena_team_member.arenateamid FROM arena_team_member JOIN arena_team ON arena_team_member.arenateamid = arena_team.arenateamid WHERE guid = ? AND type = ? LIMIT 1", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_MAIL, "SELECT id, messageType, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId FROM mail WHERE receiver = ? ORDER BY id DESC", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_PLAYERBYTES2, "SELECT playerBytes2 FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_GUID_BY_NAME, "SELECT guid FROM characters WHERE name = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_CHAR_AURA_FROZEN, "DELETE FROM character_aura WHERE spell = 9454 AND guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHAR_INVENTORY_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM character_inventory ci INNER JOIN item_instance ii ON ii.guid = ci.item WHERE itemEntry = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index 19d4a609e77..430243a8f1e 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -334,7 +334,7 @@ enum CharacterDatabaseStatements CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID, CHAR_UPD_CHAR_INSTANCE, CHAR_INS_CHAR_INSTANCE, - CHAR_UPD_GENDER_PLAYERBYTES, + CHAR_UPD_GENDER_AND_APPEARANCE, CHAR_DEL_CHARACTER_SKILL, CHAR_UPD_ADD_CHARACTER_SOCIAL_FLAGS, CHAR_UPD_REM_CHARACTER_SOCIAL_FLAGS, @@ -371,7 +371,6 @@ enum CharacterDatabaseStatements CHAR_SEL_CHAR_OLD_CHARS, CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID, CHAR_SEL_MAIL, - CHAR_SEL_CHAR_PLAYERBYTES2, CHAR_SEL_CHAR_GUID_BY_NAME, CHAR_DEL_CHAR_AURA_FROZEN, CHAR_SEL_CHAR_INVENTORY_COUNT_ITEM, @@ -538,7 +537,7 @@ enum CharacterDatabaseStatements MAX_CHARACTERDATABASE_STATEMENTS }; -class CharacterDatabaseConnection : public MySQLConnection +class TC_DATABASE_API CharacterDatabaseConnection : public MySQLConnection { public: typedef CharacterDatabaseStatements Statements; diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 2749c08594f..4f056e2686d 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -37,7 +37,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_ACCOUNT_BANNED, "DELETE FROM account_banned WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET sessionkey = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.id, UPPER(a.username), a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, " + PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, " "ab.unbandate = ab.bandate, aa.gmlevel, a.token_key, a.sha_pass_hash, a.v, a.s " "FROM account a LEFT JOIN account_access aa ON a.id = aa.id LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_RECONNECTCHALLENGE, "SELECT a.id, UPPER(a.username), a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, " diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index a3789fa2557..e206be16d73 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -116,7 +116,7 @@ enum LoginDatabaseStatements MAX_LOGINDATABASE_STATEMENTS }; -class LoginDatabaseConnection : public MySQLConnection +class TC_DATABASE_API LoginDatabaseConnection : public MySQLConnection { public: typedef LoginDatabaseStatements Statements; diff --git a/src/server/database/Database/Implementation/WorldDatabase.h b/src/server/database/Database/Implementation/WorldDatabase.h index 6ac4ce589e3..e0a02423446 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.h +++ b/src/server/database/Database/Implementation/WorldDatabase.h @@ -103,7 +103,7 @@ enum WorldDatabaseStatements MAX_WORLDDATABASE_STATEMENTS }; -class WorldDatabaseConnection : public MySQLConnection +class TC_DATABASE_API WorldDatabaseConnection : public MySQLConnection { public: typedef WorldDatabaseStatements Statements; diff --git a/src/server/database/Database/MySQLConnection.cpp b/src/server/database/Database/MySQLConnection.cpp index 41dd61d3c3a..93d2a35f310 100644 --- a/src/server/database/Database/MySQLConnection.cpp +++ b/src/server/database/Database/MySQLConnection.cpp @@ -37,7 +37,6 @@ MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo) : m_reconnecting(false), m_prepareError(false), m_queue(NULL), -m_worker(NULL), m_Mysql(NULL), m_connectionInfo(connInfo), m_connectionFlags(CONNECTION_SYNCH) { } @@ -50,24 +49,26 @@ m_Mysql(NULL), m_connectionInfo(connInfo), m_connectionFlags(CONNECTION_ASYNC) { - m_worker = new DatabaseWorker(m_queue, this); + m_worker = Trinity::make_unique<DatabaseWorker>(m_queue, this); } MySQLConnection::~MySQLConnection() { - delete m_worker; - - for (size_t i = 0; i < m_stmts.size(); ++i) - delete m_stmts[i]; - - if (m_Mysql) - mysql_close(m_Mysql); + Close(); } void MySQLConnection::Close() { - /// Only close us if we're not operating - delete this; + // Stop the worker thread before the statements are cleared + m_worker.reset(); + + m_stmts.clear(); + + if (m_Mysql) + { + mysql_close(m_Mysql); + m_Mysql = nullptr; + } } uint32 MySQLConnection::Open() @@ -412,7 +413,7 @@ int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index) { ASSERT(index < m_stmts.size()); - MySQLPreparedStatement* ret = m_stmts[index]; + MySQLPreparedStatement* ret = m_stmts[index].get(); if (!ret) TC_LOG_ERROR("sql.sql", "Could not fetch prepared statement %u on database `%s`, connection type: %s.", index, m_connectionInfo.database.c_str(), (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous"); @@ -424,16 +425,12 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection { m_queries.insert(PreparedStatementMap::value_type(index, std::make_pair(sql, flags))); - // For reconnection case - if (m_reconnecting) - delete m_stmts[index]; - // Check if specified query should be prepared on this connection // i.e. don't prepare async statements on synchronous connections // to save memory that will not be used. if (!(m_connectionFlags & flags)) { - m_stmts[index] = NULL; + m_stmts[index].reset(); return; } @@ -455,8 +452,7 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection } else { - MySQLPreparedStatement* mStmt = new MySQLPreparedStatement(stmt); - m_stmts[index] = mStmt; + m_stmts[index] = Trinity::make_unique<MySQLPreparedStatement>(stmt); } } } @@ -477,7 +473,7 @@ PreparedResultSet* MySQLConnection::Query(PreparedStatement* stmt) return new PreparedResultSet(stmt->m_stmt->GetSTMT(), result, rowCount, fieldCount); } -bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) +bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/) { switch (errNo) { @@ -486,9 +482,21 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) case CR_INVALID_CONN_HANDLE: case CR_SERVER_LOST_EXTENDED: { + if (m_Mysql) + { + TC_LOG_ERROR("sql.sql", "Lost the connection to the MySQL server!"); + + mysql_close(GetHandle()); + m_Mysql = nullptr; + } + + /*no break*/ + } + case CR_CONN_HOST_ERROR: + { + TC_LOG_INFO("sql.sql", "Attempting to reconnect to the MySQL server..."); + m_reconnecting = true; - uint64 oldThreadId = mysql_thread_id(GetHandle()); - mysql_close(GetHandle()); uint32 const lErrno = Open(); if (!lErrno) @@ -496,24 +504,37 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) // Don't remove 'this' pointer unless you want to skip loading all prepared statements... if (!this->PrepareStatements()) { - TC_LOG_ERROR("sql.sql", "Could not re-prepare statements!"); - Close(); - return false; + TC_LOG_FATAL("sql.sql", "Could not re-prepare statements!"); + std::this_thread::sleep_for(std::chrono::seconds(10)); + std::abort(); } - TC_LOG_INFO("sql.sql", "Connection to the MySQL server is active."); - if (oldThreadId != mysql_thread_id(GetHandle())) - TC_LOG_INFO("sql.sql", "Successfully reconnected to %s @%s:%s (%s).", - m_connectionInfo.database.c_str(), m_connectionInfo.host.c_str(), m_connectionInfo.port_or_socket.c_str(), - (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous"); + TC_LOG_INFO("sql.sql", "Successfully reconnected to %s @%s:%s (%s).", + m_connectionInfo.database.c_str(), m_connectionInfo.host.c_str(), m_connectionInfo.port_or_socket.c_str(), + (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous"); m_reconnecting = false; return true; } - // It's possible this attempted reconnect throws 2006 at us. To prevent crazy recursive calls, sleep here. - std::this_thread::sleep_for(std::chrono::seconds(3)); // Sleep 3 seconds - return _HandleMySQLErrno(lErrno); // Call self (recursive) + if ((--attempts) == 0) + { + // Shut down the server when the mysql server isn't + // reachable for some time + TC_LOG_FATAL("sql.sql", "Failed to reconnect to the MySQL server, " + "terminating the server to prevent data corruption!"); + + // We could also initiate a shutdown through using std::raise(SIGTERM) + std::this_thread::sleep_for(std::chrono::seconds(10)); + std::abort(); + } + else + { + // It's possible this attempted reconnect throws 2006 at us. + // To prevent crazy recursive calls, sleep here. + std::this_thread::sleep_for(std::chrono::seconds(3)); // Sleep 3 seconds + return _HandleMySQLErrno(lErrno, attempts); // Call self (recursive) + } } case ER_LOCK_DEADLOCK: diff --git a/src/server/database/Database/MySQLConnection.h b/src/server/database/Database/MySQLConnection.h index a981caa607e..566995988c0 100644 --- a/src/server/database/Database/MySQLConnection.h +++ b/src/server/database/Database/MySQLConnection.h @@ -35,7 +35,7 @@ enum ConnectionFlags CONNECTION_BOTH = CONNECTION_ASYNC | CONNECTION_SYNCH }; -struct MySQLConnectionInfo +struct TC_DATABASE_API MySQLConnectionInfo { explicit MySQLConnectionInfo(std::string const& infoString) { @@ -62,7 +62,7 @@ struct MySQLConnectionInfo typedef std::map<uint32 /*index*/, std::pair<std::string /*query*/, ConnectionFlags /*sync/async*/> > PreparedStatementMap; -class MySQLConnection +class TC_DATABASE_API MySQLConnection { template <class T> friend class DatabaseWorkerPool; friend class PingOperation; @@ -116,18 +116,18 @@ class MySQLConnection virtual void DoPrepareStatements() = 0; protected: - std::vector<MySQLPreparedStatement*> m_stmts; //! PreparedStatements storage + std::vector<std::unique_ptr<MySQLPreparedStatement>> m_stmts; //! PreparedStatements storage PreparedStatementMap m_queries; //! Query storage bool m_reconnecting; //! Are we reconnecting? bool m_prepareError; //! Was there any error while preparing statements? private: - bool _HandleMySQLErrno(uint32 errNo); + bool _HandleMySQLErrno(uint32 errNo, uint8 attempts = 5); private: ProducerConsumerQueue<SQLOperation*>* m_queue; //! Queue shared with other asynchronous connections. - DatabaseWorker* m_worker; //! Core worker task. - MYSQL * m_Mysql; //! MySQL Handle. + std::unique_ptr<DatabaseWorker> m_worker; //! Core worker task. + MYSQL* m_Mysql; //! MySQL Handle. MySQLConnectionInfo& m_connectionInfo; //! Connection info (used for logging) ConnectionFlags m_connectionFlags; //! Connection flags (for preparing relevant statements) std::mutex m_Mutex; diff --git a/src/server/database/Database/MySQLThreading.h b/src/server/database/Database/MySQLThreading.h index 1cfa11d7e5b..b6083500989 100644 --- a/src/server/database/Database/MySQLThreading.h +++ b/src/server/database/Database/MySQLThreading.h @@ -20,7 +20,7 @@ #include "Log.h" -class MySQL +class TC_DATABASE_API MySQL { public: static void Library_Init() diff --git a/src/server/database/Database/PreparedStatement.cpp b/src/server/database/Database/PreparedStatement.cpp index 848a923c75d..119f1d4c93b 100644 --- a/src/server/database/Database/PreparedStatement.cpp +++ b/src/server/database/Database/PreparedStatement.cpp @@ -344,7 +344,7 @@ void MySQLPreparedStatement::setString(const uint8 index, const char* value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - size_t len = strlen(value) + 1; + uint32 len = uint32(strlen(value) + 1); param->buffer_type = MYSQL_TYPE_VAR_STRING; delete [] static_cast<char *>(param->buffer); param->buffer = new char[len]; diff --git a/src/server/database/Database/PreparedStatement.h b/src/server/database/Database/PreparedStatement.h index 7d6c98463d0..faaec27014f 100644 --- a/src/server/database/Database/PreparedStatement.h +++ b/src/server/database/Database/PreparedStatement.h @@ -70,7 +70,7 @@ struct PreparedStatementData class MySQLPreparedStatement; //- Upper-level class that is used in code -class PreparedStatement +class TC_DATABASE_API PreparedStatement { friend class PreparedStatementTask; friend class MySQLPreparedStatement; @@ -109,7 +109,7 @@ class PreparedStatement //- Class of which the instances are unique per MySQLConnection //- access to these class objects is only done when a prepared statement task //- is executed. -class MySQLPreparedStatement +class TC_DATABASE_API MySQLPreparedStatement { friend class MySQLConnection; friend class PreparedStatement; @@ -157,7 +157,7 @@ typedef std::future<PreparedQueryResult> PreparedQueryResultFuture; typedef std::promise<PreparedQueryResult> PreparedQueryResultPromise; //- Lower-level class, enqueuable operation -class PreparedStatementTask : public SQLOperation +class TC_DATABASE_API PreparedStatementTask : public SQLOperation { public: PreparedStatementTask(PreparedStatement* stmt, bool async = false); diff --git a/src/server/database/Database/QueryHolder.h b/src/server/database/Database/QueryHolder.h index 9a5a03fda42..2446a4db2bd 100644 --- a/src/server/database/Database/QueryHolder.h +++ b/src/server/database/Database/QueryHolder.h @@ -20,7 +20,7 @@ #include <future> -class SQLQueryHolder +class TC_DATABASE_API SQLQueryHolder { friend class SQLQueryHolderTask; private: @@ -46,7 +46,7 @@ class SQLQueryHolder typedef std::future<SQLQueryHolder*> QueryResultHolderFuture; typedef std::promise<SQLQueryHolder*> QueryResultHolderPromise; -class SQLQueryHolderTask : public SQLOperation +class TC_DATABASE_API SQLQueryHolderTask : public SQLOperation { private: SQLQueryHolder* m_holder; diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp index f02457f67ca..db9e737830c 100644 --- a/src/server/database/Database/QueryResult.cpp +++ b/src/server/database/Database/QueryResult.cpp @@ -76,7 +76,7 @@ m_length(NULL) std::size_t rowSize = 0; for (uint32 i = 0; i < m_fieldCount; ++i) { - size_t size = Field::SizeForType(&field[i]); + uint32 size = Field::SizeForType(&field[i]); rowSize += size; m_rBind[i].buffer_type = field[i].type; diff --git a/src/server/database/Database/QueryResult.h b/src/server/database/Database/QueryResult.h index d4d63b5ec85..3b1691db1a6 100644 --- a/src/server/database/Database/QueryResult.h +++ b/src/server/database/Database/QueryResult.h @@ -27,7 +27,7 @@ #endif #include <mysql.h> -class ResultSet +class TC_DATABASE_API ResultSet { public: ResultSet(MYSQL_RES* result, MYSQL_FIELD* fields, uint64 rowCount, uint32 fieldCount); @@ -60,7 +60,7 @@ class ResultSet typedef std::shared_ptr<ResultSet> QueryResult; -class PreparedResultSet +class TC_DATABASE_API PreparedResultSet { public: PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES* result, uint64 rowCount, uint32 fieldCount); diff --git a/src/server/database/Database/SQLOperation.h b/src/server/database/Database/SQLOperation.h index f0500d1f232..5b3032eab87 100644 --- a/src/server/database/Database/SQLOperation.h +++ b/src/server/database/Database/SQLOperation.h @@ -53,7 +53,7 @@ union SQLResultSetUnion class MySQLConnection; -class SQLOperation +class TC_DATABASE_API SQLOperation { public: SQLOperation(): m_conn(NULL) { } diff --git a/src/server/database/Database/Transaction.h b/src/server/database/Database/Transaction.h index 5780c0363d9..7b5b6addfe4 100644 --- a/src/server/database/Database/Transaction.h +++ b/src/server/database/Database/Transaction.h @@ -25,7 +25,7 @@ class PreparedStatement; /*! Transactions, high level class. */ -class Transaction +class TC_DATABASE_API Transaction { friend class TransactionTask; friend class MySQLConnection; @@ -58,7 +58,7 @@ class Transaction typedef std::shared_ptr<Transaction> SQLTransaction; /*! Low level class*/ -class TransactionTask : public SQLOperation +class TC_DATABASE_API TransactionTask : public SQLOperation { template <class T> friend class DatabaseWorkerPool; friend class DatabaseWorker; diff --git a/src/server/database/Logging/AppenderDB.h b/src/server/database/Logging/AppenderDB.h index a6acc66b48c..225ae969802 100644 --- a/src/server/database/Logging/AppenderDB.h +++ b/src/server/database/Logging/AppenderDB.h @@ -20,7 +20,7 @@ #include "Appender.h" -class AppenderDB: public Appender +class TC_DATABASE_API AppenderDB: public Appender { public: typedef std::integral_constant<AppenderType, APPENDER_DB>::type TypeIndex; diff --git a/src/server/database/Updater/DBUpdater.cpp b/src/server/database/Updater/DBUpdater.cpp index b18d6c67612..3be81e85715 100644 --- a/src/server/database/Updater/DBUpdater.cpp +++ b/src/server/database/Updater/DBUpdater.cpp @@ -22,19 +22,11 @@ #include "DatabaseLoader.h" #include "Config.h" #include "BuiltInConfig.h" +#include "StartProcess.h" #include <fstream> #include <iostream> #include <unordered_map> -#include <boost/process.hpp> -#include <boost/iostreams/stream.hpp> -#include <boost/iostreams/copy.hpp> -#include <boost/iostreams/device/file_descriptor.hpp> -#include <boost/system/system_error.hpp> - -using namespace boost::process; -using namespace boost::process::initializers; -using namespace boost::iostreams; std::string DBUpdaterUtil::GetCorrectedMySQLExecutable() { @@ -51,19 +43,16 @@ bool DBUpdaterUtil::CheckExecutable() { exe.clear(); - try - { - exe = search_path("mysql"); - } - catch (std::runtime_error&) + if (auto path = Trinity::SearchExecutableInPath("mysql")) { - } + exe = std::move(*path); - if (!exe.empty() && exists(exe)) - { - // Correct the path to the cli - corrected_path() = absolute(exe).generic_string(); - return true; + if (!exe.empty() && exists(exe)) + { + // Correct the path to the cli + corrected_path() = absolute(exe).generic_string(); + return true; + } } TC_LOG_FATAL("sql.updates", "Didn't find executeable mysql binary at \'%s\' or in path, correct the path in the *.conf (\"Updates.MySqlCLIPath\").", @@ -387,44 +376,9 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos if (!database.empty()) args.push_back(database); - // ToDo: use the existing query in memory as virtual file if possible - file_descriptor_source source(path); - - uint32 ret; - try - { - boost::process::pipe outPipe = create_pipe(); - boost::process::pipe errPipe = create_pipe(); - - child c = execute(run_exe( - boost::filesystem::absolute(DBUpdaterUtil::GetCorrectedMySQLExecutable()).generic_string()), - set_args(args), bind_stdin(source), throw_on_error(), - bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)), - bind_stderr(file_descriptor_sink(errPipe.sink, close_handle))); - - file_descriptor_source mysqlOutfd(outPipe.source, close_handle); - file_descriptor_source mysqlErrfd(errPipe.source, close_handle); - - stream<file_descriptor_source> mysqlOutStream(mysqlOutfd); - stream<file_descriptor_source> mysqlErrStream(mysqlErrfd); - - std::stringstream out; - std::stringstream err; - - copy(mysqlOutStream, out); - copy(mysqlErrStream, err); - - TC_LOG_INFO("sql.updates", "%s", out.str().c_str()); - TC_LOG_ERROR("sql.updates", "%s", err.str().c_str()); - - ret = wait_for_exit(c); - } - catch (boost::system::system_error&) - { - ret = EXIT_FAILURE; - } - - source.close(); + // Invokes a mysql process which doesn't leak credentials to logs + int const ret = Trinity::StartProcess(DBUpdaterUtil::GetCorrectedMySQLExecutable(), args, + "sql.updates", path.generic_string(), true); if (ret != EXIT_SUCCESS) { @@ -436,6 +390,6 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos } } -template class DBUpdater<LoginDatabaseConnection>; -template class DBUpdater<WorldDatabaseConnection>; -template class DBUpdater<CharacterDatabaseConnection>; +template class TC_DATABASE_API DBUpdater<LoginDatabaseConnection>; +template class TC_DATABASE_API DBUpdater<WorldDatabaseConnection>; +template class TC_DATABASE_API DBUpdater<CharacterDatabaseConnection>; diff --git a/src/server/database/Updater/DBUpdater.h b/src/server/database/Updater/DBUpdater.h index dbb897d2527..cc5d3aad68b 100644 --- a/src/server/database/Updater/DBUpdater.h +++ b/src/server/database/Updater/DBUpdater.h @@ -23,7 +23,7 @@ #include <string> #include <boost/filesystem.hpp> -class UpdateException : public std::exception +class TC_DATABASE_API UpdateException : public std::exception { public: UpdateException(std::string const& msg) : _msg(msg) { } @@ -41,7 +41,7 @@ enum BaseLocation LOCATION_DOWNLOAD }; -struct UpdateResult +struct TC_DATABASE_API UpdateResult { UpdateResult() : updated(0), recent(0), archived(0) { } @@ -66,7 +66,7 @@ private: }; template <class T> -class DBUpdater +class TC_DATABASE_API DBUpdater { public: using Path = boost::filesystem::path; diff --git a/src/server/database/Updater/UpdateFetcher.cpp b/src/server/database/Updater/UpdateFetcher.cpp index 2d60cdb92ef..6f67867c52b 100644 --- a/src/server/database/Updater/UpdateFetcher.cpp +++ b/src/server/database/Updater/UpdateFetcher.cpp @@ -354,7 +354,7 @@ uint32 UpdateFetcher::Apply(Path const& path) const _applyFile(path); // Return time the query took to apply - return std::chrono::duration_cast<std::chrono::milliseconds>(Time::now() - begin).count(); + return uint32(std::chrono::duration_cast<std::chrono::milliseconds>(Time::now() - begin).count()); } void UpdateFetcher::UpdateEntry(AppliedFileEntry const& entry, uint32 const speed) const diff --git a/src/server/database/Updater/UpdateFetcher.h b/src/server/database/Updater/UpdateFetcher.h index c87efea2b02..a17658818ce 100644 --- a/src/server/database/Updater/UpdateFetcher.h +++ b/src/server/database/Updater/UpdateFetcher.h @@ -25,7 +25,7 @@ #include <memory> #include <vector> -class UpdateFetcher +class TC_DATABASE_API UpdateFetcher { typedef boost::filesystem::path Path; diff --git a/src/server/game/AI/CoreAI/CombatAI.h b/src/server/game/AI/CoreAI/CombatAI.h index 55b91b6969e..f1718fbdb6a 100644 --- a/src/server/game/AI/CoreAI/CombatAI.h +++ b/src/server/game/AI/CoreAI/CombatAI.h @@ -25,7 +25,7 @@ class Creature; -class AggressorAI : public CreatureAI +class TC_GAME_API AggressorAI : public CreatureAI { public: explicit AggressorAI(Creature* c) : CreatureAI(c) { } @@ -36,7 +36,7 @@ class AggressorAI : public CreatureAI typedef std::vector<uint32> SpellVct; -class CombatAI : public CreatureAI +class TC_GAME_API CombatAI : public CreatureAI { public: explicit CombatAI(Creature* c) : CreatureAI(c) { } @@ -55,7 +55,7 @@ class CombatAI : public CreatureAI SpellVct spells; }; -class CasterAI : public CombatAI +class TC_GAME_API CasterAI : public CombatAI { public: explicit CasterAI(Creature* c) : CombatAI(c) { m_attackDist = MELEE_RANGE; } @@ -67,7 +67,7 @@ class CasterAI : public CombatAI float m_attackDist; }; -struct ArcherAI : public CreatureAI +struct TC_GAME_API ArcherAI : public CreatureAI { public: explicit ArcherAI(Creature* c); @@ -80,7 +80,7 @@ struct ArcherAI : public CreatureAI float m_minRange; }; -struct TurretAI : public CreatureAI +struct TC_GAME_API TurretAI : public CreatureAI { public: explicit TurretAI(Creature* c); @@ -97,7 +97,7 @@ struct TurretAI : public CreatureAI #define VEHICLE_CONDITION_CHECK_TIME 1000 #define VEHICLE_DISMISS_TIME 5000 -struct VehicleAI : public CreatureAI +struct TC_GAME_API VehicleAI : public CreatureAI { public: explicit VehicleAI(Creature* creature); diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index 4f256a5de31..7a2f23ac804 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -26,7 +26,7 @@ #include "GameObject.h" #include "CreatureAI.h" -class GameObjectAI +class TC_GAME_API GameObjectAI { protected: GameObject* const go; @@ -63,7 +63,7 @@ class GameObjectAI virtual void EventInform(uint32 /*eventId*/) { } }; -class NullGameObjectAI : public GameObjectAI +class TC_GAME_API NullGameObjectAI : public GameObjectAI { public: explicit NullGameObjectAI(GameObject* g); diff --git a/src/server/game/AI/CoreAI/GuardAI.h b/src/server/game/AI/CoreAI/GuardAI.h index 63f2750a5d4..a6aa4b6624a 100644 --- a/src/server/game/AI/CoreAI/GuardAI.h +++ b/src/server/game/AI/CoreAI/GuardAI.h @@ -23,7 +23,7 @@ class Creature; -class GuardAI : public ScriptedAI +class TC_GAME_API GuardAI : public ScriptedAI { public: explicit GuardAI(Creature* creature); diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h index bd72cd7fbe7..5a6dba7046d 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.h +++ b/src/server/game/AI/CoreAI/PassiveAI.h @@ -21,7 +21,7 @@ #include "CreatureAI.h" -class PassiveAI : public CreatureAI +class TC_GAME_API PassiveAI : public CreatureAI { public: explicit PassiveAI(Creature* c); @@ -33,7 +33,7 @@ class PassiveAI : public CreatureAI static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; } }; -class PossessedAI : public CreatureAI +class TC_GAME_API PossessedAI : public CreatureAI { public: explicit PossessedAI(Creature* c); @@ -49,7 +49,7 @@ class PossessedAI : public CreatureAI static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; } }; -class NullCreatureAI : public CreatureAI +class TC_GAME_API NullCreatureAI : public CreatureAI { public: explicit NullCreatureAI(Creature* c); @@ -63,7 +63,7 @@ class NullCreatureAI : public CreatureAI static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; } }; -class CritterAI : public PassiveAI +class TC_GAME_API CritterAI : public PassiveAI { public: explicit CritterAI(Creature* c) : PassiveAI(c) { } @@ -72,7 +72,7 @@ class CritterAI : public PassiveAI void EnterEvadeMode(EvadeReason why) override; }; -class TriggerAI : public NullCreatureAI +class TC_GAME_API TriggerAI : public NullCreatureAI { public: explicit TriggerAI(Creature* c) : NullCreatureAI(c) { } diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 8acf6b9c9dc..68554722db6 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -150,14 +150,14 @@ void PetAI::UpdateAI(uint32 diff) if (me->GetCharmInfo() && me->GetSpellHistory()->HasGlobalCooldown(spellInfo)) continue; + // check spell cooldown + if (!me->GetSpellHistory()->IsReady(spellInfo)) + continue; + if (spellInfo->IsPositive()) { if (spellInfo->CanBeUsedInCombat()) { - // check spell cooldown & school lock - if (!me->GetSpellHistory()->IsReady(spellInfo)) - continue; - // Check if we're in combat or commanded to attack if (!me->IsInCombat() && !me->GetCharmInfo()->IsCommandAttack()) continue; @@ -225,26 +225,17 @@ void PetAI::UpdateAI(uint32 diff) //found units to cast on to if (!targetSpellStore.empty()) { - uint32 index = urand(0, targetSpellStore.size() - 1); + TargetSpellList::iterator it = targetSpellStore.begin(); + std::advance(it, urand(0, targetSpellStore.size() - 1)); - Spell* spell = targetSpellStore[index].second; - Unit* target = targetSpellStore[index].first; + Spell* spell = (*it).second; + Unit* target = (*it).first; - targetSpellStore.erase(targetSpellStore.begin() + index); + targetSpellStore.erase(it); SpellCastTargets targets; targets.SetUnitTarget(target); - if (!me->HasInArc(float(M_PI), target)) - { - me->SetInFront(target); - if (target && target->GetTypeId() == TYPEID_PLAYER) - me->SendUpdateToPlayer(target->ToPlayer()); - - if (owner && owner->GetTypeId() == TYPEID_PLAYER) - me->SendUpdateToPlayer(owner->ToPlayer()); - } - spell->prepare(&targets); } @@ -254,9 +245,9 @@ void PetAI::UpdateAI(uint32 diff) } // Update speed as needed to prevent dropping too far behind and despawning - me->UpdateSpeed(MOVE_RUN, true); - me->UpdateSpeed(MOVE_WALK, true); - me->UpdateSpeed(MOVE_FLIGHT, true); + me->UpdateSpeed(MOVE_RUN); + me->UpdateSpeed(MOVE_WALK); + me->UpdateSpeed(MOVE_FLIGHT); } diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h index 9c33baa9a9f..3ad34047b01 100644 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -25,7 +25,7 @@ class Creature; class Spell; -class PetAI : public CreatureAI +class TC_GAME_API PetAI : public CreatureAI { public: diff --git a/src/server/game/AI/CoreAI/ReactorAI.h b/src/server/game/AI/CoreAI/ReactorAI.h index e5abaac2f00..d281ca11fdf 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.h +++ b/src/server/game/AI/CoreAI/ReactorAI.h @@ -23,7 +23,7 @@ class Unit; -class ReactorAI : public CreatureAI +class TC_GAME_API ReactorAI : public CreatureAI { public: diff --git a/src/server/game/AI/CoreAI/TotemAI.h b/src/server/game/AI/CoreAI/TotemAI.h index e1d1618037f..a0e796ed7e0 100644 --- a/src/server/game/AI/CoreAI/TotemAI.h +++ b/src/server/game/AI/CoreAI/TotemAI.h @@ -25,7 +25,7 @@ class Creature; class Totem; -class TotemAI : public CreatureAI +class TC_GAME_API TotemAI : public CreatureAI { public: diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 3aadf6e59a0..844bd45ffeb 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -310,5 +310,8 @@ bool NonTankTargetSelector::operator()(Unit const* target) const if (_playerOnly && target->GetTypeId() != TYPEID_PLAYER) return false; + if (HostileReference* currentVictim = _source->getThreatManager().getCurrentVictim()) + return target->GetGUID() != currentVictim->getUnitGuid(); + return target != _source->GetVictim(); } diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 766e747d998..344ccc06249 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -40,7 +40,7 @@ enum SelectAggroTarget }; // default predicate function to select target based on distance, player and/or aura criteria -struct DefaultTargetSelector : public std::unary_function<Unit*, bool> +struct TC_GAME_API DefaultTargetSelector : public std::unary_function<Unit*, bool> { const Unit* me; float m_dist; @@ -90,7 +90,7 @@ struct DefaultTargetSelector : public std::unary_function<Unit*, bool> // Target selector for spell casts checking range, auras and attributes /// @todo Add more checks from Spell::CheckCast -struct SpellTargetSelector : public std::unary_function<Unit*, bool> +struct TC_GAME_API SpellTargetSelector : public std::unary_function<Unit*, bool> { public: SpellTargetSelector(Unit* caster, uint32 spellId); @@ -104,18 +104,18 @@ struct SpellTargetSelector : public std::unary_function<Unit*, bool> // Very simple target selector, will just skip main target // NOTE: When passing to UnitAI::SelectTarget remember to use 0 as position for random selection // because tank will not be in the temporary list -struct NonTankTargetSelector : public std::unary_function<Unit*, bool> +struct TC_GAME_API NonTankTargetSelector : public std::unary_function<Unit*, bool> { public: - NonTankTargetSelector(Creature* source, bool playerOnly = true) : _source(source), _playerOnly(playerOnly) { } + NonTankTargetSelector(Unit* source, bool playerOnly = true) : _source(source), _playerOnly(playerOnly) { } bool operator()(Unit const* target) const; private: - Creature const* _source; + Unit* _source; bool _playerOnly; }; -class UnitAI +class TC_GAME_API UnitAI { protected: Unit* const me; diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index 352ae635878..5b76b583d24 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -283,7 +283,7 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/) int32 CreatureAI::VisualizeBoundary(uint32 duration, Unit* owner, bool fill) const { typedef std::pair<int32, int32> coordinate; - + if (!owner) return -1; @@ -293,7 +293,7 @@ int32 CreatureAI::VisualizeBoundary(uint32 duration, Unit* owner, bool fill) con std::queue<coordinate> Q; std::unordered_set<coordinate> alreadyChecked; std::unordered_set<coordinate> outOfBounds; - + Position startPosition = owner->GetPosition(); if (!CheckBoundary(&startPosition)) // fall back to creature position { diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index e009e2ed0b6..f175050e107 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -66,7 +66,7 @@ enum SCEquip }; typedef std::set<AreaBoundary const*> CreatureBoundary; -class CreatureAI : public UnitAI +class TC_GAME_API CreatureAI : public UnitAI { protected: Creature* const me; @@ -137,8 +137,8 @@ class CreatureAI : public UnitAI virtual void AttackedBy(Unit* /*attacker*/) { } virtual bool IsEscorted() const { return false; } - // Called when creature is spawned or respawned (for reseting variables) - virtual void JustRespawned() { Reset(); } + // Called when creature is spawned or respawned + virtual void JustRespawned() { } // Called at waypoint reached or point movement finished virtual void MovementInform(uint32 /*type*/, uint32 /*id*/) { } diff --git a/src/server/game/AI/CreatureAISelector.h b/src/server/game/AI/CreatureAISelector.h index 7c7bc705ade..0e3be1a8604 100644 --- a/src/server/game/AI/CreatureAISelector.h +++ b/src/server/game/AI/CreatureAISelector.h @@ -27,9 +27,9 @@ class GameObject; namespace FactorySelector { - CreatureAI* selectAI(Creature*); - MovementGenerator* selectMovementGenerator(Creature*); - GameObjectAI* SelectGameObjectAI(GameObject*); + TC_GAME_API CreatureAI* selectAI(Creature*); + TC_GAME_API MovementGenerator* selectMovementGenerator(Creature*); + TC_GAME_API GameObjectAI* SelectGameObjectAI(GameObject*); } #endif diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp index bafa1a0ecf7..680ecfb9414 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.cpp +++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp @@ -167,6 +167,8 @@ Unit* SimpleCharmedPlayerAI::SelectAttackTarget() const void SimpleCharmedPlayerAI::UpdateAI(const uint32 /*diff*/) { Creature* charmer = me->GetCharmer() ? me->GetCharmer()->ToCreature() : nullptr; + if (!charmer) + return; //kill self if charm aura has infinite duration if (charmer->IsInEvadeMode()) diff --git a/src/server/game/AI/PlayerAI/PlayerAI.h b/src/server/game/AI/PlayerAI/PlayerAI.h index 1820bcf11c0..b717816f9a3 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.h +++ b/src/server/game/AI/PlayerAI/PlayerAI.h @@ -22,13 +22,13 @@ #include "Player.h" #include "Creature.h" -class PlayerAI : public UnitAI +class TC_GAME_API PlayerAI : public UnitAI { public: explicit PlayerAI(Player* player) : UnitAI(static_cast<Unit*>(player)), me(player), _isSelfHealer(PlayerAI::IsPlayerHealer(player)), _isSelfRangedAttacker(PlayerAI::IsPlayerRangedAttacker(player)) { } void OnCharmed(bool /*apply*/) override { } // charm AI application for players is handled by Unit::SetCharmedBy / Unit::RemoveCharmedBy - + // helper functions to determine player info static bool IsPlayerHealer(Player const* who); bool IsHealer(Player const* who = nullptr) const { return (!who || who == me) ? _isSelfHealer : IsPlayerHealer(who); } diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 2fc87347364..6f04a852b61 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -566,7 +566,7 @@ void BossAI::_DespawnAtEvade(uint32 delayToRespawn) me->SetCorpseDelay(corpseDelay); me->SetRespawnDelay(respawnDelay); - if(instance) + if (instance) instance->SetBossState(_bossId, FAIL); } @@ -628,27 +628,27 @@ void WorldBossAI::UpdateAI(uint32 diff) } // SD2 grid searchers. -Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive /*= true*/) +TC_GAME_API Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive /*= true*/) { return source->FindNearestCreature(entry, maxSearchRange, alive); } -GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange) +TC_GAME_API GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange) { return source->FindNearestGameObject(entry, maxSearchRange); } -void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange) +TC_GAME_API void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange) { source->GetCreatureListWithEntryInGrid(list, entry, maxSearchRange); } -void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange) +TC_GAME_API void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange) { source->GetGameObjectListWithEntryInGrid(list, entry, maxSearchRange); } -void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange) +TC_GAME_API void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange) { source->GetPlayerListInGrid(list, maxSearchRange); } diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 5452a033a17..42befa26a23 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -38,7 +38,7 @@ T* EnsureAI(U* ai) class InstanceScript; -class SummonList +class TC_GAME_API SummonList { public: typedef GuidList StorageType; @@ -123,7 +123,7 @@ private: StorageType storage_; }; -class EntryCheckPredicate +class TC_GAME_API EntryCheckPredicate { public: EntryCheckPredicate(uint32 entry) : _entry(entry) { } @@ -133,13 +133,13 @@ class EntryCheckPredicate uint32 _entry; }; -class DummyEntryCheckPredicate +class TC_GAME_API DummyEntryCheckPredicate { public: bool operator()(ObjectGuid) { return true; } }; -struct ScriptedAI : public CreatureAI +struct TC_GAME_API ScriptedAI : public CreatureAI { explicit ScriptedAI(Creature* creature); virtual ~ScriptedAI() { } @@ -334,7 +334,7 @@ struct ScriptedAI : public CreatureAI bool _isHeroic; }; -class BossAI : public ScriptedAI +class TC_GAME_API BossAI : public ScriptedAI { public: BossAI(Creature* creature, uint32 bossId); @@ -379,7 +379,7 @@ class BossAI : public ScriptedAI uint32 const _bossId; }; -class WorldBossAI : public ScriptedAI +class TC_GAME_API WorldBossAI : public ScriptedAI { public: WorldBossAI(Creature* creature); @@ -410,10 +410,10 @@ class WorldBossAI : public ScriptedAI }; // SD2 grid searchers. -Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive = true); -GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange); -void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange); -void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange); -void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange); +TC_GAME_API Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive = true); +TC_GAME_API GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange); +TC_GAME_API void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange); +TC_GAME_API void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange); +TC_GAME_API void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange); #endif // SCRIPTEDCREATURE_H_ diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h index 673f3e671a0..37a1464d812 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h @@ -49,7 +49,7 @@ enum eEscortState STATE_ESCORT_PAUSED = 0x004 //will not proceed with waypoints before state is removed }; -struct npc_escortAI : public ScriptedAI +struct TC_GAME_API npc_escortAI : public ScriptedAI { public: explicit npc_escortAI(Creature* creature); diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h index d1c976b45c8..e17fb7c8507 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h @@ -32,7 +32,7 @@ enum eFollowState STATE_FOLLOW_POSTEVENT = 0x020 //can be set at complete and allow post event to run }; -class FollowerAI : public ScriptedAI +class TC_GAME_API FollowerAI : public ScriptedAI { public: explicit FollowerAI(Creature* creature); diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 02c057247f6..aa7c9ace0b3 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -42,7 +42,7 @@ enum SmartEscortVars SMART_MAX_AID_DIST = SMART_ESCORT_MAX_PLAYER_DIST / 2 }; -class SmartAI : public CreatureAI +class TC_GAME_API SmartAI : public CreatureAI { public: ~SmartAI(){ } @@ -230,7 +230,7 @@ class SmartAI : public CreatureAI bool mJustReset; }; -class SmartGameObjectAI : public GameObjectAI +class TC_GAME_API SmartGameObjectAI : public GameObjectAI { public: SmartGameObjectAI(GameObject* g) : GameObjectAI(g) { } @@ -257,4 +257,8 @@ class SmartGameObjectAI : public GameObjectAI private: SmartScript mScript; }; + +/// Registers scripts required by the SAI scripting system +void AddSC_SmartScripts(); + #endif diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index c08d1508774..9db36c76bb4 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -489,7 +489,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u // unless target is outside spell range, out of mana, or LOS. bool _allowMove = false; - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(e.action.cast.spell); int32 mana = me->GetPower(POWER_MANA); if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) || @@ -2330,6 +2330,21 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; } } + case SMART_ACTION_SET_CORPSE_DELAY: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) + break; + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + { + if (IsCreature(*itr)) + (*itr)->ToCreature()->SetCorpseDelay(e.action.corpseDelay.timer); + } + + delete targets; + break; + } default: TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Unhandled Action type %u", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); break; diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index e8b89a813b5..a28f2234860 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -28,7 +28,7 @@ #include "SmartScriptMgr.h" //#include "SmartAI.h" -class SmartScript +class TC_GAME_API SmartScript { public: SmartScript(); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index ef3357fa6ed..86aaf45af88 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -27,6 +27,12 @@ #include "SmartScriptMgr.h" +SmartWaypointMgr* SmartWaypointMgr::instance() +{ + static SmartWaypointMgr instance; + return &instance; +} + void SmartWaypointMgr::LoadFromDB() { uint32 oldMSTime = getMSTime(); @@ -98,6 +104,12 @@ SmartWaypointMgr::~SmartWaypointMgr() } } +SmartAIMgr* SmartAIMgr::instance() +{ + static SmartAIMgr instance; + return &instance; +} + void SmartAIMgr::LoadSmartAIFromDB() { LoadHelperStores(); @@ -847,7 +859,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) if (!IsSpellValid(e, e.action.cast.spell)) return false; - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(e.action.cast.spell); for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) { if (spellInfo->Effects[j].IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellInfo->Effects[j].IsEffect(SPELL_EFFECT_KILL_CREDIT2)) @@ -1214,6 +1226,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_REMOVE_GO_FLAG: case SMART_ACTION_SUMMON_CREATURE_GROUP: case SMART_ACTION_RISE_UP: + case SMART_ACTION_SET_CORPSE_DELAY: break; default: TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index c0ea648462d..3105f087bf7 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -551,8 +551,9 @@ enum SMART_ACTION SMART_ACTION_START_CLOSEST_WAYPOINT = 113, // wp1, wp2, wp3, wp4, wp5, wp6, wp7 SMART_ACTION_RISE_UP = 114, // distance SMART_ACTION_RANDOM_SOUND = 115, // soundId1, soundId2, soundId3, soundId4, soundId5, onlySelf + SMART_ACTION_SET_CORPSE_DELAY = 116, // timer - SMART_ACTION_END = 116 + SMART_ACTION_END = 117 }; struct SmartAction @@ -1034,6 +1035,11 @@ struct SmartAction uint32 onlySelf; } randomSound; + struct + { + uint32 timer; + } corpseDelay; + //! Note for any new future actions //! All parameters must have type uint32 @@ -1434,18 +1440,14 @@ public: }; typedef std::unordered_map<uint32, ObjectGuidList*> ObjectListMap; -class SmartWaypointMgr +class TC_GAME_API SmartWaypointMgr { private: SmartWaypointMgr() { } ~SmartWaypointMgr(); public: - static SmartWaypointMgr* instance() - { - static SmartWaypointMgr instance; - return &instance; - } + static SmartWaypointMgr* instance(); void LoadFromDB(); @@ -1470,18 +1472,14 @@ typedef std::unordered_map<int32, SmartAIEventList> SmartAIEventMap; typedef std::map<uint32 /*entry*/, std::pair<uint32 /*spellId*/, SpellEffIndex /*effIndex*/> > CacheSpellContainer; typedef std::pair<CacheSpellContainer::const_iterator, CacheSpellContainer::const_iterator> CacheSpellContainerBounds; -class SmartAIMgr +class TC_GAME_API SmartAIMgr { private: SmartAIMgr() { } ~SmartAIMgr() { } public: - static SmartAIMgr* instance() - { - static SmartAIMgr instance; - return &instance; - } + static SmartAIMgr* instance(); void LoadSmartAIFromDB(); diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 737e9f37195..1b93d072fb6 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -33,17 +33,23 @@ AccountMgr::~AccountMgr() ClearRBAC(); } -AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email = "") +AccountMgr* AccountMgr::instance() +{ + static AccountMgr instance; + return &instance; +} + +AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email /*= ""*/) { if (utf8length(username) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; // username's too long + return AccountOpResult::AOR_NAME_TOO_LONG; // username's too long - normalizeString(username); - normalizeString(password); - normalizeString(email); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + Utf8ToUpperOnlyLatin(email); if (GetId(username)) - return AOR_NAME_ALREADY_EXIST; // username does already exist + return AccountOpResult::AOR_NAME_ALREADY_EXIST; // username does already exist PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT); @@ -57,7 +63,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT); LoginDatabase.Execute(stmt); - return AOR_OK; // everything's fine + return AccountOpResult::AOR_OK; // everything's fine } AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) @@ -68,7 +74,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) - return AOR_NAME_NOT_EXIST; + return AccountOpResult::AOR_NAME_NOT_EXIST; // Obtain accounts characters stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); @@ -128,7 +134,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) LoginDatabase.CommitTransaction(trans); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) @@ -139,16 +145,16 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) - return AOR_NAME_NOT_EXIST; + return AccountOpResult::AOR_NAME_NOT_EXIST; if (utf8length(newUsername) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; + return AccountOpResult::AOR_NAME_TOO_LONG; - if (utf8length(newPassword) > MAX_ACCOUNT_STR) - return AOR_PASS_TOO_LONG; + if (utf8length(newPassword) > MAX_PASS_STR) + return AccountOpResult::AOR_PASS_TOO_LONG; - normalizeString(newUsername); - normalizeString(newPassword); + Utf8ToUpperOnlyLatin(newUsername); + Utf8ToUpperOnlyLatin(newPassword); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME); @@ -158,7 +164,7 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPassword) @@ -168,17 +174,17 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass if (!GetName(accountId, username)) { sScriptMgr->OnFailedPasswordChange(accountId); - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist } - if (utf8length(newPassword) > MAX_ACCOUNT_STR) + if (utf8length(newPassword) > MAX_PASS_STR) { sScriptMgr->OnFailedPasswordChange(accountId); - return AOR_PASS_TOO_LONG; + return AccountOpResult::AOR_PASS_TOO_LONG; } - normalizeString(username); - normalizeString(newPassword); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newPassword); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD); @@ -196,7 +202,7 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass LoginDatabase.Execute(stmt); sScriptMgr->OnPasswordChange(accountId); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) @@ -206,17 +212,17 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) if (!GetName(accountId, username)) { sScriptMgr->OnFailedEmailChange(accountId); - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist } if (utf8length(newEmail) > MAX_EMAIL_STR) { sScriptMgr->OnFailedEmailChange(accountId); - return AOR_EMAIL_TOO_LONG; + return AccountOpResult::AOR_EMAIL_TOO_LONG; } - normalizeString(username); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newEmail); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL); @@ -226,7 +232,7 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) LoginDatabase.Execute(stmt); sScriptMgr->OnEmailChange(accountId); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmail) @@ -236,17 +242,17 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai if (!GetName(accountId, username)) { sScriptMgr->OnFailedEmailChange(accountId); - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist } if (utf8length(newEmail) > MAX_EMAIL_STR) { sScriptMgr->OnFailedEmailChange(accountId); - return AOR_EMAIL_TOO_LONG; + return AccountOpResult::AOR_EMAIL_TOO_LONG; } - normalizeString(username); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newEmail); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_REG_EMAIL); @@ -256,7 +262,7 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai LoginDatabase.Execute(stmt); sScriptMgr->OnEmailChange(accountId); - return AOR_OK; + return AccountOpResult::AOR_OK; } uint32 AccountMgr::GetId(std::string const& username) @@ -324,8 +330,8 @@ bool AccountMgr::CheckPassword(uint32 accountId, std::string password) if (!GetName(accountId, username)) return false; - normalizeString(username); - normalizeString(password); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD); stmt->setUInt32(0, accountId); @@ -343,8 +349,8 @@ bool AccountMgr::CheckEmail(uint32 accountId, std::string newEmail) if (!GetEmail(accountId, oldEmail)) return false; - normalizeString(oldEmail); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(oldEmail); + Utf8ToUpperOnlyLatin(newEmail); if (strcmp(oldEmail.c_str(), newEmail.c_str()) == 0) return true; @@ -362,19 +368,6 @@ uint32 AccountMgr::GetCharactersCount(uint32 accountId) return (result) ? (*result)[0].GetUInt64() : 0; } -bool AccountMgr::normalizeString(std::string& utf8String) -{ - wchar_t buffer[MAX_ACCOUNT_STR+1]; - - size_t maxLength = MAX_ACCOUNT_STR; - if (!Utf8toWStr(utf8String, buffer, maxLength)) - return false; - - std::transform(&buffer[0], buffer+maxLength, &buffer[0], wcharToUpperOnlyLatin); - - return WStrToUtf8(buffer, maxLength, utf8String); -} - std::string AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) { SHA1Hash sha; @@ -462,7 +455,7 @@ void AccountMgr::LoadRBAC() while (result->NextRow()); TC_LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading default permissions"); - result = LoginDatabase.PQuery("SELECT secId, permissionId FROM rbac_default_permissions WHERE (realmId = %u OR realmId = -1) ORDER BY secId ASC", realmID); + result = LoginDatabase.PQuery("SELECT secId, permissionId FROM rbac_default_permissions WHERE (realmId = %u OR realmId = -1) ORDER BY secId ASC", realm.Id.Realm); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 default permission definitions. DB table `rbac_default_permissions` is empty."); diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index 40ccba1f8e5..f3bb1abe64e 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -21,7 +21,7 @@ #include "RBAC.h" -enum AccountOpResult +enum class AccountOpResult : uint8 { AOR_OK, AOR_NAME_TOO_LONG, @@ -39,6 +39,7 @@ enum PasswordChangeSecurity PW_RBAC }; +#define MAX_PASS_STR 16 #define MAX_ACCOUNT_STR 16 #define MAX_EMAIL_STR 64 @@ -48,20 +49,16 @@ typedef std::map<uint32, rbac::RBACPermission*> RBACPermissionsContainer; typedef std::map<uint8, rbac::RBACPermissionContainer> RBACDefaultPermissionsContainer; } -class AccountMgr +class TC_GAME_API AccountMgr { private: AccountMgr(); ~AccountMgr(); public: - static AccountMgr* instance() - { - static AccountMgr instance; - return &instance; - } + static AccountMgr* instance(); - AccountOpResult CreateAccount(std::string username, std::string password, std::string email); + AccountOpResult CreateAccount(std::string username, std::string password, std::string email = ""); static AccountOpResult DeleteAccount(uint32 accountId); static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); @@ -78,7 +75,6 @@ class AccountMgr static uint32 GetCharactersCount(uint32 accountId); static std::string CalculateShaPassHash(std::string const& name, std::string const& password); - static bool normalizeString(std::string& utf8String); static bool IsPlayerAccount(uint32 gmlevel); static bool IsAdminAccount(uint32 gmlevel); static bool IsConsoleAccount(uint32 gmlevel); diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp index a8720b66df4..34d7687452c 100644 --- a/src/server/game/Accounts/RBAC.cpp +++ b/src/server/game/Accounts/RBAC.cpp @@ -236,10 +236,10 @@ void RBACData::AddPermissions(RBACPermissionContainer const& permsFrom, RBACPerm permsTo.insert(*itr); } -void RBACData::RemovePermissions(RBACPermissionContainer const& permsFrom, RBACPermissionContainer& permsTo) +void RBACData::RemovePermissions(RBACPermissionContainer& permsFrom, RBACPermissionContainer const& permsToRemove) { - for (RBACPermissionContainer::const_iterator itr = permsFrom.begin(); itr != permsFrom.end(); ++itr) - permsTo.erase(*itr); + for (RBACPermissionContainer::const_iterator itr = permsToRemove.begin(); itr != permsToRemove.end(); ++itr) + permsFrom.erase(*itr); } void RBACData::ExpandPermissions(RBACPermissionContainer& permissions) diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 4ebd3ae7042..5f883175157 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -670,8 +670,8 @@ enum RBACPermissions RBAC_PERM_COMMAND_WP_UNLOAD = 772, RBAC_PERM_COMMAND_WP_RELOAD = 773, RBAC_PERM_COMMAND_WP_SHOW = 774, - RBAC_PERM_COMMAND_MODIFY_CURRENCY = 775, // only 4.3.4 - RBAC_PERM_COMMAND_DEBUG_PHASE = 776, // only 4.3.4 + RBAC_PERM_COMMAND_MODIFY_CURRENCY = 775, // only 6.x + RBAC_PERM_COMMAND_DEBUG_PHASE = 776, // only 6.x RBAC_PERM_COMMAND_MAILBOX = 777, RBAC_PERM_COMMAND_AHBOT = 778, RBAC_PERM_COMMAND_AHBOT_ITEMS = 779, @@ -714,7 +714,7 @@ enum RBACCommandResult typedef std::set<uint32> RBACPermissionContainer; -class RBACPermission +class TC_GAME_API RBACPermission { public: RBACPermission(uint32 id = 0, std::string const& name = ""): @@ -749,7 +749,7 @@ class RBACPermission * - Granted permissions: through linked permissions and directly assigned * - Denied permissions: through linked permissions and directly assigned */ -class RBACData +class TC_GAME_API RBACData { public: RBACData(uint32 id, std::string const& name, int32 realmId, uint8 secLevel = 255): @@ -938,8 +938,8 @@ class RBACData /// Adds a list of permissions to another list void AddPermissions(RBACPermissionContainer const& permsFrom, RBACPermissionContainer& permsTo); - /// Removes a list of permissions to another list - void RemovePermissions(RBACPermissionContainer const& permsFrom, RBACPermissionContainer& permsTo); + /// Removes a list of permissions from another list + void RemovePermissions(RBACPermissionContainer& permsFrom, RBACPermissionContainer const& permsToRemove); /** * @name ExpandPermissions diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 40cb643bbb5..87f5ff6ce5c 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -1533,7 +1533,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) //! Since no common attributes were found, (not even in titleRewardFlags field) //! we explicitly check by ID. Maybe in the future we could move the achievement_reward //! condition fields to the condition system. - if (uint32 titleId = reward->titleId[achievement->ID == 1793 ? GetPlayer()->GetByteValue(PLAYER_BYTES_3, 0) : (GetPlayer()->GetTeam() == ALLIANCE ? 0 : 1)]) + if (uint32 titleId = reward->titleId[achievement->ID == 1793 ? GetPlayer()->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER) : (GetPlayer()->GetTeam() == ALLIANCE ? 0 : 1)]) if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId)) GetPlayer()->SetTitle(titleEntry); @@ -2246,6 +2246,12 @@ char const* AchievementGlobalMgr::GetCriteriaTypeString(AchievementCriteriaTypes return "MISSING_TYPE"; } +AchievementGlobalMgr* AchievementGlobalMgr::instance() +{ + static AchievementGlobalMgr instance; + return &instance; +} + //========================================================== void AchievementGlobalMgr::LoadAchievementCriteriaList() { diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index cc3fd55bc3a..c4ac5f0e808 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -212,7 +212,7 @@ struct AchievementCriteriaData bool Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscValue1 = 0) const; }; -struct AchievementCriteriaDataSet +struct TC_GAME_API AchievementCriteriaDataSet { AchievementCriteriaDataSet() : criteria_id(0) { } typedef std::vector<AchievementCriteriaData> Storage; @@ -262,7 +262,7 @@ enum ProgressType PROGRESS_HIGHEST }; -class AchievementMgr +class TC_GAME_API AchievementMgr { public: AchievementMgr(Player* player); @@ -306,7 +306,7 @@ class AchievementMgr TimedAchievementMap m_timedAchievements; // Criteria id/time left in MS }; -class AchievementGlobalMgr +class TC_GAME_API AchievementGlobalMgr { AchievementGlobalMgr() { } ~AchievementGlobalMgr() { } @@ -315,11 +315,7 @@ class AchievementGlobalMgr static char const* GetCriteriaTypeString(AchievementCriteriaTypes type); static char const* GetCriteriaTypeString(uint32 type); - static AchievementGlobalMgr* instance() - { - static AchievementGlobalMgr instance; - return &instance; - } + static AchievementGlobalMgr* instance(); AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type) const { diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 035d9af4369..d9f5388e3ce 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -44,6 +44,12 @@ AuctionHouseMgr::~AuctionHouseMgr() delete itr->second; } +AuctionHouseMgr* AuctionHouseMgr::instance() +{ + static AuctionHouseMgr instance; + return &instance; +} + AuctionHouseObject* AuctionHouseMgr::GetAuctionsMap(uint32 factionTemplateId) { if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) @@ -130,7 +136,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& else { bidderAccId = sObjectMgr->GetPlayerAccountIdByGUID(bidderGuid); - logGmTrade = AccountMgr::HasPermission(bidderAccId, rbac::RBAC_PERM_LOG_GM_TRADE, realmID); + logGmTrade = AccountMgr::HasPermission(bidderAccId, rbac::RBAC_PERM_LOG_GM_TRADE, realm.Id.Realm); if (logGmTrade && !sObjectMgr->GetPlayerNameByGUID(bidderGuid, bidderName)) bidderName = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h index fe4b9ed07de..42322929a30 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.h +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h @@ -70,7 +70,7 @@ enum AuctionHouses AUCTIONHOUSE_NEUTRAL = 7 }; -struct AuctionEntry +struct TC_GAME_API AuctionEntry { uint32 Id; uint8 houseId; @@ -101,7 +101,7 @@ struct AuctionEntry }; //this class is used as auctionhouse instance -class AuctionHouseObject +class TC_GAME_API AuctionHouseObject { public: ~AuctionHouseObject() @@ -146,18 +146,14 @@ class AuctionHouseObject }; -class AuctionHouseMgr +class TC_GAME_API AuctionHouseMgr { private: AuctionHouseMgr(); ~AuctionHouseMgr(); public: - static AuctionHouseMgr* instance() - { - static AuctionHouseMgr instance; - return &instance; - } + static AuctionHouseMgr* instance(); typedef std::unordered_map<ObjectGuid::LowType, Item*> ItemMap; typedef std::vector<AuctionEntry*> PlayerAuctions; diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp index e1ba9a64191..74f0aaf428a 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp @@ -24,6 +24,12 @@ #include "AuctionHouseBotBuyer.h" #include "AuctionHouseBotSeller.h" +AuctionBotConfig* AuctionBotConfig::instance() +{ + static AuctionBotConfig instance; + return &instance; +} + bool AuctionBotConfig::Initialize() { GetConfigFromFile(); @@ -426,6 +432,12 @@ void AuctionHouseBot::Rebuild(bool all) } } +AuctionHouseBot* AuctionHouseBot::instance() +{ + static AuctionHouseBot instance; + return &instance; +} + void AuctionHouseBot::Update() { // nothing do... diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.h b/src/server/game/AuctionHouseBot/AuctionHouseBot.h index 87f76a17dcc..1a438e01cdb 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBot.h +++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.h @@ -196,7 +196,7 @@ enum AuctionBotConfigFloatValues }; // All basic config data used by other AHBot classes for self-configure. -class AuctionBotConfig +class TC_GAME_API AuctionBotConfig { private: AuctionBotConfig(): _itemsPerCycleBoost(1000), _itemsPerCycleNormal(20) {} @@ -205,11 +205,7 @@ private: AuctionBotConfig& operator=(const AuctionBotConfig&); public: - static AuctionBotConfig* instance() - { - static AuctionBotConfig instance; - return &instance; - } + static AuctionBotConfig* instance(); bool Initialize(); const std::string& GetAHBotIncludes() const { return _AHBotIncludes; } @@ -274,7 +270,7 @@ typedef AuctionHouseBotStatusInfoPerType AuctionHouseBotStatusInfo[MAX_AUCTION_H // This class handle both Selling and Buying method // (holder of AuctionBotBuyer and AuctionBotSeller objects) -class AuctionHouseBot +class TC_GAME_API AuctionHouseBot { private: AuctionHouseBot(); @@ -283,11 +279,7 @@ private: AuctionHouseBot& operator=(const AuctionHouseBot&); public: - static AuctionHouseBot* instance() - { - static AuctionHouseBot instance; - return &instance; - } + static AuctionHouseBot* instance(); void Update(); void Initialize(); diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h index e1b6b425c48..979f73c0099 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h @@ -67,7 +67,7 @@ private: // This class handle all Buyer method // (holder of AuctionBotConfig for each auction house type) -class AuctionBotBuyer : public AuctionBotAgent +class TC_GAME_API AuctionBotBuyer : public AuctionBotAgent { public: AuctionBotBuyer(); diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp index 5acb56b5173..fd105c5b25f 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp @@ -582,13 +582,13 @@ void AuctionBotSeller::LoadSellerValues(SellerConfiguration& config) break; } - config.SetPriceRatioPerQuality(AUCTION_QUALITY_GRAY, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GRAY_PRICE_RATIO) / 100); - config.SetPriceRatioPerQuality(AUCTION_QUALITY_WHITE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_WHITE_PRICE_RATIO) / 100); - config.SetPriceRatioPerQuality(AUCTION_QUALITY_GREEN, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GREEN_PRICE_RATIO) / 100); - config.SetPriceRatioPerQuality(AUCTION_QUALITY_BLUE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_BLUE_PRICE_RATIO) / 100); - config.SetPriceRatioPerQuality(AUCTION_QUALITY_PURPLE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_PURPLE_PRICE_RATIO) / 100); - config.SetPriceRatioPerQuality(AUCTION_QUALITY_ORANGE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_ORANGE_PRICE_RATIO) / 100); - config.SetPriceRatioPerQuality(AUCTION_QUALITY_YELLOW, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_YELLOW_PRICE_RATIO) / 100); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_GRAY, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GRAY_PRICE_RATIO)); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_WHITE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_WHITE_PRICE_RATIO)); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_GREEN, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GREEN_PRICE_RATIO)); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_BLUE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_BLUE_PRICE_RATIO)); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_PURPLE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_PURPLE_PRICE_RATIO)); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_ORANGE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_ORANGE_PRICE_RATIO)); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_YELLOW, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_YELLOW_PRICE_RATIO)); config.SetPriceRatioPerClass(ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_PRICE_RATIO)); config.SetPriceRatioPerClass(ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_PRICE_RATIO)); @@ -701,10 +701,10 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf { uint32 classRatio = config.GetPriceRatioPerClass(ItemClass(itemProto->Class)); uint32 qualityRatio = config.GetPriceRatioPerQuality(AuctionQuality(itemProto->Quality)); - uint32 priceRatio = (classRatio * qualityRatio) / 100; + float priceRatio = (classRatio * qualityRatio) / 10000.0f; - uint32 buyPrice = itemProto->BuyPrice; - uint32 sellPrice = itemProto->SellPrice; + float buyPrice = itemProto->BuyPrice; + float sellPrice = itemProto->SellPrice; if (buyPrice == 0) { @@ -712,11 +712,11 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf buyPrice = sellPrice * GetSellModifier(itemProto); else { - uint32 divisor = ((itemProto->Class == 2 || itemProto->Class == 4) ? 284 : 80); - uint32 tempLevel = (itemProto->ItemLevel == 0 ? 1 : itemProto->ItemLevel); - uint32 tempQuality = (itemProto->Quality == 0 ? 1 : itemProto->Quality); + float divisor = ((itemProto->Class == ITEM_CLASS_WEAPON || itemProto->Class == ITEM_CLASS_ARMOR) ? 284.0f : 80.0f); + float tempLevel = (itemProto->ItemLevel == 0 ? 1.0f : itemProto->ItemLevel); + float tempQuality = (itemProto->Quality == 0 ? 1.0f : itemProto->Quality); - buyPrice = tempLevel * tempQuality * GetBuyModifier(itemProto)* tempLevel / divisor; + buyPrice = tempLevel * tempQuality * static_cast<float>(GetBuyModifier(itemProto))* tempLevel / divisor; } } @@ -725,15 +725,16 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_SELLER)) buyPrice = sellPrice; - - uint32 basePrice = (buyPrice * stackCount * priceRatio) / (itemProto->Class == 6 ? 200 : itemProto->BuyCount) / 100; - uint32 range = basePrice * 0.04; - - buyp = urand(basePrice - range, basePrice + range) + 1; - - basePrice = buyp * .5; + + float basePriceFloat = (buyPrice * stackCount * priceRatio) / (itemProto->Class == 6 ? 200.0f : static_cast<float>(itemProto->BuyCount)) / 100.0f; + float range = basePriceFloat * 0.04f; + + buyp = static_cast<uint32>(frand(basePriceFloat - range, basePriceFloat + range) + 0.5f); + if (buyp == 0) + buyp = 1; + uint32 basePrice = buyp * .5; range = buyp * .4; - bidp = urand(basePrice - range, basePrice + range) + 1; + bidp = urand(static_cast<uint32>(basePrice - range + 0.5f), static_cast<uint32>(basePrice + range + 0.5f)) + 1; } // Determines the stack size to use for the item diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h index dd82b0f3dda..563c2cda04a 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h @@ -115,7 +115,7 @@ private: // This class handle all Selling method // (holder of AHB_Seller_Config data for each auction house type) -class AuctionBotSeller : public AuctionBotAgent +class TC_GAME_API AuctionBotSeller : public AuctionBotAgent { public: typedef std::vector<uint32> ItemPool; diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index ade3e8c9699..6968e31c7bd 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -67,7 +67,7 @@ class BfGraveyard; typedef std::vector<BfGraveyard*> GraveyardVect; typedef std::map<ObjectGuid, time_t> PlayerTimerMap; -class BfCapturePoint +class TC_GAME_API BfCapturePoint { public: BfCapturePoint(Battlefield* bf); @@ -135,7 +135,7 @@ class BfCapturePoint ObjectGuid m_capturePointGUID; }; -class BfGraveyard +class TC_GAME_API BfGraveyard { public: BfGraveyard(Battlefield* Bf); @@ -182,7 +182,7 @@ class BfGraveyard Battlefield* m_Bf; }; -class Battlefield : public ZoneScript +class TC_GAME_API Battlefield : public ZoneScript { friend class BattlefieldMgr; diff --git a/src/server/game/Battlefield/BattlefieldMgr.cpp b/src/server/game/Battlefield/BattlefieldMgr.cpp index e4c10d64682..1df87fe1d6f 100644 --- a/src/server/game/Battlefield/BattlefieldMgr.cpp +++ b/src/server/game/Battlefield/BattlefieldMgr.cpp @@ -32,6 +32,12 @@ BattlefieldMgr::~BattlefieldMgr() _battlefieldMap.clear(); } +BattlefieldMgr* BattlefieldMgr::instance() +{ + static BattlefieldMgr instance; + return &instance; +} + void BattlefieldMgr::InitBattlefield() { Battlefield* wg = new BattlefieldWG(); diff --git a/src/server/game/Battlefield/BattlefieldMgr.h b/src/server/game/Battlefield/BattlefieldMgr.h index fabb33ae359..2f2af12927e 100644 --- a/src/server/game/Battlefield/BattlefieldMgr.h +++ b/src/server/game/Battlefield/BattlefieldMgr.h @@ -24,14 +24,10 @@ class Player; class ZoneScript; // class to handle player enter / leave / areatrigger / GO use events -class BattlefieldMgr +class TC_GAME_API BattlefieldMgr { public: - static BattlefieldMgr* instance() - { - static BattlefieldMgr instance; - return &instance; - } + static BattlefieldMgr* instance(); // create battlefield events void InitBattlefield(); diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h index e5cc392cef3..52789d38d8e 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.h +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -266,7 +266,7 @@ class WintergraspCapturePoint : public BfCapturePoint * WinterGrasp Battlefield * * ######################### */ -class BattlefieldWG : public Battlefield +class TC_GAME_API BattlefieldWG : public Battlefield { public: ~BattlefieldWG(); @@ -1098,7 +1098,7 @@ StaticWintergraspWorkshopInfo const WorkshopData[WG_MAX_WORKSHOP] = // ******************************************************************** // Structure for different buildings that can be destroyed during battle -struct BfWGGameObjectBuilding +struct TC_GAME_API BfWGGameObjectBuilding { private: // WG object @@ -1150,7 +1150,7 @@ public: }; // Structure for the 6 workshop -struct WintergraspWorkshop +struct TC_GAME_API WintergraspWorkshop { private: BattlefieldWG* _wg; // Pointer to wintergrasp diff --git a/src/server/game/Battlegrounds/Arena.h b/src/server/game/Battlegrounds/Arena.h index 863f1fc8c6f..1fe99f1f414 100644 --- a/src/server/game/Battlegrounds/Arena.h +++ b/src/server/game/Battlegrounds/Arena.h @@ -36,7 +36,7 @@ enum ArenaWorldStates ARENA_WORLD_STATE_ALIVE_PLAYERS_GOLD = 3601 }; -class Arena : public Battleground +class TC_GAME_API Arena : public Battleground { protected: Arena(); diff --git a/src/server/game/Battlegrounds/ArenaScore.h b/src/server/game/Battlegrounds/ArenaScore.h index c2d9d18c00b..9427a108565 100644 --- a/src/server/game/Battlegrounds/ArenaScore.h +++ b/src/server/game/Battlegrounds/ArenaScore.h @@ -21,7 +21,7 @@ #include "BattlegroundScore.h" #include "SharedDefines.h" -struct ArenaScore : public BattlegroundScore +struct TC_GAME_API ArenaScore : public BattlegroundScore { friend class Arena; @@ -56,7 +56,7 @@ struct ArenaScore : public BattlegroundScore uint8 TeamId; // BattlegroundTeamId }; -struct ArenaTeamScore +struct TC_GAME_API ArenaTeamScore { friend class Arena; friend class Battleground; diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h index f27c3761bde..7e9f490bff9 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.h +++ b/src/server/game/Battlegrounds/ArenaTeam.h @@ -85,7 +85,7 @@ enum ArenaTeamTypes ARENA_TEAM_5v5 = 5 }; -struct ArenaTeamMember +struct TC_GAME_API ArenaTeamMember { ObjectGuid Guid; std::string Name; @@ -113,7 +113,7 @@ struct ArenaTeamStats #define MAX_ARENA_SLOT 3 // 0..2 slots -class ArenaTeam +class TC_GAME_API ArenaTeam { public: ArenaTeam(); diff --git a/src/server/game/Battlegrounds/ArenaTeamMgr.cpp b/src/server/game/Battlegrounds/ArenaTeamMgr.cpp index b838131fd03..5dd0b6f29c3 100644 --- a/src/server/game/Battlegrounds/ArenaTeamMgr.cpp +++ b/src/server/game/Battlegrounds/ArenaTeamMgr.cpp @@ -35,6 +35,12 @@ ArenaTeamMgr::~ArenaTeamMgr() delete itr->second; } +ArenaTeamMgr* ArenaTeamMgr::instance() +{ + static ArenaTeamMgr instance; + return &instance; +} + // Arena teams collection ArenaTeam* ArenaTeamMgr::GetArenaTeamById(uint32 arenaTeamId) const { diff --git a/src/server/game/Battlegrounds/ArenaTeamMgr.h b/src/server/game/Battlegrounds/ArenaTeamMgr.h index 432a4ff598f..7f6800bd71b 100644 --- a/src/server/game/Battlegrounds/ArenaTeamMgr.h +++ b/src/server/game/Battlegrounds/ArenaTeamMgr.h @@ -20,18 +20,14 @@ #include "ArenaTeam.h" -class ArenaTeamMgr +class TC_GAME_API ArenaTeamMgr { private: ArenaTeamMgr(); ~ArenaTeamMgr(); public: - static ArenaTeamMgr* instance() - { - static ArenaTeamMgr instance; - return &instance; - } + static ArenaTeamMgr* instance(); typedef std::unordered_map<uint32, ArenaTeam*> ArenaTeamContainer; diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 03f138a5a8b..bb6ae360536 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -221,7 +221,7 @@ This class is used to: 3. some certain cases, same for all battlegrounds 4. It has properties same for all battlegrounds */ -class Battleground +class TC_GAME_API Battleground { public: Battleground(); diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index 8942ca7a18e..683547ef3fc 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -76,6 +76,12 @@ void BattlegroundMgr::DeleteAllBattlegrounds() bgDataStore.clear(); } +BattlegroundMgr* BattlegroundMgr::instance() +{ + static BattlegroundMgr instance; + return &instance; +} + // used to update running battlegrounds, and delete finished ones void BattlegroundMgr::Update(uint32 diff) { diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 595745e53fb..dbba964d4b3 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -55,18 +55,14 @@ struct BattlegroundTemplate bool IsArena() const { return BattlemasterEntry->type == MAP_ARENA; } }; -class BattlegroundMgr +class TC_GAME_API BattlegroundMgr { private: BattlegroundMgr(); ~BattlegroundMgr(); public: - static BattlegroundMgr* instance() - { - static BattlegroundMgr instance; - return &instance; - } + static BattlegroundMgr* instance(); void Update(uint32 diff); diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp index 34588c7e380..796afe472fe 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp +++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp @@ -161,9 +161,9 @@ GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, Battlegr //announce world (this don't need mutex) if (isRated && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE)) { - ArenaTeam* Team = sArenaTeamMgr->GetArenaTeamById(arenateamid); - if (Team) - sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, Team->GetName().c_str(), ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating); + ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(arenateamid); + if (team) + sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, team->GetName().c_str(), ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating); } //add players from group to ginfo @@ -354,8 +354,8 @@ void BattlegroundQueue::RemovePlayer(ObjectGuid guid, bool decreaseInvitedCount) // announce to world if arena team left queue for rated match, show only once if (group->ArenaType && group->IsRated && group->Players.empty() && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE)) - if (ArenaTeam* Team = sArenaTeamMgr->GetArenaTeamById(group->ArenaTeamId)) - sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, Team->GetName().c_str(), group->ArenaType, group->ArenaType, group->ArenaTeamRating); + if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(group->ArenaTeamId)) + sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, team->GetName().c_str(), group->ArenaType, group->ArenaType, group->ArenaTeamRating); // if player leaves queue and he is invited to rated arena match, then he have to lose if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount) diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.h b/src/server/game/Battlegrounds/BattlegroundQueue.h index 31f108053d9..f56ccb9bdbf 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.h +++ b/src/server/game/Battlegrounds/BattlegroundQueue.h @@ -72,7 +72,7 @@ enum BattlegroundQueueInvitationType }; class Battleground; -class BattlegroundQueue +class TC_GAME_API BattlegroundQueue { public: BattlegroundQueue(); @@ -142,7 +142,7 @@ class BattlegroundQueue This class is used to invite player to BG again, when minute lasts from his first invitation it is capable to solve all possibilities */ -class BGQueueInviteEvent : public BasicEvent +class TC_GAME_API BGQueueInviteEvent : public BasicEvent { public: BGQueueInviteEvent(ObjectGuid pl_guid, uint32 BgInstanceGUID, BattlegroundTypeId BgTypeId, uint8 arenaType, uint32 removeTime) : @@ -165,7 +165,7 @@ class BGQueueInviteEvent : public BasicEvent We must store removeInvite time in case player left queue and joined and is invited again We must store bgQueueTypeId, because battleground can be deleted already, when player entered it */ -class BGQueueRemoveEvent : public BasicEvent +class TC_GAME_API BGQueueRemoveEvent : public BasicEvent { public: BGQueueRemoveEvent(ObjectGuid pl_guid, uint32 bgInstanceGUID, BattlegroundTypeId BgTypeId, BattlegroundQueueTypeId bgQueueTypeId, uint32 removeTime) diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 4d41fbc32eb..239e59d6dbb 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -8,207 +8,72 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -file(GLOB_RECURSE sources_Accounts Accounts/*.cpp Accounts/*.h) -file(GLOB_RECURSE sources_Achievements Achievements/*.cpp Achievements/*.h) -file(GLOB_RECURSE sources_Addons Addons/*.cpp Addons/*.h) -file(GLOB_RECURSE sources_AI AI/*.cpp AI/*.h) -file(GLOB_RECURSE sources_AuctionHouse AuctionHouse/*.cpp AuctionHouse/*.h) -file(GLOB_RECURSE sources_AuctionHouseBot AuctionHouseBot/*.cpp AuctionHouseBot/*.h) -file(GLOB_RECURSE sources_Battlefield Battlefield/*.cpp Battlefield/*.h) -file(GLOB_RECURSE sources_Battlegrounds Battlegrounds/*.cpp Battlegrounds/*.h) -file(GLOB_RECURSE sources_Calendar Calendar/*.cpp Calendar/*.h) -file(GLOB_RECURSE sources_Chat Chat/*.cpp Chat/*.h) -file(GLOB_RECURSE sources_Combat Combat/*.cpp Combat/*.h) -file(GLOB_RECURSE sources_Conditions Conditions/*.cpp Conditions/*.h) -file(GLOB_RECURSE sources_DataStores DataStores/*.cpp DataStores/*.h) -file(GLOB_RECURSE sources_DungeonFinding DungeonFinding/*.cpp DungeonFinding/*.h) -file(GLOB_RECURSE sources_Entities Entities/*.cpp Entities/*.h) -file(GLOB_RECURSE sources_Events Events/*.cpp Events/*.h) -file(GLOB_RECURSE sources_Globals Globals/*.cpp Globals/*.h) -file(GLOB_RECURSE sources_Grids Grids/*.cpp Grids/*.h) -file(GLOB_RECURSE sources_Groups Groups/*.cpp Groups/*.h) -file(GLOB_RECURSE sources_Guilds Guilds/*.cpp Guilds/*.h) -file(GLOB_RECURSE sources_Handlers Handlers/*.cpp Handlers/*.h) -file(GLOB_RECURSE sources_Instances Instances/*.cpp Instances/*.h) -file(GLOB_RECURSE sources_Loot Loot/*.cpp Loot/*.h) -file(GLOB_RECURSE sources_Mails Mails/*.cpp Mails/*.h) -file(GLOB_RECURSE sources_Maps Maps/*.cpp Maps/*.h) -file(GLOB_RECURSE sources_Miscellaneous Miscellaneous/*.cpp Miscellaneous/*.h) -file(GLOB_RECURSE sources_Movement Movement/*.cpp Movement/*.h) -file(GLOB_RECURSE sources_OutdoorPvP OutdoorPvP/*.cpp OutdoorPvP/*.h) -file(GLOB_RECURSE sources_Pools Pools/*.cpp Pools/*.h) -file(GLOB_RECURSE sources_Quests Quests/*.cpp Quests/*.h) -file(GLOB_RECURSE sources_Reputation Reputation/*.cpp Reputation/*.h) -file(GLOB_RECURSE sources_Scripting Scripting/*.cpp Scripting/*.h) -file(GLOB_RECURSE sources_Server Server/*.cpp Server/*.h) -file(GLOB_RECURSE sources_Skills Skills/*.cpp Skills/*.h) -file(GLOB_RECURSE sources_Spells Spells/*.cpp Spells/*.h) -file(GLOB_RECURSE sources_Texts Texts/*.cpp Texts/*.h) -file(GLOB_RECURSE sources_Tools Tools/*.cpp Tools/*.h) -file(GLOB_RECURSE sources_Tickets Tickets/*.cpp Tickets/*.h) -file(GLOB_RECURSE sources_Warden Warden/*.cpp Warden/*.h) -file(GLOB_RECURSE sources_Weather Weather/*.cpp Weather/*.h) -file(GLOB_RECURSE sources_World World/*.cpp World/*.h) - -# Create game-libary +CollectSourceFiles( + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE_SOURCES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) if (USE_COREPCH) - set(game_STAT_PCH_HDR PrecompiledHeaders/gamePCH.h) - set(game_STAT_PCH_SRC PrecompiledHeaders/gamePCH.cpp) + set(PRIVATE_PCH_HEADER PrecompiledHeaders/gamePCH.h) + set(PRIVATE_PCH_SOURCE PrecompiledHeaders/gamePCH.cpp) endif () -set(game_STAT_SRCS - ${game_STAT_SRCS} - ${sources_Accounts} - ${sources_Achievements} - ${sources_Addons} - ${sources_AI} - ${sources_AuctionHouse} - ${sources_AuctionHouseBot} - ${sources_Battlefield} - ${sources_Battlegrounds} - ${sources_Calendar} - ${sources_Chat} - ${sources_Combat} - ${sources_Conditions} - ${sources_DataStores} - ${sources_DungeonFinding} - ${sources_Entities} - ${sources_Events} - ${sources_Globals} - ${sources_Grids} - ${sources_Groups} - ${sources_Guilds} - ${sources_Handlers} - ${sources_Instances} - ${sources_Loot} - ${sources_Mails} - ${sources_Maps} - ${sources_Miscellaneous} - ${sources_Movement} - ${sources_OutdoorPvP} - ${sources_Pools} - ${sources_Quests} - ${sources_Reputation} - ${sources_Scripting} - ${sources_Server} - ${sources_Skills} - ${sources_Spells} - ${sources_Texts} - ${sources_Tools} - ${sources_Tickets} - ${sources_Warden} - ${sources_Weather} - ${sources_World} -) +GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/Accounts - ${CMAKE_CURRENT_SOURCE_DIR}/Achievements - ${CMAKE_CURRENT_SOURCE_DIR}/Addons - ${CMAKE_CURRENT_SOURCE_DIR}/AI - ${CMAKE_CURRENT_SOURCE_DIR}/AI/CoreAI - ${CMAKE_CURRENT_SOURCE_DIR}/AI/PlayerAI - ${CMAKE_CURRENT_SOURCE_DIR}/AI/ScriptedAI - ${CMAKE_CURRENT_SOURCE_DIR}/AI/SmartScripts - ${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouse - ${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouseBot - ${CMAKE_CURRENT_SOURCE_DIR}/Battlefield - ${CMAKE_CURRENT_SOURCE_DIR}/Battlefield/Zones - ${CMAKE_CURRENT_SOURCE_DIR}/Battlegrounds - ${CMAKE_CURRENT_SOURCE_DIR}/Battlegrounds/Zones - ${CMAKE_CURRENT_SOURCE_DIR}/Calendar - ${CMAKE_CURRENT_SOURCE_DIR}/Chat - ${CMAKE_CURRENT_SOURCE_DIR}/Chat/Channels - ${CMAKE_CURRENT_SOURCE_DIR}/Combat - ${CMAKE_CURRENT_SOURCE_DIR}/Conditions - ${CMAKE_CURRENT_SOURCE_DIR}/DataStores - ${CMAKE_CURRENT_SOURCE_DIR}/DungeonFinding - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Corpse - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Creature - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/DynamicObject - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/GameObject - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Item - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Item/Container - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Object - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Object/Updates - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Pet - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Player - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Totem - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Transport - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Unit - ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Vehicle - ${CMAKE_CURRENT_SOURCE_DIR}/Events - ${CMAKE_CURRENT_SOURCE_DIR}/Globals - ${CMAKE_CURRENT_SOURCE_DIR}/Grids - ${CMAKE_CURRENT_SOURCE_DIR}/Grids/Cells - ${CMAKE_CURRENT_SOURCE_DIR}/Grids/Notifiers - ${CMAKE_CURRENT_SOURCE_DIR}/Groups - ${CMAKE_CURRENT_SOURCE_DIR}/Guilds - ${CMAKE_CURRENT_SOURCE_DIR}/Handlers - ${CMAKE_CURRENT_SOURCE_DIR}/Instances - ${CMAKE_CURRENT_SOURCE_DIR}/Loot - ${CMAKE_CURRENT_SOURCE_DIR}/Mails - ${CMAKE_CURRENT_SOURCE_DIR}/Maps - ${CMAKE_CURRENT_SOURCE_DIR}/Miscellaneous - ${CMAKE_CURRENT_SOURCE_DIR}/Movement - ${CMAKE_CURRENT_SOURCE_DIR}/Movement/MovementGenerators - ${CMAKE_CURRENT_SOURCE_DIR}/Movement/Spline - ${CMAKE_CURRENT_SOURCE_DIR}/Movement/Waypoints - ${CMAKE_CURRENT_SOURCE_DIR}/OutdoorPvP - ${CMAKE_CURRENT_SOURCE_DIR}/Pools - ${CMAKE_CURRENT_SOURCE_DIR}/Quests - ${CMAKE_CURRENT_SOURCE_DIR}/Reputation - ${CMAKE_CURRENT_SOURCE_DIR}/Scripting - ${CMAKE_CURRENT_SOURCE_DIR}/Server - ${CMAKE_CURRENT_SOURCE_DIR}/Server/Protocol - ${CMAKE_CURRENT_SOURCE_DIR}/Skills - ${CMAKE_CURRENT_SOURCE_DIR}/Spells - ${CMAKE_CURRENT_SOURCE_DIR}/Spells/Auras - ${CMAKE_CURRENT_SOURCE_DIR}/Texts - ${CMAKE_CURRENT_SOURCE_DIR}/Tickets - ${CMAKE_CURRENT_SOURCE_DIR}/Tools - ${CMAKE_CURRENT_SOURCE_DIR}/Warden - ${CMAKE_CURRENT_SOURCE_DIR}/Warden/Modules - ${CMAKE_CURRENT_SOURCE_DIR}/Weather - ${CMAKE_CURRENT_SOURCE_DIR}/World - ${CMAKE_SOURCE_DIR}/dep/cppformat - ${CMAKE_SOURCE_DIR}/dep/g3dlite/include - ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include - ${CMAKE_SOURCE_DIR}/dep/zlib - ${CMAKE_SOURCE_DIR}/src/common - ${CMAKE_SOURCE_DIR}/src/common/Collision - ${CMAKE_SOURCE_DIR}/src/common/Collision/Management - ${CMAKE_SOURCE_DIR}/src/common/Collision/Maps - ${CMAKE_SOURCE_DIR}/src/common/Collision/Models - ${CMAKE_SOURCE_DIR}/src/common/Configuration - ${CMAKE_SOURCE_DIR}/src/common/Cryptography - ${CMAKE_SOURCE_DIR}/src/common/Cryptography/Authentication - ${CMAKE_SOURCE_DIR}/src/common/Debugging - ${CMAKE_SOURCE_DIR}/src/common/Logging - ${CMAKE_SOURCE_DIR}/src/common/Threading - ${CMAKE_SOURCE_DIR}/src/common/Utilities - ${CMAKE_SOURCE_DIR}/src/server/database - ${CMAKE_SOURCE_DIR}/src/server/database/Database - ${CMAKE_SOURCE_DIR}/src/server/shared - ${CMAKE_SOURCE_DIR}/src/server/shared/DataStores - ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic - ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference - ${CMAKE_SOURCE_DIR}/src/server/shared/Networking - ${CMAKE_SOURCE_DIR}/src/server/shared/Packets - ${MYSQL_INCLUDE_DIR} - ${OPENSSL_INCLUDE_DIR} - ${VALGRIND_INCLUDE_DIR} -) +add_definitions(-DTRINITY_API_EXPORT_GAME) -GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) +CollectIncludeDirectories( + ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC_INCLUDES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) + +# Provide an interface target for the game project to allow +# dependent projects to build meanwhile. +add_library(game-interface INTERFACE) + +target_include_directories(game-interface + INTERFACE + ${PUBLIC_INCLUDES}) + +target_link_libraries(game-interface + INTERFACE + shared + Detour) + +add_library(game + ${PRIVATE_PCH_SOURCE} + ${PRIVATE_SOURCES}) + +target_include_directories(game + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) + +target_link_libraries(game + PUBLIC + game-interface + PRIVATE + efsw) + +set_target_properties(game + PROPERTIES + FOLDER + "server") -add_library(game STATIC - ${game_STAT_SRCS} - ${game_STAT_PCH_SRC} -) +if( BUILD_SHARED_LIBS ) + if( UNIX ) + install(TARGETS game + LIBRARY + DESTINATION lib) + elseif( WIN32 ) + install(TARGETS game + RUNTIME + DESTINATION "${CMAKE_INSTALL_PREFIX}") + endif() +endif() # Generate precompiled header if (USE_COREPCH) - add_cxx_pch(game ${game_STAT_PCH_HDR} ${game_STAT_PCH_SRC}) + add_cxx_pch(game ${PRIVATE_PCH_HEADER} ${PRIVATE_PCH_SOURCE}) endif () diff --git a/src/server/game/Calendar/CalendarMgr.cpp b/src/server/game/Calendar/CalendarMgr.cpp index 9d50b290c5e..b27aac7876a 100644 --- a/src/server/game/Calendar/CalendarMgr.cpp +++ b/src/server/game/Calendar/CalendarMgr.cpp @@ -45,6 +45,12 @@ CalendarMgr::~CalendarMgr() delete *itr2; } +CalendarMgr* CalendarMgr::instance() +{ + static CalendarMgr instance; + return &instance; +} + void CalendarMgr::LoadFromDB() { uint32 count = 0; diff --git a/src/server/game/Calendar/CalendarMgr.h b/src/server/game/Calendar/CalendarMgr.h index 59303a18324..c282e3e202c 100644 --- a/src/server/game/Calendar/CalendarMgr.h +++ b/src/server/game/Calendar/CalendarMgr.h @@ -126,7 +126,7 @@ enum CalendarError #define CALENDAR_MAX_GUILD_EVENTS 100 #define CALENDAR_MAX_INVITES 100 -struct CalendarInvite +struct TC_GAME_API CalendarInvite { public: CalendarInvite(CalendarInvite const& calendarInvite, uint64 inviteId, uint64 eventId) @@ -186,7 +186,7 @@ struct CalendarInvite std::string _text; }; -struct CalendarEvent +struct TC_GAME_API CalendarEvent { public: CalendarEvent(CalendarEvent const& calendarEvent, uint64 eventId) @@ -266,7 +266,7 @@ typedef std::vector<CalendarInvite*> CalendarInviteStore; typedef std::set<CalendarEvent*> CalendarEventStore; typedef std::map<uint64 /* eventId */, CalendarInviteStore > CalendarEventInviteStore; -class CalendarMgr +class TC_GAME_API CalendarMgr { private: CalendarMgr(); @@ -281,11 +281,7 @@ class CalendarMgr uint64 _maxInviteId; public: - static CalendarMgr* instance() - { - static CalendarMgr instance; - return &instance; - } + static CalendarMgr* instance(); void LoadFromDB(); diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h index 26bc6989d07..319105d2a8d 100644 --- a/src/server/game/Chat/Channels/Channel.h +++ b/src/server/game/Chat/Channels/Channel.h @@ -118,7 +118,7 @@ enum ChannelMemberFlags // 0x80 }; -class Channel +class TC_GAME_API Channel { struct PlayerInfo { diff --git a/src/server/game/Chat/Channels/ChannelMgr.h b/src/server/game/Chat/Channels/ChannelMgr.h index 2cd4edc4fb1..abe45690997 100644 --- a/src/server/game/Chat/Channels/ChannelMgr.h +++ b/src/server/game/Chat/Channels/ChannelMgr.h @@ -28,7 +28,7 @@ #define MAX_CHANNEL_PASS_STR 31 -class ChannelMgr +class TC_GAME_API ChannelMgr { typedef std::map<std::wstring, Channel*> ChannelMap; diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index aa0f6ce09fc..ec90a5f7efb 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -32,18 +32,19 @@ #include "ScriptMgr.h" #include "ChatLink.h" -bool ChatHandler::load_command_table = true; +// Lazy loading of the command table cache from commands and the +// ScriptMgr should be thread safe since the player commands, +// cli commands and ScriptMgr updates are all dispatched one after +// one inside the world update loop. +static Optional<std::vector<ChatCommand>> commandTableCache; std::vector<ChatCommand> const& ChatHandler::getCommandTable() { - static std::vector<ChatCommand> commandTableCache; - - if (LoadCommandTable()) + if (!commandTableCache) { - SetLoadCommandTable(false); - - std::vector<ChatCommand> cmds = sScriptMgr->GetChatCommands(); - commandTableCache.swap(cmds); + // We need to initialize this at top since SetDataForCommandInTable + // calls getCommandTable() recursively. + commandTableCache = sScriptMgr->GetChatCommands(); PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_COMMANDS); PreparedQueryResult result = WorldDatabase.Query(stmt); @@ -54,13 +55,18 @@ std::vector<ChatCommand> const& ChatHandler::getCommandTable() Field* fields = result->Fetch(); std::string name = fields[0].GetString(); - SetDataForCommandInTable(commandTableCache, name.c_str(), fields[1].GetUInt16(), fields[2].GetString(), name); + SetDataForCommandInTable(*commandTableCache, name.c_str(), fields[1].GetUInt16(), fields[2].GetString(), name); } while (result->NextRow()); } } - return commandTableCache; + return *commandTableCache; +} + +void ChatHandler::invalidateCommandTable() +{ + commandTableCache.reset(); } char const* ChatHandler::GetTrinityString(uint32 entry) const @@ -108,7 +114,7 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac if (target) target_sec = target->GetSecurity(); else if (target_account) - target_sec = AccountMgr::GetSecurity(target_account, realmID); + target_sec = AccountMgr::GetSecurity(target_account, realm.Id.Realm); else return true; // caller must report error for (target == NULL && target_account == 0) diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 7ce0792cdf9..1c9368275ad 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -36,7 +36,7 @@ class WorldObject; struct GameTele; -class ChatCommand +class TC_GAME_API ChatCommand { typedef bool(*pHandler)(ChatHandler*, char const*); @@ -52,7 +52,7 @@ class ChatCommand std::vector<ChatCommand> ChildCommands; }; -class ChatHandler +class TC_GAME_API ChatHandler { public: WorldSession* GetSession() { return m_session; } @@ -96,6 +96,7 @@ class ChatHandler bool ParseCommands(const char* text); static std::vector<ChatCommand> const& getCommandTable(); + static void invalidateCommandTable(); bool isValidChatMessage(const char* msg); void SendGlobalSysMessage(const char *str); @@ -143,8 +144,6 @@ class ChatHandler GameObject* GetObjectGlobalyWithGuidOrNearWithDbGuid(ObjectGuid::LowType lowguid, uint32 entry); bool HasSentErrorMessage() const { return sentErrorMessage; } void SetSentErrorMessage(bool val){ sentErrorMessage = val; } - static bool LoadCommandTable() { return load_command_table; } - static void SetLoadCommandTable(bool val) { load_command_table = val; } bool ShowHelpForCommand(std::vector<ChatCommand> const& table, const char* cmd); protected: @@ -157,11 +156,10 @@ class ChatHandler WorldSession* m_session; // != NULL for chat command call and NULL for CLI command // common global flag - static bool load_command_table; bool sentErrorMessage; }; -class CliHandler : public ChatHandler +class TC_GAME_API CliHandler : public ChatHandler { public: typedef void Print(void*, char const*); diff --git a/src/server/game/Chat/ChatLink.h b/src/server/game/Chat/ChatLink.h index 4adb61bbbf1..0d413ce49df 100644 --- a/src/server/game/Chat/ChatLink.h +++ b/src/server/game/Chat/ChatLink.h @@ -34,7 +34,7 @@ class Quest; /////////////////////////////////////////////////////////////////////////////////////////////////// // ChatLink - abstract base class for various links -class ChatLink +class TC_GAME_API ChatLink { public: ChatLink() : _color(0), _startPos(0), _endPos(0) { } @@ -54,7 +54,7 @@ protected: }; // ItemChatLink - link to item -class ItemChatLink : public ChatLink +class TC_GAME_API ItemChatLink : public ChatLink { public: ItemChatLink() : ChatLink(), _item(NULL), _suffix(NULL), _property(NULL) @@ -74,7 +74,7 @@ protected: }; // QuestChatLink - link to quest -class QuestChatLink : public ChatLink +class TC_GAME_API QuestChatLink : public ChatLink { public: QuestChatLink() : ChatLink(), _quest(nullptr), _questLevel(0) { } @@ -87,7 +87,7 @@ protected: }; // SpellChatLink - link to quest -class SpellChatLink : public ChatLink +class TC_GAME_API SpellChatLink : public ChatLink { public: SpellChatLink() : ChatLink(), _spell(nullptr) { } @@ -99,7 +99,7 @@ protected: }; // AchievementChatLink - link to quest -class AchievementChatLink : public ChatLink +class TC_GAME_API AchievementChatLink : public ChatLink { public: AchievementChatLink() : ChatLink(), _guid(0), _achievement(NULL) @@ -116,7 +116,7 @@ protected: }; // TradeChatLink - link to trade info -class TradeChatLink : public SpellChatLink +class TC_GAME_API TradeChatLink : public SpellChatLink { public: TradeChatLink() : SpellChatLink(), _minSkillLevel(0), _maxSkillLevel(0), _guid(0) { } @@ -129,7 +129,7 @@ private: }; // TalentChatLink - link to talent -class TalentChatLink : public SpellChatLink +class TC_GAME_API TalentChatLink : public SpellChatLink { public: TalentChatLink() : SpellChatLink(), _talentId(0), _rankId(0) { } @@ -141,7 +141,7 @@ private: }; // EnchantmentChatLink - link to enchantment -class EnchantmentChatLink : public SpellChatLink +class TC_GAME_API EnchantmentChatLink : public SpellChatLink { public: EnchantmentChatLink() : SpellChatLink() { } @@ -149,7 +149,7 @@ public: }; // GlyphChatLink - link to glyph -class GlyphChatLink : public SpellChatLink +class TC_GAME_API GlyphChatLink : public SpellChatLink { public: GlyphChatLink() : SpellChatLink(), _slotId(0), _glyph(NULL) { } @@ -159,7 +159,7 @@ private: GlyphPropertiesEntry const* _glyph; }; -class LinkExtractor +class TC_GAME_API LinkExtractor { public: explicit LinkExtractor(const char* msg); diff --git a/src/server/game/Combat/HostileRefManager.h b/src/server/game/Combat/HostileRefManager.h index 96152ed46f7..855f9e3d272 100644 --- a/src/server/game/Combat/HostileRefManager.h +++ b/src/server/game/Combat/HostileRefManager.h @@ -29,7 +29,7 @@ class SpellInfo; //================================================= -class HostileRefManager : public RefManager<Unit, ThreatManager> +class TC_GAME_API HostileRefManager : public RefManager<Unit, ThreatManager> { private: Unit* iOwner; diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index 588e7b1a93b..9767d69e2aa 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -335,7 +335,7 @@ HostileReference* ThreatContainer::selectNextVictim(Creature* attacker, HostileR { // current victim is a second choice target, so don't compare threat with it below if (currentRef == currentVictim) - currentVictim = NULL; + currentVictim = nullptr; ++iter; continue; } @@ -437,12 +437,15 @@ void ThreatManager::_addThreat(Unit* victim, float threat) if (!ref) // there was no ref => create a new one { + bool isFirst = iThreatContainer.empty(); // threat has to be 0 here HostileReference* hostileRef = new HostileReference(victim, this, 0); iThreatContainer.addReference(hostileRef); hostileRef->addThreat(threat); // now we add the real threat if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->IsGameMaster()) hostileRef->setOnlineOfflineState(false); // GM is always offline + else if (isFirst) + setCurrentVictim(hostileRef); } } diff --git a/src/server/game/Combat/ThreatManager.h b/src/server/game/Combat/ThreatManager.h index 7d20e99c128..a68d803304d 100644 --- a/src/server/game/Combat/ThreatManager.h +++ b/src/server/game/Combat/ThreatManager.h @@ -39,14 +39,14 @@ class SpellInfo; //============================================================== // Class to calculate the real threat based -struct ThreatCalcHelper +struct TC_GAME_API ThreatCalcHelper { static float calcThreat(Unit* hatedUnit, Unit* hatingUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = NULL); static bool isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell = NULL); }; //============================================================== -class HostileReference : public Reference<Unit, ThreatManager> +class TC_GAME_API HostileReference : public Reference<Unit, ThreatManager> { public: HostileReference(Unit* refUnit, ThreatManager* threatManager, float threat); @@ -141,7 +141,7 @@ class HostileReference : public Reference<Unit, ThreatManager> //============================================================== class ThreatManager; -class ThreatContainer +class TC_GAME_API ThreatContainer { friend class ThreatManager; @@ -169,7 +169,7 @@ class ThreatContainer HostileReference* getMostHated() const { - return iThreatList.empty() ? NULL : iThreatList.front(); + return iThreatList.empty() ? nullptr : iThreatList.front(); } HostileReference* getReferenceByTarget(Unit* victim) const; @@ -198,7 +198,7 @@ class ThreatContainer //================================================= -class ThreatManager +class TC_GAME_API ThreatManager { public: friend class HostileReference; diff --git a/src/server/game/Combat/UnitEvents.h b/src/server/game/Combat/UnitEvents.h index e501cdaa4a2..f50edcf3c7d 100644 --- a/src/server/game/Combat/UnitEvents.h +++ b/src/server/game/Combat/UnitEvents.h @@ -81,7 +81,7 @@ class UnitBaseEvent //============================================================== -class ThreatRefStatusChangeEvent : public UnitBaseEvent +class TC_GAME_API ThreatRefStatusChangeEvent : public UnitBaseEvent { private: HostileReference* iHostileReference; diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 81dc7894592..afb6255079b 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -55,7 +55,8 @@ char const* const ConditionMgr::StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX] "SmartScript", "Npc Vendor", "Spell Proc", - "Phase Def" + "Terrain Swap", + "Phase" }; ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[CONDITION_MAX] = @@ -101,6 +102,7 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND { "Health Pct", true, true, false }, { "Realm Achievement", true, false, false }, { "In Water", false, false, false }, + { "Terrain Swap", false, false, false }, { "Sit/stand state", true, true, false } }; @@ -438,7 +440,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const if (Unit* unit = object->ToUnit()) { if (ConditionValue1 == 0) - condMeets = (unit->getStandState() == ConditionValue2); + condMeets = (unit->GetStandState() == ConditionValue2); else if (ConditionValue2 == 0) condMeets = unit->IsStandState(); else if (ConditionValue2 == 1) @@ -926,6 +928,12 @@ bool ConditionMgr::IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 return true; } +ConditionMgr* ConditionMgr::instance() +{ + static ConditionMgr instance; + return &instance; +} + void ConditionMgr::LoadConditions(bool isReload) { uint32 oldMSTime = getMSTime(); @@ -1234,7 +1242,7 @@ bool ConditionMgr::addToGossipMenuItems(Condition* cond) const bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const { uint32 conditionEffMask = cond->SourceGroup; - SpellInfo* spellInfo = const_cast<SpellInfo*>(sSpellMgr->EnsureSpellInfo(cond->SourceEntry)); + SpellInfo* spellInfo = const_cast<SpellInfo*>(sSpellMgr->AssertSpellInfo(cond->SourceEntry)); std::list<uint32> sharedMasks; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { @@ -1650,9 +1658,14 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const } break; } - case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: + case CONDITION_SOURCE_TYPE_TERRAIN_SWAP: { - TC_LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_PHASE_DEFINITION:: is only for 4.3.4 branch, skipped"); + TC_LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_TERRAIN_SWAP: is only for 6.x branch, skipped"); + return false; + } + case CONDITION_SOURCE_TYPE_PHASE: + { + TC_LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_PHASE: is only for 6.x branch, skipped"); return false; } case CONDITION_SOURCE_TYPE_GOSSIP_MENU: @@ -1670,7 +1683,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const { if (cond->ConditionType == CONDITION_NONE || cond->ConditionType >= CONDITION_MAX) { - TC_LOG_ERROR("sql.sql", "%s Invalid ConditionType in `condition` table, ignoring.", cond->ToString().c_str()); + TC_LOG_ERROR("sql.sql", "%s Invalid ConditionType in `condition` table, ignoring.", cond->ToString(true).c_str()); return false; } @@ -2107,6 +2120,9 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const } case CONDITION_IN_WATER: break; + case CONDITION_TERRAIN_SWAP: + TC_LOG_ERROR("sql.sql", "%s is not valid for this branch, skipped.", cond->ToString(true).c_str()); + return false; case CONDITION_STAND_STATE: { bool valid = false; diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 3123aaca86a..83e714781c3 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -71,8 +71,9 @@ enum ConditionTypes CONDITION_HP_PCT = 38, // hpPct ComparisonType 0 true if unit's hp matches given pct CONDITION_REALM_ACHIEVEMENT = 39, // achievement_id 0 0 true if realm achievement is complete CONDITION_IN_WATER = 40, // 0 0 0 true if unit in water - CONDITION_STAND_STATE = 41, // stateType state 0 true if unit matches specified sitstate (0,x: has exactly state x; 1,0: any standing state; 1,1: any sitting state;) - CONDITION_MAX = 42 // MAX + CONDITION_TERRAIN_SWAP = 41, // only for 6.x + CONDITION_STAND_STATE = 42, // stateType state 0 true if unit matches specified sitstate (0,x: has exactly state x; 1,0: any standing state; 1,1: any sitting state;) + CONDITION_MAX = 43 // MAX }; /*! Documentation on implementing a new ConditionSourceType: @@ -129,8 +130,9 @@ enum ConditionSourceType CONDITION_SOURCE_TYPE_SMART_EVENT = 22, CONDITION_SOURCE_TYPE_NPC_VENDOR = 23, CONDITION_SOURCE_TYPE_SPELL_PROC = 24, - CONDITION_SOURCE_TYPE_PHASE_DEFINITION = 25, // only 4.3.4 - CONDITION_SOURCE_TYPE_MAX = 26 // MAX + CONDITION_SOURCE_TYPE_TERRAIN_SWAP = 25, // only 6.x + CONDITION_SOURCE_TYPE_PHASE = 26, // only 6.x + CONDITION_SOURCE_TYPE_MAX = 27 // MAX }; enum RelationType @@ -157,7 +159,7 @@ enum MaxConditionTargets MAX_CONDITION_TARGETS = 3 }; -struct ConditionSourceInfo +struct TC_GAME_API ConditionSourceInfo { WorldObject* mConditionTargets[MAX_CONDITION_TARGETS]; // an array of targets available for conditions Condition const* mLastFailedCondition; @@ -170,7 +172,7 @@ struct ConditionSourceInfo } }; -struct Condition +struct TC_GAME_API Condition { ConditionSourceType SourceType; //SourceTypeOrReferenceId uint32 SourceGroup; @@ -222,18 +224,14 @@ typedef std::unordered_map<uint32, ConditionsByEntryMap> ConditionEntriesByCreat typedef std::unordered_map<std::pair<int32, uint32 /*SAI source_type*/>, ConditionsByEntryMap> SmartEventConditionContainer; typedef std::unordered_map<uint32, ConditionContainer> ConditionReferenceContainer;//only used for references -class ConditionMgr +class TC_GAME_API ConditionMgr { private: ConditionMgr(); ~ConditionMgr(); public: - static ConditionMgr* instance() - { - static ConditionMgr instance; - return &instance; - } + static ConditionMgr* instance(); void LoadConditions(bool isReload = false); bool isConditionTypeValid(Condition* cond) const; diff --git a/src/server/game/Conditions/DisableMgr.h b/src/server/game/Conditions/DisableMgr.h index e74b7a9c319..cae1e0329e8 100644 --- a/src/server/game/Conditions/DisableMgr.h +++ b/src/server/game/Conditions/DisableMgr.h @@ -57,11 +57,11 @@ enum MMapDisableTypes namespace DisableMgr { - void LoadDisables(); - bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags = 0); - void CheckQuestDisables(); - bool IsVMAPDisabledFor(uint32 entry, uint8 flags); - bool IsPathfindingEnabled(uint32 mapId); + TC_GAME_API void LoadDisables(); + TC_GAME_API bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags = 0); + TC_GAME_API void CheckQuestDisables(); + TC_GAME_API bool IsVMAPDisabledFor(uint32 entry, uint8 flags); + TC_GAME_API bool IsPathfindingEnabled(uint32 mapId); } #endif //TRINITY_DISABLEMGR_H diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 6c51c71fe7b..5ede70da2a3 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -27,6 +27,9 @@ #include <boost/regex.hpp> #include <map> +#include <fstream> +#include <iostream> +#include <iomanip> typedef std::map<uint16, uint32> AreaFlagByAreaID; typedef std::map<uint32, uint32> AreaFlagByMapID; @@ -73,6 +76,7 @@ DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt); DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt); DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt); DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt); +DBCStorage <CinematicCameraEntry> sCinematicCameraStore(CinematicCameraEntryfmt); DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt); DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt); DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt); @@ -217,6 +221,8 @@ DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt); DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt); DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt); +std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore; + typedef std::list<std::string> StoreProblemList; uint32 DBCFileCount = 0; @@ -311,6 +317,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sChatChannelsStore, dbcPath, "ChatChannels.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sChrClassesStore, dbcPath, "ChrClasses.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sChrRacesStore, dbcPath, "ChrRaces.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sCinematicCameraStore, dbcPath, "CinematicCamera.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sCinematicSequencesStore, dbcPath, "CinematicSequences.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoStore, dbcPath, "CreatureDisplayInfo.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoExtraStore, dbcPath, "CreatureDisplayInfoExtra.dbc"); @@ -717,10 +724,250 @@ void LoadDBCStores(const std::string& dataPath) exit(1); } + LoadM2Cameras(dataPath); + TC_LOG_INFO("server.loading", ">> Initialized %d data stores in %u ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime)); } +// Convert the geomoetry from a spline value, to an actual WoW XYZ +G3D::Vector3 TranslateLocation(G3D::Vector4 const* DBCPosition, G3D::Vector3 const* basePosition, G3D::Vector3 const* splineVector) +{ + G3D::Vector3 work; + float x = basePosition->x + splineVector->x; + float y = basePosition->y + splineVector->y; + float z = basePosition->z + splineVector->z; + float const distance = sqrt((x * x) + (y * y)); + float angle = std::atan2(x, y) - DBCPosition->w; + + if (angle < 0) + angle += 2 * float(M_PI); + + work.x = DBCPosition->x + (distance * sin(angle)); + work.y = DBCPosition->y + (distance * cos(angle)); + work.z = DBCPosition->z + z; + return work; +} + +// Number of cameras not used. Multiple cameras never used in 3.3.5 +bool readCamera(M2Camera const* cam, uint32 buffSize, M2Header const* header, CinematicCameraEntry const* dbcentry) +{ + char const* buffer = reinterpret_cast<char const*>(header); + + FlyByCameraCollection cameras; + FlyByCameraCollection targetcam; + + G3D::Vector4 DBCData; + DBCData.x = dbcentry->base_x; + DBCData.y = dbcentry->base_y; + DBCData.z = dbcentry->base_z; + DBCData.w = dbcentry->base_o; + + // Read target locations, only so that we can calculate orientation + for (uint32 k = 0; k < cam->target_positions.timestamps.number; ++k) + { + // Extract Target positions + if (cam->target_positions.timestamps.offset_elements + sizeof(M2Array) > buffSize) + return false; + M2Array const* targTsArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.timestamps.offset_elements); + if (targTsArray->offset_elements + sizeof(uint32) > buffSize || cam->target_positions.values.offset_elements + sizeof(M2Array) > buffSize) + return false; + uint32 const* targTimestamps = reinterpret_cast<uint32 const*>(buffer + targTsArray->offset_elements); + M2Array const* targArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.values.offset_elements); + + if (targArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) + return false; + M2SplineKey<G3D::Vector3> const* targPositions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + targArray->offset_elements); + + // Read the data for this set + uint32 currPos = targArray->offset_elements; + for (uint32 i = 0; i < targTsArray->number; ++i) + { + if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) + return false; + // Translate co-ordinates + G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->target_position_base, &targPositions->p0); + + // Add to vector + FlyByCamera thisCam; + thisCam.timeStamp = targTimestamps[i]; + thisCam.locations.x = newPos.x; + thisCam.locations.y = newPos.y; + thisCam.locations.z = newPos.z; + thisCam.locations.w = 0.0f; + targetcam.push_back(thisCam); + targPositions++; + currPos += sizeof(M2SplineKey<G3D::Vector3>); + } + } + + // Read camera positions and timestamps (translating first position of 3 only, we don't need to translate the whole spline) + for (uint32 k = 0; k < cam->positions.timestamps.number; ++k) + { + // Extract Camera positions for this set + if (cam->positions.timestamps.offset_elements + sizeof(M2Array) > buffSize) + return false; + M2Array const* posTsArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.timestamps.offset_elements); + if (posTsArray->offset_elements + sizeof(uint32) > buffSize || cam->positions.values.offset_elements + sizeof(M2Array) > buffSize) + return false; + uint32 const* posTimestamps = reinterpret_cast<uint32 const*>(buffer + posTsArray->offset_elements); + M2Array const* posArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.values.offset_elements); + if (posArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) + return false; + M2SplineKey<G3D::Vector3> const* positions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + posArray->offset_elements); + + // Read the data for this set + uint32 currPos = posArray->offset_elements; + for (uint32 i = 0; i < posTsArray->number; ++i) + { + if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) + return false; + // Translate co-ordinates + G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->position_base, &positions->p0); + + // Add to vector + FlyByCamera thisCam; + thisCam.timeStamp = posTimestamps[i]; + thisCam.locations.x = newPos.x; + thisCam.locations.y = newPos.y; + thisCam.locations.z = newPos.z; + + if (targetcam.size() > 0) + { + // Find the target camera before and after this camera + FlyByCamera lastTarget; + FlyByCamera nextTarget; + + // Pre-load first item + lastTarget = targetcam[0]; + nextTarget = targetcam[0]; + for (uint32 j = 0; j < targetcam.size(); ++j) + { + nextTarget = targetcam[j]; + if (targetcam[j].timeStamp > posTimestamps[i]) + break; + + lastTarget = targetcam[j]; + } + + float x = lastTarget.locations.x; + float y = lastTarget.locations.y; + float z = lastTarget.locations.z; + + // Now, the timestamps for target cam and position can be different. So, if they differ we interpolate + if (lastTarget.timeStamp != posTimestamps[i]) + { + uint32 timeDiffTarget = nextTarget.timeStamp - lastTarget.timeStamp; + uint32 timeDiffThis = posTimestamps[i] - lastTarget.timeStamp; + float xDiff = nextTarget.locations.x - lastTarget.locations.x; + float yDiff = nextTarget.locations.y - lastTarget.locations.y; + float zDiff = nextTarget.locations.z - lastTarget.locations.z; + x = lastTarget.locations.x + (xDiff * (float(timeDiffThis) / float(timeDiffTarget))); + y = lastTarget.locations.y + (yDiff * (float(timeDiffThis) / float(timeDiffTarget))); + z = lastTarget.locations.z + (zDiff * (float(timeDiffThis) / float(timeDiffTarget))); + } + float xDiff = x - thisCam.locations.x; + float yDiff = y - thisCam.locations.y; + thisCam.locations.w = std::atan2(yDiff, xDiff); + + if (thisCam.locations.w < 0) + thisCam.locations.w += 2 * float(M_PI); + } + + cameras.push_back(thisCam); + positions++; + currPos += sizeof(M2SplineKey<G3D::Vector3>); + } + } + + sFlyByCameraStore[dbcentry->id] = cameras; + return true; +} + +void LoadM2Cameras(const std::string& dataPath) +{ + sFlyByCameraStore.clear(); + TC_LOG_INFO("server.loading", ">> Loading Cinematic Camera files"); + + uint32 oldMSTime = getMSTime(); + for (uint32 i = 0; i < sCinematicCameraStore.GetNumRows(); ++i) + { + if (CinematicCameraEntry const* dbcentry = sCinematicCameraStore.LookupEntry(i)) + { + std::string filename = dataPath.c_str(); + filename.append(dbcentry->filename); + + // Replace slashes + size_t loc = filename.find("\\"); + while (loc != std::string::npos) + { + filename.replace(loc, 1, "/"); + loc = filename.find("\\"); + } + + // Replace mdx to .m2 + loc = filename.find(".mdx"); + if (loc != std::string::npos) + filename.replace(loc, 4, ".m2"); + + std::ifstream m2file(filename.c_str(), std::ios::in | std::ios::binary); + if (!m2file.is_open()) + continue; + + // Get file size + m2file.seekg(0, std::ios::end); + std::streamoff const fileSize = m2file.tellg(); + + // Reject if not at least the size of the header + if (static_cast<uint32 const>(fileSize) < sizeof(M2Header)) + { + TC_LOG_ERROR("server.loading", "Camera file %s is damaged. File is smaller than header size", filename.c_str()); + m2file.close(); + continue; + } + + // Read 4 bytes (signature) + m2file.seekg(0, std::ios::beg); + char fileCheck[5]; + m2file.read(fileCheck, 4); + fileCheck[4] = 0; + + // Check file has correct magic (MD20) + if (strcmp(fileCheck, "MD20")) + { + TC_LOG_ERROR("server.loading", "Camera file %s is damaged. File identifier not found", filename.c_str()); + m2file.close(); + continue; + } + + // Now we have a good file, read it all into a vector of char's, then close the file. + std::vector<char> buffer(fileSize); + m2file.seekg(0, std::ios::beg); + if (!m2file.read(buffer.data(), fileSize)) + { + m2file.close(); + continue; + } + m2file.close(); + + // Read header + M2Header const* header = reinterpret_cast<M2Header const*>(buffer.data()); + + if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32 const>(fileSize)) + { + TC_LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.c_str()); + continue; + } + + // Get camera(s) - Main header, then dump them. + M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras); + if (!readCamera(cam, fileSize, header, dbcentry)) + TC_LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.c_str()); + } + } + TC_LOG_INFO("server.loading", ">> Loaded %u cinematic waypoint sets in %u ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime)); +} + SimpleFactionsList const* GetFactionTeamList(uint32 faction) { FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction); @@ -1017,5 +1264,6 @@ ResponseCodes ValidateName(std::string const& name, LocaleConstant locale) EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender) { - return sEmotesTextSoundMap[EmotesTextSoundKey(emote, race, gender)]; + auto itr = sEmotesTextSoundMap.find(EmotesTextSoundKey(emote, race, gender)); + return itr != sEmotesTextSoundMap.end() ? itr->second : nullptr; } diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 56ee1f618dd..6cad13fdf9a 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -27,18 +27,20 @@ #include <list> typedef std::list<uint32> SimpleFactionsList; -SimpleFactionsList const* GetFactionTeamList(uint32 faction); +typedef std::vector<FlyByCamera> FlyByCameraCollection; -char* GetPetName(uint32 petfamily, uint32 dbclang); -uint32 GetTalentSpellCost(uint32 spellId); -TalentSpellPos const* GetTalentSpellPos(uint32 spellId); +TC_GAME_API SimpleFactionsList const* GetFactionTeamList(uint32 faction); -char const* GetRaceName(uint8 race, uint8 locale); -char const* GetClassName(uint8 class_, uint8 locale); +TC_GAME_API char* GetPetName(uint32 petfamily, uint32 dbclang); +TC_GAME_API uint32 GetTalentSpellCost(uint32 spellId); +TC_GAME_API TalentSpellPos const* GetTalentSpellPos(uint32 spellId); -WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid); +TC_GAME_API char const* GetRaceName(uint8 race, uint8 locale); +TC_GAME_API char const* GetClassName(uint8 class_, uint8 locale); -uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId); +TC_GAME_API WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid); + +TC_GAME_API uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId); enum ContentLevels { @@ -46,154 +48,157 @@ enum ContentLevels CONTENT_61_70, CONTENT_71_80 }; -ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId); +TC_GAME_API ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId); -bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId); +TC_GAME_API bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId); -void Zone2MapCoordinates(float &x, float &y, uint32 zone); -void Map2ZoneCoordinates(float &x, float &y, uint32 zone); +TC_GAME_API void Zone2MapCoordinates(float &x, float &y, uint32 zone); +TC_GAME_API void Map2ZoneCoordinates(float &x, float &y, uint32 zone); typedef std::map<uint32/*pair32(map, diff)*/, MapDifficulty> MapDifficultyMap; -MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); -MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty); +TC_GAME_API MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); +TC_GAME_API MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty); -uint32 const* /*[MAX_TALENT_TABS]*/ GetTalentTabPages(uint8 cls); +TC_GAME_API uint32 const* /*[MAX_TALENT_TABS]*/ GetTalentTabPages(uint8 cls); -uint32 GetLiquidFlags(uint32 liquidType); +TC_GAME_API uint32 GetLiquidFlags(uint32 liquidType); -PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level); -PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id); +TC_GAME_API PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level); +TC_GAME_API PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id); -CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender); -CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color); +TC_GAME_API CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender); +TC_GAME_API CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color); -LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty); +TC_GAME_API LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty); -uint32 GetDefaultMapLight(uint32 mapId); +TC_GAME_API uint32 GetDefaultMapLight(uint32 mapId); typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRaceClassInfoMap; typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds; -SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); - -ResponseCodes ValidateName(std::string const& name, LocaleConstant locale); - -EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender); - -extern DBCStorage <AchievementEntry> sAchievementStore; -extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore; -extern DBCStorage <AreaTableEntry> sAreaTableStore; -extern DBCStorage <AreaGroupEntry> sAreaGroupStore; -extern DBCStorage <AreaPOIEntry> sAreaPOIStore; -extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore; -extern DBCStorage <AuctionHouseEntry> sAuctionHouseStore; -extern DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore; -extern DBCStorage <BannedAddOnsEntry> sBannedAddOnsStore; -extern DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore; -extern DBCStorage <BattlemasterListEntry> sBattlemasterListStore; -extern DBCStorage <ChatChannelsEntry> sChatChannelsStore; -extern DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore; -extern DBCStorage <CharSectionsEntry> sCharSectionsStore; -extern DBCStorage <CharTitlesEntry> sCharTitlesStore; -extern DBCStorage <ChrClassesEntry> sChrClassesStore; -extern DBCStorage <ChrRacesEntry> sChrRacesStore; -extern DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore; -extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore; -extern DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore; -extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore; -extern DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore; -extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore; -extern DBCStorage <CreatureTypeEntry> sCreatureTypeStore; -extern DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore; -extern DBCStorage <DestructibleModelDataEntry> sDestructibleModelDataStore; -extern DBCStorage <DungeonEncounterEntry> sDungeonEncounterStore; -extern DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore; -extern DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore; -extern DBCStorage <EmotesEntry> sEmotesStore; -extern DBCStorage <EmotesTextEntry> sEmotesTextStore; -extern DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore; -extern DBCStorage <FactionEntry> sFactionStore; -extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore; -extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore; -extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore; -extern DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore; -extern DBCStorage <GlyphSlotEntry> sGlyphSlotStore; - -extern DBCStorage <GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore; -extern DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore; -extern DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore; -extern DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore; -extern DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore; -extern DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore; -extern DBCStorage <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore; -extern DBCStorage <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore; -extern DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore; -//extern DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore; -- not used currently -extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore; -extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore; -extern DBCStorage <HolidaysEntry> sHolidaysStore; -extern DBCStorage <ItemEntry> sItemStore; -extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore; -//extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore; -- not used currently -extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore; -extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore; -extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore; -extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore; -extern DBCStorage <ItemSetEntry> sItemSetStore; -extern DBCStorage <LFGDungeonEntry> sLFGDungeonStore; -extern DBCStorage <LiquidTypeEntry> sLiquidTypeStore; -extern DBCStorage <LockEntry> sLockStore; -extern DBCStorage <MailTemplateEntry> sMailTemplateStore; -extern DBCStorage <MapEntry> sMapStore; -//extern DBCStorage <MapDifficultyEntry> sMapDifficultyStore; -- use GetMapDifficultyData insteed -extern MapDifficultyMap sMapDifficultyMap; -extern DBCStorage <MovieEntry> sMovieStore; -extern DBCStorage <OverrideSpellDataEntry> sOverrideSpellDataStore; -extern DBCStorage <PowerDisplayEntry> sPowerDisplayStore; -extern DBCStorage <QuestSortEntry> sQuestSortStore; -extern DBCStorage <QuestXPEntry> sQuestXPStore; -extern DBCStorage <QuestFactionRewEntry> sQuestFactionRewardStore; -extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore; -extern DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore; -extern DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore; -extern DBCStorage <SkillLineEntry> sSkillLineStore; -extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore; -extern DBCStorage <SkillTiersEntry> sSkillTiersStore; -extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore; -extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore; -extern DBCStorage <SpellCategoryEntry> sSpellCategoryStore; -extern DBCStorage <SpellDifficultyEntry> sSpellDifficultyStore; -extern DBCStorage <SpellDurationEntry> sSpellDurationStore; -extern DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore; -extern DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore; -extern DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore; -extern PetFamilySpellsStore sPetFamilySpellsStore; -extern DBCStorage <SpellRadiusEntry> sSpellRadiusStore; -extern DBCStorage <SpellRangeEntry> sSpellRangeStore; -extern DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore; -extern DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore; -extern DBCStorage <SpellEntry> sSpellStore; -extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore; -extern DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore; -extern DBCStorage <TalentEntry> sTalentStore; -extern DBCStorage <TalentTabEntry> sTalentTabStore; -extern DBCStorage <TaxiNodesEntry> sTaxiNodesStore; -extern DBCStorage <TaxiPathEntry> sTaxiPathStore; -extern TaxiMask sTaxiNodesMask; -extern TaxiMask sOldContinentsNodesMask; -extern TaxiMask sHordeTaxiNodesMask; -extern TaxiMask sAllianceTaxiNodesMask; -extern TaxiMask sDeathKnightTaxiNodesMask; -extern TaxiPathSetBySource sTaxiPathSetBySource; -extern TaxiPathNodesByPath sTaxiPathNodesByPath; -extern DBCStorage <TeamContributionPointsEntry> sTeamContributionPointsStore; -extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore; -extern DBCStorage <VehicleEntry> sVehicleStore; -extern DBCStorage <VehicleSeatEntry> sVehicleSeatStore; -extern DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore; -//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates -extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore; -extern DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore; - -void LoadDBCStores(const std::string& dataPath); +TC_GAME_API SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); + +TC_GAME_API ResponseCodes ValidateName(std::string const& name, LocaleConstant locale); + +TC_GAME_API EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender); + +TC_GAME_API extern DBCStorage <AchievementEntry> sAchievementStore; +TC_GAME_API extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore; +TC_GAME_API extern DBCStorage <AreaTableEntry> sAreaTableStore; +TC_GAME_API extern DBCStorage <AreaGroupEntry> sAreaGroupStore; +TC_GAME_API extern DBCStorage <AreaPOIEntry> sAreaPOIStore; +TC_GAME_API extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore; +TC_GAME_API extern DBCStorage <AuctionHouseEntry> sAuctionHouseStore; +TC_GAME_API extern DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore; +TC_GAME_API extern DBCStorage <BannedAddOnsEntry> sBannedAddOnsStore; +TC_GAME_API extern DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore; +TC_GAME_API extern DBCStorage <BattlemasterListEntry> sBattlemasterListStore; +TC_GAME_API extern DBCStorage <ChatChannelsEntry> sChatChannelsStore; +TC_GAME_API extern DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore; +TC_GAME_API extern DBCStorage <CharSectionsEntry> sCharSectionsStore; +TC_GAME_API extern DBCStorage <CharTitlesEntry> sCharTitlesStore; +TC_GAME_API extern DBCStorage <ChrClassesEntry> sChrClassesStore; +TC_GAME_API extern DBCStorage <ChrRacesEntry> sChrRacesStore; +TC_GAME_API extern DBCStorage <CinematicCameraEntry> sCinematicCameraStore; +TC_GAME_API extern DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore; +TC_GAME_API extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore; +TC_GAME_API extern DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore; +TC_GAME_API extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore; +TC_GAME_API extern DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore; +TC_GAME_API extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore; +TC_GAME_API extern DBCStorage <CreatureTypeEntry> sCreatureTypeStore; +TC_GAME_API extern DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore; +TC_GAME_API extern DBCStorage <DestructibleModelDataEntry> sDestructibleModelDataStore; +TC_GAME_API extern DBCStorage <DungeonEncounterEntry> sDungeonEncounterStore; +TC_GAME_API extern DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore; +TC_GAME_API extern DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore; +TC_GAME_API extern DBCStorage <EmotesEntry> sEmotesStore; +TC_GAME_API extern DBCStorage <EmotesTextEntry> sEmotesTextStore; +TC_GAME_API extern DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore; +TC_GAME_API extern DBCStorage <FactionEntry> sFactionStore; +TC_GAME_API extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore; +TC_GAME_API extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore; +TC_GAME_API extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore; +TC_GAME_API extern DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore; +TC_GAME_API extern DBCStorage <GlyphSlotEntry> sGlyphSlotStore; + +TC_GAME_API extern DBCStorage <GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore; +TC_GAME_API extern DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore; +TC_GAME_API extern DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore; +TC_GAME_API extern DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore; +TC_GAME_API extern DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore; +TC_GAME_API extern DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore; +TC_GAME_API extern DBCStorage <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore; +TC_GAME_API extern DBCStorage <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore; +TC_GAME_API extern DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore; +//TC_GAME_API extern DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore; -- not used currently +TC_GAME_API extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore; +TC_GAME_API extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore; +TC_GAME_API extern DBCStorage <HolidaysEntry> sHolidaysStore; +TC_GAME_API extern DBCStorage <ItemEntry> sItemStore; +TC_GAME_API extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore; +//TC_GAME_API extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore; -- not used currently +TC_GAME_API extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore; +TC_GAME_API extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore; +TC_GAME_API extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore; +TC_GAME_API extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore; +TC_GAME_API extern DBCStorage <ItemSetEntry> sItemSetStore; +TC_GAME_API extern DBCStorage <LFGDungeonEntry> sLFGDungeonStore; +TC_GAME_API extern DBCStorage <LiquidTypeEntry> sLiquidTypeStore; +TC_GAME_API extern DBCStorage <LockEntry> sLockStore; +TC_GAME_API extern DBCStorage <MailTemplateEntry> sMailTemplateStore; +TC_GAME_API extern DBCStorage <MapEntry> sMapStore; +//TC_GAME_API extern DBCStorage <MapDifficultyEntry> sMapDifficultyStore; -- use GetMapDifficultyData insteed +TC_GAME_API extern MapDifficultyMap sMapDifficultyMap; +TC_GAME_API extern DBCStorage <MovieEntry> sMovieStore; +TC_GAME_API extern DBCStorage <OverrideSpellDataEntry> sOverrideSpellDataStore; +TC_GAME_API extern DBCStorage <PowerDisplayEntry> sPowerDisplayStore; +TC_GAME_API extern DBCStorage <QuestSortEntry> sQuestSortStore; +TC_GAME_API extern DBCStorage <QuestXPEntry> sQuestXPStore; +TC_GAME_API extern DBCStorage <QuestFactionRewEntry> sQuestFactionRewardStore; +TC_GAME_API extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore; +TC_GAME_API extern DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore; +TC_GAME_API extern DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore; +TC_GAME_API extern DBCStorage <SkillLineEntry> sSkillLineStore; +TC_GAME_API extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore; +TC_GAME_API extern DBCStorage <SkillTiersEntry> sSkillTiersStore; +TC_GAME_API extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore; +TC_GAME_API extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore; +TC_GAME_API extern DBCStorage <SpellCategoryEntry> sSpellCategoryStore; +TC_GAME_API extern DBCStorage <SpellDifficultyEntry> sSpellDifficultyStore; +TC_GAME_API extern DBCStorage <SpellDurationEntry> sSpellDurationStore; +TC_GAME_API extern DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore; +TC_GAME_API extern DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore; +TC_GAME_API extern DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore; +TC_GAME_API extern PetFamilySpellsStore sPetFamilySpellsStore; +TC_GAME_API extern DBCStorage <SpellRadiusEntry> sSpellRadiusStore; +TC_GAME_API extern DBCStorage <SpellRangeEntry> sSpellRangeStore; +TC_GAME_API extern DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore; +TC_GAME_API extern DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore; +TC_GAME_API extern DBCStorage <SpellEntry> sSpellStore; +TC_GAME_API extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore; +TC_GAME_API extern DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore; +TC_GAME_API extern DBCStorage <TalentEntry> sTalentStore; +TC_GAME_API extern DBCStorage <TalentTabEntry> sTalentTabStore; +TC_GAME_API extern DBCStorage <TaxiNodesEntry> sTaxiNodesStore; +TC_GAME_API extern DBCStorage <TaxiPathEntry> sTaxiPathStore; +TC_GAME_API extern TaxiMask sTaxiNodesMask; +TC_GAME_API extern TaxiMask sOldContinentsNodesMask; +TC_GAME_API extern TaxiMask sHordeTaxiNodesMask; +TC_GAME_API extern TaxiMask sAllianceTaxiNodesMask; +TC_GAME_API extern TaxiMask sDeathKnightTaxiNodesMask; +TC_GAME_API extern TaxiPathSetBySource sTaxiPathSetBySource; +TC_GAME_API extern TaxiPathNodesByPath sTaxiPathNodesByPath; +TC_GAME_API extern DBCStorage <TeamContributionPointsEntry> sTeamContributionPointsStore; +TC_GAME_API extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore; +TC_GAME_API extern DBCStorage <VehicleEntry> sVehicleStore; +TC_GAME_API extern DBCStorage <VehicleSeatEntry> sVehicleSeatStore; +TC_GAME_API extern DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore; +//TC_GAME_API extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates +TC_GAME_API extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore; +TC_GAME_API extern DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore; +TC_GAME_API extern std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore; + +TC_GAME_API void LoadDBCStores(const std::string& dataPath); +TC_GAME_API void LoadM2Cameras(const std::string& dataPath); #endif diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index b5dc4489148..51b3dcbd38b 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -725,24 +725,22 @@ struct ChrRacesEntry uint32 expansion; // 68 (0 - original race, 1 - tbc addon, ...) }; -/* not used struct CinematicCameraEntry { uint32 id; // 0 index char* filename; // 1 uint32 soundid; // 2 in SoundEntries.dbc or 0 - float start_x; // 3 - float start_y; // 4 - float start_z; // 5 - float unk6; // 6 speed? + float base_x; // 3 + float base_y; // 4 + float base_z; // 5 + float base_o; // 6 }; -*/ struct CinematicSequencesEntry { uint32 Id; // 0 index //uint32 unk1; // 1 always 0 - //uint32 cinematicCamera; // 2 id in CinematicCamera.dbc + uint32 cinematicCamera; // 2 id in CinematicCamera.dbc // 3-9 always 0 }; diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index c61ec997bc2..1accc81714b 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -38,7 +38,8 @@ char const CharTitlesEntryfmt[] = "nxssssssssssssssssxssssssssssssssssxi"; char const ChatChannelsEntryfmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxx"; char const ChrClassesEntryfmt[] = "nxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii"; char const ChrRacesEntryfmt[] = "niixiixixxxxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; -char const CinematicSequencesEntryfmt[] = "nxxxxxxxxx"; +char const CinematicCameraEntryfmt[] = "nsiffff"; +char const CinematicSequencesEntryfmt[] = "nxixxxxxxx"; char const CreatureDisplayInfofmt[] = "nixifxxxxxxxxxxx"; char const CreatureDisplayInfoExtrafmt[] = "diixxxxxxxxxxxxxxxxxx"; char const CreatureFamilyfmt[] = "nfifiiiiixssssssssssssssssxx"; diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h index 73c123723b1..b837a0df272 100644 --- a/src/server/game/DungeonFinding/LFG.h +++ b/src/server/game/DungeonFinding/LFG.h @@ -101,9 +101,9 @@ typedef std::map<ObjectGuid, LfgLockMap> LfgLockPartyMap; typedef std::map<ObjectGuid, uint8> LfgRolesMap; typedef std::map<ObjectGuid, ObjectGuid> LfgGroupsMap; -std::string ConcatenateDungeons(LfgDungeonSet const& dungeons); -std::string GetRolesString(uint8 roles); -std::string GetStateString(LfgState state); +TC_GAME_API std::string ConcatenateDungeons(LfgDungeonSet const& dungeons); +TC_GAME_API std::string GetRolesString(uint8 roles); +TC_GAME_API std::string GetStateString(LfgState state); } // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGGroupData.h b/src/server/game/DungeonFinding/LFGGroupData.h index 7ae4777cd4d..62a41b6b350 100644 --- a/src/server/game/DungeonFinding/LFGGroupData.h +++ b/src/server/game/DungeonFinding/LFGGroupData.h @@ -31,7 +31,7 @@ enum LfgGroupEnum /** Stores all lfg data needed about a group. */ -class LfgGroupData +class TC_GAME_API LfgGroupData { public: LfgGroupData(); diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index b0a1777f19a..e72859c23e7 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -40,8 +40,6 @@ namespace lfg LFGMgr::LFGMgr(): m_QueueTimer(0), m_lfgProposalId(1), m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK)) { - new LFGPlayerScript(); - new LFGGroupScript(); } LFGMgr::~LFGMgr() @@ -261,6 +259,12 @@ void LFGMgr::LoadLFGDungeons(bool reload /* = false */) } } +LFGMgr* LFGMgr::instance() +{ + static LFGMgr instance; + return &instance; +} + void LFGMgr::Update(uint32 diff) { if (!isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER)) @@ -1142,7 +1146,7 @@ void LFGMgr::RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdate for (GuidList::const_iterator it = proposal.queues.begin(); it != proposal.queues.end(); ++it) { ObjectGuid guid = *it; - queue.AddToQueue(guid); + queue.AddToQueue(guid, true); } ProposalsStore.erase(itProposal); diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 90a8d802f9d..c72c0a3cdab 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -289,18 +289,14 @@ struct LFGDungeonData uint32 Entry() const { return id + (type << 24); } }; -class LFGMgr +class TC_GAME_API LFGMgr { private: LFGMgr(); ~LFGMgr(); public: - static LFGMgr* instance() - { - static LFGMgr instance; - return &instance; - } + static LFGMgr* instance(); // Functions used outside lfg namespace void Update(uint32 diff); diff --git a/src/server/game/DungeonFinding/LFGPlayerData.h b/src/server/game/DungeonFinding/LFGPlayerData.h index 859317ca956..91e4153a6d5 100644 --- a/src/server/game/DungeonFinding/LFGPlayerData.h +++ b/src/server/game/DungeonFinding/LFGPlayerData.h @@ -26,7 +26,7 @@ namespace lfg /** Stores all lfg data needed about the player. */ -class LfgPlayerData +class TC_GAME_API LfgPlayerData { public: LfgPlayerData(); diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index 314803d1602..d156158dee6 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -117,7 +117,7 @@ std::string LFGQueue::GetDetailedMatchRoles(GuidList const& check) const return o.str(); } -void LFGQueue::AddToQueue(ObjectGuid guid) +void LFGQueue::AddToQueue(ObjectGuid guid, bool reAdd) { LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(guid); if (itQueue == QueueDataStore.end()) @@ -126,7 +126,10 @@ void LFGQueue::AddToQueue(ObjectGuid guid) return; } - AddToNewQueue(guid); + if (reAdd) + AddToFrontCurrentQueue(guid); + else + AddToNewQueue(guid); } void LFGQueue::RemoveFromQueue(ObjectGuid guid) @@ -171,6 +174,11 @@ void LFGQueue::AddToCurrentQueue(ObjectGuid guid) currentQueueStore.push_back(guid); } +void LFGQueue::AddToFrontCurrentQueue(ObjectGuid guid) +{ + currentQueueStore.push_front(guid); +} + void LFGQueue::RemoveFromCurrentQueue(ObjectGuid guid) { currentQueueStore.remove(guid); diff --git a/src/server/game/DungeonFinding/LFGQueue.h b/src/server/game/DungeonFinding/LFGQueue.h index ed8193ab605..32711e81468 100644 --- a/src/server/game/DungeonFinding/LFGQueue.h +++ b/src/server/game/DungeonFinding/LFGQueue.h @@ -83,13 +83,13 @@ typedef std::map<ObjectGuid, LfgQueueData> LfgQueueDataContainer; /** Stores all data related to queue */ -class LFGQueue +class TC_GAME_API LFGQueue { public: // Add/Remove from queue std::string GetDetailedMatchRoles(GuidList const& check) const; - void AddToQueue(ObjectGuid guid); + void AddToQueue(ObjectGuid guid, bool reAdd = false); void RemoveFromQueue(ObjectGuid guid); void AddQueueData(ObjectGuid guid, time_t joinTime, LfgDungeonSet const& dungeons, LfgRolesMap const& rolesMap); void RemoveQueueData(ObjectGuid guid); @@ -116,6 +116,7 @@ class LFGQueue void AddToNewQueue(ObjectGuid guid); void AddToCurrentQueue(ObjectGuid guid); + void AddToFrontCurrentQueue(ObjectGuid guid); void RemoveFromNewQueue(ObjectGuid guid); void RemoveFromCurrentQueue(ObjectGuid guid); diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp index 79d36055870..1d2b963b254 100644 --- a/src/server/game/DungeonFinding/LFGScripts.cpp +++ b/src/server/game/DungeonFinding/LFGScripts.cpp @@ -241,4 +241,10 @@ void LFGGroupScript::OnInviteMember(Group* group, ObjectGuid guid) sLFGMgr->LeaveLfg(leader); } +void AddSC_LFGScripts() +{ + new LFGPlayerScript(); + new LFGGroupScript(); +} + } // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGScripts.h b/src/server/game/DungeonFinding/LFGScripts.h index 377614bc55d..9f52668ea61 100644 --- a/src/server/game/DungeonFinding/LFGScripts.h +++ b/src/server/game/DungeonFinding/LFGScripts.h @@ -29,7 +29,7 @@ class Group; namespace lfg { -class LFGPlayerScript : public PlayerScript +class TC_GAME_API LFGPlayerScript : public PlayerScript { public: LFGPlayerScript(); @@ -40,7 +40,7 @@ class LFGPlayerScript : public PlayerScript void OnMapChanged(Player* player) override; }; -class LFGGroupScript : public GroupScript +class TC_GAME_API LFGGroupScript : public GroupScript { public: LFGGroupScript(); @@ -53,4 +53,6 @@ class LFGGroupScript : public GroupScript void OnInviteMember(Group* group, ObjectGuid guid) override; }; +/*keep private*/ void AddSC_LFGScripts(); + } // namespace lfg diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h index 5062645eac8..c9dd0b01509 100644 --- a/src/server/game/Entities/Corpse/Corpse.h +++ b/src/server/game/Entities/Corpse/Corpse.h @@ -46,7 +46,7 @@ enum CorpseFlags CORPSE_FLAG_LOOTABLE = 0x20 }; -class Corpse : public WorldObject, public GridObject<Corpse> +class TC_GAME_API Corpse : public WorldObject, public GridObject<Corpse> { public: explicit Corpse(CorpseType type = CORPSE_BONES); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 5d62b740947..d3843c86aa4 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -54,7 +54,7 @@ TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const if (itr != spellList.end()) return &itr->second; - return NULL; + return nullptr; } bool VendorItemData::RemoveItem(uint32 item_id) @@ -78,7 +78,7 @@ VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint32 extend for (VendorItemList::const_iterator i = m_items.begin(); i != m_items.end(); ++i) if ((*i)->item == item_id && (*i)->ExtendedCost == extendedCost) return *i; - return NULL; + return nullptr; } uint32 CreatureTemplate::GetRandomValidModelId() const @@ -183,7 +183,7 @@ m_lootRecipient(), m_lootRecipientGroup(0), _skinner(), _pickpocketLootRestore(0 m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), -m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(NULL), m_creatureData(NULL), m_waypointID(0), m_path_id(0), m_formation(NULL) +m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_focusSpell(nullptr), m_focusDelay(0) { m_regenTimer = CREATURE_REGEN_INTERVAL; m_valuesCount = UNIT_END; @@ -197,16 +197,14 @@ m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo( m_CombatDistance = 0;//MELEE_RANGE; ResetLootMode(); // restore default loot mode - TriggerJustRespawned = false; + m_TriggerJustRespawned = false; m_isTempWorldObject = false; - _focusSpell = NULL; - _focusDelay = 0; } Creature::~Creature() { delete i_AI; - i_AI = NULL; + i_AI = nullptr; //if (m_uint32Values) // TC_LOG_ERROR("entities.unit", "Deconstruct Creature Entry = %u", GetEntry()); @@ -344,10 +342,10 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) m_creatureInfo = cinfo; // map mode related always // equal to player Race field, but creature does not have race - SetByteValue(UNIT_FIELD_BYTES_0, 0, 0); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_RACE, 0); // known valid are: CLASS_WARRIOR, CLASS_PALADIN, CLASS_ROGUE, CLASS_MAGE - SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class)); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, uint8(cinfo->unit_class)); // Cancel load if no model defined if (!(cinfo->GetFirstValidModelId())) @@ -366,7 +364,7 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) SetDisplayId(displayID); SetNativeDisplayId(displayID); - SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); // Load creature equipment if (data && data->equipmentId != 0) @@ -381,10 +379,10 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); - SetSpeed(MOVE_WALK, cinfo->speed_walk); - SetSpeed(MOVE_RUN, cinfo->speed_run); - SetSpeed(MOVE_SWIM, 1.0f); // using 1.0 rate - SetSpeed(MOVE_FLIGHT, 1.0f); // using 1.0 rate + SetSpeedRate(MOVE_WALK, cinfo->speed_walk); + SetSpeedRate(MOVE_RUN, cinfo->speed_run); + SetSpeedRate(MOVE_SWIM, 1.0f); // using 1.0 rate + SetSpeedRate(MOVE_FLIGHT, 1.0f); // using 1.0 rate // Will set UNIT_FIELD_BOUNDINGRADIUS and UNIT_FIELD_COMBATREACH SetObjectScale(cinfo->scale); @@ -490,9 +488,9 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/) void Creature::Update(uint32 diff) { - if (IsAIEnabled && TriggerJustRespawned) + if (IsAIEnabled && m_TriggerJustRespawned) { - TriggerJustRespawned = false; + m_TriggerJustRespawned = false; AI()->JustRespawned(); if (m_vehicleKit) m_vehicleKit->Reset(); @@ -578,7 +576,8 @@ void Creature::Update(uint32 diff) IsAIEnabled = true; if (!IsInEvadeMode() && LastCharmerGUID) if (Unit* charmer = ObjectAccessor::GetUnit(*this, LastCharmerGUID)) - i_AI->AttackStart(charmer); + if (CanStartAttack(charmer, true)) + i_AI->AttackStart(charmer); LastCharmerGUID.Clear(); } @@ -768,7 +767,7 @@ void Creature::DoFleeToGetAssistance() float radius = sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS); if (radius >0) { - Creature* creature = NULL; + Creature* creature = nullptr; CellCoord p(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY())); Cell cell(p); @@ -781,7 +780,7 @@ void Creature::DoFleeToGetAssistance() cell.Visit(p, grid_creature_searcher, *GetMap(), *this, radius); SetNoSearchAssistance(true); - UpdateSpeed(MOVE_RUN, false); + UpdateSpeed(MOVE_RUN); if (!creature) //SetFeared(true, EnsureVictim()->GetGUID(), 0, sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY)); @@ -792,6 +791,24 @@ void Creature::DoFleeToGetAssistance() } } +bool Creature::AIM_Destroy() +{ + if (m_AI_locked) + { + TC_LOG_DEBUG("scripts", "AIM_Destroy: failed to destroy, locked."); + return false; + } + + ASSERT(!i_disabledAI, + "The disabled AI wasn't cleared!"); + + delete i_AI; + i_AI = nullptr; + + IsAIEnabled = false; + return true; +} + bool Creature::AIM_Initialize(CreatureAI* ai) { // make sure nothing can change the AI during AI update @@ -801,12 +818,12 @@ bool Creature::AIM_Initialize(CreatureAI* ai) return false; } - UnitAI* oldAI = i_AI; + AIM_Destroy(); Motion_Initialize(); i_AI = ai ? ai : FactorySelector::selectAI(this); - delete oldAI; + IsAIEnabled = true; i_AI->InitializeAI(); // Initialize vehicle @@ -890,7 +907,7 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, u { SetDisplayId(displayID); SetNativeDisplayId(displayID); - SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); } LastUsedScriptID = GetCreatureTemplate()->ScriptID; @@ -968,14 +985,14 @@ bool Creature::isCanTrainingAndResetTalentsOf(Player* player) const Player* Creature::GetLootRecipient() const { if (!m_lootRecipient) - return NULL; + return nullptr; return ObjectAccessor::FindConnectedPlayer(m_lootRecipient); } Group* Creature::GetLootRecipientGroup() const { if (!m_lootRecipientGroup) - return NULL; + return nullptr; return sGroupMgr->GetGroupByGUID(m_lootRecipientGroup); } @@ -983,7 +1000,7 @@ void Creature::SetLootRecipient(Unit* unit) { // set the player whose group should receive the right // to loot the creature after it dies - // should be set to NULL after the loot disappears + // should be set to nullptr after the loot disappears if (!unit) { @@ -1356,8 +1373,8 @@ bool Creature::LoadCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool ad m_deathState = DEAD; if (CanFly()) { - float tz = map->GetHeight(GetPhaseMask(), data->posX, data->posY, data->posZ, false); - if (data->posZ - tz > 0.1f) + float tz = map->GetHeight(GetPhaseMask(), data->posX, data->posY, data->posZ, true, MAX_FALL_DISTANCE); + if (data->posZ - tz > 0.1f && Trinity::IsValidMapCoord(tz)) Relocate(data->posX, data->posY, tz); } } @@ -1607,7 +1624,7 @@ void Creature::setDeathState(DeathState s) if (sWorld->getBoolConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY) || isWorldBoss()) SaveRespawnTime(); - ReleaseFocus(); // remove spellcast focus (this also clears unit target) + ReleaseFocus(nullptr, false); // remove spellcast focus SetTarget(ObjectGuid::Empty); // drop target - dead mobs shouldn't ever target things SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); @@ -1619,7 +1636,7 @@ void Creature::setDeathState(DeathState s) if (HasSearchedAssistance()) { SetNoSearchAssistance(false); - UpdateSpeed(MOVE_RUN, false); + UpdateSpeed(MOVE_RUN); } //Dismiss group if is leader @@ -1636,7 +1653,7 @@ void Creature::setDeathState(DeathState s) //if (IsPet()) // setActive(true); SetFullHealth(); - SetLootRecipient(NULL); + SetLootRecipient(nullptr); ResetPlayerDamageReq(); UpdateMovementFlags(); @@ -1706,7 +1723,7 @@ void Creature::Respawn(bool force) { SetDisplayId(displayID); SetNativeDisplayId(displayID); - SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); } GetMotionMaster()->InitDefault(); @@ -1716,7 +1733,7 @@ void Creature::Respawn(bool force) { //reset the AI to be sure no dirty or uninitialized values will be used till next tick AI()->Reset(); - TriggerJustRespawned = true;//delay event to next tick so all creatures are created on the map before processing + m_TriggerJustRespawned = true;//delay event to next tick so all creatures are created on the map before processing } uint32 poolid = GetSpawnId() ? sPoolMgr->IsPartOfAPool<Creature>(GetSpawnId()) : 0; @@ -1813,7 +1830,7 @@ bool Creature::isWorldBoss() const SpellInfo const* Creature::reachWithSpellAttack(Unit* victim) { if (!victim) - return NULL; + return nullptr; for (uint32 i=0; i < CREATURE_MAX_SPELLS; ++i) { @@ -1855,13 +1872,13 @@ SpellInfo const* Creature::reachWithSpellAttack(Unit* victim) continue; return spellInfo; } - return NULL; + return nullptr; } SpellInfo const* Creature::reachWithSpellCure(Unit* victim) { if (!victim) - return NULL; + return nullptr; for (uint32 i=0; i < CREATURE_MAX_SPELLS; ++i) { @@ -1902,7 +1919,7 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim) continue; return spellInfo; } - return NULL; + return nullptr; } // select nearest hostile unit within the given distance (regardless of threat list). @@ -1912,7 +1929,7 @@ Unit* Creature::SelectNearestTarget(float dist, bool playerOnly /* = false */) c Cell cell(p); cell.SetNoCreate(); - Unit* target = NULL; + Unit* target = nullptr; { if (dist == 0.0f) @@ -1938,7 +1955,7 @@ Unit* Creature::SelectNearestTargetInAttackDistance(float dist) const Cell cell(p); cell.SetNoCreate(); - Unit* target = NULL; + Unit* target = nullptr; if (dist > MAX_VISIBILITY_DISTANCE) { @@ -1962,7 +1979,7 @@ Unit* Creature::SelectNearestTargetInAttackDistance(float dist) const Player* Creature::SelectNearestPlayer(float distance) const { - Player* target = NULL; + Player* target = nullptr; Trinity::NearestPlayerInObjectRangeCheck checker(this, distance); Trinity::PlayerLastSearcher<Trinity::NearestPlayerInObjectRangeCheck> searcher(this, target, checker); @@ -2259,7 +2276,7 @@ void Creature::SendZoneUnderAttackMessage(Player* attacker) WorldPacket data(SMSG_ZONE_UNDER_ATTACK, 4); data << (uint32)GetAreaId(); - sWorld->SendGlobalMessage(&data, NULL, (enemy_team == ALLIANCE ? HORDE : ALLIANCE)); + sWorld->SendGlobalMessage(&data, nullptr, (enemy_team == ALLIANCE ? HORDE : ALLIANCE)); } void Creature::SetInCombatWithZone() @@ -2756,13 +2773,13 @@ void Creature::SetTarget(ObjectGuid guid) bool Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) { // already focused - if (_focusSpell) + if (m_focusSpell) return false; if ((!target || target == this) && !focusSpell->GetCastTime()) // instant cast, untargeted (or self-targeted) spell doesn't need any facing updates return false; - _focusSpell = focusSpell; + m_focusSpell = focusSpell; // "instant" creature casts that require re-targeting will be delayed by a short moment to prevent facing bugs bool shouldDelay = false; @@ -2774,43 +2791,39 @@ bool Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) SetGuidValue(UNIT_FIELD_TARGET, newTarget); if (target) SetFacingToObject(target); - + if ( // here we determine if the (relatively expensive) forced update is worth it, or whether we can afford to wait until the scheduled update tick ( // only require instant update for spells that actually have a visual focusSpell->GetSpellInfo()->SpellVisual[0] || focusSpell->GetSpellInfo()->SpellVisual[1] - ) && ( + ) && ( !focusSpell->GetCastTime() || // if the spell is instant cast focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST) // client gets confused if we attempt to turn at the regularly scheduled update packet ) ) { - const MapRefManager& mapPlayers = GetMap()->GetPlayers(); - for (MapRefManager::const_iterator it = mapPlayers.begin(); it != mapPlayers.end(); ++it) - if (Player* player = (*it).GetSource()) + std::list<Player*> playersNearby; + GetPlayerListInGrid(playersNearby, GetVisibilityRange()); + for (Player* player : playersNearby) + { + // only update players that are known to the client (have already been created) + if (player->HaveAtClient(this)) { - // only update players that can both see us, and are actually in combat with us (this is a performance tradeoff) - if (player->CanSeeOrDetect(this, false, true) && IsInCombatWith(player)) - { - SendUpdateToPlayer(player); - shouldDelay = true; - } + SendUpdateToPlayer(player); + shouldDelay = true; } + } if (shouldDelay) shouldDelay = !(focusSpell->IsTriggered() || focusSpell->GetCastTime() || focusSpell->GetSpellInfo()->IsChanneled()); - } } - // tell the creature that it should reacquire its current target after the cast is done (this is handled in ::Attack) - MustReacquireTarget(); - bool canTurnDuringCast = !focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST); // Face the target - we need to do this before the unit state is modified for no-turn spells if (target) SetInFront(target); else if (!canTurnDuringCast) - if(Unit* victim = GetVictim()) + if (Unit* victim = GetVictim()) SetInFront(victim); // ensure server-side orientation is correct at beginning of cast if (!canTurnDuringCast) @@ -2827,16 +2840,16 @@ bool Creature::IsFocusing(Spell const* focusSpell, bool withDelay) return false; } - if (focusSpell && (focusSpell != _focusSpell)) + if (focusSpell && (focusSpell != m_focusSpell)) return false; - if (!_focusSpell) + if (!m_focusSpell) { - if (!withDelay || !_focusDelay) + if (!withDelay || !m_focusDelay) return false; - if (GetMSTimeDiffToNow(_focusDelay) > 1000) // @todo figure out if we can get rid of this magic number somehow + if (GetMSTimeDiffToNow(m_focusDelay) > 1000) // @todo figure out if we can get rid of this magic number somehow { - _focusDelay = 0; // save checks in the future + m_focusDelay = 0; // save checks in the future return false; } } @@ -2846,20 +2859,25 @@ bool Creature::IsFocusing(Spell const* focusSpell, bool withDelay) void Creature::ReleaseFocus(Spell const* focusSpell, bool withDelay) { - if (!_focusSpell) + if (!m_focusSpell) return; // focused to something else - if (focusSpell && focusSpell != _focusSpell) + if (focusSpell && focusSpell != m_focusSpell) return; - SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty); + if (IsPet()) // player pets do not use delay system + SetGuidValue(UNIT_FIELD_TARGET, GetVictim() ? EnsureVictim()->GetGUID() : ObjectGuid::Empty); + else + // tell the creature that it should reacquire its actual target after the delay expires (this is handled in ::Attack) + // player pets don't need to do this, as they automatically reacquire their target on focus release + MustReacquireTarget(); - if (_focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST)) + if (m_focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST)) ClearUnitState(UNIT_STATE_CANNOT_TURN); - _focusSpell = nullptr; - _focusDelay = withDelay ? getMSTime() : 0; // don't allow re-target right away to prevent visual bugs + m_focusSpell = nullptr; + m_focusDelay = (!IsPet() && withDelay) ? getMSTime() : 0; // don't allow re-target right away to prevent visual bugs } void Creature::StartPickPocketRefillTimer() diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 0803345f4f0..8466dad9e95 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -75,7 +75,7 @@ enum CreatureFlagsExtra #define CREATURE_MAX_SPELLS 8 // from `creature_template` table -struct CreatureTemplate +struct TC_GAME_API CreatureTemplate { uint32 Entry; uint32 DifficultyEntry[MAX_DIFFICULTY - 1]; @@ -179,7 +179,7 @@ typedef std::unordered_map<uint32, CreatureTemplate> CreatureTemplateContainer; #pragma pack(push, 1) // Defines base stats for creatures (used to calculate HP/mana/armor/attackpower/rangedattackpower/all damage). -struct CreatureBaseStats +struct TC_GAME_API CreatureBaseStats { uint32 BaseHealth[MAX_EXPANSIONS]; uint32 BaseMana; @@ -401,7 +401,7 @@ struct TrainerSpell typedef std::unordered_map<uint32 /*spellid*/, TrainerSpell> TrainerSpellMap; -struct TrainerSpellData +struct TC_GAME_API TrainerSpellData { TrainerSpellData() : trainerType(0) { } ~TrainerSpellData() { spellList.clear(); } @@ -421,7 +421,7 @@ struct TrainerSpellData typedef std::vector<uint8> CreatureTextRepeatIds; typedef std::unordered_map<uint8, CreatureTextRepeatIds> CreatureTextRepeatGroup; -class Creature : public Unit, public GridObject<Creature>, public MapObject +class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public MapObject { public: @@ -476,6 +476,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject bool IsInEvadeMode() const { return HasUnitState(UNIT_STATE_EVADE); } + bool AIM_Destroy(); bool AIM_Initialize(CreatureAI* ai = NULL); void Motion_Initialize(); @@ -746,15 +747,15 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject //Formation var CreatureGroup* m_formation; - bool TriggerJustRespawned; + bool m_TriggerJustRespawned; - Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing - uint32 _focusDelay; + Spell const* m_focusSpell; ///> Locks the target during spell cast for proper facing + uint32 m_focusDelay; CreatureTextRepeatGroup m_textRepeat; }; -class AssistDelayEvent : public BasicEvent +class TC_GAME_API AssistDelayEvent : public BasicEvent { public: AssistDelayEvent(ObjectGuid victim, Unit& owner) : BasicEvent(), m_victim(victim), m_owner(owner) { } @@ -769,7 +770,7 @@ class AssistDelayEvent : public BasicEvent Unit& m_owner; }; -class ForcedDespawnDelayEvent : public BasicEvent +class TC_GAME_API ForcedDespawnDelayEvent : public BasicEvent { public: ForcedDespawnDelayEvent(Creature& owner) : BasicEvent(), m_owner(owner) { } diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index 9f26c927374..0c41089efce 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -30,6 +30,12 @@ FormationMgr::~FormationMgr() delete itr->second; } +FormationMgr* FormationMgr::instance() +{ + static FormationMgr instance; + return &instance; +} + void FormationMgr::AddCreatureToGroup(uint32 leaderGuid, Creature* creature) { Map* map = creature->FindMap(); diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h index 7b16585a996..14472a30293 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.h +++ b/src/server/game/Entities/Creature/CreatureGroups.h @@ -38,18 +38,14 @@ struct FormationInfo typedef std::unordered_map<uint32/*memberDBGUID*/, FormationInfo*> CreatureGroupInfoType; -class FormationMgr +class TC_GAME_API FormationMgr { private: FormationMgr() { } ~FormationMgr(); public: - static FormationMgr* instance() - { - static FormationMgr instance; - return &instance; - } + static FormationMgr* instance(); void AddCreatureToGroup(uint32 group_id, Creature* creature); void RemoveCreatureFromGroup(CreatureGroup* group, Creature* creature); @@ -57,7 +53,7 @@ class FormationMgr CreatureGroupInfoType CreatureGroupMap; }; -class CreatureGroup +class TC_GAME_API CreatureGroup { private: Creature* m_leader; //Important do not forget sometimes to work with pointers instead synonims :D:D diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h index 1e64e83c86a..01b27032286 100644 --- a/src/server/game/Entities/Creature/GossipDef.h +++ b/src/server/game/Entities/Creature/GossipDef.h @@ -157,7 +157,7 @@ struct QuestMenuItem typedef std::vector<QuestMenuItem> QuestMenuItemList; -class GossipMenu +class TC_GAME_API GossipMenu { public: GossipMenu(); @@ -222,7 +222,7 @@ class GossipMenu LocaleConstant _locale; }; -class QuestMenu +class TC_GAME_API QuestMenu { public: QuestMenu(); @@ -252,7 +252,7 @@ class QuestMenu QuestMenuItemList _questMenuItems; }; -class PlayerMenu +class TC_GAME_API PlayerMenu { public: explicit PlayerMenu(WorldSession* session); diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index 8bf3a1e2846..12e3af3c290 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -227,6 +227,11 @@ void TempSummon::InitSummon() } } +void TempSummon::UpdateObjectVisibilityOnCreate() +{ + WorldObject::UpdateObjectVisibility(true); +} + void TempSummon::SetTempSummonType(TempSummonType type) { m_type = type; diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index 6d058f405a8..87cb883b261 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -37,7 +37,7 @@ struct TempSummonData uint32 time; ///< Despawn time, usable only with certain temp summon types }; -class TempSummon : public Creature +class TC_GAME_API TempSummon : public Creature { public: explicit TempSummon(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject); @@ -45,6 +45,7 @@ class TempSummon : public Creature void Update(uint32 time) override; virtual void InitStats(uint32 lifetime); virtual void InitSummon(); + void UpdateObjectVisibilityOnCreate() override; virtual void UnSummon(uint32 msTime = 0); void RemoveFromWorld() override; void SetTempSummonType(TempSummonType type); @@ -63,7 +64,7 @@ class TempSummon : public Creature ObjectGuid m_summonerGUID; }; -class Minion : public TempSummon +class TC_GAME_API Minion : public TempSummon { public: Minion(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject); @@ -81,7 +82,7 @@ class Minion : public TempSummon float m_followAngle; }; -class Guardian : public Minion +class TC_GAME_API Guardian : public Minion { public: Guardian(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject); @@ -105,7 +106,7 @@ class Guardian : public Minion float m_statFromOwner[MAX_STATS]; }; -class Puppet : public Minion +class TC_GAME_API Puppet : public Minion { public: Puppet(SummonPropertiesEntry const* properties, Unit* owner); @@ -115,7 +116,7 @@ class Puppet : public Minion void RemoveFromWorld() override; }; -class ForcedUnsummonDelayEvent : public BasicEvent +class TC_GAME_API ForcedUnsummonDelayEvent : public BasicEvent { public: ForcedUnsummonDelayEvent(TempSummon& owner) : BasicEvent(), m_owner(owner) { } diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h index 9443a5b5b89..d7c1f0190fd 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.h +++ b/src/server/game/Entities/DynamicObject/DynamicObject.h @@ -32,7 +32,7 @@ enum DynamicObjectType DYNAMIC_OBJECT_FARSIGHT_FOCUS = 0x2 }; -class DynamicObject : public WorldObject, public GridObject<DynamicObject>, public MapObject +class TC_GAME_API DynamicObject : public WorldObject, public GridObject<DynamicObject>, public MapObject { public: DynamicObject(bool isWorldObject); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 1acfeacbf83..7f922f89572 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -71,9 +71,15 @@ GameObject::~GameObject() // CleanupsBeforeDelete(); } -bool GameObject::AIM_Initialize() +void GameObject::AIM_Destroy() { delete m_AI; + m_AI = nullptr; +} + +bool GameObject::AIM_Initialize() +{ + AIM_Destroy(); m_AI = FactorySelector::SelectGameObjectAI(this); @@ -1282,8 +1288,8 @@ void GameObject::Use(Unit* user) { if (Player* ChairUser = ObjectAccessor::FindPlayer(itr->second)) { - if (ChairUser->IsSitState() && ChairUser->getStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f) - continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->getStandState() != UNIT_STAND_STATE_SIT check is required. + if (ChairUser->IsSitState() && ChairUser->GetStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f) + continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->GetStandState() != UNIT_STAND_STATE_SIT check is required. else itr->second.Clear(); // This seat is unoccupied. } diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 7be78556a50..2b092427178 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -640,7 +640,7 @@ class GameObjectModel; // 5 sec for bobber catch #define FISHING_BOBBER_READY_TIME 5 -class GameObject : public WorldObject, public GridObject<GameObject>, public MapObject +class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>, public MapObject { public: explicit GameObject(); @@ -849,8 +849,10 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map void UpdateModelPosition(); - protected: + void AIM_Destroy(); bool AIM_Initialize(); + + protected: GameObjectModel* CreateModel(); void UpdateModel(); // updates model in case displayId were changed uint32 m_spellId; diff --git a/src/server/game/Entities/Item/Container/Bag.h b/src/server/game/Entities/Item/Container/Bag.h index 5bfafa4238c..89615f94e52 100644 --- a/src/server/game/Entities/Item/Container/Bag.h +++ b/src/server/game/Entities/Item/Container/Bag.h @@ -25,7 +25,7 @@ #include "Item.h" #include "ItemPrototype.h" -class Bag : public Item +class TC_GAME_API Bag : public Item { public: diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 378d7f5e2e4..8658200c28c 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -203,7 +203,7 @@ enum ItemUpdateState bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto); -class Item : public Object +class TC_GAME_API Item : public Object { public: static Item* CreateItem(uint32 itemEntry, uint32 count, Player const* player = NULL); diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp index a7b410bc04b..b44a3e7ad7b 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp @@ -44,7 +44,7 @@ typedef std::unordered_map<uint32, EnchStoreList> EnchantmentStore; static EnchantmentStore RandomItemEnch; -void LoadRandomEnchantmentsTable() +TC_GAME_API void LoadRandomEnchantmentsTable() { uint32 oldMSTime = getMSTime(); @@ -77,7 +77,7 @@ void LoadRandomEnchantmentsTable() TC_LOG_ERROR("server.loading", ">> Loaded 0 Item Enchantment definitions. DB table `item_enchantment_template` is empty."); } -uint32 GetItemEnchantMod(int32 entry) +TC_GAME_API uint32 GetItemEnchantMod(int32 entry) { if (!entry) return 0; @@ -118,7 +118,7 @@ uint32 GetItemEnchantMod(int32 entry) return 0; } -uint32 GenerateEnchSuffixFactor(uint32 item_id) +TC_GAME_API uint32 GenerateEnchSuffixFactor(uint32 item_id) { ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_id); diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.h b/src/server/game/Entities/Item/ItemEnchantmentMgr.h index 2d5c27177b1..8ce9ae780fe 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.h +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.h @@ -21,8 +21,9 @@ #include "Common.h" -void LoadRandomEnchantmentsTable(); -uint32 GetItemEnchantMod(int32 entry); -uint32 GenerateEnchSuffixFactor(uint32 item_id); +TC_GAME_API void LoadRandomEnchantmentsTable(); +TC_GAME_API uint32 GetItemEnchantMod(int32 entry); +TC_GAME_API uint32 GenerateEnchSuffixFactor(uint32 item_id); + #endif diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 4877ff094e1..45952ba51ac 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -221,7 +221,10 @@ void Object::SendUpdateToPlayer(Player* player) UpdateData upd; WorldPacket packet; - BuildCreateUpdateBlockForPlayer(&upd, player); + if (player->HaveAtClient(this)) + BuildValuesUpdateBlockForPlayer(&upd, player); + else + BuildCreateUpdateBlockForPlayer(&upd, player); upd.BuildPacket(&packet); player->GetSession()->SendPacket(&packet); } @@ -925,6 +928,11 @@ bool Object::HasByteFlag(uint16 index, uint8 offset, uint8 flag) const return (((uint8*)&m_uint32Values[index])[offset] & flag) != 0; } +void Object::ApplyModByteFlag(uint16 index, uint8 offset, uint8 flag, bool apply) +{ + if (apply) SetByteFlag(index, offset, flag); else RemoveByteFlag(index, offset, flag); +} + void Object::SetFlag64(uint16 index, uint64 newFlag) { uint64 oldval = GetUInt64Value(index); @@ -1462,9 +1470,20 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const float WorldObject::GetGridActivationRange() const { if (ToPlayer()) + { + if (ToPlayer()->IsOnCinematic()) + return DEFAULT_VISIBILITY_INSTANCE; return GetMap()->GetVisibilityRange(); + } else if (ToCreature()) return ToCreature()->m_SightDistance; + else if (ToDynObject()) + { + if (isActiveObject()) + return GetMap()->GetVisibilityRange(); + else + return 0.0f; + } else return 0.0f; } @@ -1485,6 +1504,8 @@ float WorldObject::GetSightRange(const WorldObject* target) const { if (target && target->isActiveObject() && !target->ToPlayer()) return MAX_VISIBILITY_DISTANCE; + else if (ToPlayer()->IsOnCinematic()) + return DEFAULT_VISIBILITY_INSTANCE; else return GetMap()->GetVisibilityRange(); } @@ -1494,6 +1515,11 @@ float WorldObject::GetSightRange(const WorldObject* target) const return SIGHT_RANGE_UNIT; } + if (ToDynObject() && isActiveObject()) + { + return GetMap()->GetVisibilityRange(); + } + return 0.0f; } @@ -1878,7 +1904,9 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert AddToMap(summon->ToCreature()); summon->InitSummon(); - //ObjectAccessor::UpdateObjectVisibility(summon); + // call MoveInLineOfSight for nearby creatures + Trinity::AIRelocationNotifier notifier(*summon); + summon->VisitNearbyObject(GetVisibilityRange(), notifier); return summon; } diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 419044081e3..d4c8fc35451 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -90,7 +90,7 @@ class ZoneScript; typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType; -class Object +class TC_GAME_API Object { public: virtual ~Object(); @@ -160,6 +160,7 @@ class Object void RemoveByteFlag(uint16 index, uint8 offset, uint8 newFlag); void ToggleByteFlag(uint16 index, uint8 offset, uint8 flag); bool HasByteFlag(uint16 index, uint8 offset, uint8 flag) const; + void ApplyModByteFlag(uint16 index, uint8 offset, uint8 flag, bool apply); void SetFlag64(uint16 index, uint64 newFlag); void RemoveFlag64(uint16 index, uint64 oldFlag); @@ -397,7 +398,7 @@ enum MapObjectCellMoveState MAP_OBJECT_CELL_MOVE_INACTIVE, //in move list but should not move }; -class MapObject +class TC_GAME_API MapObject { friend class Map; //map for moving creatures friend class ObjectGridLoader; //grid loader for loading creatures @@ -422,7 +423,7 @@ class MapObject } }; -class WorldObject : public Object, public WorldLocation +class TC_GAME_API WorldObject : public Object, public WorldLocation { protected: explicit WorldObject(bool isWorldObject); //note: here it means if it is in grid object list or world object list @@ -555,6 +556,11 @@ class WorldObject : public Object, public WorldLocation void DestroyForNearbyPlayers(); virtual void UpdateObjectVisibility(bool forced = true); + virtual void UpdateObjectVisibilityOnCreate() + { + UpdateObjectVisibility(true); + } + void BuildUpdate(UpdateDataMapType&) override; void AddToObjectUpdate() override; diff --git a/src/server/game/Entities/Object/ObjectGuid.cpp b/src/server/game/Entities/Object/ObjectGuid.cpp index 3e2bd000b6e..2fb766c5201 100644 --- a/src/server/game/Entities/Object/ObjectGuid.cpp +++ b/src/server/game/Entities/Object/ObjectGuid.cpp @@ -95,4 +95,19 @@ void ObjectGuidGeneratorBase::HandleCounterOverflow(HighGuid high) { TC_LOG_ERROR("misc", "%s guid overflow!! Can't continue, shutting down server. ", ObjectGuid::GetTypeName(high)); World::StopNow(ERROR_EXIT_CODE); -}
\ No newline at end of file +} + +#define GUID_TRAIT_INSTANTIATE_GUID( HIGH_GUID ) \ + template class TC_GAME_API ObjectGuidGenerator< HIGH_GUID >; + +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::Container) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::Player) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::GameObject) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::Transport) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::Unit) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::Pet) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::Vehicle) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::DynamicObject) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::Mo_Transport) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::Instance) +GUID_TRAIT_INSTANTIATE_GUID(HighGuid::Group) diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h index 44644421567..71c66622790 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -111,7 +111,7 @@ struct PackedGuidReader ObjectGuid* GuidPtr; }; -class ObjectGuid +class TC_GAME_API ObjectGuid { public: static ObjectGuid const Empty; @@ -252,9 +252,9 @@ typedef std::unordered_set<ObjectGuid> GuidUnorderedSet; // minimum buffer size for packed guid is 9 bytes #define PACKED_GUID_MIN_BUFFER_SIZE 9 -class PackedGuid +class TC_GAME_API PackedGuid { - friend ByteBuffer& operator<<(ByteBuffer& buf, PackedGuid const& guid); + friend TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, PackedGuid const& guid); public: explicit PackedGuid() : _packedGuid(PACKED_GUID_MIN_BUFFER_SIZE) { _packedGuid.appendPackGUID(0); } @@ -270,8 +270,7 @@ class PackedGuid ByteBuffer _packedGuid; }; - -class ObjectGuidGeneratorBase +class TC_GAME_API ObjectGuidGeneratorBase { public: ObjectGuidGeneratorBase(ObjectGuid::LowType start = 1) : _nextGuid(start) { } @@ -286,7 +285,7 @@ protected: }; template<HighGuid high> -class ObjectGuidGenerator : public ObjectGuidGeneratorBase +class TC_GAME_API ObjectGuidGenerator : public ObjectGuidGeneratorBase { public: explicit ObjectGuidGenerator(ObjectGuid::LowType start = 1) : ObjectGuidGeneratorBase(start) { } @@ -299,11 +298,11 @@ public: } }; -ByteBuffer& operator<<(ByteBuffer& buf, ObjectGuid const& guid); -ByteBuffer& operator>>(ByteBuffer& buf, ObjectGuid& guid); +TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, ObjectGuid const& guid); +TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, ObjectGuid& guid); -ByteBuffer& operator<<(ByteBuffer& buf, PackedGuid const& guid); -ByteBuffer& operator>>(ByteBuffer& buf, PackedGuidReader const& guid); +TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, PackedGuid const& guid); +TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, PackedGuidReader const& guid); inline PackedGuid ObjectGuid::WriteAsPacked() const { return PackedGuid(*this); } diff --git a/src/server/game/Entities/Object/ObjectPosSelector.h b/src/server/game/Entities/Object/ObjectPosSelector.h index 26a23678009..84c694abf08 100644 --- a/src/server/game/Entities/Object/ObjectPosSelector.h +++ b/src/server/game/Entities/Object/ObjectPosSelector.h @@ -30,7 +30,7 @@ inline UsedPosType operator ~(UsedPosType uptype) return uptype==USED_POS_PLUS ? USED_POS_MINUS : USED_POS_PLUS; } -struct ObjectPosSelector +struct TC_GAME_API ObjectPosSelector { struct UsedPos { diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h index 18d356c28d4..6325cc51fe2 100644 --- a/src/server/game/Entities/Object/Position.h +++ b/src/server/game/Entities/Object/Position.h @@ -22,7 +22,7 @@ class ByteBuffer; -struct Position +struct TC_GAME_API Position { Position(float x = 0, float y = 0, float z = 0, float o = 0) : m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { } @@ -216,11 +216,11 @@ public: } }; -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); +TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); +TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); +TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); +TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); +TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); +TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); #endif // Trinity_game_Position_h__ diff --git a/src/server/game/Entities/Object/Updates/UpdateFieldFlags.h b/src/server/game/Entities/Object/Updates/UpdateFieldFlags.h index 0b4e59f4f9b..8208a5e9894 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFieldFlags.h +++ b/src/server/game/Entities/Object/Updates/UpdateFieldFlags.h @@ -35,10 +35,10 @@ enum UpdatefieldFlags UF_FLAG_DYNAMIC = 0x100 }; -extern uint32 ItemUpdateFieldFlags[CONTAINER_END]; -extern uint32 UnitUpdateFieldFlags[PLAYER_END]; -extern uint32 GameObjectUpdateFieldFlags[GAMEOBJECT_END]; -extern uint32 DynamicObjectUpdateFieldFlags[DYNAMICOBJECT_END]; -extern uint32 CorpseUpdateFieldFlags[CORPSE_END]; +TC_GAME_API extern uint32 ItemUpdateFieldFlags[CONTAINER_END]; +TC_GAME_API extern uint32 UnitUpdateFieldFlags[PLAYER_END]; +TC_GAME_API extern uint32 GameObjectUpdateFieldFlags[GAMEOBJECT_END]; +TC_GAME_API extern uint32 DynamicObjectUpdateFieldFlags[DYNAMICOBJECT_END]; +TC_GAME_API extern uint32 CorpseUpdateFieldFlags[CORPSE_END]; #endif // _UPDATEFIELDFLAGS_H diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 0da63c5e500..37fb23b38f5 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -213,12 +213,14 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c case SUMMON_PET: petlevel = owner->getLevel(); - SetUInt32Value(UNIT_FIELD_BYTES_0, 0x800); // class = mage + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, uint8(CLASS_MAGE)); SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet dismiss, cancel) break; case HUNTER_PET: - SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); // class = warrior, gender = none, power = focus + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, CLASS_WARRIOR); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, GENDER_NONE); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE, POWER_FOCUS); SetSheath(SHEATH_STATE_MELEE); SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED); @@ -226,7 +228,6 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c // this enables popup window (pet abandon, cancel) SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); SetPower(POWER_HAPPINESS, fields[12].GetUInt32()); - setPowerType(POWER_FOCUS); break; default: if (!IsPetGhoul()) @@ -822,7 +823,9 @@ bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phas if (cinfo->type == CREATURE_TYPE_BEAST) { - SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, CLASS_WARRIOR); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, GENDER_NONE); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE, POWER_FOCUS); SetSheath(SHEATH_STATE_MELEE); SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED); } diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index b0863a371e6..3a65fb44e04 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -37,7 +37,7 @@ typedef std::vector<uint32> AutoSpellList; class Player; -class Pet : public Guardian +class TC_GAME_API Pet : public Guardian { public: explicit Pet(Player* owner, PetType type = MAX_PET_TYPE); diff --git a/src/server/game/Entities/Player/KillRewarder.h b/src/server/game/Entities/Player/KillRewarder.h index 08530de900c..210e5ff0246 100644 --- a/src/server/game/Entities/Player/KillRewarder.h +++ b/src/server/game/Entities/Player/KillRewarder.h @@ -24,7 +24,7 @@ class Player; class Unit; class Group; -class KillRewarder +class TC_GAME_API KillRewarder { public: KillRewarder(Player* killer, Unit* victim, bool isBattleGround); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index cbf29980057..c58f2c940fc 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -96,6 +96,9 @@ #define SKILL_PERM_BONUS(x) int16(PAIR32_HIPART(x)) #define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p) +#define CINEMATIC_LOOKAHEAD (2 * IN_MILLISECONDS) +#define CINEMATIC_UPDATEDIFF 500 + enum CharacterFlags { CHARACTER_FLAG_NONE = 0x00000000, @@ -306,7 +309,7 @@ Player::Player(WorldSession* session): Unit(true) m_ExtraFlags = 0; - m_spellModTakingSpell = NULL; + m_spellModTakingSpell = nullptr; //m_pad = 0; // players always accept @@ -332,19 +335,17 @@ Player::Player(WorldSession* session): Unit(true) m_nextSave = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE); - clearResurrectRequestData(); - memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT); - m_social = NULL; + m_social = nullptr; // group is initialized in the reference constructor - SetGroupInvite(NULL); + SetGroupInvite(nullptr); m_groupUpdateMask = 0; m_auraRaidUpdateMask = 0; m_bPassOnGroupLoot = false; - duel = NULL; + duel = nullptr; m_GuildIdInvited = 0; m_ArenaTeamIdInvited = 0; @@ -359,7 +360,7 @@ Player::Player(WorldSession* session): Unit(true) m_bHasDelayedTeleport = false; m_teleport_options = 0; - m_trade = NULL; + m_trade = nullptr; m_cinematic = 0; @@ -394,7 +395,7 @@ Player::Player(WorldSession* session): Unit(true) m_bgBattlegroundQueueID[j].invitedToInstance = 0; } - m_logintime = time(NULL); + m_logintime = time(nullptr); m_Last_tick = m_logintime; m_Played_time[PLAYED_TIME_TOTAL] = 0; m_Played_time[PLAYED_TIME_LEVEL] = 0; @@ -470,7 +471,7 @@ Player::Player(WorldSession* session): Unit(true) m_spellPenetrationItemMod = 0; // Honor System - m_lastHonorUpdateTime = time(NULL); + m_lastHonorUpdateTime = time(nullptr); m_IsBGRandomWinner = false; @@ -499,11 +500,11 @@ Player::Player(WorldSession* session): Unit(true) m_contestedPvPTimer = 0; - m_declinedname = NULL; + m_declinedname = nullptr; m_isActive = true; - m_runes = NULL; + m_runes = nullptr; m_lastFallTime = 0; m_lastFallZ = 0; @@ -537,13 +538,21 @@ Player::Player(WorldSession* session): Unit(true) _activeCheats = CHEAT_NONE; healthBeforeDuel = 0; manaBeforeDuel = 0; + + m_cinematicDiff = 0; + m_lastCinematicCheck = 0; + m_activeCinematicCameraId = 0; + m_cinematicCamera = nullptr; + m_remoteSightPosition = Position(0.0f, 0.0f, 0.0f); + m_CinematicObject = nullptr; + m_achievementMgr = new AchievementMgr(this); m_reputationMgr = new ReputationMgr(this); } Player::~Player() { - // it must be unloaded already in PlayerLogout and accessed only for loggined player + // it must be unloaded already in PlayerLogout and accessed only for logged in player //m_social = NULL; // Note: buy back item already deleted from DB when player was saved @@ -611,7 +620,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo } for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; i++) - m_items[i] = NULL; + m_items[i] = nullptr; Relocate(info->positionX, info->positionY, info->positionZ, info->orientation); @@ -645,9 +654,10 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo return false; } - uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Gender << 16); - - SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24))); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_RACE, createInfo->Race); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, createInfo->Class); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, createInfo->Gender); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE, powertype); InitDisplayIds(); if (sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP) { @@ -660,13 +670,14 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); // -1 is default value - SetUInt32Value(PLAYER_BYTES, (createInfo->Skin | (createInfo->Face << 8) | (createInfo->HairStyle << 16) | (createInfo->HairColor << 24))); - SetUInt32Value(PLAYER_BYTES_2, (createInfo->FacialHair | - (0x00 << 8) | - (0x00 << 16) | - (((GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0) ? REST_STATE_RAF_LINKED : REST_STATE_NOT_RAF_LINKED) << 24))); - SetByteValue(PLAYER_BYTES_3, 0, createInfo->Gender); - SetByteValue(PLAYER_BYTES_3, 3, 0); // BattlefieldArenaFaction (0 or 1) + SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID, createInfo->Skin); + SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID, createInfo->Face); + SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID, createInfo->HairStyle); + SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID, createInfo->HairColor); + SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE, createInfo->FacialHair); + SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE, (GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0) ? REST_STATE_RAF_LINKED : REST_STATE_NOT_RAF_LINKED); + SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER, createInfo->Gender); + SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_ARENA_FACTION, 0); SetUInt32Value(PLAYER_GUILDID, 0); SetUInt32Value(PLAYER_GUILDRANK, 0); @@ -752,7 +763,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo } // Played time - m_Last_tick = time(NULL); + m_Last_tick = time(nullptr); m_Played_time[PLAYED_TIME_TOTAL] = 0; m_Played_time[PLAYED_TIME_LEVEL] = 0; @@ -851,7 +862,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo if (msg == EQUIP_ERR_OK) { RemoveItem(INVENTORY_SLOT_BAG_0, i, true); - pItem = StoreItem(sDest, pItem, true); + StoreItem(sDest, pItem, true); } // if this is ammo then use it @@ -868,7 +879,8 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo bool Player::StoreNewItemInBestSlots(uint32 titem_id, uint32 titem_amount) { - TC_LOG_DEBUG("entities.player.items", "STORAGE: Creating initial item, itemId = %u, count = %u", titem_id, titem_amount); + TC_LOG_DEBUG("entities.player.items", "Player::StoreNewItemInBestSlots: Player '%s' (%s) creates initial item (ItemID: %u, Count: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), titem_id, titem_amount); // attempt equip by one while (titem_amount > 0) @@ -897,7 +909,8 @@ bool Player::StoreNewItemInBestSlots(uint32 titem_id, uint32 titem_amount) } // item can't be added - TC_LOG_ERROR("entities.player.items", "STORAGE: Can't equip or store initial item %u for race %u class %u, error msg = %u", titem_id, getRace(), getClass(), msg); + TC_LOG_ERROR("entities.player.items", "Player::StoreNewItemInBestSlots: Player '%s' (%s) can't equip or store initial item (ItemID: %u, Race: %u, Class: %u, InventoryResult: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), titem_id, getRace(), getClass(), msg); return false; } @@ -927,10 +940,10 @@ void Player::StopMirrorTimer(MirrorTimerType Type) GetSession()->SendPacket(&data); } -bool Player::IsImmuneToEnvironmentalDamage() +bool Player::IsImmuneToEnvironmentalDamage() const { // check for GM and death state included in isAttackableByAOE - return (!isTargetableForAttack(false)); + return !isTargetableForAttack(false); } uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) @@ -958,13 +971,14 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) data << uint32(resist); SendMessageToSet(&data, true); - uint32 final_damage = DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + uint32 final_damage = DealDamage(this, damage, nullptr, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); if (!IsAlive()) { if (type == DAMAGE_FALL) // DealDamage does not apply item durability loss from self-induced damage. { - TC_LOG_DEBUG("entities.player", "You have died from falling, losing 10 percent total armor durability."); + TC_LOG_DEBUG("entities.player", "Player::EnvironmentalDamage: Player '%s' (%s) fall to death, losing 10%% durability", + GetName().c_str(), GetGUID().ToString().c_str()); DurabilityLossAll(0.10f, false); // durability lost message WorldPacket data2(SMSG_DURABILITY_DAMAGE_DEATH, 0); @@ -977,7 +991,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) return final_damage; } -int32 Player::getMaxTimer(MirrorTimerType timer) +int32 Player::getMaxTimer(MirrorTimerType timer) const { switch (timer) { @@ -1018,7 +1032,7 @@ void Player::StopMirrorTimers() StopMirrorTimer(FIRE_TIMER); } -bool Player::IsMirrorTimerActive(MirrorTimerType type) +bool Player::IsMirrorTimerActive(MirrorTimerType type) const { return m_MirrorTimer[type] == getMaxTimer(type); } @@ -1178,7 +1192,7 @@ void Player::SetDrunkValue(uint8 newDrunkValue, uint32 itemId /*= 0*/) m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK); uint32 newDrunkenState = Player::GetDrunkenstateByValue(newDrunkValue); - SetByteValue(PLAYER_BYTES_3, 1, newDrunkValue); + SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_INEBRIATION, newDrunkValue); UpdateObjectVisibility(); if (!isSobering) @@ -1200,7 +1214,7 @@ void Player::Update(uint32 p_time) return; // undelivered mail - if (m_nextMailDelivereTime && m_nextMailDelivereTime <= time(NULL)) + if (m_nextMailDelivereTime && m_nextMailDelivereTime <= time(nullptr)) { SendNewMail(); ++unReadMails; @@ -1216,8 +1230,17 @@ void Player::Update(uint32 p_time) { //TC_LOG_FATAL("entities.player", "Player has m_pad %u during update!", m_pad); //if (m_spellModTakingSpell) - TC_LOG_FATAL("spells", "Player has m_spellModTakingSpell %u during update!", m_spellModTakingSpell->m_spellInfo->Id); - m_spellModTakingSpell = NULL; + TC_LOG_FATAL("spells", "Player::Update: Player '%s' (%s) has m_spellModTakingSpell (SpellID: %u) during update!", + GetName().c_str(), GetGUID().ToString().c_str(), m_spellModTakingSpell->m_spellInfo->Id); + m_spellModTakingSpell = nullptr; + } + + // Update cinematic location, if 500ms have passed and we're doing a cinematic now. + m_cinematicDiff += p_time; + if (m_cinematicCamera && m_activeCinematicCameraId && GetMSTimeDiffToNow(m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF) + { + m_lastCinematicCheck = getMSTime(); + UpdateCinematicLocation(p_time); } //used to implement delayed far teleports @@ -1225,7 +1248,7 @@ void Player::Update(uint32 p_time) Unit::Update(p_time); SetCanDelayTeleport(false); - time_t now = time(NULL); + time_t now = time(nullptr); UpdatePvPFlag(now); @@ -1239,6 +1262,12 @@ void Player::Update(uint32 p_time) if (IsAIEnabled && GetAI()) GetAI()->UpdateAI(p_time); + else if (NeedChangeAI) + { + UpdateCharmAI(); + NeedChangeAI = false; + IsAIEnabled = (GetAI() != nullptr); + } // Update items that have just a limited lifetime if (now > m_Last_tick) @@ -1436,7 +1465,7 @@ void Player::Update(uint32 p_time) { // m_nextSave reset in SaveToDB call SaveToDB(); - TC_LOG_DEBUG("entities.player", "Player '%s' (GUID: %u) saved", GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player", "Player::Update: Player '%s' (%s) saved", GetName().c_str(), GetGUID().ToString().c_str()); } else m_nextSave -= p_time; @@ -1546,7 +1575,7 @@ void Player::setDeathState(DeathState s) { if (!cur) { - TC_LOG_ERROR("entities.player", "setDeathState: Attempted to kill a dead player %s(%d)", GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::setDeathState: Attempt to kill a dead player '%s' (%s)", GetName().c_str(), GetGUID().ToString().c_str()); return; } @@ -1555,10 +1584,10 @@ void Player::setDeathState(DeathState s) // lost combo points at any target (targeted combo points clear in Unit::setDeathState) ClearComboPoints(); - clearResurrectRequestData(); + ClearResurrectRequestData(); //FIXME: is pet dismissed at dying or releasing spirit? if second, add setDeathState(DEAD) to HandleRepopRequestOpcode and define pet unsummon here with (s == DEAD) - RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); + RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT, true); // save value before aura remove in Unit::setDeathState ressSpellId = GetUInt32Value(PLAYER_SELF_RES_SPELL); @@ -1587,12 +1616,14 @@ void Player::setDeathState(DeathState s) bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) { - // 0 1 2 3 4 5 6 7 - // "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " - // 8 9 10 11 12 13 14 - // "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " - // 15 16 17 18 19 20 21 - // "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_banned.guid, character_declinedname.genitive " + // 0 1 2 3 4 5 6 7 + // SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.skin, characters.face, characters.hairStyle, + // 8 9 10 11 12 13 14 15 + // characters.hairColor, characters.facialStyle, characters.level, characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, + // 16 17 18 19 20 21 22 + // guild_member.guildid, characters.playerFlags, characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache, + // 23 24 + // character_banned.guid, character_declinedname.genitive Field* fields = result->Fetch(); @@ -1619,12 +1650,15 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) *data << uint8(plrClass); // class *data << uint8(gender); // gender - uint32 playerBytes = fields[5].GetUInt32(); - uint32 playerBytes2 = fields[6].GetUInt32(); + uint8 skin = fields[5].GetUInt8(); + uint8 face = fields[6].GetUInt8(); + uint8 hairStyle = fields[7].GetUInt8(); + uint8 hairColor = fields[8].GetUInt8(); + uint8 facialStyle = fields[9].GetUInt8(); - uint16 atLoginFlags = fields[15].GetUInt16(); + uint16 atLoginFlags = fields[18].GetUInt16(); - if (!ValidateAppearance(uint8(plrRace), uint8(plrClass), gender, uint8(playerBytes >> 16), uint8(playerBytes >> 24), uint8(playerBytes >> 8), uint8(playerBytes2), uint8(playerBytes))) + if (!ValidateAppearance(uint8(plrRace), uint8(plrClass), gender, hairStyle, hairColor, face, facialStyle, skin)) { TC_LOG_ERROR("entities.player.loading", "Player %u has wrong Appearance values (Hair/Skin/Color), forcing recustomize", guid); @@ -1638,25 +1672,24 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) } } - *data << uint8(playerBytes); // skin - *data << uint8(playerBytes >> 8); // face - *data << uint8(playerBytes >> 16); // hair style - *data << uint8(playerBytes >> 24); // hair color + *data << uint8(skin); + *data << uint8(face); + *data << uint8(hairStyle); + *data << uint8(hairColor); + *data << uint8(facialStyle); - *data << uint8(playerBytes2 & 0xFF); // facial hair + *data << uint8(fields[10].GetUInt8()); // level + *data << uint32(fields[11].GetUInt16()); // zone + *data << uint32(fields[12].GetUInt16()); // map - *data << uint8(fields[7].GetUInt8()); // level - *data << uint32(fields[8].GetUInt16()); // zone - *data << uint32(fields[9].GetUInt16()); // map + *data << fields[13].GetFloat(); // x + *data << fields[14].GetFloat(); // y + *data << fields[15].GetFloat(); // z - *data << fields[10].GetFloat(); // x - *data << fields[11].GetFloat(); // y - *data << fields[12].GetFloat(); // z - - *data << uint32(fields[13].GetUInt32()); // guild id + *data << uint32(fields[16].GetUInt32()); // guild id uint32 charFlags = 0; - uint32 playerFlags = fields[14].GetUInt32(); + uint32 playerFlags = fields[17].GetUInt32(); if (atLoginFlags & AT_LOGIN_RESURRECT) playerFlags &= ~PLAYER_FLAGS_GHOST; if (playerFlags & PLAYER_FLAGS_HIDE_HELM) @@ -1667,11 +1700,11 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) charFlags |= CHARACTER_FLAG_GHOST; if (atLoginFlags & AT_LOGIN_RENAME) charFlags |= CHARACTER_FLAG_RENAME; - if (fields[20].GetUInt32()) + if (fields[23].GetUInt32()) charFlags |= CHARACTER_FLAG_LOCKED_BY_BILLING; if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) { - if (!fields[21].GetString().empty()) + if (!fields[24].GetString().empty()) charFlags |= CHARACTER_FLAG_DECLINED; } else @@ -1700,12 +1733,12 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) // show pet at selection character in character list only for non-ghost character if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (plrClass == CLASS_WARLOCK || plrClass == CLASS_HUNTER || plrClass == CLASS_DEATH_KNIGHT)) { - uint32 entry = fields[16].GetUInt32(); + uint32 entry = fields[19].GetUInt32(); CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry); if (creatureInfo) { - petDisplayId = fields[17].GetUInt32(); - petLevel = fields[18].GetUInt16(); + petDisplayId = fields[20].GetUInt32(); + petLevel = fields[21].GetUInt16(); petFamily = creatureInfo->family; } } @@ -1714,7 +1747,7 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) *data << uint32(petLevel); *data << uint32(petFamily); - Tokenizer equipment(fields[19].GetString(), ' '); + Tokenizer equipment(fields[22].GetString(), ' '); for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot) { uint32 visualBase = slot * 2; @@ -1734,7 +1767,7 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot) { // values stored in 2 uint16 - uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot*16); + uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot * 16); if (!enchantId) continue; @@ -1794,14 +1827,14 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati { if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation)) { - TC_LOG_ERROR("maps", "TeleportTo: invalid map (%d) or invalid coordinates (X: %f, Y: %f, Z: %f, O: %f) given when teleporting player (GUID: %u, name: %s, map: %d, X: %f, Y: %f, Z: %f, O: %f).", - mapid, x, y, z, orientation, GetGUID().GetCounter(), GetName().c_str(), GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); + TC_LOG_ERROR("maps", "Player::TeleportTo: Invalid map (%d) or invalid coordinates (X: %f, Y: %f, Z: %f, O: %f) given when teleporting player '%s' (%s, MapID: %d, X: %f, Y: %f, Z: %f, O: %f).", + mapid, x, y, z, orientation, GetGUID().ToString().c_str(), GetName().c_str(), GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); return false; } if (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_DISABLE_MAP) && DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, mapid, this)) { - TC_LOG_ERROR("maps", "Player (GUID: %u, name: %s) tried to enter a forbidden map %u", GetGUID().GetCounter(), GetName().c_str(), mapid); + TC_LOG_ERROR("maps", "Player::TeleportTo: Player '%s' (%s) tried to enter a forbidden map (MapID: %u)", GetGUID().ToString().c_str(), GetName().c_str(), mapid); SendTransferAborted(mapid, TRANSFER_ABORT_MAP_NOT_ALLOWED); return false; } @@ -1819,7 +1852,8 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // client without expansion support if (GetSession()->Expansion() < mEntry->Expansion()) { - TC_LOG_DEBUG("maps", "Player %s using client without required expansion tried teleporting to non accessible map %u", GetName().c_str(), mapid); + TC_LOG_DEBUG("maps", "Player '%s' (%s) using client without required expansion tried teleport to non accessible map (MapID: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), mapid); if (Transport* transport = GetTransport()) { @@ -1832,7 +1866,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati return false; // normal client can't teleport to this map... } else - TC_LOG_DEBUG("maps", "Player %s is being teleported to map %u", GetName().c_str(), mapid); + TC_LOG_DEBUG("maps", "Player %s (%s) is being teleported to map (MapID: %u)", GetName().c_str(), GetGUID().ToString().c_str(), mapid); if (m_vehicle) ExitVehicle(); @@ -1857,7 +1891,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (GetMapId() == mapid) { - //lets reset far teleport flag if it wasn't reset during chained teleports + //lets reset far teleport flag if it wasn't reset during chained teleport SetSemaphoreTeleportFar(false); //setup delayed teleport flag SetDelayedTeleportFlag(IsCanDelayTeleport()); @@ -2041,24 +2075,7 @@ void Player::ProcessDelayedOperations() return; if (m_DelayedOperations & DELAYED_RESURRECT_PLAYER) - { - ResurrectPlayer(0.0f, false); - - if (GetMaxHealth() > m_resurrectHealth) - SetHealth(m_resurrectHealth); - else - SetFullHealth(); - - if (GetMaxPower(POWER_MANA) > m_resurrectMana) - SetPower(POWER_MANA, m_resurrectMana); - else - SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); - - SetPower(POWER_RAGE, 0); - SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); - - SpawnCorpseBones(); - } + ResurrectUsingRequestDataImpl(); if (m_DelayedOperations & DELAYED_SAVE_PLAYER) SaveToDB(); @@ -2141,8 +2158,8 @@ void Player::RemoveFromWorld() { if (WorldObject* viewpoint = GetViewpoint()) { - TC_LOG_ERROR("entities.player", "Player %s has viewpoint %u %u when removed from world", - GetName().c_str(), viewpoint->GetEntry(), viewpoint->GetTypeId()); + TC_LOG_ERROR("entities.player", "Player::RemoveFromWorld: Player '%s' (%s) has viewpoint (Entry:%u, Type: %u) when removed from world", + GetName().c_str(), GetGUID().ToString().c_str(), viewpoint->GetEntry(), viewpoint->GetTypeId()); SetViewpoint(viewpoint, false); } } @@ -2383,14 +2400,14 @@ void Player::ResetAllPowers() } } -bool Player::CanInteractWithQuestGiver(Object* questGiver) +bool Player::CanInteractWithQuestGiver(Object* questGiver) const { switch (questGiver->GetTypeId()) { case TYPEID_UNIT: - return GetNPCIfCanInteractWith(questGiver->GetGUID(), UNIT_NPC_FLAG_QUESTGIVER) != NULL; + return GetNPCIfCanInteractWith(questGiver->GetGUID(), UNIT_NPC_FLAG_QUESTGIVER) != nullptr; case TYPEID_GAMEOBJECT: - return GetGameObjectIfCanInteractWith(questGiver->GetGUID(), GAMEOBJECT_TYPE_QUESTGIVER) != NULL; + return GetGameObjectIfCanInteractWith(questGiver->GetGUID(), GAMEOBJECT_TYPE_QUESTGIVER) != nullptr; case TYPEID_PLAYER: return IsAlive() && questGiver->ToPlayer()->IsAlive(); case TYPEID_ITEM: @@ -2401,46 +2418,46 @@ bool Player::CanInteractWithQuestGiver(Object* questGiver) return false; } -Creature* Player::GetNPCIfCanInteractWith(ObjectGuid const& guid, uint32 npcflagmask) +Creature* Player::GetNPCIfCanInteractWith(ObjectGuid const& guid, uint32 npcflagmask) const { // unit checks if (!guid) - return NULL; + return nullptr; if (!IsInWorld()) - return NULL; + return nullptr; if (IsInFlight()) - return NULL; + return nullptr; // exist (we need look pets also for some interaction (quest/etc) Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, guid); if (!creature) - return NULL; + return nullptr; // Deathstate checks if (!IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_GHOST)) - return NULL; + return nullptr; // alive or spirit healer if (!creature->IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_DEAD_INTERACT)) - return NULL; + return nullptr; // appropriate npc type if (npcflagmask && !creature->HasFlag(UNIT_NPC_FLAGS, npcflagmask)) - return NULL; + return nullptr; // not allow interaction under control, but allow with own pets if (creature->GetCharmerGUID()) - return NULL; + return nullptr; // not unfriendly/hostile if (creature->GetReactionTo(this) <= REP_UNFRIENDLY) - return NULL; + return nullptr; // not too far if (!creature->IsWithinDistInMap(this, INTERACTION_DISTANCE)) - return NULL; + return nullptr; return creature; } @@ -2468,8 +2485,8 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid, Gameo if (go->IsWithinDistInMap(this, go->GetInteractionDistance())) return go; - TC_LOG_DEBUG("maps", "GetGameObjectIfCanInteractWith: GameObject '%s' [GUID: %u] is too far away from player %s [GUID: %u] to be used by him (distance=%f, maximal %f is allowed)", go->GetGOInfo()->name.c_str(), - go->GetGUID().GetCounter(), GetName().c_str(), GetGUID().GetCounter(), go->GetDistance(this), go->GetInteractionDistance()); + TC_LOG_DEBUG("maps", "Player::GetGameObjectIfCanInteractWith: GameObject '%s' (%s) is too far away from player '%s' (%s) to be used by him (Distance: %f, maximal 10 is allowed)", + go->GetGOInfo()->name.c_str(), go->GetGUID().ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str(), go->GetDistance(this)); } } @@ -2620,14 +2637,14 @@ bool Player::IsGroupVisibleFor(Player const* p) const bool Player::IsInSameGroupWith(Player const* p) const { - return p == this || (GetGroup() != NULL && + return p == this || (GetGroup() != nullptr && GetGroup() == p->GetGroup() && GetGroup()->SameSubGroup(this, p)); } bool Player::IsInSameRaidWith(Player const* p) const { - return p == this || (GetGroup() != NULL && GetGroup() == p->GetGroup()); + return p == this || (GetGroup() != nullptr && GetGroup() == p->GetGroup()); } ///- If the player is invited, remove him. If the group if then only 1 person, disband the group. @@ -2662,7 +2679,7 @@ void Player::RemoveFromGroup(Group* group, ObjectGuid guid, RemoveMethod method group->RemoveMember(guid, method, kicker, reason); } -void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend, float /*group_rate*/) +void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend, float /*group_rate*/) const { WorldPacket data(SMSG_LOG_XPGAIN, 21); // guess size? data << uint64(victim ? victim->GetGUID() : ObjectGuid::Empty); @@ -2703,7 +2720,7 @@ void Player::GiveXP(uint32 xp, Unit* victim, float group_rate) if (level >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) return; - uint32 bonus_xp = 0; + uint32 bonus_xp; bool recruitAFriend = GetsRecruitAFriendBonus(true); // RaF does NOT stack with rested experience @@ -2826,8 +2843,8 @@ void Player::GiveLevel(uint8 level) { ++m_grantableLevels; - if (!HasByteFlag(PLAYER_FIELD_BYTES, 1, 0x01)) - SetByteFlag(PLAYER_FIELD_BYTES, 1, 0x01); + if (!HasByteFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_RAF_GRANTABLE_LEVEL, 0x01)) + SetByteFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_RAF_GRANTABLE_LEVEL, 0x01); } sScriptMgr->OnPlayerLevelChanged(this, oldLevel); @@ -3064,8 +3081,6 @@ void Player::SendInitialSpells() GetSpellHistory()->WritePacket<Player>(data); GetSession()->SendPacket(&data); - - TC_LOG_DEBUG("network", "CHARACTER: Sent Initial Spells"); } void Player::RemoveMail(uint32 id) @@ -3081,7 +3096,7 @@ void Player::RemoveMail(uint32 id) } } -void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError, ObjectGuid::LowType item_guid, uint32 item_count) +void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError, ObjectGuid::LowType item_guid, uint32 item_count) const { WorldPacket data(SMSG_SEND_MAIL_RESULT, (4+4+4+(mailError == MAIL_ERR_EQUIP_ERROR?4:(mailAction == MAIL_ITEM_TAKEN?4+4:0)))); data << (uint32) mailId; @@ -3097,7 +3112,7 @@ void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResp GetSession()->SendPacket(&data); } -void Player::SendNewMail() +void Player::SendNewMail() const { // deliver undelivered mail WorldPacket data(SMSG_RECEIVED_MAIL, 4); @@ -3109,7 +3124,7 @@ void Player::UpdateNextMailTimeAndUnreads() { // calculate next delivery time (min. from non-delivered mails // and recalculate unReadMail - time_t cTime = time(NULL); + time_t cTime = time(nullptr); m_nextMailDelivereTime = 0; unReadMails = 0; for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) @@ -3126,7 +3141,7 @@ void Player::UpdateNextMailTimeAndUnreads() void Player::AddNewMailDeliverTime(time_t deliver_time) { - if (deliver_time <= time(NULL)) // ready now + if (deliver_time <= time(nullptr)) // ready now { ++unReadMails; SendNewMail(); @@ -3159,12 +3174,12 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - TC_LOG_ERROR("spells", "Player::addSpell: Non-existing spell #%u requested from SpellStore. Deleting spell for all characters in `character_spell`.", spellId); + TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: %u) does not exist. Deleting for all characters in `character_spell` and `character_talent`.", spellId); DeleteSpellFromAllPlayers(spellId); } else - TC_LOG_ERROR("spells", "Player::addSpell: Non-existing spell #%u requested from SpellStore.", spellId); + TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: %u) does not exist", spellId); return false; } @@ -3174,12 +3189,12 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u, learning this spell is not allowed. Deleting this spell for all characters in `character_talent`.", spellId); + TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: %u) is invalid. Deleting for all characters in `character_spell` and `character_talent`.", spellId); DeleteSpellFromAllPlayers(spellId); } else - TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u, learning this spell is not allowed.", spellId); + TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: %u) is invalid", spellId); return false; } @@ -3224,12 +3239,12 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - TC_LOG_ERROR("spells", "Player::addSpell: Non-existing spell #%u requested from SpellStore. Deleting for all characters in `character_spell`.", spellId); + TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: %u) does not exist. deleting for all characters in `character_spell` and `character_talent`.", spellId); DeleteSpellFromAllPlayers(spellId); } else - TC_LOG_ERROR("spells", "Player::addSpell: Non-existing spell #%u requested from SpellStore.", spellId); + TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: %u) does not exist", spellId); return false; } @@ -3239,12 +3254,12 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - TC_LOG_ERROR("spells", "Player::addSpell: Broken spell #%u, learning this spell is not allowed. Deleting this spell for all characters in `character_spell`.", spellId); + TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: %u) is invalid. deleting for all characters in `character_spell` and `character_talent`.", spellId); DeleteSpellFromAllPlayers(spellId); } else - TC_LOG_ERROR("spells", "Player::addSpell: Broken spell #%u, learning this spell is not allowed.", spellId); + TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: %u) is invalid", spellId); return false; } @@ -3847,7 +3862,7 @@ bool Player::Has310Flyer(bool checkAllSpells, uint32 excludeSpellId) if (_spell_idx->second->skillId != SKILL_MOUNTS) break; // We can break because mount spells belong only to one skillline (at least 310 flyers do) - spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); + spellInfo = sSpellMgr->AssertSpellInfo(itr->first); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && spellInfo->Effects[i].CalcValue() == 310) @@ -3867,7 +3882,7 @@ void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns) // remove cooldowns on spells that have < 10 min CD GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS; }, true); @@ -3934,12 +3949,12 @@ bool Player::ResetTalents(bool no_cost) if (!HasEnoughMoney(cost)) { - SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0); + SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, nullptr, 0, 0); return false; } } - RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); + RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT, true); for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) { @@ -4019,7 +4034,7 @@ Mail* Player::GetMail(uint32 id) if ((*itr)->messageID == id) return (*itr); - return NULL; + return nullptr; } void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const @@ -4028,7 +4043,7 @@ void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c { for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) { - if (m_items[i] == NULL) + if (m_items[i] == nullptr) continue; m_items[i]->BuildCreateUpdateBlockForPlayer(data, target); @@ -4036,7 +4051,7 @@ void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c for (uint8 i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) { - if (m_items[i] == NULL) + if (m_items[i] == nullptr) continue; m_items[i]->BuildCreateUpdateBlockForPlayer(data, target); @@ -4059,7 +4074,7 @@ void Player::DestroyForPlayer(Player* target, bool onDeath) const for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i) { - if (m_items[i] == NULL) + if (m_items[i] == nullptr) continue; m_items[i]->DestroyForPlayer(target); @@ -4069,7 +4084,7 @@ void Player::DestroyForPlayer(Player* target, bool onDeath) const { for (uint8 i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) { - if (m_items[i] == NULL) + if (m_items[i] == nullptr) continue; m_items[i]->DestroyForPlayer(target); @@ -4159,7 +4174,7 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell } // check primary prof. limit - // first rank of primary profession spell when there are no proffesions avalible is disabled + // first rank of primary profession spell when there are no professions available is disabled for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (!trainer_spell->learnedSpell[i]) @@ -4537,7 +4552,8 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe break; } default: - TC_LOG_ERROR("entities.player", "Player::DeleteFromDB: Unsupported delete method: %u.", charDelete_method); + TC_LOG_ERROR("entities.player", "Player::DeleteFromDB: Tried to delete player (%s) with unsupported delete method (%u).", + playerguid.ToString().c_str(), charDelete_method); return; } @@ -4566,19 +4582,19 @@ void Player::DeleteOldCharacters() * * @see Player::DeleteFromDB * - * @param keepDays overrite the config option by another amount of days + * @param keepDays overwrite the config option by another amount of days */ void Player::DeleteOldCharacters(uint32 keepDays) { - TC_LOG_INFO("entities.player", "Player::DeleteOldChars: Removing characters older than %u day(s)", keepDays); + TC_LOG_INFO("entities.player", "Player::DeleteOldCharacters: Deleting all characters which have been deleted %u days before...", keepDays); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_OLD_CHARS); - stmt->setUInt32(0, uint32(time(NULL) - time_t(keepDays * DAY))); + stmt->setUInt32(0, uint32(time(nullptr) - time_t(keepDays * DAY))); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { - TC_LOG_DEBUG("entities.player", "Player::DeleteOldChars: " UI64FMTD " character(s) to remove", result->GetRowCount()); + TC_LOG_DEBUG("entities.player", "Player::DeleteOldCharacters: Found " UI64FMTD " character(s) to delete", result->GetRowCount()); do { Field* fields = result->Fetch(); @@ -4627,7 +4643,7 @@ void Player::BuildPlayerRepop() WorldLocation corpseLocation = GetCorpseLocation(); if (corpseLocation.GetMapId() == GetMapId()) { - TC_LOG_ERROR("entities.player", "BuildPlayerRepop: player %s(%d) already has a corpse", GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::BuildPlayerRepop: Player '%s' (%s) already has a corpse", GetName().c_str(), GetGUID().ToString().c_str()); return; } @@ -4635,7 +4651,7 @@ void Player::BuildPlayerRepop() Corpse* corpse = CreateCorpse(); if (!corpse) { - TC_LOG_ERROR("entities.player", "Error creating corpse for Player %s [%u]", GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::BuildPlayerRepop: Error creating corpse for player '%s' (%s)", GetName().c_str(), GetGUID().ToString().c_str()); return; } GetMap()->AddToMap(corpse); @@ -4744,30 +4760,9 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) } } -void Player::SendGhoulResurrectRequest(Player* target) -{ - target->m_ghoulResurrectPlayerGUID = GetGUID(); - - WorldPacket data(SMSG_RESURRECT_REQUEST, 8 + 4 + 1 + 1); - data << uint64(GetGUID()); - data << uint32(0); - data << uint8(0); - data << uint8(0); - target->GetSession()->SendPacket(&data); -} - -void Player::GhoulResurrect() -{ - CastSpell(this, 46619 /*SPELL_DK_RAISE_ALLY*/, true, nullptr, nullptr, m_ghoulResurrectPlayerGUID); - - m_ghoulResurrectPlayerGUID = ObjectGuid::Empty; -} - void Player::RemoveGhoul() { - if (IsGhouled()) - if (Creature* ghoul = ObjectAccessor::GetCreature(*this, m_ghoulResurrectGhoulGUID)) - ghoul->DespawnOrUnsummon(); // Raise Ally aura will handle unauras + RemoveAura(SPELL_DK_RAISE_ALLY); } void Player::KillPlayer() @@ -4815,7 +4810,7 @@ Corpse* Player::CreateCorpse() // prevent the existence of 2 corpses for one player SpawnCorpseBones(); - uint32 _pb, _pb2, _cfb1, _cfb2; + uint32 _cfb1, _cfb2; Corpse* corpse = new Corpse((m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) ? CORPSE_RESURRECTABLE_PVP : CORPSE_RESURRECTABLE_PVE); SetPvPDeath(false); @@ -4828,16 +4823,13 @@ Corpse* Player::CreateCorpse() _corpseLocation.WorldRelocate(*this); - _pb = GetUInt32Value(PLAYER_BYTES); - _pb2 = GetUInt32Value(PLAYER_BYTES_2); - - uint8 skin = (uint8)(_pb); - uint8 face = (uint8)(_pb >> 8); - uint8 hairstyle = (uint8)(_pb >> 16); - uint8 haircolor = (uint8)(_pb >> 24); - uint8 facialhair = (uint8)(_pb2); + uint8 skin = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID); + uint8 face = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID); + uint8 hairstyle = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID); + uint8 haircolor = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID); + uint8 facialhair = GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE); - _cfb1 = ((0x00) | (getRace() << 8) | (GetByteValue(PLAYER_BYTES_3, 0) << 16) | (skin << 24)); + _cfb1 = ((0x00) | (getRace() << 8) | (GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER) << 16) | (skin << 24)); _cfb2 = ((face) | (hairstyle << 8) | (haircolor << 16) | (facialhair << 24)); corpse->SetUInt32Value(CORPSE_FIELD_BYTES_1, _cfb1); @@ -4957,7 +4949,7 @@ void Player::DurabilityPointsLossAll(int32 points, bool inventory) //for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - if (Bag* pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + if (Bag* pBag = static_cast<Bag*>(GetItemByPos(INVENTORY_SLOT_BAG_0, i))) for (uint32 j = 0; j < pBag->GetBagSize(); j++) if (Item* pItem = GetItemByPos(i, j)) DurabilityPointsLoss(pItem, points); @@ -5037,7 +5029,8 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g DurabilityCostsEntry const* dcost = sDurabilityCostsStore.LookupEntry(ditemProto->ItemLevel); if (!dcost) { - TC_LOG_ERROR("entities.player.items", "RepairDurability: Wrong item level %u", ditemProto->ItemLevel); + TC_LOG_ERROR("entities.player.items", "Player::DurabilityRepair: Player '%s' (%s) tried to repair an item (ItemID: %u) with invalid item level %u", + GetName().c_str(), GetGUID().ToString().c_str(), ditemProto->ItemId, ditemProto->ItemLevel); return TotalCost; } @@ -5045,7 +5038,8 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g DurabilityQualityEntry const* dQualitymodEntry = sDurabilityQualityStore.LookupEntry(dQualitymodEntryId); if (!dQualitymodEntry) { - TC_LOG_ERROR("entities.player.items", "RepairDurability: Wrong dQualityModEntry %u", dQualitymodEntryId); + TC_LOG_ERROR("entities.player.items", "Player::DurabilityRepair: Player '%s' (%s) tried to repair an item (ItemID: %u) with invalid QualitymodEntry %u", + GetName().c_str(), GetGUID().ToString().c_str(), ditemProto->ItemId, dQualitymodEntryId); return TotalCost; } @@ -5061,7 +5055,8 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g { if (GetGuildId() == 0) { - TC_LOG_DEBUG("entities.player.items", "You are not member of a guild."); + TC_LOG_DEBUG("entities.player.items", "Player::DurabilityRepair: Player '%s' (%s) tried to repair item in a guild bank but is not member of a guild", + GetName().c_str(), GetGUID().ToString().c_str()); return TotalCost; } @@ -5076,7 +5071,8 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g } else if (!HasEnoughMoney(costs)) { - TC_LOG_DEBUG("entities.player.items", "You do not have enough money."); + TC_LOG_DEBUG("entities.player.items", "Player::DurabilityRepair: Player '%s' (%s) has not enough money to repair item", + GetName().c_str(), GetGUID().ToString().c_str()); return TotalCost; } else @@ -5107,7 +5103,7 @@ void Player::RepopAtGraveyard() SpawnCorpseBones(); } - WorldSafeLocsEntry const* ClosestGrave = NULL; + WorldSafeLocsEntry const* ClosestGrave; // Special handle for battleground maps if (Battleground* bg = GetBattleground()) @@ -5144,7 +5140,7 @@ void Player::RepopAtGraveyard() RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); } -bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone) +bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone) const { if (channel->flags & CHANNEL_DBC_FLAG_ZONE_DEP && zone->flags & AREA_FLAG_ARENA_INSTANCE) return false; @@ -5178,7 +5174,7 @@ void Player::CleanupChannels() if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetTeam())) cMgr->LeftChannel(ch->GetName()); // deleted channel if empty } - TC_LOG_DEBUG("chat.system", "Player %s: channels cleaned up!", GetName().c_str()); + TC_LOG_DEBUG("chat.system", "Player::CleanupChannels: Channels of player '%s' (%s) cleaned up.", GetName().c_str(), GetGUID().ToString().c_str()); } void Player::UpdateLocalChannels(uint32 newZone) @@ -5200,7 +5196,7 @@ void Player::UpdateLocalChannels(uint32 newZone) { if (ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i)) { - Channel* usedChannel = NULL; + Channel* usedChannel = nullptr; for (JoinedChannelsList::iterator itr = m_channels.begin(); itr != m_channels.end(); ++itr) { @@ -5211,8 +5207,8 @@ void Player::UpdateLocalChannels(uint32 newZone) } } - Channel* removeChannel = NULL; - Channel* joinChannel = NULL; + Channel* removeChannel = nullptr; + Channel* joinChannel = nullptr; bool sendRemove = true; if (CanJoinConstantChannelInZone(channel, current_zone)) @@ -5241,7 +5237,7 @@ void Player::UpdateLocalChannels(uint32 newZone) sendRemove = false; // Do not send leave channel, it already replaced at client } else - joinChannel = NULL; + joinChannel = nullptr; } } else @@ -5286,7 +5282,8 @@ void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, floa { if (modGroup >= BASEMOD_END || modType >= MOD_END) { - TC_LOG_ERROR("spells", "ERROR in HandleBaseModValue(): Non-existing BaseModGroup or wrong BaseModType!"); + TC_LOG_ERROR("spells", "Player::HandleBaseModValue: Invalid BaseModGroup/BaseModType (%u/%u) for player '%s' (%s)", + modGroup, modType, GetName().c_str(), GetGUID().ToString().c_str()); return; } @@ -5312,7 +5309,8 @@ float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const { if (modGroup >= BASEMOD_END || modType >= MOD_END) { - TC_LOG_ERROR("spells", "Attempt to access non-existing BaseModGroup or wrong BaseModType!"); + TC_LOG_ERROR("spells", "Player::GetBaseModValue: Invalid BaseModGroup/BaseModType (%u/%u) for player '%s' (%s)", + modGroup, modType, GetName().c_str(), GetGUID().ToString().c_str()); return 0.0f; } @@ -5326,7 +5324,8 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const { if (modGroup >= BASEMOD_END) { - TC_LOG_ERROR("spells", "Wrong BaseModGroup in GetTotalBaseModValue()!"); + TC_LOG_ERROR("spells", "Player::GetTotalBaseModValue: Invalid BaseModGroup (%u) for player '%s' (%s)", + modGroup, GetName().c_str(), GetGUID().ToString().c_str()); return 0.0f; } @@ -5345,7 +5344,7 @@ uint32 Player::GetShieldBlockValue() const return uint32(value); } -float Player::GetMeleeCritFromAgility() +float Player::GetMeleeCritFromAgility() const { uint8 level = getLevel(); uint32 pclass = getClass(); @@ -5355,14 +5354,14 @@ float Player::GetMeleeCritFromAgility() GtChanceToMeleeCritBaseEntry const* critBase = sGtChanceToMeleeCritBaseStore.LookupEntry(pclass-1); GtChanceToMeleeCritEntry const* critRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (critBase == NULL || critRatio == NULL) + if (critBase == nullptr || critRatio == nullptr) return 0.0f; float crit = critBase->base + GetStat(STAT_AGILITY)*critRatio->ratio; return crit*100.0f; } -void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) +void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) const { // Table for base dodge values const float dodge_base[MAX_CLASSES] = @@ -5403,7 +5402,7 @@ void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) // Dodge per agility is proportional to crit per agility, which is available from DBC files GtChanceToMeleeCritEntry const* dodgeRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (dodgeRatio == NULL || pclass > MAX_CLASSES) + if (dodgeRatio == nullptr || pclass > MAX_CLASSES) return; /// @todo research if talents/effects that increase total agility by x% should increase non-diminishing part @@ -5415,7 +5414,7 @@ void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) nondiminishing = 100.0f * (dodge_base[pclass-1] + base_agility * dodgeRatio->ratio * crit_to_dodge[pclass-1]); } -float Player::GetSpellCritFromIntellect() +float Player::GetSpellCritFromIntellect() const { uint8 level = getLevel(); uint32 pclass = getClass(); @@ -5425,7 +5424,7 @@ float Player::GetSpellCritFromIntellect() GtChanceToSpellCritBaseEntry const* critBase = sGtChanceToSpellCritBaseStore.LookupEntry(pclass-1); GtChanceToSpellCritEntry const* critRatio = sGtChanceToSpellCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (critBase == NULL || critRatio == NULL) + if (critBase == nullptr || critRatio == nullptr) return 0.0f; float crit=critBase->base + GetStat(STAT_INTELLECT)*critRatio->ratio; @@ -5467,7 +5466,7 @@ float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const return 0.0f; } -float Player::OCTRegenHPPerSpirit() +float Player::OCTRegenHPPerSpirit() const { uint8 level = getLevel(); uint32 pclass = getClass(); @@ -5490,7 +5489,7 @@ float Player::OCTRegenHPPerSpirit() return regen; } -float Player::OCTRegenMPPerSpirit() +float Player::OCTRegenMPPerSpirit() const { uint8 level = getLevel(); uint32 pclass = getClass(); @@ -5500,7 +5499,7 @@ float Player::OCTRegenMPPerSpirit() // GtOCTRegenMPEntry const* baseRatio = sGtOCTRegenMPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); GtRegenMPPerSptEntry const* moreRatio = sGtRegenMPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (moreRatio == NULL) + if (moreRatio == nullptr) return 0.0f; // Formula get from PaperDollFrame script @@ -5698,7 +5697,8 @@ inline int SkillGainChance(uint32 SkillValue, uint32 GrayLevel, uint32 GreenLeve bool Player::UpdateCraftSkill(uint32 spellid) { - TC_LOG_DEBUG("entities.player.skills", "UpdateCraftSkill spellid %d", spellid); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateCraftSkill: Player '%s' (%s), SpellID: %d", + GetName().c_str(), GetGUID().ToString().c_str(), spellid); SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellid); @@ -5730,7 +5730,8 @@ bool Player::UpdateCraftSkill(uint32 spellid) bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator) { - TC_LOG_DEBUG("entities.player.skills", "UpdateGatherSkill(SkillId %d SkillLevel %d RedLevel %d)", SkillId, SkillValue, RedLevel); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateGatherSkill: Player '%s' (%s), SkillID: %u, SkillLevel: %u, RedLevel: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), SkillId, SkillValue, RedLevel); uint32 gathering_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_GATHERING); @@ -5758,7 +5759,7 @@ bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLeve bool Player::UpdateFishingSkill() { - TC_LOG_DEBUG("entities.player.skills", "UpdateFishingSkill"); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateFishingSkill: Player '%s' (%s)", GetName().c_str(), GetGUID().ToString().c_str()); uint32 SkillValue = GetPureSkillValue(SKILL_FISHING); @@ -5777,13 +5778,15 @@ static const size_t bonusSkillLevelsSize = sizeof(bonusSkillLevels) / sizeof(uin bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) { - TC_LOG_DEBUG("entities.player.skills", "UpdateSkillPro(SkillId %d, Chance %3.1f%%)", SkillId, Chance / 10.0f); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro: Player '%s' (%s), SkillID: %u, Chance: %3.1f%%)", + GetName().c_str(), GetGUID().ToString().c_str(), SkillId, Chance / 10.0f); if (!SkillId) return false; if (Chance <= 0) // speedup in 0 chance case { - TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro Chance=%3.1f%% missed", Chance / 10.0f); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro: Player '%s' (%s), SkillID: %u, Chance: %3.1f%% missed", + GetName().c_str(), GetGUID().ToString().c_str(), SkillId, Chance / 10.0f); return false; } @@ -5822,11 +5825,13 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) } UpdateSkillEnchantments(SkillId, SkillValue, new_value); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, SkillId); - TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro Chance=%3.1f%% taken", Chance / 10.0f); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro: Player '%s' (%s), SkillID: %u, Chance: %3.1f%% taken", + GetName().c_str(), GetGUID().ToString().c_str(), SkillId, Chance / 10.0f); return true; } - TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro Chance=%3.1f%% missed", Chance / 10.0f); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro: Player '%s' (%s), SkillID: %u, Chance: %3.1f%% missed", + GetName().c_str(), GetGUID().ToString().c_str(), SkillId, Chance / 10.0f); return false; } @@ -6060,7 +6065,8 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(id); if (!pSkill) { - TC_LOG_ERROR("entities.player.skills", "Skill not found in SkillLineStore: skill #%u", id); + TC_LOG_ERROR("misc", "Player::SetSkill: Skill (SkillID: %u) not found in SkillLineStore for player '%s' (%s)", + id, GetName().c_str(), GetGUID().ToString().c_str()); return; } @@ -6242,20 +6248,22 @@ void Player::SendActionButtons(uint32 state) const } GetSession()->SendPacket(&data); - TC_LOG_DEBUG("network", "SMSG_ACTION_BUTTONS sent '%u' spec '%u' Sent", GetGUID().GetCounter(), m_activeSpec); + } -bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) +bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) const { if (button >= MAX_ACTION_BUTTONS) { - TC_LOG_DEBUG("entities.player", "Action %u not added into button %u for player %s (GUID: %u): button must be < %u", action, button, GetName().c_str(), GetGUID().GetCounter(), MAX_ACTION_BUTTONS ); + TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Action %u not added into button %u for player %s (%s): button must be < %u", + action, button, GetName().c_str(), GetGUID().ToString().c_str(), MAX_ACTION_BUTTONS); return false; } if (action >= MAX_ACTION_BUTTON_ACTION_VALUE) { - TC_LOG_DEBUG("entities.player", "Action %u not added into button %u for player %s (GUID: %u): action must be < %u", action, button, GetName().c_str(), GetGUID().GetCounter(), MAX_ACTION_BUTTON_ACTION_VALUE); + TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Action %u not added into button %u for player %s (%s): action must be < %u", + action, button, GetName().c_str(), GetGUID().ToString().c_str(), MAX_ACTION_BUTTON_ACTION_VALUE); return false; } @@ -6264,20 +6272,23 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) case ACTION_BUTTON_SPELL: if (!sSpellMgr->GetSpellInfo(action)) { - TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): spell does not exist", action, button, GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Spell action %u not added into button %u for player %s (%s): spell not exist", + action, button, GetName().c_str(), GetGUID().ToString().c_str()); return false; } if (!HasSpell(action)) { - TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): player does not know this spell", action, button, GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Spell action %u not added into button %u for player %s (%s): player don't known this spell", + action, button, GetName().c_str(), GetGUID().ToString().c_str()); return false; } break; case ACTION_BUTTON_ITEM: if (!sObjectMgr->GetItemTemplate(action)) { - TC_LOG_DEBUG("entities.player", "Item action %u not added into button %u for player %s (GUID: %u): item does not exist", action, button, GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Item action %u not added into button %u for player %s (%s): item not exist", + action, button, GetName().c_str(), GetGUID().ToString().c_str()); return false; } break; @@ -6287,7 +6298,7 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) case ACTION_BUTTON_EQSET: break; default: - TC_LOG_DEBUG("entities.player", "Unknown action type %u", type); + TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Unknown action type %u", type); return false; // other cases not checked at this moment } @@ -6297,7 +6308,7 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type) { if (!IsActionButtonDataValid(button, action, type)) - return NULL; + return nullptr; // it create new button (NEW state) if need or return existing ActionButton& ab = m_actionButtons[button]; @@ -6305,7 +6316,8 @@ ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type) // set data and update to CHANGED if not NEW ab.SetActionAndType(action, ActionButtonType(type)); - TC_LOG_DEBUG("entities.player", "Player '%u' Added Action '%u' (type %u) to Button '%u'", GetGUID().GetCounter(), action, type, button); + TC_LOG_DEBUG("entities.player", "Player::AddActionButton: Player '%s' (%s) added action '%u' (type %u) to button '%u'", + GetName().c_str(), GetGUID().ToString().c_str(), action, type, button); return &ab; } @@ -6320,14 +6332,15 @@ void Player::removeActionButton(uint8 button) else buttonItr->second.uState = ACTIONBUTTON_DELETED; // saved, will deleted at next save - TC_LOG_DEBUG("entities.player", "Action Button '%u' Removed from Player '%u'", button, GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player", "Player::RemoveActionButton: Player '%s' (%s) removed action button '%u'", + GetName().c_str(), GetGUID().ToString().c_str(), button); } ActionButton const* Player::GetActionButton(uint8 button) { ActionButtonList::iterator buttonItr = m_actionButtons.find(button); if (buttonItr == m_actionButtons.end() || buttonItr->second.uState == ACTIONBUTTON_DELETED) - return NULL; + return nullptr; return &buttonItr->second; } @@ -6399,7 +6412,7 @@ void Player::SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) VisitNearbyWorldObject(GetVisibilityRange(), notifier); } -void Player::SendDirectMessage(WorldPacket* data) +void Player::SendDirectMessage(WorldPacket const* data) const { m_session->SendPacket(data); } @@ -6409,9 +6422,11 @@ void Player::SendCinematicStart(uint32 CinematicSequenceId) WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4); data << uint32(CinematicSequenceId); SendDirectMessage(&data); + if (const CinematicSequencesEntry* sequence = sCinematicSequencesStore.LookupEntry(CinematicSequenceId)) + SetActiveCinematicCamera(sequence->cinematicCamera); } -void Player::SendMovieStart(uint32 MovieId) +void Player::SendMovieStart(uint32 MovieId) const { WorldPacket data(SMSG_TRIGGER_MOVIE, 4); data << uint32(MovieId); @@ -6470,7 +6485,7 @@ void Player::CheckAreaExploreAndOutdoor() else { int32 diff = int32(getLevel()) - areaEntry->area_level; - uint32 XP = 0; + uint32 XP; if (diff < -5) { XP = uint32(sObjectMgr->GetBaseXP(getLevel()+5)*sWorld->getRate(RATE_XP_EXPLORE)); @@ -6488,7 +6503,7 @@ void Player::CheckAreaExploreAndOutdoor() XP = uint32(sObjectMgr->GetBaseXP(areaEntry->area_level)*sWorld->getRate(RATE_XP_EXPLORE)); } - GiveXP(XP, NULL); + GiveXP(XP, nullptr); SendExplorationExperience(areaId, XP); } TC_LOG_DEBUG("entities.player", "Player '%s' (%s) discovered a new area: %u", GetName().c_str(),GetGUID().ToString().c_str(), areaId); @@ -6705,8 +6720,8 @@ void Player::RewardReputation(Quest const* quest) void Player::UpdateHonorFields() { /// called when rewarding honor and at each save - time_t now = time_t(time(NULL)); - time_t today = time_t(time(NULL) / DAY) * DAY; + time_t now = time_t(time(nullptr)); + time_t today = time_t(time(nullptr) / DAY) * DAY; if (m_lastHonorUpdateTime < today) { @@ -6830,7 +6845,7 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto } } - if (victim != NULL) + if (victim != nullptr) { if (groupsize > 1) honor_f /= groupsize; @@ -6975,6 +6990,7 @@ void Player::SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type) SetArenaTeamInfoField(slot, ARENA_TEAM_ID, ArenaTeamId); SetArenaTeamInfoField(slot, ARENA_TEAM_TYPE, type); } + void Player::SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value) { SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + type, value); @@ -7207,7 +7223,7 @@ void Player::CheckDuelDistance(time_t currTime) } } -bool Player::IsOutdoorPvPActive() +bool Player::IsOutdoorPvPActive() const { return IsAlive() && !HasInvisibilityAura() && !HasStealthAura() && IsPvP() && !HasUnitMovementFlag(MOVEMENTFLAG_FLYING) && !IsInFlight(); } @@ -7218,7 +7234,8 @@ void Player::DuelComplete(DuelCompleteType type) if (!duel) return; - TC_LOG_DEBUG("entities.unit", "Duel Complete %s %s", GetName().c_str(), duel->opponent->GetName().c_str()); + TC_LOG_DEBUG("entities.unit", "Player::DuelComplete: Player '%s' (%s), Opponent: '%s' (%s)", + GetName().c_str(), GetGUID().ToString().c_str(), duel->opponent->GetName().c_str(), duel->opponent->GetGUID().ToString().c_str()); WorldPacket data(SMSG_DUEL_COMPLETE, (1)); data << (uint8)((type != DUEL_INTERRUPTED) ? 1 : 0); @@ -7266,7 +7283,7 @@ void Player::DuelComplete(DuelCompleteType type) // Honor points after duel (the winner) - ImpConfig if (uint32 amount = sWorld->getIntConfig(CONFIG_HONOR_AFTER_DUEL)) - duel->opponent->RewardHonor(NULL, 1, amount); + duel->opponent->RewardHonor(nullptr, 1, amount); break; default: @@ -7321,9 +7338,9 @@ void Player::DuelComplete(DuelCompleteType type) duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 0); delete duel->opponent->duel; - duel->opponent->duel = NULL; + duel->opponent->duel = nullptr; delete duel; - duel = NULL; + duel = nullptr; } //---------------------------------------------------------// @@ -7342,7 +7359,7 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply) if (item->IsBroken()) return; - TC_LOG_DEBUG("entities.player.items", "applying mods for item %u ", item->GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: Applying mods for item %s", item->GetGUID().ToString().c_str()); uint8 attacktype = Player::GetAttackBySlot(slot); @@ -7360,7 +7377,7 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply) ApplyItemEquipSpell(item, apply); ApplyEnchantment(item, apply); - TC_LOG_DEBUG("entities.player.items", "_ApplyItemMods complete."); + TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: completed"); } void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply, bool only_level_scale /*= false*/) @@ -7736,7 +7753,7 @@ void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attac if (aura->GetSpellInfo()->EquippedItemClass == -1) return; - BaseModGroup mod = BASEMOD_END; + BaseModGroup mod; switch (attackType) { case BASE_ATTACK: mod = CRIT_PERCENTAGE; break; @@ -7763,7 +7780,7 @@ void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType att if (aura->GetSpellInfo()->EquippedItemClass == -1) return; - UnitMods unitMod = UNIT_MOD_END; + UnitMods unitMod; switch (attackType) { case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; @@ -7772,7 +7789,7 @@ void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType att default: return; } - UnitModifierType unitModType = TOTAL_VALUE; + UnitModifierType unitModType; switch (aura->GetAuraType()) { case SPELL_AURA_MOD_DAMAGE_DONE: unitModType = TOTAL_VALUE; break; @@ -7839,7 +7856,8 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, return; } - TC_LOG_DEBUG("entities.player", "WORLD: cast %s Equip spellId - %i", (item ? "item" : "itemset"), spellInfo->Id); + TC_LOG_DEBUG("entities.player", "Player::ApplyEquipSpell: Player '%s' (%s) cast %s equip spell (ID: %i)", + GetName().c_str(), GetGUID().ToString().c_str(), (item ? "item" : "itemset"), spellInfo->Id); CastSpell(this, spellInfo, true, item); } @@ -7945,7 +7963,8 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellData.SpellId); if (!spellInfo) { - TC_LOG_ERROR("entities.player.items", "WORLD: Unknown item spellid %i", spellData.SpellId); + TC_LOG_ERROR("entities.player.items", "Player::CastItemCombatSpell: Player '%s' (%s) cast unknown item spell (ID: %i)", + GetName().c_str(), GetGUID().ToString().c_str(), spellData.SpellId); continue; } @@ -8000,8 +8019,8 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->spellid[s]); if (!spellInfo) { - TC_LOG_ERROR("entities.player.items", "Player::CastItemCombatSpell(GUID: %u, name: %s, enchant: %i): unknown spell %i is cast, ignoring...", - GetGUID().GetCounter(), GetName().c_str(), pEnchant->ID, pEnchant->spellid[s]); + TC_LOG_ERROR("entities.player.items", "Player::CastItemCombatSpell: Player '%s' (%s) cast unknown spell (EnchantID: %u, SpellID: %i), ignoring", + GetName().c_str(), GetGUID().ToString().c_str(), pEnchant->ID, pEnchant->spellid[s]); continue; } @@ -8074,7 +8093,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellData.SpellId); if (!spellInfo) { - TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring.", proto->ItemId, spellData.SpellId); + TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring", proto->ItemId, spellData.SpellId); continue; } @@ -8101,7 +8120,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->spellid[s]); if (!spellInfo) { - TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell Enchant %i casts unknown spell %i.", pEnchant->ID, pEnchant->spellid[s]); + TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Enchant %i, cast unknown spell %i", pEnchant->ID, pEnchant->spellid[s]); continue; } @@ -8320,7 +8339,7 @@ void Player::RemovedInsignia(Player* looterPlr) looterPlr->SendLoot(bones->GetGUID(), LOOT_INSIGNIA); } -void Player::SendLootRelease(ObjectGuid guid) +void Player::SendLootRelease(ObjectGuid guid) const { WorldPacket data(SMSG_LOOT_RELEASE_RESPONSE, (8+1)); data << uint64(guid) << uint8(1); @@ -8332,13 +8351,13 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) if (ObjectGuid lguid = GetLootGUID()) m_session->DoLootRelease(lguid); - Loot* loot = 0; + Loot* loot; PermissionTypes permission = ALL_PERMISSION; - TC_LOG_DEBUG("loot", "Player::SendLoot"); + TC_LOG_DEBUG("loot", "Player::SendLoot: Player: '%s' (%s), Loot: %s", + GetName().c_str(), GetGUID().ToString().c_str(), guid.ToString().c_str()); if (guid.IsGameObject()) { - TC_LOG_DEBUG("loot", "IS_GAMEOBJECT_GUID(guid)"); GameObject* go = GetMap()->GetGameObject(guid); // not check distance for GO in case owned GO (fishing bobber case, for example) @@ -8547,7 +8566,6 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) } else { - permission = NONE_PERMISSION; SendLootError(guid, LOOT_ERROR_ALREADY_PICKPOCKETED); return; } @@ -8662,7 +8680,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); } -void Player::SendLootError(ObjectGuid guid, LootError error) +void Player::SendLootError(ObjectGuid guid, LootError error) const { WorldPacket data(SMSG_LOOT_RESPONSE, 10); data << uint64(guid); @@ -8671,20 +8689,20 @@ void Player::SendLootError(ObjectGuid guid, LootError error) SendDirectMessage(&data); } -void Player::SendNotifyLootMoneyRemoved() +void Player::SendNotifyLootMoneyRemoved() const { WorldPacket data(SMSG_LOOT_CLEAR_MONEY, 0); GetSession()->SendPacket(&data); } -void Player::SendNotifyLootItemRemoved(uint8 lootSlot) +void Player::SendNotifyLootItemRemoved(uint8 lootSlot) const { WorldPacket data(SMSG_LOOT_REMOVED, 1); data << uint8(lootSlot); GetSession()->SendPacket(&data); } -void Player::SendUpdateWorldState(uint32 Field, uint32 Value) +void Player::SendUpdateWorldState(uint32 Field, uint32 Value) const { WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8); data << Field; @@ -9319,7 +9337,7 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) SendBattlefieldWorldStates(); } -void Player::SendBGWeekendWorldStates() +void Player::SendBGWeekendWorldStates() const { for (uint32 i = 1; i < sBattlemasterListStore.GetNumRows(); ++i) { @@ -9334,7 +9352,7 @@ void Player::SendBGWeekendWorldStates() } } -void Player::SendBattlefieldWorldStates() +void Player::SendBattlefieldWorldStates() const { /// Send misc stuff that needs to be sent on every login, like the battle timers. if (sWorld->getBoolConfig(CONFIG_WINTERGRASP_ENABLE)) @@ -9343,7 +9361,7 @@ void Player::SendBattlefieldWorldStates() { SendUpdateWorldState(BATTLEFIELD_WG_WORLD_STATE_ACTIVE, wg->IsWarTime() ? 0 : 1); uint32 timer = wg->IsWarTime() ? 0 : (wg->GetTimer() / 1000); // 0 - Time to next battle - SendUpdateWorldState(ClockWorldState[1], uint32(time(NULL) + timer)); + SendUpdateWorldState(ClockWorldState[1], uint32(time(nullptr) + timer)); } } } @@ -9357,18 +9375,18 @@ uint32 Player::GetXPRestBonus(uint32 xp) SetRestBonus(GetRestBonus() - rested_bonus); - TC_LOG_DEBUG("entities.player", "GetXPRestBonus: Player %s (%u) gains %u xp (+%u Rested Bonus). Rested points=%f", GetName().c_str(), GetGUID().GetCounter(), xp+rested_bonus, rested_bonus, GetRestBonus()); + TC_LOG_DEBUG("entities.player", "Player::GetXPRestBonus: Player '%s' (%s) gain %u xp (+%u Rested Bonus). Rested points=%f", GetGUID().ToString().c_str(), GetName().c_str(), xp + rested_bonus, rested_bonus, GetRestBonus()); return rested_bonus; } -void Player::SetBindPoint(ObjectGuid guid) +void Player::SetBindPoint(ObjectGuid guid) const { WorldPacket data(SMSG_BINDER_CONFIRM, 8); data << uint64(guid); GetSession()->SendPacket(&data); } -void Player::SendTalentWipeConfirm(ObjectGuid guid) +void Player::SendTalentWipeConfirm(ObjectGuid guid) const { WorldPacket data(MSG_TALENT_WIPE_CONFIRM, (8+4)); data << uint64(guid); @@ -9425,24 +9443,24 @@ void Player::SetSheath(SheathState sheathed) switch (sheathed) { case SHEATH_STATE_UNARMED: // no prepared weapon - SetVirtualItemSlot(0, NULL); - SetVirtualItemSlot(1, NULL); - SetVirtualItemSlot(2, NULL); + SetVirtualItemSlot(0, nullptr); + SetVirtualItemSlot(1, nullptr); + SetVirtualItemSlot(2, nullptr); break; case SHEATH_STATE_MELEE: // prepared melee weapon SetVirtualItemSlot(0, GetWeaponForAttack(BASE_ATTACK, true)); SetVirtualItemSlot(1, GetWeaponForAttack(OFF_ATTACK, true)); - SetVirtualItemSlot(2, NULL); + SetVirtualItemSlot(2, nullptr); break; case SHEATH_STATE_RANGED: // prepared ranged weapon - SetVirtualItemSlot(0, NULL); - SetVirtualItemSlot(1, NULL); + SetVirtualItemSlot(0, nullptr); + SetVirtualItemSlot(1, nullptr); SetVirtualItemSlot(2, GetWeaponForAttack(RANGED_ATTACK, true)); break; default: - SetVirtualItemSlot(0, NULL); - SetVirtualItemSlot(1, NULL); - SetVirtualItemSlot(2, NULL); + SetVirtualItemSlot(0, nullptr); + SetVirtualItemSlot(1, nullptr); + SetVirtualItemSlot(2, nullptr); break; } Unit::SetSheath(sheathed); // this must visualize Sheath changing for other players... @@ -9790,7 +9808,7 @@ Item* Player::GetItemByGuid(ObjectGuid guid) const if (pItem->GetGUID() == guid) return pItem; - return NULL; + return nullptr; } Item* Player::GetItemByPos(uint16 pos) const @@ -9804,9 +9822,9 @@ Item* Player::GetItemByPos(uint8 bag, uint8 slot) const { if (bag == INVENTORY_SLOT_BAG_0 && (slot < BANK_SLOT_BAG_END || (slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END))) return m_items[slot]; - else if (Bag* pBag = GetBagByPos(bag)) + if (Bag* pBag = GetBagByPos(bag)) return pBag->GetItemByPos(slot); - return NULL; + return nullptr; } //Does additional check for disarmed weapons @@ -9823,7 +9841,7 @@ Bag* Player::GetBagByPos(uint8 bag) const || (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END)) if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, bag)) return item->ToBag(); - return NULL; + return nullptr; } Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable /*= false*/) const @@ -9834,41 +9852,41 @@ Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable /*= f case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break; case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break; case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break; - default: return NULL; + default: return nullptr; } - Item* item = NULL; + Item* item; if (useable) item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, slot); else item = GetItemByPos(INVENTORY_SLOT_BAG_0, slot); if (!item || item->GetTemplate()->Class != ITEM_CLASS_WEAPON) - return NULL; + return nullptr; if (!useable) return item; if (item->IsBroken() || IsInFeralForm()) - return NULL; + return nullptr; return item; } Item* Player::GetShield(bool useable) const { - Item* item = NULL; + Item* item; if (useable) item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); else item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); if (!item || item->GetTemplate()->Class != ITEM_CLASS_ARMOR) - return NULL; + return nullptr; if (!useable) return item; if (item->IsBroken()) - return NULL; + return nullptr; return item; } @@ -9928,7 +9946,7 @@ bool Player::IsBagPos(uint16 pos) return false; } -bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) +bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) const { // post selected if (bag == NULL_BAG && !explicit_pos) @@ -10185,7 +10203,7 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item InventoryResult Player::CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count /*= NULL*/) const { - return CanStoreItem(bag, slot, dest, item, count, NULL, false, no_space_count); + return CanStoreItem(bag, slot, dest, item, count, nullptr, false, no_space_count); } InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap /*= false*/) const @@ -10193,7 +10211,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& des if (!pItem) return EQUIP_ERR_ITEM_NOT_FOUND; uint32 count = pItem->GetCount(); - return CanStoreItem(bag, slot, dest, pItem->GetEntry(), count, pItem, swap, NULL); + return CanStoreItem(bag, slot, dest, pItem->GetEntry(), count, pItem, swap, nullptr); } bool Player::HasItemTotemCategory(uint32 TotemCategory) const @@ -10232,7 +10250,7 @@ InventoryResult Player::CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemP // ignore move item (this slot will be empty at move) if (pItem2 == pSrcItem) - pItem2 = NULL; + pItem2 = nullptr; uint32 need_space; @@ -10318,7 +10336,7 @@ InventoryResult Player::CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, Ite if (!pBagProto) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - // specialized bag mode or non-specilized + // specialized bag mode or non-specialized if (non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER)) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; @@ -10335,10 +10353,10 @@ InventoryResult Player::CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, Ite // ignore move item (this slot will be empty at move) if (pItem2 == pSrcItem) - pItem2 = NULL; + pItem2 = nullptr; // if merge skip empty, if !merge skip non-empty - if ((pItem2 != NULL) != merge) + if ((pItem2 != nullptr) != merge) continue; uint32 need_space = pProto->GetMaxStackSize(); @@ -10346,8 +10364,7 @@ InventoryResult Player::CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, Ite if (pItem2) { // can be merged at least partly - uint8 res = pItem2->CanBeMergedPartlyWith(pProto); - if (res != EQUIP_ERR_OK) + if (pItem2->CanBeMergedPartlyWith(pProto) != EQUIP_ERR_OK) continue; // descrease at current stacksize @@ -10386,10 +10403,10 @@ InventoryResult Player::CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 sl // ignore move item (this slot will be empty at move) if (pItem2 == pSrcItem) - pItem2 = NULL; + pItem2 = nullptr; // if merge skip empty, if !merge skip non-empty - if ((pItem2 != NULL) != merge) + if ((pItem2 != nullptr) != merge) continue; uint32 need_space = pProto->GetMaxStackSize(); @@ -10397,8 +10414,7 @@ InventoryResult Player::CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 sl if (pItem2) { // can be merged at least partly - uint8 res = pItem2->CanBeMergedPartlyWith(pProto); - if (res != EQUIP_ERR_OK) + if (pItem2->CanBeMergedPartlyWith(pProto) != EQUIP_ERR_OK) continue; // descrease at current stacksize @@ -10423,7 +10439,7 @@ InventoryResult Player::CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 sl InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 entry, uint32 count, Item* pItem, bool swap, uint32* no_space_count) const { - TC_LOG_DEBUG("entities.player.items", "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, entry, count); + TC_LOG_DEBUG("entities.player.items", "Player::CanStoreItem: Bag: %u, Slot: %u, Item: %u, Count: %u", bag, slot, entry, count); ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(entry); if (!pProto) @@ -10908,7 +10924,8 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit if (!item) continue; - TC_LOG_DEBUG("entities.player.items", "STORAGE: CanStoreItems %i. item = %u, count = %u", k + 1, item->GetEntry(), item->GetCount()); + TC_LOG_DEBUG("entities.player.items", "Player::CanStoreItems: Player '%s' (%s), Index: %i ItemID: %u, Count: %u", + GetName().c_str(), GetGUID().ToString().c_str(), k + 1, item->GetEntry(), item->GetCount()); ItemTemplate const* pProto = item->GetTemplate(); // strange item @@ -11075,7 +11092,7 @@ InventoryResult Player::CanStoreItems(Item** items, int count, uint32* itemLimit continue; // search free slot in bags - for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t) + for (uint8 t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t) { if (Bag* bag = GetBagByPos(t)) { @@ -11125,7 +11142,8 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool dest = 0; if (pItem) { - TC_LOG_DEBUG("entities.player.items", "STORAGE: CanEquipItem slot = %u, item = %u, count = %u", slot, pItem->GetEntry(), pItem->GetCount()); + TC_LOG_DEBUG("entities.player.items", "Player::CanEquipItem: Player '%s' (%s), Slot: %u, Item: %u, Count: %u", + GetName().c_str(), GetGUID().ToString().c_str(), slot, pItem->GetEntry(), pItem->GetCount()); ItemTemplate const* pProto = pItem->GetTemplate(); if (pProto) { @@ -11295,7 +11313,8 @@ InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const if (!pItem) return EQUIP_ERR_OK; - TC_LOG_DEBUG("entities.player.items", "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount()); + TC_LOG_DEBUG("entities.player.items", "Player::CanUnequipItem: Player '%s' (%s), Slot: %u, Item: %u, Count: %u", + GetName().c_str(), GetGUID().ToString().c_str(), pos, pItem->GetEntry(), pItem->GetCount()); ItemTemplate const* pProto = pItem->GetTemplate(); if (!pProto) @@ -11331,7 +11350,8 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest uint32 count = pItem->GetCount(); - TC_LOG_DEBUG("entities.player.items", "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount()); + TC_LOG_DEBUG("entities.player.items", "Player::CanBankItem: Player '%s' (%s), Bag: %u, Slot: %u, Item: %u, Count: %u", + GetName().c_str(), GetGUID().ToString().c_str(), bag, slot, pItem->GetEntry(), pItem->GetCount()); ItemTemplate const* pProto = pItem->GetTemplate(); if (!pProto) return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; @@ -11347,8 +11367,8 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest uint8 pItemslot = pItem->GetSlot(); if (pItemslot >= CURRENCYTOKEN_SLOT_START && pItemslot < CURRENCYTOKEN_SLOT_END) { - TC_LOG_ERROR("entities.player", "Possible hacking attempt: Player %s [guid: %u] tried to move token [guid: %u, entry: %u] out of the currency bag!", - GetName().c_str(), GetGUID().GetCounter(), pItem->GetGUID().GetCounter(), pProto->ItemId); + TC_LOG_ERROR("entities.player", "Possible hacking attempt: Player %s (%s) tried to move token [%s entry: %u] out of the currency bag!", + GetName().c_str(), GetGUID().ToString().c_str(), pItem->GetGUID().ToString().c_str(), pProto->ItemId); return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED; } @@ -11515,7 +11535,8 @@ InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const { if (pItem) { - TC_LOG_DEBUG("entities.player.items", "STORAGE: CanUseItem item = %u", pItem->GetEntry()); + TC_LOG_DEBUG("entities.player.items", "Player::CanUseItem: Player '%s' (%s), Item: %u", + GetName().c_str(), GetGUID().ToString().c_str(), pItem->GetEntry()); if (!IsAlive() && not_loading) return EQUIP_ERR_YOU_ARE_DEAD; @@ -11796,7 +11817,7 @@ Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update Item* Player::StoreItem(ItemPosCountVec const& dest, Item* pItem, bool update) { if (!pItem) - return NULL; + return nullptr; Item* lastItem = pItem; for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end();) @@ -11821,12 +11842,13 @@ Item* Player::StoreItem(ItemPosCountVec const& dest, Item* pItem, bool update) Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool update) { if (!pItem) - return NULL; + return nullptr; uint8 bag = pos >> 8; uint8 slot = pos & 255; - TC_LOG_DEBUG("entities.player.items", "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u, guid = %u", bag, slot, pItem->GetEntry(), count, pItem->GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player.items", "Player::_StoreItem: Player '%s' (%s), Bag: %u, Slot: %u, Item: %u (%s), Count: %u", + GetName().c_str(), GetGUID().ToString().c_str(), bag, slot, pItem->GetEntry(), pItem->GetGUID().ToString().c_str(), count); Item* pItem2 = GetItemByPos(bag, slot); @@ -11838,7 +11860,7 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool pItem->SetCount(count); if (!pItem) - return NULL; + return nullptr; if (pItem->GetTemplate()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetTemplate()->Bonding == BIND_QUEST_ITEM || @@ -11854,7 +11876,7 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool pItem->SetGuidValue(ITEM_FIELD_OWNER, GetGUID()); pItem->SetSlot(slot); - pItem->SetContainer(NULL); + pItem->SetContainer(nullptr); // need update known currency if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END) @@ -11939,7 +11961,7 @@ Item* Player::EquipNewItem(uint16 pos, uint32 item, bool update) return EquipItem(pos, pItem, update); } - return NULL; + return nullptr; } Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) @@ -11972,7 +11994,8 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell); if (!spellProto) - TC_LOG_ERROR("entities.player", "Weapon switch cooldown spell %u could not be found in Spell.dbc", cooldownSpell); + TC_LOG_ERROR("entities.player", "Player::EquipItem: Weapon switch cooldown spell %u for player '%s' (%s) couldn't be found in Spell.dbc", + cooldownSpell, GetName().c_str(), GetGUID().ToString().c_str()); else { m_weaponChangeTimer = spellProto->StartRecoveryTime; @@ -12092,14 +12115,15 @@ void Player::VisualizeItem(uint8 slot, Item* pItem) if (pItem->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || pItem->GetTemplate()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetTemplate()->Bonding == BIND_QUEST_ITEM) pItem->SetBinding(true); - TC_LOG_DEBUG("entities.player.items", "STORAGE: EquipItem slot = %u, item = %u", slot, pItem->GetEntry()); + TC_LOG_DEBUG("entities.player.items", "Player::SetVisibleItemSlot: Player '%s' (%s), Slot: %u, Item: %u", + GetName().c_str(), GetGUID().ToString().c_str(), slot, pItem->GetEntry()); m_items[slot] = pItem; SetGuidValue(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2), pItem->GetGUID()); pItem->SetGuidValue(ITEM_FIELD_CONTAINED, GetGUID()); pItem->SetGuidValue(ITEM_FIELD_OWNER, GetGUID()); pItem->SetSlot(slot); - pItem->SetContainer(NULL); + pItem->SetContainer(nullptr); if (slot < EQUIPMENT_SLOT_END) SetVisibleItemSlot(slot, pItem); @@ -12122,7 +12146,8 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update) Item* pItem = GetItemByPos(bag, slot); if (pItem) { - TC_LOG_DEBUG("entities.player.items", "STORAGE: RemoveItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry()); + TC_LOG_DEBUG("entities.player.items", "Player::RemoveItem: Player '%s' (%s), Bag: %u, Slot: %u, Item: %u", + GetName().c_str(), GetGUID().ToString().c_str(), bag, slot, pItem->GetEntry()); RemoveEnchantmentDurations(pItem); RemoveItemDurations(pItem); @@ -12176,11 +12201,11 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update) } } - m_items[slot] = NULL; + m_items[slot] = nullptr; SetGuidValue(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2), ObjectGuid::Empty); if (slot < EQUIPMENT_SLOT_END) - SetVisibleItemSlot(slot, NULL); + SetVisibleItemSlot(slot, nullptr); } else if (Bag* pBag = GetBagByPos(bag)) pBag->RemoveItem(slot, update); @@ -12241,7 +12266,8 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update) Item* pItem = GetItemByPos(bag, slot); if (pItem) { - TC_LOG_DEBUG("entities.player.items", "STORAGE: DestroyItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry()); + TC_LOG_DEBUG("entities.player.items", "Player::DestroyItem: Player '%s' (%s), Bag: %u, Slot: %u, Item: %u", + GetName().c_str(), GetGUID().ToString().c_str(), bag, slot, pItem->GetEntry()); // Also remove all contained items if the item is a bag. // This if () prevents item saving crashes if the condition for a bag to be empty before being destroyed was bypassed somehow. if (pItem->IsNotEmptyBag()) @@ -12310,10 +12336,10 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update) UpdateExpertise(OFF_ATTACK); // equipment visual show - SetVisibleItemSlot(slot, NULL); + SetVisibleItemSlot(slot, nullptr); } - m_items[slot] = NULL; + m_items[slot] = nullptr; } else if (Bag* pBag = GetBagByPos(bag)) pBag->RemoveItem(slot, update); @@ -12339,7 +12365,8 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update) void Player::DestroyItemCount(uint32 itemEntry, uint32 count, bool update, bool unequip_check) { - TC_LOG_DEBUG("entities.player.items", "STORAGE: DestroyItemCount item = %u, count = %u", itemEntry, count); + TC_LOG_DEBUG("entities.player.items", "Player::DestroyItemCount: Player '%s' (%s), Item: %u, Count: %u", + GetName().c_str(), GetGUID().ToString().c_str(), itemEntry, count); uint32 remcount = 0; // in inventory @@ -12530,7 +12557,8 @@ void Player::DestroyItemCount(uint32 itemEntry, uint32 count, bool update, bool void Player::DestroyZoneLimitedItem(bool update, uint32 new_zone) { - TC_LOG_DEBUG("entities.player.items", "STORAGE: DestroyZoneLimitedItem in map %u and area %u", GetMapId(), new_zone); + TC_LOG_DEBUG("entities.player.items", "Player::DestroyZoneLimitedItem: In map %u and area %u for player '%s' (%s)", + GetMapId(), new_zone, GetName().c_str(), GetGUID().ToString().c_str()); // in inventory for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) @@ -12562,7 +12590,8 @@ void Player::DestroyConjuredItems(bool update) { // used when entering arena // destroys all conjured items - TC_LOG_DEBUG("entities.player.items", "STORAGE: DestroyConjuredItems"); + TC_LOG_DEBUG("entities.player.items", "Player::DestroyConjuredItems: Player '%s' (%s)", + GetName().c_str(), GetGUID().ToString().c_str()); // in inventory for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) @@ -12588,7 +12617,7 @@ void Player::DestroyConjuredItems(bool update) Item* Player::GetItemByEntry(uint32 entry) const { // in inventory - for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) if (pItem->GetEntry() == entry) return pItem; @@ -12598,19 +12627,19 @@ Item* Player::GetItemByEntry(uint32 entry) const if (pItem->GetEntry() == entry) return pItem; - for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) if (Bag* pBag = GetBagByPos(i)) for (uint32 j = 0; j < pBag->GetBagSize(); ++j) if (Item* pItem = pBag->GetItemByPos(j)) if (pItem->GetEntry() == entry) return pItem; - for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; ++i) if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) if (pItem->GetEntry() == entry) return pItem; - return NULL; + return nullptr; } void Player::DestroyItemCount(Item* pItem, uint32 &count, bool update) @@ -12618,7 +12647,8 @@ void Player::DestroyItemCount(Item* pItem, uint32 &count, bool update) if (!pItem) return; - TC_LOG_DEBUG("entities.player.items", "STORAGE: DestroyItemCount item (GUID: %u, Entry: %u) count = %u", pItem->GetGUID().GetCounter(), pItem->GetEntry(), count); + TC_LOG_DEBUG("entities.player.items", "Player::DestroyItemCount: Player '%s' (%s), Item (%s, Entry: %u), Count: %u", + GetName().c_str(), GetGUID().ToString().c_str(), pItem->GetGUID().ToString().c_str(), pItem->GetEntry(), count); if (pItem->GetCount() <= count) { @@ -12648,28 +12678,28 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count) Item* pSrcItem = GetItemByPos(srcbag, srcslot); if (!pSrcItem) { - SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL); + SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, nullptr); return; } if (pSrcItem->m_lootGenerated) // prevent split looting item (item { //best error message found for attempting to split while looting - SendEquipError(EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL); + SendEquipError(EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, nullptr); return; } // not let split all items (can be only at cheating) if (pSrcItem->GetCount() == count) { - SendEquipError(EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL); + SendEquipError(EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, nullptr); return; } // not let split more existing items (can be only at cheating) if (pSrcItem->GetCount() < count) { - SendEquipError(EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT, pSrcItem, NULL); + SendEquipError(EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT, pSrcItem, nullptr); return; } @@ -12681,11 +12711,12 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count) return; } - TC_LOG_DEBUG("entities.player.items", "STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count); + TC_LOG_DEBUG("entities.player.items", "Player::SplitItem: Player '%s' (%s), Bag: %u, Slot: %u, Item: %u, Count: %u", + GetName().c_str(), GetGUID().ToString().c_str(), dstbag, dstslot, pSrcItem->GetEntry(), count); Item* pNewItem = pSrcItem->CloneItem(count, this); if (!pNewItem) { - SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL); + SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, nullptr); return; } @@ -12700,7 +12731,7 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count) { delete pNewItem; pSrcItem->SetCount(pSrcItem->GetCount() + count); - SendEquipError(msg, pSrcItem, NULL); + SendEquipError(msg, pSrcItem, nullptr); return; } @@ -12720,7 +12751,7 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count) { delete pNewItem; pSrcItem->SetCount(pSrcItem->GetCount() + count); - SendEquipError(msg, pSrcItem, NULL); + SendEquipError(msg, pSrcItem, nullptr); return; } @@ -12740,7 +12771,7 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count) { delete pNewItem; pSrcItem->SetCount(pSrcItem->GetCount() + count); - SendEquipError(msg, pSrcItem, NULL); + SendEquipError(msg, pSrcItem, nullptr); return; } @@ -12766,7 +12797,8 @@ void Player::SwapItem(uint16 src, uint16 dst) if (!pSrcItem) return; - TC_LOG_DEBUG("entities.player.items", "STORAGE: SwapItem bag = %u, slot = %u, item = %u", dstbag, dstslot, pSrcItem->GetEntry()); + TC_LOG_DEBUG("entities.player.items", "Player::SwapItem: Player '%s' (%s), Bag: %u, Slot: %u, Item: %u", + GetName().c_str(), GetGUID().ToString().c_str(), dstbag, dstslot, pSrcItem->GetEntry()); if (!IsAlive()) { @@ -12831,7 +12863,7 @@ void Player::SwapItem(uint16 src, uint16 dst) InventoryResult msg = CanStoreItem(dstbag, dstslot, dest, pSrcItem, false); if (msg != EQUIP_ERR_OK) { - SendEquipError(msg, pSrcItem, NULL); + SendEquipError(msg, pSrcItem, nullptr); return; } @@ -12846,7 +12878,7 @@ void Player::SwapItem(uint16 src, uint16 dst) InventoryResult msg = CanBankItem(dstbag, dstslot, dest, pSrcItem, false); if (msg != EQUIP_ERR_OK) { - SendEquipError(msg, pSrcItem, NULL); + SendEquipError(msg, pSrcItem, nullptr); return; } @@ -12860,7 +12892,7 @@ void Player::SwapItem(uint16 src, uint16 dst) InventoryResult msg = CanEquipItem(dstslot, dest, pSrcItem, false); if (msg != EQUIP_ERR_OK) { - SendEquipError(msg, pSrcItem, NULL); + SendEquipError(msg, pSrcItem, nullptr); return; } @@ -12969,8 +13001,8 @@ void Player::SwapItem(uint16 src, uint16 dst) { if (Bag* dstBag = pDstItem->ToBag()) { - Bag* emptyBag = NULL; - Bag* fullBag = NULL; + Bag* emptyBag = nullptr; + Bag* fullBag = nullptr; if (srcBag->IsEmpty() && !IsBagPos(src)) { emptyBag = srcBag; @@ -13083,7 +13115,6 @@ void Player::SwapItem(uint16 src, uint16 dst) if (bagItem->m_lootGenerated) { m_session->DoLootRelease(GetLootGUID()); - released = true; // not realy needed here break; } } @@ -13128,10 +13159,11 @@ void Player::AddItemToBuyBackSlot(Item* pItem) } RemoveItemFromBuyBackSlot(slot, true); - TC_LOG_DEBUG("entities.player.items", "STORAGE: AddItemToBuyBackSlot item = %u, slot = %u", pItem->GetEntry(), slot); + TC_LOG_DEBUG("entities.player.items", "Player::AddItemToBuyBackSlot: Player '%s' (%s), Item: %u, Slot: %u", + GetName().c_str(), GetGUID().ToString().c_str(), pItem->GetEntry(), slot); m_items[slot] = pItem; - time_t base = time(NULL); + time_t base = time(nullptr); uint32 etime = uint32(base - m_logintime + (30 * 3600)); uint32 eslot = slot - BUYBACK_SLOT_START; @@ -13150,15 +13182,17 @@ void Player::AddItemToBuyBackSlot(Item* pItem) Item* Player::GetItemFromBuyBackSlot(uint32 slot) { - TC_LOG_DEBUG("entities.player.items", "STORAGE: GetItemFromBuyBackSlot slot = %u", slot); + TC_LOG_DEBUG("entities.player.items", "Player::GetItemFromBuyBackSlot: Player '%s' (%s), Slot: %u", + GetName().c_str(), GetGUID().ToString().c_str(), slot); if (slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END) return m_items[slot]; - return NULL; + return nullptr; } void Player::RemoveItemFromBuyBackSlot(uint32 slot, bool del) { - TC_LOG_DEBUG("entities.player.items", "STORAGE: RemoveItemFromBuyBackSlot slot = %u", slot); + TC_LOG_DEBUG("entities.player.items", "Player::RemoveItemFromBuyBackSlot: Player '%s' (%s), Slot: %u", + GetName().c_str(), GetGUID().ToString().c_str(), slot); if (slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END) { Item* pItem = m_items[slot]; @@ -13169,7 +13203,7 @@ void Player::RemoveItemFromBuyBackSlot(uint32 slot, bool del) pItem->SetState(ITEM_REMOVED, this); } - m_items[slot] = NULL; + m_items[slot] = nullptr; uint32 eslot = slot - BUYBACK_SLOT_START; SetGuidValue(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), ObjectGuid::Empty); @@ -13182,9 +13216,9 @@ void Player::RemoveItemFromBuyBackSlot(uint32 slot, bool del) } } -void Player::SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2, uint32 itemid) +void Player::SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2, uint32 itemid) const { - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_INVENTORY_CHANGE_FAILURE (%u)", msg); + WorldPacket data(SMSG_INVENTORY_CHANGE_FAILURE, (msg == EQUIP_ERR_CANT_EQUIP_LEVEL_I ? 22 : 18)); data << uint8(msg); @@ -13225,9 +13259,8 @@ void Player::SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2, uint GetSession()->SendPacket(&data); } -void Player::SendBuyError(BuyResult msg, Creature* creature, uint32 item, uint32 param) +void Player::SendBuyError(BuyResult msg, Creature* creature, uint32 item, uint32 param) const { - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_BUY_FAILED"); WorldPacket data(SMSG_BUY_FAILED, (8+4+4+1)); data << uint64(creature ? creature->GetGUID() : ObjectGuid::Empty); data << uint32(item); @@ -13237,9 +13270,8 @@ void Player::SendBuyError(BuyResult msg, Creature* creature, uint32 item, uint32 GetSession()->SendPacket(&data); } -void Player::SendSellError(SellResult msg, Creature* creature, ObjectGuid guid, uint32 param) +void Player::SendSellError(SellResult msg, Creature* creature, ObjectGuid guid, uint32 param) const { - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_SELL_ITEM"); WorldPacket data(SMSG_SELL_ITEM, (8+8+(param?4:0)+1)); // last check 2.0.10 data << uint64(creature ? creature->GetGUID() : ObjectGuid::Empty); data << uint64(guid); @@ -13275,9 +13307,9 @@ void Player::TradeCancel(bool sendback) // cleanup delete m_trade; - m_trade = NULL; + m_trade = nullptr; delete trader->m_trade; - trader->m_trade = NULL; + trader->m_trade = nullptr; } } @@ -13309,7 +13341,8 @@ void Player::UpdateItemDuration(uint32 time, bool realtimeonly) if (m_itemDuration.empty()) return; - TC_LOG_DEBUG("entities.player.items", "Player::UpdateItemDuration(%u, %u)", time, realtimeonly); + TC_LOG_DEBUG("entities.player.items", "Player::UpdateItemDuration: Player '%s' (%s), Time: %u, RealTimeOnly: %u", + GetName().c_str(), GetGUID().ToString().c_str(), time, realtimeonly); for (ItemDurationList::const_iterator itr = m_itemDuration.begin(); itr != m_itemDuration.end();) { @@ -13770,7 +13803,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool { if (getClass() == CLASS_SHAMAN) { - float addValue = 0.0f; + float addValue; if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) { addValue = float(enchant_amount * item->GetTemplate()->Delay / 1000.0f); @@ -13791,10 +13824,11 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool // nothing do.. break; default: - TC_LOG_ERROR("entities.player", "Unknown item enchantment (id = %d) display type: %d", enchant_id, enchant_display_type); + TC_LOG_ERROR("entities.player", "Player::ApplyEnchantment: Unknown item enchantment (ID: %u, DisplayType: %u) for player '%s' (%s)", + enchant_id, enchant_display_type, GetName().c_str(), GetGUID().ToString().c_str()); break; - } /*switch (enchant_display_type)*/ - } /*for*/ + } + } } // visualize enchantment at player and equipped items @@ -14053,14 +14087,14 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool if (!optionBroadcastText) { /// Find localizations from database. - if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, menuId))) + if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, itr->second.OptionIndex))) ObjectMgr::GetLocaleString(gossipMenuLocale->OptionText, locale, strOptionText); } if (!boxBroadcastText) { /// Find localizations from database. - if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, menuId))) + if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, itr->second.OptionIndex))) ObjectMgr::GetLocaleString(gossipMenuLocale->BoxText, locale, strBoxText); } } @@ -14125,7 +14159,8 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men { if (gossipOptionId > GOSSIP_OPTION_QUESTGIVER) { - TC_LOG_ERROR("entities.player", "Player guid %u requested invalid gossip option for GameObject entry %u.", GetGUID().GetCounter(), source->GetEntry()); + TC_LOG_ERROR("entities.player", "Player '%s' (%s) requests invalid gossip option for GameObject (Entry: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), source->GetEntry()); return; } } @@ -14137,7 +14172,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men int32 cost = int32(item->BoxMoney); if (!HasEnoughMoney(cost)) { - SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0); + SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, nullptr, 0, 0); PlayerTalkClass->SendCloseGossip(); return; } @@ -14162,7 +14197,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men break; case GOSSIP_OPTION_SPIRITHEALER: if (isDead()) - source->ToCreature()->CastSpell(source->ToCreature(), 17251, true, NULL, NULL, GetGUID()); + source->ToCreature()->CastSpell(source->ToCreature(), 17251, true, nullptr, nullptr, GetGUID()); break; case GOSSIP_OPTION_QUESTGIVER: PrepareQuestMenu(guid); @@ -14183,8 +14218,8 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men { // Cast spells that teach dual spec // Both are also ImplicitTarget self and must be cast by player - CastSpell(this, 63680, true, NULL, NULL, GetGUID()); - CastSpell(this, 63624, true, NULL, NULL, GetGUID()); + CastSpell(this, 63680, true, nullptr, nullptr, GetGUID()); + CastSpell(this, 63624, true, nullptr, nullptr, GetGUID()); // Should show another Gossip text with "Congratulations..." PlayerTalkClass->SendCloseGossip(); @@ -14229,7 +14264,8 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men if (bgTypeId == BATTLEGROUND_TYPE_NONE) { - TC_LOG_ERROR("entities.player", "User (guid %u) requested battlegroundlist from an NPC who is not a battlemaster.", GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player '%s' (%s) requested battlegroundlist from an invalid creature (%s)", + GetName().c_str(), GetGUID().ToString().c_str(), source->GetGUID().ToString().c_str()); return; } @@ -14437,7 +14473,7 @@ bool Player::IsActiveQuest(uint32 quest_id) const return m_QuestStatus.find(quest_id) != m_QuestStatus.end(); } -Quest const* Player::GetNextQuest(ObjectGuid guid, Quest const* quest) +Quest const* Player::GetNextQuest(ObjectGuid guid, Quest const* quest) const { QuestRelationBounds objectQR; @@ -14454,7 +14490,7 @@ Quest const* Player::GetNextQuest(ObjectGuid guid, Quest const* quest) if (pGameObject) objectQR = sObjectMgr->GetGOQuestRelationBounds(pGameObject->GetEntry()); else - return NULL; + return nullptr; } uint32 nextQuestID = quest->GetNextQuestInChain(); @@ -14464,7 +14500,7 @@ Quest const* Player::GetNextQuest(ObjectGuid guid, Quest const* quest) return sObjectMgr->GetQuestTemplate(nextQuestID); } - return NULL; + return nullptr; } bool Player::CanSeeStartQuest(Quest const* quest) @@ -14494,7 +14530,7 @@ bool Player::CanTakeQuest(Quest const* quest, bool msg) && SatisfyQuestConditions(quest, msg); } -bool Player::CanAddQuest(Quest const* quest, bool msg) +bool Player::CanAddQuest(Quest const* quest, bool msg) const { if (!SatisfyQuestLog(msg)) return false; @@ -14509,9 +14545,9 @@ bool Player::CanAddQuest(Quest const* quest, bool msg) // player already have max number (in most case 1) source item, no additional item needed and quest can be added. if (msg2 == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS) return true; - else if (msg2 != EQUIP_ERR_OK) + if (msg2 != EQUIP_ERR_OK) { - SendEquipError(msg2, NULL, NULL, srcitem); + SendEquipError(msg2, nullptr, nullptr, srcitem); return false; } } @@ -14630,7 +14666,7 @@ bool Player::CanRewardQuest(Quest const* quest, bool msg) GetItemCount(quest->RequiredItemId[i]) < quest->RequiredItemCount[i]) { if (msg) - SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL, quest->RequiredItemId[i]); + SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, nullptr, nullptr, quest->RequiredItemId[i]); return false; } } @@ -14662,7 +14698,7 @@ void Player::AddQuestAndCheckCompletion(Quest const* quest, Object* questGiver) case TYPEID_ITEM: case TYPEID_CONTAINER: { - Item* item = (Item*)questGiver; + Item* item = static_cast<Item*>(questGiver); sScriptMgr->OnQuestAccept(this, item, quest); // destroy not required for quest finish quest starting item @@ -14704,7 +14740,7 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg) InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, quest->RewardChoiceItemId[reward], quest->RewardChoiceItemCount[reward]); if (res != EQUIP_ERR_OK) { - SendEquipError(res, NULL, NULL, quest->RewardChoiceItemId[reward]); + SendEquipError(res, nullptr, nullptr, quest->RewardChoiceItemId[reward]); return false; } } @@ -14719,7 +14755,7 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg) InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, quest->RewardItemId[i], quest->RewardItemIdCount[i]); if (res != EQUIP_ERR_OK) { - SendEquipError(res, NULL, NULL, quest->RewardItemId[i]); + SendEquipError(res, nullptr, nullptr, quest->RewardItemId[i]); return false; } } @@ -14782,7 +14818,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) AddTimedQuest(quest_id); questStatusData.Timer = timeAllowed * IN_MILLISECONDS; - qtime = static_cast<uint32>(time(NULL)) + timeAllowed; + qtime = static_cast<uint32>(time(nullptr)) + timeAllowed; } else questStatusData.Timer = 0; @@ -14836,7 +14872,7 @@ void Player::CompleteQuest(uint32 quest_id) if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled { - // prepare Quest Tracker datas + // prepare Quest Tracker data PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_QUEST_TRACK_COMPLETE_TIME); stmt->setUInt32(0, quest_id); stmt->setUInt32(1, GetGUID().GetCounter()); @@ -14930,7 +14966,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, int32 moneyRew = 0; if (getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - GiveXP(XP, NULL); + GiveXP(XP, nullptr); else moneyRew = int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY)); @@ -14948,7 +14984,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, // honor reward if (uint32 honor = quest->CalculateHonorGain(getLevel())) - RewardHonor(NULL, 0, honor); + RewardHonor(nullptr, 0, honor); // title reward if (quest->GetCharTitleId()) @@ -14998,7 +15034,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, // StoreNewItem, mail reward, etc. save data directly to the database // to prevent exploitable data desynchronisation we save the quest status to the database too // (to prevent rewarding this quest another time while rewards were already given out) - SQLTransaction trans = SQLTransaction(NULL); + SQLTransaction trans = SQLTransaction(nullptr); _SaveQuestStatus(trans); if (announce) @@ -15102,7 +15138,8 @@ bool Player::SatisfyQuestSkill(Quest const* qInfo, bool msg) const if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestSkill: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have required skill value.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestSkill: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have the required skill value.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; @@ -15111,30 +15148,33 @@ bool Player::SatisfyQuestSkill(Quest const* qInfo, bool msg) const return true; } -bool Player::SatisfyQuestLevel(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestLevel(Quest const* qInfo, bool msg) const { if (getLevel() < qInfo->GetMinLevel()) { if (msg) { SendCanTakeQuestResponse(INVALIDREASON_QUEST_FAILED_LOW_LEVEL); - TC_LOG_DEBUG("misc", "SatisfyQuestLevel: Sent INVALIDREASON_QUEST_FAILED_LOW_LEVEL (questId: %u) because player does not have required (min) level.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestLevel: Sent INVALIDREASON_QUEST_FAILED_LOW_LEVEL (QuestID: %u) because player '%s' (%s) doesn't have the required (min) level.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } - else if (qInfo->GetMaxLevel() > 0 && getLevel() > qInfo->GetMaxLevel()) + + if (qInfo->GetMaxLevel() > 0 && getLevel() > qInfo->GetMaxLevel()) { if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); // There doesn't seem to be a specific response for too high player level - TC_LOG_DEBUG("misc", "SatisfyQuestLevel: Sent INVALIDREASON_QUEST_FAILED_LOW_LEVEL (questId: %u) because player does not have required (max) level.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestLevel: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have the required (max) level.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } return true; } -bool Player::SatisfyQuestLog(bool msg) +bool Player::SatisfyQuestLog(bool msg) const { // exist free slot if (FindQuestSlot(0) < MAX_QUEST_LOG_SIZE) @@ -15144,7 +15184,6 @@ bool Player::SatisfyQuestLog(bool msg) { WorldPacket data(SMSG_QUESTLOG_FULL, 0); GetSession()->SendPacket(&data); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTLOG_FULL"); } return false; } @@ -15188,7 +15227,8 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required quest(s) (1).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have the required quest (1).", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } @@ -15221,7 +15261,8 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required quest(s) (2).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have the required quest (2).", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; @@ -15237,7 +15278,8 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required quest(s) (3).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have required quest (3).", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; @@ -15255,7 +15297,8 @@ bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestClass: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player is not (one of) the required class(es).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestClass: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have required class.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; @@ -15264,7 +15307,7 @@ bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const return true; } -bool Player::SatisfyQuestRace(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestRace(Quest const* qInfo, bool msg) const { uint32 reqraces = qInfo->GetAllowableRaces(); if (reqraces == 0) @@ -15274,7 +15317,8 @@ bool Player::SatisfyQuestRace(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_QUEST_FAILED_WRONG_RACE); - TC_LOG_DEBUG("misc", "SatisfyQuestRace: Sent INVALIDREASON_QUEST_FAILED_WRONG_RACE (questId: %u) because player is not (one of) the required race(s).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestRace: Sent INVALIDREASON_QUEST_FAILED_WRONG_RACE (QuestID: %u) because player '%s' (%s) doesn't have required race.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; @@ -15290,7 +15334,8 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required reputation (min).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't required reputation (min).", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } @@ -15301,7 +15346,8 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required reputation (max).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't required reputation (max).", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } @@ -15322,14 +15368,15 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) return true; } -bool Player::SatisfyQuestStatus(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestStatus(Quest const* qInfo, bool msg) const { if (GetQuestStatus(qInfo->GetQuestId()) != QUEST_STATUS_NONE) { if (msg) { SendCanTakeQuestResponse(INVALIDREASON_QUEST_ALREADY_ON); - TC_LOG_DEBUG("misc", "SatisfyQuestStatus: Sent INVALIDREASON_QUEST_ALREADY_ON (questId: %u) because player quest status is not NONE.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestStatus: Sent INVALIDREASON_QUEST_ALREADY_ON (QuestID: %u) because player '%s' (%s) quest status is not NONE.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } @@ -15343,7 +15390,8 @@ bool Player::SatisfyQuestConditions(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestConditions: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not meet the conditions.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestConditions: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't meet conditions.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } TC_LOG_DEBUG("condition", "Player::SatisfyQuestConditions: conditions not met for quest %u", qInfo->GetQuestId()); return false; @@ -15351,14 +15399,15 @@ bool Player::SatisfyQuestConditions(Quest const* qInfo, bool msg) return true; } -bool Player::SatisfyQuestTimed(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestTimed(Quest const* qInfo, bool msg) const { if (!m_timedquests.empty() && qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED)) { if (msg) { SendCanTakeQuestResponse(INVALIDREASON_QUEST_ONLY_ONE_TIMED); - TC_LOG_DEBUG("misc", "SatisfyQuestTimed: Sent INVALIDREASON_QUEST_ONLY_ONE_TIMED (questId: %u) because player is already on a timed quest.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestTimed: Sent INVALIDREASON_QUEST_ONLY_ONE_TIMED (QuestID: %u) because player '%s' (%s) is already on a timed quest.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } @@ -15389,7 +15438,8 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestExclusiveGroup: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player already did all daily quests in exclusive group.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestExclusiveGroup: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) already did daily quests in exclusive group.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; @@ -15401,7 +15451,8 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestExclusiveGroup: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player has already taken one or more quests in the exclusive group.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestExclusiveGroup: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) already did quest in exclusive group.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } @@ -15409,7 +15460,7 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) return true; } -bool Player::SatisfyQuestNextChain(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestNextChain(Quest const* qInfo, bool msg) const { uint32 nextQuest = qInfo->GetNextQuestInChain(); if (!nextQuest) @@ -15421,7 +15472,8 @@ bool Player::SatisfyQuestNextChain(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestNextChain: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player already did or started next quest in chain.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestNextChain: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) already did or started next quest in chain.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } @@ -15448,7 +15500,8 @@ bool Player::SatisfyQuestPrevChain(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestNextChain: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player already did or started next quest in chain.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestNextChain: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) already did or started next quest in chain.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); } return false; } @@ -15463,7 +15516,7 @@ bool Player::SatisfyQuestPrevChain(Quest const* qInfo, bool msg) return true; } -bool Player::SatisfyQuestDay(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestDay(Quest const* qInfo, bool msg) const { if (!qInfo->IsDaily() && !qInfo->IsDFQuest()) return true; @@ -15551,8 +15604,8 @@ bool Player::GiveQuestSourceItem(Quest const* quest) // player already have max amount required item, just report success else if (msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS) return true; - else - SendEquipError(msg, NULL, NULL, srcitem); + + SendEquipError(msg, nullptr, nullptr, srcitem); return false; } @@ -15581,7 +15634,7 @@ bool Player::TakeQuestSourceItem(uint32 questId, bool msg) if (res != EQUIP_ERR_OK) { if (msg) - SendEquipError(res, NULL, NULL, srcItemId); + SendEquipError(res, nullptr, nullptr, srcItemId); return false; } @@ -15827,15 +15880,17 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) } // not used in Trinity, but used in scripting code -uint16 Player::GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry) +uint16 Player::GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry) const { Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id); if (!qInfo) return 0; - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) - if (qInfo->RequiredNpcOrGo[j] == entry) - return m_QuestStatus[quest_id].CreatureOrGOCount[j]; + auto itr = m_QuestStatus.find(quest_id); + if (itr != m_QuestStatus.end()) + for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) + if (qInfo->RequiredNpcOrGo[j] == entry) + return itr->second.CreatureOrGOCount[j]; return 0; } @@ -15958,7 +16013,7 @@ void Player::GroupEventHappens(uint32 questId, WorldObject const* pEventObject) { if (Group* group = GetGroup()) { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* player = itr->GetSource(); @@ -16068,7 +16123,7 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::E { uint16 addkillcount = 1; uint32 real_entry = entry; - Creature* killed = NULL; + Creature* killed = nullptr; if (guid) { killed = GetMap()->GetCreature(guid); @@ -16421,21 +16476,19 @@ bool Player::HasQuestForItem(uint32 itemid) const return false; } -void Player::SendQuestComplete(uint32 quest_id) +void Player::SendQuestComplete(uint32 quest_id) const { if (quest_id) { WorldPacket data(SMSG_QUESTUPDATE_COMPLETE, 4); data << uint32(quest_id); GetSession()->SendPacket(&data); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTUPDATE_COMPLETE quest = %u", quest_id); } } -void Player::SendQuestReward(Quest const* quest, uint32 XP) +void Player::SendQuestReward(Quest const* quest, uint32 XP) const { uint32 questid = quest->GetQuestId(); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid); sGameEventMgr->HandleQuestComplete(questid); WorldPacket data(SMSG_QUESTGIVER_QUEST_COMPLETE, (4+4+4+4+4)); data << uint32(questid); @@ -16457,7 +16510,7 @@ void Player::SendQuestReward(Quest const* quest, uint32 XP) GetSession()->SendPacket(&data); } -void Player::SendQuestFailed(uint32 questId, InventoryResult reason) +void Player::SendQuestFailed(uint32 questId, InventoryResult reason) const { if (questId) { @@ -16465,11 +16518,10 @@ void Player::SendQuestFailed(uint32 questId, InventoryResult reason) data << uint32(questId); data << uint32(reason); // failed reason (valid reasons: 4, 16, 50, 17, 74, other values show default message) GetSession()->SendPacket(&data); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED"); } } -void Player::SendQuestTimerFailed(uint32 quest_id) +void Player::SendQuestTimerFailed(uint32 quest_id) const { if (quest_id) { @@ -16488,7 +16540,7 @@ void Player::SendCanTakeQuestResponse(QuestFailedReason msg) const TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_QUEST_INVALID"); } -void Player::SendQuestConfirmAccept(const Quest* quest, Player* pReceiver) +void Player::SendQuestConfirmAccept(const Quest* quest, Player* pReceiver) const { if (pReceiver) { @@ -16509,7 +16561,7 @@ void Player::SendQuestConfirmAccept(const Quest* quest, Player* pReceiver) } } -void Player::SendPushToPartyResponse(Player* player, uint8 msg) +void Player::SendPushToPartyResponse(Player* player, uint8 msg) const { if (player) { @@ -16521,7 +16573,7 @@ void Player::SendPushToPartyResponse(Player* player, uint8 msg) } } -void Player::SendQuestUpdateAddItem(Quest const* /*quest*/, uint32 /*item_idx*/, uint16 /*count*/) +void Player::SendQuestUpdateAddItem(Quest const* /*quest*/, uint32 /*item_idx*/, uint16 /*count*/) const { WorldPacket data(SMSG_QUESTUPDATE_ADD_ITEM, 0); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTUPDATE_ADD_ITEM"); @@ -16558,7 +16610,6 @@ void Player::SendQuestUpdateAddPlayer(Quest const* quest, uint16 old_count, uint ASSERT(old_count + add_count < 65536 && "player count store in 16 bits"); WorldPacket data(SMSG_QUESTUPDATE_ADD_PVP_KILL, (3*4)); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTUPDATE_ADD_PVP_KILL"); data << uint32(quest->GetQuestId()); data << uint32(old_count + add_count); data << uint32(quest->GetPlayersSlain()); @@ -16766,22 +16817,22 @@ bool Player::IsLoading() const bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) { - //// 0 1 2 3 4 5 6 7 8 9 10 11 - //QueryResult* result = CharacterDatabase.PQuery("SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, " - // 12 13 14 15 16 17 18 19 20 21 22 23 24 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + //QueryResult* result = CharacterDatabase.PQuery("SELECT guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, playerFlags, " + // 17 18 19 20 21 22 23 24 25 26 27 28 29 //"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " - // 25 26 27 28 29 30 31 32 33 34 35 36 37 38 + // 30 31 32 33 34 35 36 37 38 39 40 41 42 43 //"resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, " - // 39 40 41 42 43 44 45 46 47 48 49 + // 44 45 46 47 48 49 50 51 52 53 54 //"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk, " - // 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 + // 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 //"health, power1, power2, power3, power4, power5, power6, power7, instance_id, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, ammoId, knownTitles, actionBars, grantableLevels FROM characters WHERE guid = '%u'", guid); PreparedQueryResult result = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM); if (!result) { std::string name = "<unknown>"; sObjectMgr->GetPlayerNameByGUID(guid, name); - TC_LOG_ERROR("entities.player", "Player %s %s not found in table `characters`, can't load.", name.c_str(), guid.ToString().c_str()); + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player '%s' (%s) not found in table `characters`, can't load. ", name.c_str(), guid.ToString().c_str()); return false; } @@ -16793,13 +16844,13 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // player should be able to load/delete character only with correct account! if (dbAccountId != GetSession()->GetAccountId()) { - TC_LOG_ERROR("entities.player", "Player %s attempts to load from wrong account (current: %u, should be: %u)", guid.ToString().c_str(), GetSession()->GetAccountId(), dbAccountId); + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) loading from wrong account (is: %u, should be: %u)", guid.ToString().c_str(), GetSession()->GetAccountId(), dbAccountId); return false; } if (holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BANNED)) { - TC_LOG_ERROR("entities.player", "%s is banned, can't load.", guid.ToString().c_str()); + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) is banned, can't load.", guid.ToString().c_str()); return false; } @@ -16809,8 +16860,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // check name limitations if (ObjectMgr::CheckPlayerName(m_name, GetSession()->GetSessionDbcLocale()) != CHAR_NAME_SUCCESS || - (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && - sObjectMgr->IsReservedName(m_name))) + (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(m_name))) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_RENAME)); @@ -16825,30 +16875,27 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) uint8 gender = fields[5].GetUInt8(); if (!IsValidGender(gender)) { - TC_LOG_ERROR("entities.player", "Player %s is the wrong gender (%u) and can't be loaded.", guid.ToString().c_str(), gender); + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has wrong gender (%u), can't load.", guid.ToString().c_str(), gender); return false; } - // overwrite some data fields - uint32 bytes0 = 0; - bytes0 |= fields[3].GetUInt8(); // race - bytes0 |= fields[4].GetUInt8() << 8; // class - bytes0 |= gender << 16; // gender - SetUInt32Value(UNIT_FIELD_BYTES_0, bytes0); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_RACE, fields[3].GetUInt8()); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, fields[4].GetUInt8()); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, gender); // check if race/class combination is valid PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); if (!info) { - TC_LOG_ERROR("entities.player", "Player %s has an invalid race/class combination (%u/%u) and can't be loaded.", guid.ToString().c_str(), getRace(), getClass()); + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has wrong race/class (%u/%u), can't load.", guid.ToString().c_str(), getRace(), getClass()); return false; } SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8()); SetUInt32Value(PLAYER_XP, fields[7].GetUInt32()); - _LoadIntoDataField(fields[61].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE); - _LoadIntoDataField(fields[64].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE * 2); + _LoadIntoDataField(fields[66].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE); + _LoadIntoDataField(fields[69].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE * 2); SetObjectScale(1.0f); SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); @@ -16861,33 +16908,39 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) money = MAX_MONEY_AMOUNT; SetMoney(money); - SetUInt32Value(PLAYER_BYTES, fields[9].GetUInt32()); - SetUInt32Value(PLAYER_BYTES_2, fields[10].GetUInt32()); - SetByteValue(PLAYER_BYTES_3, 0, fields[5].GetUInt8()); - SetByteValue(PLAYER_BYTES_3, 1, fields[49].GetUInt8()); + SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID, fields[9].GetUInt8()); + SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID, fields[10].GetUInt8()); + SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID, fields[11].GetUInt8()); + SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID, fields[12].GetUInt8()); + SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE, fields[13].GetUInt8()); + SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS, fields[14].GetUInt8()); + SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE, fields[15].GetUInt8()); + SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER, fields[5].GetUInt8()); + SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_INEBRIATION, fields[54].GetUInt8()); if (!ValidateAppearance( fields[3].GetUInt8(), // race fields[4].GetUInt8(), // class - gender, GetByteValue(PLAYER_BYTES, 2), // hair type - GetByteValue(PLAYER_BYTES, 3), //hair color - uint8(fields[9].GetUInt32() >> 8), // face - GetByteValue(PLAYER_BYTES_2, 0), // facial hair - GetByteValue(PLAYER_BYTES, 0))) // skin color - { - TC_LOG_ERROR("entities.player", "Player %s has wrong Appearance values (Hair/Skin/Color) and can't be loaded.", guid.ToString().c_str()); + gender, + GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID), + GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID), + GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID), + GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE), + GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID))) + { + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has wrong Appearance values (Hair/Skin/Color), can't load.", guid.ToString().c_str()); return false; } - SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32()); - SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[48].GetUInt32()); + SetUInt32Value(PLAYER_FLAGS, fields[16].GetUInt32()); + SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[53].GetUInt32()); - SetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES, fields[47].GetUInt64()); + SetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES, fields[52].GetUInt64()); - SetUInt32Value(PLAYER_AMMO_ID, fields[63].GetUInt32()); + SetUInt32Value(PLAYER_AMMO_ID, fields[68].GetUInt32()); // set which actionbars the client has active - DO NOT REMOVE EVER AGAIN (can be changed though, if it does change fieldwise) - SetByteValue(PLAYER_FIELD_BYTES, 2, fields[65].GetUInt8()); + SetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES, fields[70].GetUInt8()); InitDisplayIds(); @@ -16895,13 +16948,13 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) { SetGuidValue(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2), ObjectGuid::Empty); - SetVisibleItemSlot(slot, NULL); + SetVisibleItemSlot(slot, nullptr); delete m_items[slot]; - m_items[slot] = NULL; + m_items[slot] = nullptr; } - TC_LOG_DEBUG("entities.player.loading", "Load Basic values of player %s: ", m_name.c_str()); + TC_LOG_DEBUG("entities.player.loading", "Player::LoadFromDB: Load Basic value of player '%s' is: ", m_name.c_str()); outDebugValues(); //Need to call it to initialize m_team (m_team can be calculated from race) @@ -16915,21 +16968,21 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) InitPrimaryProfessions(); // to max set before any spell loaded // init saved position, and fix it later if problematic - ObjectGuid::LowType transLowGUID = fields[30].GetUInt32(); - Relocate(fields[12].GetFloat(), fields[13].GetFloat(), fields[14].GetFloat(), fields[16].GetFloat()); - uint32 mapId = fields[15].GetUInt16(); - uint32 instanceId = fields[58].GetUInt32(); + ObjectGuid::LowType transLowGUID = fields[35].GetUInt32(); + Relocate(fields[17].GetFloat(), fields[18].GetFloat(), fields[19].GetFloat(), fields[21].GetFloat()); + uint32 mapId = fields[20].GetUInt16(); + uint32 instanceId = fields[63].GetUInt32(); - uint32 dungeonDiff = fields[38].GetUInt8() & 0x0F; + uint32 dungeonDiff = fields[43].GetUInt8() & 0x0F; if (dungeonDiff >= MAX_DUNGEON_DIFFICULTY) dungeonDiff = DUNGEON_DIFFICULTY_NORMAL; - uint32 raidDiff = (fields[38].GetUInt8() >> 4) & 0x0F; + uint32 raidDiff = (fields[43].GetUInt8() >> 4) & 0x0F; if (raidDiff >= MAX_RAID_DIFFICULTY) raidDiff = RAID_DIFFICULTY_10MAN_NORMAL; SetDungeonDifficulty(Difficulty(dungeonDiff)); // may be changed in _LoadGroup SetRaidDifficulty(Difficulty(raidDiff)); // may be changed in _LoadGroup - std::string taxi_nodes = fields[37].GetString(); + std::string taxi_nodes = fields[42].GetString(); #define RelocateToHomebind(){ mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); } @@ -16937,7 +16990,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) _LoadArenaTeamInfo(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO)); - SetArenaPoints(fields[39].GetUInt32()); + SetArenaPoints(fields[44].GetUInt32()); // check arena teams integrity for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) @@ -16955,12 +17008,12 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) SetArenaTeamInfoField(arena_slot, ArenaTeamInfoType(j), 0); } - SetHonorPoints(fields[40].GetUInt32()); - SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, fields[41].GetUInt32()); - SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, fields[42].GetUInt32()); - SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, fields[43].GetUInt32()); - SetUInt16Value(PLAYER_FIELD_KILLS, 0, fields[44].GetUInt16()); - SetUInt16Value(PLAYER_FIELD_KILLS, 1, fields[45].GetUInt16()); + SetHonorPoints(fields[45].GetUInt32()); + SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, fields[46].GetUInt32()); + SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, fields[47].GetUInt32()); + SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, fields[48].GetUInt32()); + SetUInt16Value(PLAYER_FIELD_KILLS, 0, fields[49].GetUInt16()); + SetUInt16Value(PLAYER_FIELD_KILLS, 1, fields[50].GetUInt16()); _LoadBoundInstances(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES)); _LoadInstanceTimeRestrictions(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES)); @@ -16970,14 +17023,14 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); if (!mapEntry || !IsPositionValid()) { - TC_LOG_ERROR("entities.player", "Player %s has invalid coordinates (MapId: %u X: %f Y: %f Z: %f O: %f). Teleporting player to default race/class location.", + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has invalid coordinates (MapId: %u X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.", guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); RelocateToHomebind(); } // Player was saved in Arena or Bg else if (mapEntry && mapEntry->IsBattlegroundOrArena()) { - Battleground* currentBg = NULL; + Battleground* currentBg = nullptr; if (m_bgData.bgInstanceID) //saved in Battleground currentBg = sBattlegroundMgr->GetBattleground(m_bgData.bgInstanceID, BATTLEGROUND_TYPE_NONE); @@ -17011,7 +17064,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) //if (mapId == MAPID_INVALID) -- code kept for reference if (int16(mapId) == int16(-1)) // Battleground Entry Point not found (???) { - TC_LOG_ERROR("entities.player", "Player %s was in BG in database, but BG was not found and entry point was invalid! Teleporting to default race/class locations.", + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) was in BG in database, but BG was not found and entry point was invalid! Teleport to default race/class locations.", guid.ToString().c_str()); RelocateToHomebind(); } @@ -17027,13 +17080,13 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) { ObjectGuid transGUID(HighGuid::Mo_Transport, transLowGUID); - Transport* transport = NULL; + Transport* transport = nullptr; if (Transport* go = HashMapHolder<Transport>::Find(transGUID)) transport = go; if (transport) { - float x = fields[26].GetFloat(), y = fields[27].GetFloat(), z = fields[28].GetFloat(), o = fields[29].GetFloat(); + float x = fields[31].GetFloat(), y = fields[32].GetFloat(), z = fields[33].GetFloat(), o = fields[34].GetFloat(); m_movementInfo.transport.pos.Relocate(x, y, z, o); transport->CalculatePassengerPosition(x, y, z, &o); @@ -17043,7 +17096,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) std::fabs(m_movementInfo.transport.pos.GetPositionY()) > 250.0f || std::fabs(m_movementInfo.transport.pos.GetPositionZ()) > 250.0f) { - TC_LOG_ERROR("entities.player", "Player %s has invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleporting player to bind location.", + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to bind location.", guid.ToString().c_str(), x, y, z, o); m_movementInfo.transport.Reset(); @@ -17060,7 +17113,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) } else { - TC_LOG_ERROR("entities.player", "Player %s has problems with transport guid (%u). Teleporting to bind location.", + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has problems with transport guid (%u). Teleport to bind location.", guid.ToString().c_str(), transLowGUID); RelocateToHomebind(); @@ -17080,18 +17133,18 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) else if (!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes, GetTeam())) { // problems with taxi path loading - TaxiNodesEntry const* nodeEntry = NULL; + TaxiNodesEntry const* nodeEntry = nullptr; if (uint32 node_id = m_taxi.GetTaxiSource()) nodeEntry = sTaxiNodesStore.LookupEntry(node_id); if (!nodeEntry) // don't know taxi start node, teleport to homebind { - TC_LOG_ERROR("entities.player", "Character %u has wrong data in taxi destination list. Teleporting player to homebind.", GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has wrong data in taxi destination list, teleport to homebind.", GetGUID().ToString().c_str()); RelocateToHomebind(); } else // has start node, teleport to it { - TC_LOG_ERROR("entities.player", "Character %u has too short taxi destination list. Teleporting player to original node.", GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) has too short taxi destination list, teleport to original node.", GetGUID().ToString().c_str()); mapId = nodeEntry->map_id; Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z, 0.0f); } @@ -17120,7 +17173,8 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) { if (GetSession()->Expansion() < mapEntry->Expansion()) { - TC_LOG_DEBUG("entities.player.loading", "Player %s is using client without required expansion, tried to log in to inaccessible map %u.", GetName().c_str(), mapId); + TC_LOG_DEBUG("entities.player.loading", "Player::LoadFromDB: Player '%s' (%s) using client without required expansion tried login at non accessible map %u", + GetName().c_str(), GetGUID().ToString().c_str(), mapId); RelocateToHomebind(); } @@ -17134,7 +17188,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // NOW player must have valid map // load the player's map here if it's not already loaded Map* map = sMapMgr->CreateMap(mapId, this, instanceId); - AreaTrigger const* areaTrigger = NULL; + AreaTrigger const* areaTrigger = nullptr; bool check = false; if (!map) @@ -17189,10 +17243,10 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) } else { - TC_LOG_ERROR("entities.player", "Player %s %s Map: %u, X: %f, Y: %f, Z: %f, O: %f. Areatrigger not found.", + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player '%s' (%s) Map: %u, X: %f, Y: %f, Z: %f, O: %f. Areatrigger not found.", m_name.c_str(), guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); RelocateToHomebind(); - map = NULL; + map = nullptr; } } @@ -17203,7 +17257,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) map = sMapMgr->CreateMap(mapId, this); if (!map) { - TC_LOG_ERROR("entities.player", "Player %s %s Map: %u, X: %f, Y: %f, Z: %f, O: %f. Invalid default map coordinates or instance couldn't be created.", + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player '%s' (%s) Map: %u, X: %f, Y: %f, Z: %f, O: %f. Invalid default map coordinates or instance couldn't be created.", m_name.c_str(), guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); return false; } @@ -17218,12 +17272,12 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE] // this must help in case next save after mass player load after server startup - m_nextSave = urand(m_nextSave/2, m_nextSave*3/2); + m_nextSave = urand(m_nextSave / 2, m_nextSave * 3 / 2); SaveRecallPosition(); - time_t now = time(NULL); - time_t logoutTime = time_t(fields[22].GetUInt32()); + time_t now = time(nullptr); + time_t logoutTime = time_t(fields[27].GetUInt32()); // since last logout (in seconds) uint32 time_diff = uint32(now - logoutTime); //uint64 is excessive for a time_diff in seconds.. uint32 allows for 136~ year difference. @@ -17236,29 +17290,30 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) SetDrunkValue(newDrunkValue); - m_cinematic = fields[18].GetUInt8(); - m_Played_time[PLAYED_TIME_TOTAL]= fields[19].GetUInt32(); - m_Played_time[PLAYED_TIME_LEVEL]= fields[20].GetUInt32(); + m_cinematic = fields[23].GetUInt8(); + m_Played_time[PLAYED_TIME_TOTAL] = fields[24].GetUInt32(); + m_Played_time[PLAYED_TIME_LEVEL] = fields[25].GetUInt32(); - m_resetTalentsCost = fields[24].GetUInt32(); - m_resetTalentsTime = time_t(fields[25].GetUInt32()); + m_resetTalentsCost = fields[29].GetUInt32(); + m_resetTalentsTime = time_t(fields[30].GetUInt32()); - m_taxi.LoadTaxiMask(fields[17].GetString()); // must be before InitTaxiNodesForLevel + m_taxi.LoadTaxiMask(fields[22].GetString()); // must be before InitTaxiNodesForLevel - uint32 extraflags = fields[31].GetUInt16(); + uint32 extraflags = fields[36].GetUInt16(); - m_stableSlots = fields[32].GetUInt8(); + m_stableSlots = fields[37].GetUInt8(); if (m_stableSlots > MAX_PET_STABLES) { - TC_LOG_ERROR("entities.player", "Player can not have more than %u stable slots, but has %u in DB.", MAX_PET_STABLES, uint32(m_stableSlots)); + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) can't have more stable slots than %u, but has %u in DB", + GetGUID().ToString().c_str(), MAX_PET_STABLES, uint32(m_stableSlots)); m_stableSlots = MAX_PET_STABLES; } - m_atLoginFlags = fields[33].GetUInt16(); + m_atLoginFlags = fields[38].GetUInt16(); if (HasAtLoginFlag(AT_LOGIN_RENAME)) { - TC_LOG_ERROR("entities.player", "Player (GUID: %u) tried to login while forced to rename, could not load player.", GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player (%s) tried to login while forced to rename, can't load.'", GetGUID().ToString().c_str()); return false; } @@ -17267,7 +17322,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) m_lastHonorUpdateTime = logoutTime; UpdateHonorFields(); - m_deathExpireTime = time_t(fields[36].GetUInt32()); + m_deathExpireTime = time_t(fields[41].GetUInt32()); if (m_deathExpireTime > now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP) m_deathExpireTime = now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP - 1; @@ -17304,7 +17359,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) InitRunes(); // rest bonus can only be calculated after InitStatsForLevel() - m_rest_bonus = fields[21].GetFloat(); + m_rest_bonus = fields[26].GetFloat(); if (time_diff > 0) { @@ -17312,11 +17367,11 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) float bubble0 = 0.031f; //speed collect rest bonus in offline, in logout, in tavern, city (section/in hour) float bubble1 = 0.125f; - float bubble = fields[23].GetUInt8() > 0 + float bubble = fields[28].GetUInt8() > 0 ? bubble1*sWorld->getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY) : bubble0*sWorld->getRate(RATE_REST_OFFLINE_IN_WILDERNESS); - SetRestBonus(GetRestBonus()+ time_diff*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/72000)*bubble); + SetRestBonus(GetRestBonus() + time_diff*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 72000)*bubble); } // load skills after InitStatsForLevel because it triggering aura apply also @@ -17328,14 +17383,15 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) //mails are loaded only when needed ;-) - when player in game click on mailbox. //_LoadMail(); - m_specsCount = fields[59].GetUInt8(); - m_activeSpec = fields[60].GetUInt8(); + m_specsCount = fields[64].GetUInt8(); + m_activeSpec = fields[65].GetUInt8(); // sanity check if (m_specsCount > MAX_TALENT_SPECS || m_activeSpec > MAX_TALENT_SPEC || m_specsCount < MIN_TALENT_SPECS) { + TC_LOG_ERROR("entities.player", "Player::LoadFromDB: Player %s (%s) has invalid SpecCount = %u and/or invalid ActiveSpec = %u.", + GetName().c_str(), GetGUID().ToString().c_str(), uint32(m_specsCount), uint32(m_activeSpec)); m_activeSpec = 0; - TC_LOG_ERROR("entities.player", "Player %s(GUID: %u) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUID().GetCounter(), m_specsCount, m_activeSpec); } _LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS)); @@ -17379,7 +17435,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES // note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded - uint32 curTitle = fields[46].GetUInt32(); + uint32 curTitle = fields[51].GetUInt32(); if (curTitle && !HasTitle(curTitle)) curTitle = 0; @@ -17402,15 +17458,15 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) UpdateAllStats(); // restore remembered power/health values (but not more max values) - uint32 savedHealth = fields[50].GetUInt32(); + uint32 savedHealth = fields[55].GetUInt32(); SetHealth(savedHealth > GetMaxHealth() ? GetMaxHealth() : savedHealth); for (uint8 i = 0; i < MAX_POWERS; ++i) { - uint32 savedPower = fields[51+i].GetUInt32(); + uint32 savedPower = fields[56 + i].GetUInt32(); SetPower(Powers(i), savedPower > GetMaxPower(Powers(i)) ? GetMaxPower(Powers(i)) : savedPower); } - TC_LOG_DEBUG("entities.player.loading", "The value of player %s after load item and aura is: ", m_name.c_str()); + TC_LOG_DEBUG("entities.player.loading", "Player::LoadFromDB: The value of player '%s' after load item and aura is: ", m_name.c_str()); outDebugValues(); // GM state @@ -17462,12 +17518,12 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) } // RaF stuff. - m_grantableLevels = fields[66].GetUInt8(); + m_grantableLevels = fields[71].GetUInt8(); if (GetSession()->IsARecruiter() || (GetSession()->GetRecruiterId() != 0)) SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_REFER_A_FRIEND); if (m_grantableLevels > 0) - SetByteValue(PLAYER_FIELD_BYTES, 1, 0x01); + SetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_RAF_GRANTABLE_LEVEL, 0x01); _LoadDeclinedNames(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES)); @@ -17545,7 +17601,8 @@ void Player::_LoadActions(PreparedQueryResult result) ab->uState = ACTIONBUTTON_UNCHANGED; else { - TC_LOG_ERROR("entities.player", " ...at loading, and will also be deleted in DB."); + TC_LOG_ERROR("entities.player", "Player::_LoadActions: Player '%s' (%s) has an invalid action button (Button: %u, Action: %u, Type: %u). It will be deleted at next save.", + GetName().c_str(), GetGUID().ToString().c_str(), button, action, type); // Will be deleted in DB at next save (it can create data until save but marked as deleted). m_actionButtons[button].uState = ACTIONBUTTON_DELETED; @@ -17556,7 +17613,7 @@ void Player::_LoadActions(PreparedQueryResult result) void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) { - TC_LOG_DEBUG("entities.player.loading", "Loading auras for player %u.", GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player.loading", "Player::_LoadAuras: Loading auras for %s", GetGUID().ToString().c_str()); /* 0 1 2 3 4 5 6 7 8 9 10 QueryResult* result = CharacterDatabase.PQuery("SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, @@ -17589,7 +17646,8 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); if (!spellInfo) { - TC_LOG_ERROR("entities.player", "Unknown aura (spellid %u), ignored.", spellid); + TC_LOG_ERROR("entities.player", "Player::_LoadAuras: Player '%s' (%s) has an invalid aura (SpellID: %u), ignoring.", + GetName().c_str(), GetGUID().ToString().c_str(), spellid); continue; } @@ -17613,7 +17671,7 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) else remaincharges = 0; - if (Aura* aura = Aura::TryCreate(spellInfo, effmask, this, NULL, &baseDamage[0], NULL, caster_guid)) + if (Aura* aura = Aura::TryCreate(spellInfo, effmask, this, nullptr, &baseDamage[0], nullptr, caster_guid)) { if (!aura->CanBeSaved()) { @@ -17623,7 +17681,8 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]); aura->ApplyForTargets(); - TC_LOG_DEBUG("entities.player", "Added aura spellid %u, effectmask %u.", spellInfo->Id, effmask); + TC_LOG_DEBUG("entities.player", "Player::_LoadAuras: Added aura (SpellID: %u, EffectMask: %u) to player '%s (%s)", + spellInfo->Id, effmask, GetName().c_str(), GetGUID().ToString().c_str()); } } while (result->NextRow()); @@ -17646,13 +17705,13 @@ void Player::_LoadGlyphAuras() continue; } else - TC_LOG_ERROR("entities.player", "Player %s has glyph with typeflags %u in slot with typeflags %u, removing.", m_name.c_str(), gp->TypeFlags, gs->TypeFlags); + TC_LOG_ERROR("entities.player", "Player::_LoadGlyphAuras: Player '%s' (%s) has glyph with typeflags %u in slot with typeflags %u, removing.", GetName().c_str(), GetGUID().ToString().c_str(), gp->TypeFlags, gs->TypeFlags); } else - TC_LOG_ERROR("entities.player", "Player %s has non-existing glyph slot entry %u on index %u.", m_name.c_str(), GetGlyphSlot(i), i); + TC_LOG_ERROR("entities.player", "Player::_LoadGlyphAuras: Player '%s' (%s) has not existing glyph slot entry %u on index %u", GetName().c_str(), GetGUID().ToString().c_str(), GetGlyphSlot(i), i); } else - TC_LOG_ERROR("entities.player", "Player %s has non-existing glyph entry %u on index %u.", m_name.c_str(), glyph, i); + TC_LOG_ERROR("entities.player", "Player::_LoadGlyphAuras: Player '%s' (%s) has not existing glyph entry %u on index %u", GetName().c_str(), GetGUID().ToString().c_str(), glyph, i); // On any error remove glyph SetGlyph(i, 0); @@ -17671,7 +17730,7 @@ void Player::LoadCorpse(PreparedQueryResult result) { Field* fields = result->Fetch(); _corpseLocation.WorldRelocate(fields[0].GetUInt16(), fields[1].GetFloat(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat()); - ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(_corpseLocation.GetMapId())->Instanceable()); + ApplyModByteFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_FLAGS, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(_corpseLocation.GetMapId())->Instanceable()); } else ResurrectPlayer(0.5f); @@ -17707,11 +17766,11 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) ObjectGuid::LowType bagGuid = fields[11].GetUInt32(); uint8 slot = fields[12].GetUInt8(); - uint8 err = EQUIP_ERR_OK; + InventoryResult err = EQUIP_ERR_OK; // Item is not in bag if (!bagGuid) { - item->SetContainer(NULL); + item->SetContainer(nullptr); item->SetSlot(slot); if (IsInventoryPos(INVENTORY_SLOT_BAG_0, slot)) @@ -17768,8 +17827,8 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) } else { - TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player (GUID: %u, name: '%s') has item (GUID: %u, entry: %u) which doesnt have a valid bag (Bag GUID: %u, slot: %u). Possible cheat?", - GetGUID().GetCounter(), GetName().c_str(), item->GetGUID().GetCounter(), item->GetEntry(), bagGuid, slot); + TC_LOG_ERROR("entities.player", "Player::_LoadInventory: Player '%s' (%s) has item (%s, entry: %u) which doesnt have a valid bag (Bag %u, slot: %u). Possible cheat?", + GetName().c_str(), GetGUID().ToString().c_str(), item->GetGUID().ToString().c_str(), item->GetEntry(), bagGuid, slot); item->DeleteFromInventoryDB(trans); delete item; continue; @@ -17782,8 +17841,8 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) item->SetState(ITEM_UNCHANGED, this); else { - TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player (GUID: %u, name: '%s') has item (GUID: %u, entry: %u) which can't be loaded into inventory (Bag GUID: %u, slot: %u) for reason %u. Item will be sent by mail.", - GetGUID().GetCounter(), GetName().c_str(), item->GetGUID().GetCounter(), item->GetEntry(), bagGuid, slot, err); + TC_LOG_ERROR("entities.player", "Player::_LoadInventory: Player '%s' (%s) has item (%s, entry: %u) which can't be loaded into inventory (Bag %u, slot: %u) by reason %u. Item will be sent by mail.", + GetName().c_str(), GetGUID().ToString().c_str(), item->GetGUID().ToString().c_str(), item->GetEntry(), bagGuid, slot, uint32(err)); item->DeleteFromInventoryDB(trans); problematicItems.push_back(item); } @@ -17813,7 +17872,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, Field* fields) { - Item* item = NULL; + Item* item = nullptr; ObjectGuid::LowType itemGuid = fields[13].GetUInt32(); uint32 itemEntry = fields[14].GetUInt32(); if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry)) @@ -17822,7 +17881,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F item = NewItemOrBag(proto); if (item->LoadFromDB(itemGuid, GetGUID(), fields, itemEntry)) { - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; // Do not allow to have item limited to another map/zone in alive state if (IsAlive() && item->IsLimitedToAnotherMapOrZone(GetMapId(), zoneId)) @@ -17925,7 +17984,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F Item::DeleteFromInventoryDB(trans, itemGuid); item->FSetState(ITEM_REMOVED); item->SaveToDB(trans); // it also deletes item object! - item = NULL; + item = nullptr; } } else @@ -17961,7 +18020,8 @@ void Player::_LoadMailedItems(Mail* mail) if (!proto) { - TC_LOG_ERROR("entities.player", "Player %u has an unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUID().GetCounter(), itemGuid, itemTemplate, mail->messageID); + TC_LOG_ERROR("entities.player", "Player '%s' (%s) has unknown item_template in mailed items (GUID: %u, Entry: %u) in mail (%u), deleted.", + GetName().c_str(), GetGUID().ToString().c_str(), itemGuid, itemTemplate, mail->messageID); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM); stmt->setUInt32(0, itemGuid); @@ -17977,7 +18037,7 @@ void Player::_LoadMailedItems(Mail* mail) if (!item->LoadFromDB(itemGuid, ObjectGuid(HighGuid::Player, fields[13].GetUInt32()), fields, itemTemplate)) { - TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems - Item in mail (%u) doesn't exist!!! - item guid: %u, deleted from mail.", mail->messageID, itemGuid); + TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: %u) in mail (%u) doesn't exist, deleted from mail.", itemGuid, mail->messageID); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM); stmt->setUInt32(0, itemGuid); @@ -17985,7 +18045,7 @@ void Player::_LoadMailedItems(Mail* mail) item->FSetState(ITEM_REMOVED); - SQLTransaction temp = SQLTransaction(NULL); + SQLTransaction temp = SQLTransaction(nullptr); item->SaveToDB(temp); // it also deletes item object ! continue; } @@ -18040,7 +18100,7 @@ void Player::_LoadMail() if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId)) { - TC_LOG_ERROR("entities.player", "Player::_LoadMail - Mail (%u) contains a non-existing MailTemplateId (%u), removing at load.", m->messageID, m->mailTemplateId); + TC_LOG_ERROR("entities.player", "Player::_LoadMail: Mail (%u) has nonexistent MailTemplateId (%u), remove at load", m->messageID, m->mailTemplateId); m->mailTemplateId = 0; } @@ -18097,8 +18157,8 @@ void Player::_LoadQuestStatus(PreparedQueryResult result) else { questStatusData.Status = QUEST_STATUS_INCOMPLETE; - TC_LOG_ERROR("entities.player", "Player %s (GUID: %u) has invalid quest %d status (%u), replaced by QUEST_STATUS_INCOMPLETE(3).", - GetName().c_str(), GetGUID().GetCounter(), quest_id, qstatus); + TC_LOG_ERROR("entities.player", "Player::_LoadQuestStatus: Player '%s' (%s) has invalid quest %d status (%u), replaced by QUEST_STATUS_INCOMPLETE(3).", + GetName().c_str(), GetGUID().ToString().c_str(), quest_id, qstatus); } questStatusData.Explored = (fields[2].GetUInt8() > 0); @@ -18147,7 +18207,8 @@ void Player::_LoadQuestStatus(PreparedQueryResult result) ++slot; } - TC_LOG_DEBUG("entities.player.loading", "Quest status is {%u} for quest {%u} for player (GUID: %u)", questStatusData.Status, quest_id, GetGUID().GetCounter()); + + TC_LOG_DEBUG("entities.player.loading", "Player::_LoadQuestStatus: Quest status is {%u} for quest {%u} for player (%s)", questStatusData.Status, quest_id, GetGUID().ToString().c_str()); } } while (result->NextRow()); @@ -18237,7 +18298,8 @@ void Player::_LoadDailyQuestStatus(PreparedQueryResult result) SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx, quest_id); ++quest_daily_idx; - TC_LOG_DEBUG("entities.player.loading", "Daily quest (%u) cooldown for player (GUID: %u)", quest_id, GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player.loading", "Player::_LoadDailyQuestStatus: Loaded daily quest cooldown (QuestID: %u) for player '%s' (%s)", + quest_id, GetName().c_str(), GetGUID().ToString().c_str()); } while (result->NextRow()); } @@ -18260,7 +18322,9 @@ void Player::_LoadWeeklyQuestStatus(PreparedQueryResult result) continue; m_weeklyquests.insert(quest_id); - TC_LOG_DEBUG("entities.player.loading", "Weekly quest {%u} cooldown for player (GUID: %u)", quest_id, GetGUID().GetCounter()); + + TC_LOG_DEBUG("entities.player.loading", "Player::_LoadWeeklyQuestStatus: Loaded weekly quest cooldown (QuestID: %u) for player '%s' (%s)", + quest_id, GetName().c_str(), GetGUID().ToString().c_str()); } while (result->NextRow()); } @@ -18284,7 +18348,8 @@ void Player::_LoadSeasonalQuestStatus(PreparedQueryResult result) continue; m_seasonalquests[event_id].insert(quest_id); - TC_LOG_DEBUG("entities.player.loading", "Seasonal quest {%u} cooldown for player (GUID: %u)", quest_id, GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player.loading", "Player::_LoadSeasonalQuestStatus: Loaded seasonal quest cooldown (QuestID: %u) for player '%s' (%s)", + quest_id, GetName().c_str(), GetGUID().ToString().c_str()); } while (result->NextRow()); } @@ -18307,7 +18372,8 @@ void Player::_LoadMonthlyQuestStatus(PreparedQueryResult result) continue; m_monthlyquests.insert(quest_id); - TC_LOG_DEBUG("entities.player.loading", "Monthly quest {%u} cooldown for player (GUID: %u)", quest_id, GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player.loading", "Player::_LoadMonthlyQuestStatus: Loaded monthly quest cooldown (QuestID: %u) for player '%s' (%s)", + quest_id, GetName().c_str(), GetGUID().ToString().c_str()); } while (result->NextRow()); } @@ -18384,12 +18450,14 @@ void Player::_LoadBoundInstances(PreparedQueryResult result) if (!mapEntry || !mapEntry->IsDungeon()) { - TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) has bind to a non-existing or non-dungeon map %d (%s).", GetName().c_str(), GetGUID().GetCounter(), mapId, mapname.c_str()); + TC_LOG_ERROR("entities.player", "Player::_LoadBoundInstances: Player '%s' (%s) has bind to not existed or not dungeon map %d (%s)", + GetName().c_str(), GetGUID().ToString().c_str(), mapId, mapname.c_str()); deleteInstance = true; } else if (difficulty >= MAX_DIFFICULTY) { - TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) has a bind to a non-existing difficulty %d instance for map %u (%s)", GetName().c_str(), GetGUID().GetCounter(), difficulty, mapId, mapname.c_str()); + TC_LOG_ERROR("entities.player", "Player::_LoadBoundInstances: player '%s' (%s) has bind to not existed difficulty %d instance for map %u (%s)", + GetName().c_str(), GetGUID().ToString().c_str(), difficulty, mapId, mapname.c_str()); deleteInstance = true; } else @@ -18397,12 +18465,14 @@ void Player::_LoadBoundInstances(PreparedQueryResult result) MapDifficulty const* mapDiff = GetMapDifficultyData(mapId, Difficulty(difficulty)); if (!mapDiff) { - TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) has a bind to a non-existing difficulty %d instance for map %u (%s).", GetName().c_str(), GetGUID().GetCounter(), difficulty, mapId, mapname.c_str()); + TC_LOG_ERROR("entities.player", "Player::_LoadBoundInstances: player '%s' (%s) has bind to not existed difficulty %d instance for map %u (%s)", + GetName().c_str(), GetGUID().ToString().c_str(), difficulty, mapId, mapname.c_str()); deleteInstance = true; } else if (!perm && group) { - TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) is in group %d, but has a non-permanent character bind to map %d (%s), %d, %d.", GetName().c_str(), GetGUID().GetCounter(), group->GetLowGUID(), mapId, mapname.c_str(), instanceId, difficulty); + TC_LOG_ERROR("entities.player", "Player::_LoadBoundInstances: player '%s' (%s) is in group %s but has a non-permanent character bind to map %d (%s), %d, %d", + GetName().c_str(), GetGUID().ToString().c_str(), group->GetGUID().ToString().c_str(), mapId, mapname.c_str(), instanceId, difficulty); deleteInstance = true; } } @@ -18432,7 +18502,7 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty // some instances only have one difficulty MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(mapid, difficulty); if (!mapDiff) - return NULL; + return nullptr; BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); if (itr != m_boundInstances[difficulty].end()) @@ -18538,12 +18608,13 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, B bind.perm = permanent; bind.extendState = extendState; if (!load) - TC_LOG_DEBUG("maps", "Player::BindToInstance: %s(%d) is now bound to map %d, instance %d, difficulty %d", GetName().c_str(), GetGUID().GetCounter(), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty()); - sScriptMgr->OnPlayerBindToInstance(this, save->GetDifficulty(), save->GetMapId(), permanent, uint8(extendState)); + TC_LOG_DEBUG("maps", "Player::BindToInstance: Player '%s' (%s) is now bound to map (ID: %d, Instance: %d, Difficulty: %d)", + GetName().c_str(), GetGUID().ToString().c_str(), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty()); + sScriptMgr->OnPlayerBindToInstance(this, save->GetDifficulty(), save->GetMapId(), permanent, extendState); return &bind; } - return NULL; + return nullptr; } void Player::BindToInstance() @@ -18577,7 +18648,7 @@ void Player::SendRaidInfo() size_t p_counter = data.wpos(); data << uint32(counter); // placeholder - time_t now = time(NULL); + time_t now = time(nullptr); for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { @@ -18800,7 +18871,8 @@ bool Player::_LoadHomeBind(PreparedQueryResult result) PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); if (!info) { - TC_LOG_ERROR("entities.player", "Player (Name %s) has incorrect race/class pair. Can't be loaded.", GetName().c_str()); + TC_LOG_ERROR("entities.player", "Player::_LoadHomeBind: Player '%s' (%s) has incorrect race/class (%u/%u) pair. Can't load.", + GetGUID().ToString().c_str(), GetName().c_str(), uint32(getRace()), uint32(getClass())); return false; } @@ -18848,8 +18920,8 @@ bool Player::_LoadHomeBind(PreparedQueryResult result) CharacterDatabase.Execute(stmt); } - TC_LOG_DEBUG("entities.player", "Setting player home position - mapid: %u, areaid: %u, X: %f, Y: %f, Z: %f", - m_homebindMapId, m_homebindAreaId, m_homebindX, m_homebindY, m_homebindZ); + TC_LOG_DEBUG("entities.player", "Player::_LoadHomeBind: Setting home position (MapID: %u, AreaID: %u, X: %f, Y: %f, Z: %f) of player '%s' (%s)", + m_homebindMapId, m_homebindAreaId, m_homebindX, m_homebindY, m_homebindZ, GetName().c_str(), GetGUID().ToString().c_str()); return true; } @@ -18873,13 +18945,13 @@ void Player::SaveToDB(bool create /*=false*/) // first save/honor gain after midnight will also update the player's honor fields UpdateHonorFields(); - TC_LOG_DEBUG("entities.unit", "The value of player %s at save: ", m_name.c_str()); + TC_LOG_DEBUG("entities.unit", "Player::SaveToDB: The value of player %s at save: ", m_name.c_str()); outDebugValues(); if (!create) sScriptMgr->OnPlayerSave(this); - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; uint8 index = 0; if (create) @@ -18892,12 +18964,17 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setString(index++, GetName()); stmt->setUInt8(index++, getRace()); stmt->setUInt8(index++, getClass()); - stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_3, 0)); // save gender from PLAYER_BYTES_3, UNIT_BYTES_0 changes with every transform effect + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER)); // save gender from PLAYER_BYTES_3, UNIT_BYTES_0 changes with every transform effect stmt->setUInt8(index++, getLevel()); stmt->setUInt32(index++, GetUInt32Value(PLAYER_XP)); stmt->setUInt32(index++, GetMoney()); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_BYTES)); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_BYTES_2)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_FLAGS)); stmt->setUInt16(index++, (uint16)GetMapId()); stmt->setUInt32(index++, (uint32)GetInstanceId()); @@ -18922,7 +18999,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_TOTAL]); stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_LEVEL]); stmt->setFloat(index++, finiteAlways(m_rest_bonus)); - stmt->setUInt32(index++, uint32(time(NULL))); + stmt->setUInt32(index++, uint32(time(nullptr))); stmt->setUInt8(index++, (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0)); //save, far from tavern/city //save, but in tavern/city @@ -18987,8 +19064,8 @@ void Player::SaveToDB(bool create /*=false*/) ss << GetUInt32Value(PLAYER__FIELD_KNOWN_TITLES + i) << ' '; stmt->setString(index++, ss.str()); - stmt->setUInt8(index++, GetByteValue(PLAYER_FIELD_BYTES, 2)); - stmt->setUInt32(index++, m_grantableLevels); + stmt->setUInt8(index++, GetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES)); + stmt->setUInt32(index, m_grantableLevels); } else { @@ -18997,12 +19074,17 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setString(index++, GetName()); stmt->setUInt8(index++, getRace()); stmt->setUInt8(index++, getClass()); - stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_3, 0)); // save gender from PLAYER_BYTES_3, UNIT_BYTES_0 changes with every transform effect + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER)); // save gender from PLAYER_BYTES_3, UNIT_BYTES_0 changes with every transform effect stmt->setUInt8(index++, getLevel()); stmt->setUInt32(index++, GetUInt32Value(PLAYER_XP)); stmt->setUInt32(index++, GetMoney()); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_BYTES)); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_BYTES_2)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS)); + stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_FLAGS)); if (!IsBeingTeleported()) @@ -19042,7 +19124,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_TOTAL]); stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_LEVEL]); stmt->setFloat(index++, finiteAlways(m_rest_bonus)); - stmt->setUInt32(index++, uint32(time(NULL))); + stmt->setUInt32(index++, uint32(time(nullptr))); stmt->setUInt8(index++, (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0)); //save, far from tavern/city //save, but in tavern/city @@ -19107,7 +19189,7 @@ void Player::SaveToDB(bool create /*=false*/) ss << GetUInt32Value(PLAYER__FIELD_KNOWN_TITLES + i) << ' '; stmt->setString(index++, ss.str()); - stmt->setUInt8(index++, GetByteValue(PLAYER_FIELD_BYTES, 2)); + stmt->setUInt8(index++, GetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES)); stmt->setUInt32(index++, m_grantableLevels); stmt->setUInt8(index++, IsInWorld() && !GetSession()->PlayerLogout() ? 1 : 0); @@ -19161,7 +19243,7 @@ void Player::SaveInventoryAndGoldToDB(SQLTransaction& trans) SaveGoldToDB(trans); } -void Player::SaveGoldToDB(SQLTransaction& trans) +void Player::SaveGoldToDB(SQLTransaction& trans) const { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_MONEY); stmt->setUInt32(0, GetMoney()); @@ -19171,7 +19253,7 @@ void Player::SaveGoldToDB(SQLTransaction& trans) void Player::_SaveActions(SQLTransaction& trans) { - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; for (ActionButtonList::iterator itr = m_actionButtons.begin(); itr != m_actionButtons.end();) { @@ -19275,7 +19357,7 @@ void Player::_SaveAuras(SQLTransaction& trans) void Player::_SaveInventory(SQLTransaction& trans) { - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; // force items in buyback slots to new state // and remove those that aren't already for (uint8 i = BUYBACK_SLOT_START; i < BUYBACK_SLOT_END; ++i) @@ -19313,7 +19395,8 @@ void Player::_SaveInventory(SQLTransaction& trans) } else { - TC_LOG_ERROR("entities.player", "Can't find %s, but is in refundable storage for player %u ! Removing.", itr->ToString().c_str(), GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::_SaveInventory: Can't find item (%s) in refundable storage for player '%s' (%s), removing.", + itr->ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str()); m_refundableItems.erase(itr); } } @@ -19339,12 +19422,14 @@ void Player::_SaveInventory(SQLTransaction& trans) if (item->GetState() != ITEM_REMOVED) { Item* test = GetItemByPos(item->GetBagSlot(), item->GetSlot()); - if (test == NULL) + if (test == nullptr) { ObjectGuid::LowType bagTestGUID = 0; if (Item* test2 = GetItemByPos(INVENTORY_SLOT_BAG_0, item->GetBagSlot())) bagTestGUID = test2->GetGUID().GetCounter(); - TC_LOG_ERROR("entities.player", "Player(GUID: %u Name: %s)::_SaveInventory - the bag(%u) and slot(%u) values for the item with guid %u (state %d) are incorrect, the player doesn't have an item at that position!", lowGuid, GetName().c_str(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().GetCounter(), (int32)item->GetState()); + + TC_LOG_ERROR("entities.player", "Player::_SaveInventory: Player '%s' (%s) has incorrect values (Bag: %u, Slot: %u) for the item (%s, State: %d). The player doesn't have an item at that position.", + GetName().c_str(), GetGUID().ToString().c_str(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().ToString().c_str(), (int32)item->GetState()); // according to the test that was just performed nothing should be in this slot, delete stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_BAG_SLOT); stmt->setUInt32(0, bagTestGUID); @@ -19360,7 +19445,8 @@ void Player::_SaveInventory(SQLTransaction& trans) } else if (test != item) { - TC_LOG_ERROR("entities.player", "Player(GUID: %u Name: %s)::_SaveInventory - the bag(%u) and slot(%u) values for the item with guid %u are incorrect, the item with guid %u is there instead!", lowGuid, GetName().c_str(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().GetCounter(), test->GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player::_SaveInventory: Player '%s' (%s) has incorrect values (Bag: %u, Slot: %u) for the item (%s). %s is there instead!", + GetName().c_str(), GetGUID().ToString().c_str(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().ToString().c_str(), test->GetGUID().ToString().c_str()); // save all changes to the item... if (item->GetState() != ITEM_NEW) // only for existing items, no duplicates item->SaveToDB(trans); @@ -19399,7 +19485,7 @@ void Player::_SaveMail(SQLTransaction& trans) if (!m_mailsLoaded) return; - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) { @@ -19475,7 +19561,7 @@ void Player::_SaveQuestStatus(SQLTransaction& trans) QuestStatusSaveMap::iterator saveItr; QuestStatusMap::iterator statusItr; - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; bool keepAbandoned = !(sWorld->GetCleaningFlags() & CharacterDatabaseCleaner::CLEANING_FLAG_QUESTSTATUS); @@ -19657,7 +19743,7 @@ void Player::_SaveMonthlyQuestStatus(SQLTransaction& trans) void Player::_SaveSkills(SQLTransaction& trans) { - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; // we don't need transactions here. for (SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end();) { @@ -19713,7 +19799,7 @@ void Player::_SaveSkills(SQLTransaction& trans) void Player::_SaveSpells(SQLTransaction& trans) { - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end();) { @@ -19751,13 +19837,13 @@ void Player::_SaveSpells(SQLTransaction& trans) // save player stats -- only for external usage // real stats will be recalculated on player login -void Player::_SaveStats(SQLTransaction& trans) +void Player::_SaveStats(SQLTransaction& trans) const { // check if stat saving is enabled and if char level is high enough if (!sWorld->getIntConfig(CONFIG_MIN_LEVEL_STAT_SAVE) || getLevel() < sWorld->getIntConfig(CONFIG_MIN_LEVEL_STAT_SAVE)) return; - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_STATS); stmt->setUInt32(0, GetGUID().GetCounter()); @@ -19821,7 +19907,7 @@ void Player::UpdateSpeakTime() if (GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHAT_SPAM)) return; - time_t current = time (NULL); + time_t current = time(nullptr); if (m_speakTime > current) { uint32 max_count = sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_COUNT); @@ -19847,14 +19933,14 @@ void Player::UpdateSpeakTime() bool Player::CanSpeak() const { - return GetSession()->m_muteTime <= time (NULL); + return GetSession()->m_muteTime <= time (nullptr); } /*********************************************************/ /*** LOW LEVEL FUNCTIONS:Notifiers ***/ /*********************************************************/ -void Player::SendAttackSwingNotInRange() +void Player::SendAttackSwingNotInRange() const { WorldPacket data(SMSG_ATTACKSWING_NOTINRANGE, 0); GetSession()->SendPacket(&data); @@ -19888,48 +19974,38 @@ void Player::SetUInt32ValueInArray(Tokenizer& tokens, uint16 index, uint32 value void Player::Customize(CharacterCustomizeInfo const* customizeInfo, SQLTransaction& trans) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PLAYERBYTES2); - stmt->setUInt32(0, customizeInfo->Guid.GetCounter()); - PreparedQueryResult result = CharacterDatabase.Query(stmt); - - if (!result) - return; - - Field* fields = result->Fetch(); - - uint32 playerBytes2 = fields[0].GetUInt32(); - playerBytes2 &= ~0xFF; - playerBytes2 |= customizeInfo->FacialHair; - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GENDER_PLAYERBYTES); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GENDER_AND_APPEARANCE); stmt->setUInt8(0, customizeInfo->Gender); - stmt->setUInt32(1, customizeInfo->Skin | (customizeInfo->Face << 8) | (customizeInfo->HairStyle << 16) | (customizeInfo->HairColor << 24)); - stmt->setUInt32(2, playerBytes2); - stmt->setUInt32(3, customizeInfo->Guid.GetCounter()); + stmt->setUInt8(1, customizeInfo->Skin); + stmt->setUInt8(2, customizeInfo->Face); + stmt->setUInt8(3, customizeInfo->HairStyle); + stmt->setUInt8(4, customizeInfo->HairColor); + stmt->setUInt8(5, customizeInfo->FacialHair); + stmt->setUInt32(6, customizeInfo->Guid.GetCounter()); CharacterDatabase.ExecuteOrAppend(trans, stmt); } -void Player::SendAttackSwingDeadTarget() +void Player::SendAttackSwingDeadTarget() const { WorldPacket data(SMSG_ATTACKSWING_DEADTARGET, 0); GetSession()->SendPacket(&data); } -void Player::SendAttackSwingCantAttack() +void Player::SendAttackSwingCantAttack() const { WorldPacket data(SMSG_ATTACKSWING_CANT_ATTACK, 0); GetSession()->SendPacket(&data); } -void Player::SendAttackSwingCancelAttack() +void Player::SendAttackSwingCancelAttack() const { WorldPacket data(SMSG_CANCEL_COMBAT, 0); GetSession()->SendPacket(&data); } -void Player::SendAttackSwingBadFacingAttack() +void Player::SendAttackSwingBadFacingAttack() const { WorldPacket data(SMSG_ATTACKSWING_BADFACING, 0); GetSession()->SendPacket(&data); @@ -19942,7 +20018,7 @@ void Player::SendAutoRepeatCancel(Unit* target) SendMessageToSet(&data, false); } -void Player::SendExplorationExperience(uint32 Area, uint32 Experience) +void Player::SendExplorationExperience(uint32 Area, uint32 Experience) const { WorldPacket data(SMSG_EXPLORATION_EXPERIENCE, 8); data << uint32(Area); @@ -19950,7 +20026,7 @@ void Player::SendExplorationExperience(uint32 Area, uint32 Experience) GetSession()->SendPacket(&data); } -void Player::SendDungeonDifficulty(bool IsInGroup) +void Player::SendDungeonDifficulty(bool IsInGroup) const { uint8 val = 0x00000001; WorldPacket data(MSG_SET_DUNGEON_DIFFICULTY, 12); @@ -19960,7 +20036,7 @@ void Player::SendDungeonDifficulty(bool IsInGroup) GetSession()->SendPacket(&data); } -void Player::SendRaidDifficulty(bool IsInGroup, int32 forcedDifficulty) +void Player::SendRaidDifficulty(bool IsInGroup, int32 forcedDifficulty) const { uint8 val = 0x00000001; WorldPacket data(MSG_SET_RAID_DIFFICULTY, 12); @@ -19970,7 +20046,7 @@ void Player::SendRaidDifficulty(bool IsInGroup, int32 forcedDifficulty) GetSession()->SendPacket(&data); } -void Player::SendResetFailedNotify(uint32 mapid) +void Player::SendResetFailedNotify(uint32 mapid) const { WorldPacket data(SMSG_RESET_FAILED_NOTIFY, 4); data << uint32(mapid); @@ -20026,14 +20102,14 @@ void Player::ResetInstances(uint8 method, bool isRaid) } } -void Player::SendResetInstanceSuccess(uint32 MapId) +void Player::SendResetInstanceSuccess(uint32 MapId) const { WorldPacket data(SMSG_INSTANCE_RESET, 4); data << uint32(MapId); GetSession()->SendPacket(&data); } -void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) +void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) const { /*reasons for instance reset failure: // 0: There are players inside the instance. @@ -20111,12 +20187,12 @@ Pet* Player::GetPet() const if (ObjectGuid pet_guid = GetPetGUID()) { if (!pet_guid.IsPet()) - return NULL; + return nullptr; Pet* pet = ObjectAccessor::GetPet(*this, pet_guid); if (!pet) - return NULL; + return nullptr; if (IsInWorld() && pet) return pet; @@ -20126,7 +20202,7 @@ Pet* Player::GetPet() const //const_cast<Player*>(this)->SetPetGUID(0); } - return NULL; + return nullptr; } void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) @@ -20136,7 +20212,8 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) if (pet) { - TC_LOG_DEBUG("entities.pet", "RemovePet %u, %u, %u", pet->GetEntry(), mode, returnreagent); + TC_LOG_DEBUG("entities.pet", "Player::RemovePet: Player '%s' (%s), Pet (Entry: %u, Mode: %u, ReturnReagent: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), pet->GetEntry(), mode, returnreagent); if (pet->m_removed) return; @@ -20221,7 +20298,7 @@ void Player::StopCastingCharm() if (charm->GetTypeId() == TYPEID_UNIT) { if (charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET)) - ((Puppet*)charm)->UnSummon(); + static_cast<Puppet*>(charm)->UnSummon(); else if (charm->IsVehicle()) ExitVehicle(); } @@ -20230,14 +20307,14 @@ void Player::StopCastingCharm() if (GetCharmGUID()) { - TC_LOG_FATAL("entities.player", "Player %s (%s) is not able to uncharm unit (%s)!", GetName().c_str(), GetGUID().ToString().c_str(), GetCharmGUID().ToString().c_str()); - if (charm->GetCharmerGUID()) + TC_LOG_FATAL("entities.player", "Player::StopCastingCharm: Player '%s' (%s) is not able to uncharm unit (%s)", GetName().c_str(), GetGUID().ToString().c_str(), GetCharmGUID().ToString().c_str()); + if (!charm->GetCharmerGUID().IsEmpty()) { - TC_LOG_FATAL("entities.player", "Charmed unit has charmer %s", charm->GetCharmerGUID().ToString().c_str()); + TC_LOG_FATAL("entities.player", "Player::StopCastingCharm: Charmed unit has charmer %s", charm->GetCharmerGUID().ToString().c_str()); ABORT(); } - else - SetCharm(charm, false); + + SetCharm(charm, false); } } @@ -20325,7 +20402,7 @@ bool Player::RemoveMItem(uint32 id) return mMitems.erase(id) ? true : false; } -void Player::SendOnCancelExpectedVehicleRideAura() +void Player::SendOnCancelExpectedVehicleRideAura() const { WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0); GetSession()->SendPacket(&data); @@ -20390,7 +20467,7 @@ void Player::PossessSpellInitialize() if (!charmInfo) { - TC_LOG_ERROR("entities.player", "Player::PossessSpellInitialize(): charm (%s) has no charminfo!", charm->GetGUID().ToString().c_str()); + TC_LOG_ERROR("entities.player", "Player::PossessSpellInitialize: charm (%s) has no charminfo!", charm->GetGUID().ToString().c_str()); return; } @@ -20437,7 +20514,8 @@ void Player::VehicleSpellInitialize() if (!sConditionMgr->IsObjectMeetingVehicleSpellConditions(vehicle->GetEntry(), spellId, this, vehicle)) { - TC_LOG_DEBUG("condition", "VehicleSpellInitialize: conditions not met for Vehicle entry %u spell %u", vehicle->ToCreature()->GetEntry(), spellId); + TC_LOG_DEBUG("condition", "Player::VehicleSpellInitialize: Player '%s' (%s) doesn't meet conditions for vehicle (Entry: %u, Spell: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), vehicle->ToCreature()->GetEntry(), spellId); data << uint16(0) << uint8(0) << uint8(i+8); continue; } @@ -20467,7 +20545,8 @@ void Player::CharmSpellInitialize() CharmInfo* charmInfo = charm->GetCharmInfo(); if (!charmInfo) { - TC_LOG_ERROR("entities.player", "Player::CharmSpellInitialize(): the player's charm (%s) has no charminfo!", charm->GetGUID().ToString().c_str()); + TC_LOG_ERROR("entities.player", "Player::CharmSpellInitialize(): Player '%s' (%s) has a charm (%s) but no no charminfo!", + GetName().c_str(), GetGUID().ToString().c_str(), charm->GetGUID().ToString().c_str()); return; } @@ -20512,14 +20591,14 @@ void Player::CharmSpellInitialize() GetSession()->SendPacket(&data); } -void Player::SendRemoveControlBar() +void Player::SendRemoveControlBar() const { WorldPacket data(SMSG_PET_SPELLS, 8); data << uint64(0); GetSession()->SendPacket(&data); } -bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell) +bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell) const { if (!mod || !spellInfo) return false; @@ -20537,7 +20616,7 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod void Player::AddSpellMod(SpellModifier* mod, bool apply) { - TC_LOG_DEBUG("spells", "Player::AddSpellMod %d", mod->spellId); + TC_LOG_DEBUG("spells", "Player::AddSpellMod: Player '%s' (%s), SpellID: %d", GetName().c_str(), GetGUID().ToString().c_str(), mod->spellId); uint16 Opcode = (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; int i = 0; @@ -20708,7 +20787,7 @@ void Player::SetSpellModTakingSpell(Spell* spell, bool apply) } // send Proficiency -void Player::SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) +void Player::SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) const { WorldPacket data(SMSG_SET_PROFICIENCY, 1 + 4); data << uint8(itemClass) << uint32(itemSubclassMask); @@ -20830,13 +20909,13 @@ void Player::SetRestBonus(float rest_bonus_new) // update data for client if ((GetsRecruitAFriendBonus(true) && (GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0))) - SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RAF_LINKED); + SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE, REST_STATE_RAF_LINKED); else { if (m_rest_bonus > 10) - SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RESTED); + SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE, REST_STATE_RESTED); else if (m_rest_bonus <= 1) - SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NOT_RAF_LINKED); + SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE, REST_STATE_NOT_RAF_LINKED); } //RestTickUpdate @@ -20954,7 +21033,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc uint32 firstcost = 0; uint32 prevnode = sourcenode; - uint32 lastnode = 0; + uint32 lastnode; for (uint32 i = 1; i < nodes.size(); ++i) { @@ -20987,7 +21066,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 // change but I couldn't find a suitable alternative. OK to use class because only DK // can use this taxi. - uint32 mount_display_id = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetTeam(), npc == NULL || (sourcenode == 315 && getClass() == CLASS_DEATH_KNIGHT)); + uint32 mount_display_id = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetTeam(), npc == nullptr || (sourcenode == 315 && getClass() == CLASS_DEATH_KNIGHT)); // in spell case allow 0 model if ((mount_display_id == 0 && spellid == 0) || sourcepath == 0) @@ -21047,7 +21126,7 @@ bool Player::ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid /*= 0*/) nodes[0] = entry->from; nodes[1] = entry->to; - return ActivateTaxiPathTo(nodes, NULL, spellid); + return ActivateTaxiPathTo(nodes, nullptr, spellid); } void Player::CleanupAfterTaxiFlight() @@ -21058,13 +21137,13 @@ void Player::CleanupAfterTaxiFlight() getHostileRefManager().setOnlineOfflineState(true); } -void Player::ContinueTaxiFlight() +void Player::ContinueTaxiFlight() const { uint32 sourceNode = m_taxi.GetTaxiSource(); if (!sourceNode) return; - TC_LOG_DEBUG("entities.unit", "WORLD: Restart character %u taxi flight", GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.unit", "Player::ContinueTaxiFlight: Restart %s taxi flight", GetGUID().ToString().c_str()); uint32 mountDisplayId = sObjectMgr->GetTaxiMountDisplayId(sourceNode, GetTeam(), true); if (!mountDisplayId) @@ -21077,7 +21156,7 @@ void Player::ContinueTaxiFlight() TaxiPathNodeList const& nodeList = sTaxiPathNodesByPath[path]; - float distPrev = MAP_SIZE*MAP_SIZE; + float distPrev; float distNext = (nodeList[0]->LocX - GetPositionX())*(nodeList[0]->LocX - GetPositionX()) + (nodeList[0]->LocY - GetPositionY())*(nodeList[0]->LocY - GetPositionY()) + @@ -21166,11 +21245,11 @@ void Player::InitDisplayIds() PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); if (!info) { - TC_LOG_ERROR("entities.player", "Player %s (%s) has incorrect race/class pair. Can't init display ids.", GetName().c_str(), GetGUID().ToString().c_str()); + TC_LOG_ERROR("entities.player", "Player::InitDisplayIds: Player '%s' (%s) has incorrect race/class pair. Can't init display ids.", GetName().c_str(), GetGUID().ToString().c_str()); return; } - uint8 gender = GetByteValue(PLAYER_BYTES_3, 0); + uint8 gender = GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER); switch (gender) { case GENDER_FEMALE: @@ -21182,7 +21261,7 @@ void Player::InitDisplayIds() SetNativeDisplayId(info->displayId_m); break; default: - TC_LOG_ERROR("entities.player", "Player %s (%s) has invalid gender %u", GetName().c_str(), GetGUID().ToString().c_str(), gender); + TC_LOG_ERROR("entities.player", "Player::InitDisplayIds: Player '%s' (%s) has invalid gender %u", GetName().c_str(), GetGUID().ToString().c_str(), gender); } } @@ -21195,7 +21274,7 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c CanEquipNewItem(slot, uiDest, item, false); if (msg != EQUIP_ERR_OK) { - SendEquipError(msg, NULL, NULL, item); + SendEquipError(msg, nullptr, nullptr, item); return false; } @@ -21265,13 +21344,13 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item); if (!pProto) { - SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, item, 0); + SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, item, 0); return false; } if (!(pProto->AllowableClass & getClassMask()) && pProto->Bonding == BIND_WHEN_PICKED_UP && !IsGameMaster()) { - SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, item, 0); + SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, item, 0); return false; } @@ -21281,14 +21360,16 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin Creature* creature = GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); if (!creature) { - TC_LOG_DEBUG("network", "WORLD: BuyItemFromVendor - %s not found or you can't interact with him.", vendorguid.ToString().c_str()); - SendBuyError(BUY_ERR_DISTANCE_TOO_FAR, NULL, item, 0); + TC_LOG_DEBUG("network", "Player::BuyItemFromVendorSlot: Vendor (%s) not found or player '%s' (%s) can't interact with him.", + vendorguid.ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str()); + SendBuyError(BUY_ERR_DISTANCE_TOO_FAR, nullptr, item, 0); return false; } if (!sConditionMgr->IsObjectMeetingVendorItemConditions(creature->GetEntry(), item, this, creature)) { - TC_LOG_DEBUG("condition", "BuyItemFromVendor: conditions not met for creature entry %u item %u", creature->GetEntry(), item); + TC_LOG_DEBUG("condition", "Player::BuyItemFromVendorSlot: Player '%s' (%s) doesn't meed conditions for creature (Entry: %u, Item: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), creature->GetEntry(), item); SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, item, 0); return false; } @@ -21335,21 +21416,21 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); if (!iece) { - TC_LOG_ERROR("entities.player", "Item %u has wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost); + TC_LOG_ERROR("entities.player", "Player::BuyItemFromVendorSlot: Item %u has wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost); return false; } // honor points price if (GetHonorPoints() < (iece->reqhonorpoints * count)) { - SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL); + SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, nullptr, nullptr); return false; } // arena points price if (GetArenaPoints() < (iece->reqarenapoints * count)) { - SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL); + SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, nullptr, nullptr); return false; } @@ -21358,7 +21439,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin { if (iece->reqitem[i] && !HasItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count))) { - SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, nullptr, nullptr); return false; } } @@ -21367,7 +21448,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin if (GetMaxPersonalArenaRatingRequirement(iece->reqarenaslot) < iece->reqpersonalarenarating) { // probably not the proper equip err - SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK, NULL, NULL); + SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK, nullptr, nullptr); return false; } } @@ -21378,7 +21459,8 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin uint32 maxCount = MAX_MONEY_AMOUNT / pProto->BuyPrice; if ((uint32)count > maxCount) { - TC_LOG_ERROR("entities.player", "Player %s tried to buy %u item id %u, causing overflow.", GetName().c_str(), (uint32)count, pProto->ItemId); + TC_LOG_ERROR("entities.player", "Player::BuyItemFromVendorSlot: Player '%s' (%s) tried to buy item (ItemID: %u, Count: %u), causing overflow", + GetName().c_str(), GetGUID().ToString().c_str(), pProto->ItemId, (uint32)count); count = (uint8)maxCount; } price = pProto->BuyPrice * count; //it should not exceed MAX_MONEY_AMOUNT @@ -21402,7 +21484,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin { if (pProto->BuyCount * count != 1) { - SendEquipError(EQUIP_ERR_ITEM_CANT_BE_EQUIPPED, NULL, NULL); + SendEquipError(EQUIP_ERR_ITEM_CANT_BE_EQUIPPED, nullptr, nullptr); return false; } if (!_StoreOrEquipNewItem(vendorslot, item, count, bag, slot, price, pProto, creature, crItem, false)) @@ -21410,7 +21492,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin } else { - SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, nullptr, nullptr); return false; } @@ -21472,7 +21554,8 @@ void Player::UpdateHomebindTime(uint32 time) data << uint32(m_HomebindTimer); data << uint32(1); GetSession()->SendPacket(&data); - TC_LOG_DEBUG("maps", "PLAYER: Player '%s' (GUID: %u) will be teleported to homebind in 60 seconds.", GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_DEBUG("maps", "Player::UpdateHomebindTime: Player '%s' (%s) will be teleported to homebind in 60 seconds", + GetName().c_str(), GetGUID().ToString().c_str()); } } @@ -21508,7 +21591,7 @@ void Player::UpdatePvPState(bool onlyFFA) else // in friendly area { if (IsPvP() && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP) && !pvpInfo.EndTimer) - pvpInfo.EndTimer = time(NULL); // start toggle-off + pvpInfo.EndTimer = time(nullptr); // start toggle-off } } @@ -21528,7 +21611,7 @@ void Player::UpdatePvP(bool state, bool _override) } else { - pvpInfo.EndTimer = time(NULL); + pvpInfo.EndTimer = time(nullptr); SetPvP(state); } } @@ -21556,26 +21639,19 @@ void Player::UpdatePotionCooldown(Spell* spell) m_lastPotionId = 0; } -void Player::setResurrectRequestData(ObjectGuid guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana) +void Player::SetResurrectRequestData(Unit* caster, uint32 health, uint32 mana, uint32 appliedAura) { - m_resurrectGUID = guid; - m_resurrectMap = mapId; - m_resurrectX = X; - m_resurrectY = Y; - m_resurrectZ = Z; - m_resurrectHealth = health; - m_resurrectMana = mana; + ASSERT(!IsResurrectRequested()); + _resurrectionData.reset(new ResurrectionData()); + _resurrectionData->GUID = caster->GetGUID(); + _resurrectionData->Location.WorldRelocate(*caster); + _resurrectionData->Health = health; + _resurrectionData->Mana = mana; + _resurrectionData->Aura = appliedAura; } -void Player::clearResurrectRequestData() -{ - setResurrectRequestData(ObjectGuid::Empty, 0, 0.0f, 0.0f, 0.0f, 0, 0); - - m_ghoulResurrectPlayerGUID = ObjectGuid::Empty; - m_ghoulResurrectGhoulGUID = ObjectGuid::Empty; -} //slot to be excluded while counting -bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) +bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) const { if (!enchantmentcondition) return true; @@ -21654,7 +21730,8 @@ bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) } } - TC_LOG_DEBUG("entities.player.items", "Checking Condition %u, there are %u Meta Gems, %u Red Gems, %u Yellow Gems and %u Blue Gems, Activate:%s", enchantmentcondition, curcount[0], curcount[1], curcount[2], curcount[3], activate ? "yes" : "no"); + TC_LOG_DEBUG("entities.player.items", "Player::EnchantmentFitsRequirements: Checking Condition %u, there are %u Meta Gems, %u Red Gems, %u Yellow Gems and %u Blue Gems, Activate:%s", + enchantmentcondition, curcount[0], curcount[1], curcount[2], curcount[3], activate ? "yes" : "no"); return activate; } @@ -21766,7 +21843,7 @@ void Player::SetBattlegroundEntryPoint() if (const WorldSafeLocsEntry* entry = sObjectMgr->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam())) m_bgData.joinPos = WorldLocation(entry->map_id, entry->x, entry->y, entry->z, 0.0f); else - TC_LOG_ERROR("entities.player", "SetBattlegroundEntryPoint: Dungeon map %u has no linked graveyard, setting home location as entry point.", GetMapId()); + TC_LOG_ERROR("entities.player", "Player::SetBattlegroundEntryPoint: Dungeon (MapID: %u) has no linked graveyard, setting home location as entry point.", GetMapId()); } // If new entry point is not BG or arena set it else if (!GetMap()->IsBattlegroundOrArena()) @@ -21780,7 +21857,7 @@ void Player::SetBattlegroundEntryPoint() void Player::SetBGTeam(uint32 team) { m_bgData.bgTeam = team; - SetByteValue(PLAYER_BYTES_3, 3, uint8(team == ALLIANCE ? 1 : 0)); + SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_ARENA_FACTION, uint8(team == ALLIANCE ? 1 : 0)); } uint32 Player::GetBGTeam() const @@ -21880,7 +21957,7 @@ WorldLocation Player::GetStartPosition() const return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0); } -bool Player::HaveAtClient(WorldObject const* u) const +bool Player::HaveAtClient(Object const* u) const { return u == this || m_clientGUIDs.find(u->GetGUID()) != m_clientGUIDs.end(); } @@ -21977,7 +22054,7 @@ template<> inline void BeforeVisibilityDestroy<Creature>(Creature* t, Player* p) { if (p->GetPetGUID() == t->GetGUID() && t->IsPet()) - ((Pet*)t)->Remove(PET_SAVE_NOT_IN_SLOT, true); + t->ToPet()->Remove(PET_SAVE_NOT_IN_SLOT, true); } void Player::UpdateVisibilityOf(WorldObject* target) @@ -22011,7 +22088,7 @@ void Player::UpdateVisibilityOf(WorldObject* target) // target aura duration for caster show only if target exist at caster client // send data at target visibility change (adding to client) if (target->isType(TYPEMASK_UNIT)) - SendInitialVisiblePackets((Unit*)target); + SendInitialVisiblePackets(static_cast<Unit*>(target)); } } } @@ -22058,7 +22135,7 @@ void Player::UpdateTriggerVisibility() GetSession()->SendPacket(&packet); } -void Player::SendInitialVisiblePackets(Unit* target) +void Player::SendInitialVisiblePackets(Unit* target) const { SendAurasForTarget(target); if (target->IsAlive()) @@ -22147,7 +22224,7 @@ bool Player::ModifyMoney(int32 amount, bool sendError /*= true*/) sScriptMgr->OnPlayerMoneyLimit(this, amount); if (sendError) - SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); + SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, nullptr, nullptr); return false; } } @@ -22178,14 +22255,14 @@ Unit* Player::GetSelectedUnit() const { if (ObjectGuid selectionGUID = GetTarget()) return ObjectAccessor::GetUnit(*this, selectionGUID); - return NULL; + return nullptr; } Player* Player::GetSelectedPlayer() const { if (ObjectGuid selectionGUID = GetTarget()) return ObjectAccessor::GetPlayer(*this, selectionGUID); - return NULL; + return nullptr; } void Player::SendComboPoints() @@ -22276,7 +22353,7 @@ void Player::ClearComboPoints() void Player::SetGroup(Group* group, int8 subgroup) { - if (group == NULL) + if (group == nullptr) m_group.unlink(); else { @@ -22416,7 +22493,7 @@ void Player::SendUpdateToOutOfRangeGroupMembers() pet->ResetAuraUpdateMaskForRaid(); } -void Player::SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 arg) +void Player::SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 arg) const { WorldPacket data(SMSG_TRANSFER_ABORTED, 4+2); data << uint32(mapid); @@ -22435,7 +22512,7 @@ void Player::SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 GetSession()->SendPacket(&data); } -void Player::SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time, bool welcome) +void Player::SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time, bool welcome) const { // type of warning, based on the time remaining until reset uint32 type; @@ -22481,7 +22558,7 @@ void Player::ApplyEquipCooldown(Item* pItem) continue; // Don't replace longer cooldowns by equip cooldown if we have any. - if (GetSpellHistory()->GetRemainingCooldown(sSpellMgr->EnsureSpellInfo(spellData.SpellId)) > 30 * IN_MILLISECONDS) + if (GetSpellHistory()->GetRemainingCooldown(sSpellMgr->AssertSpellInfo(spellData.SpellId)) > 30 * IN_MILLISECONDS) continue; GetSpellHistory()->AddCooldown(spellData.SpellId, pItem->GetEntry(), std::chrono::seconds(30)); @@ -22559,7 +22636,8 @@ void Player::LearnCustomSpells() for (PlayerCreateInfoSpells::const_iterator itr = info->customSpells.begin(); itr != info->customSpells.end(); ++itr) { uint32 tspell = *itr; - TC_LOG_DEBUG("entities.player.loading", "PLAYER (Class: %u Race: %u): Adding initial spell, id = %u", uint32(getClass()), uint32(getRace()), tspell); + TC_LOG_DEBUG("entities.player.loading", "Player::LearnCustomSpells: Player '%s' (%s, Class: %u Race: %u): Adding initial spell (SpellID: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), uint32(getClass()), uint32(getRace()), tspell); if (!IsInWorld()) // will send in INITIAL_SPELLS in list anyway at map add AddSpell(tspell, true, true, true, false); else // but send in normal spell in game learn case @@ -22731,7 +22809,7 @@ void Player::LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue) } } -void Player::SendAurasForTarget(Unit* target) +void Player::SendAurasForTarget(Unit* target) const { if (!target || target->GetVisibleAuras()->empty()) // speedup things return; @@ -22772,7 +22850,7 @@ void Player::SetDailyQuestStatus(uint32 quest_id) if (!GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx)) { SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx, quest_id); - m_lastDailyQuestTime = time(NULL); // last daily quest time + m_lastDailyQuestTime = time(nullptr); // last daily quest time m_DailyQuestChanged = true; break; } @@ -22780,7 +22858,7 @@ void Player::SetDailyQuestStatus(uint32 quest_id) } else { m_DFQuests.insert(quest_id); - m_lastDailyQuestTime = time(NULL); + m_lastDailyQuestTime = time(nullptr); m_DailyQuestChanged = true; } } @@ -22853,7 +22931,7 @@ void Player::ResetMonthlyQuestStatus() Battleground* Player::GetBattleground() const { if (GetBattlegroundId() == 0) - return NULL; + return nullptr; return sBattlegroundMgr->GetBattleground(GetBattlegroundId(), m_bgData.bgTypeID); } @@ -22912,7 +22990,7 @@ uint32 Player::AddBattlegroundQueueId(BattlegroundQueueTypeId val) return PLAYER_MAX_BATTLEGROUND_QUEUES; } -bool Player::HasFreeBattlegroundQueueId() +bool Player::HasFreeBattlegroundQueueId() const { for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) if (m_bgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE) @@ -23100,7 +23178,7 @@ void Player::UpdateForQuestWorldObjects() void Player::SetSummonPoint(uint32 mapid, float x, float y, float z) { - m_summon_expire = time(NULL) + MAX_PLAYER_SUMMON_DELAY; + m_summon_expire = time(nullptr) + MAX_PLAYER_SUMMON_DELAY; m_summon_mapid = mapid; m_summon_x = x; m_summon_y = y; @@ -23116,7 +23194,7 @@ void Player::SummonIfPossible(bool agree) } // expire and auto declined - if (m_summon_expire < time(NULL)) + if (m_summon_expire < time(nullptr)) return; // stop taxi flight at summon @@ -23174,8 +23252,7 @@ void Player::AutoUnequipOffhandIfNeed(bool force /*= false*/) return; ItemPosCountVec off_dest; - uint8 off_msg = CanStoreItem(NULL_BAG, NULL_SLOT, off_dest, offItem, false); - if (off_msg == EQUIP_ERR_OK) + if (CanStoreItem(NULL_BAG, NULL_SLOT, off_dest, offItem, false) == EQUIP_ERR_OK) { RemoveItem(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND, true); StoreItem(off_dest, offItem, true); @@ -23237,7 +23314,7 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons break; } default: - TC_LOG_ERROR("entities.player", "HasItemFitToSpellRequirements: Spell requirement not handled for item class %u", spellInfo->EquippedItemClass); + TC_LOG_ERROR("entities.player", "Player::HasItemFitToSpellRequirements: Not handled spell requirement for item class %u", spellInfo->EquippedItemClass); break; } @@ -23363,7 +23440,7 @@ bool Player::GetsRecruitAFriendBonus(bool forXP) { if (Group* group = this->GetGroup()) { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* player = itr->GetSource(); if (!player) @@ -23412,7 +23489,7 @@ void Player::RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewar // prepare data for near group iteration if (Group* group = GetGroup()) { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* player = itr->GetSource(); if (!player) @@ -23478,8 +23555,14 @@ void Player::ResurrectUsingRequestData() { RemoveGhoul(); + if (uint32 aura = _resurrectionData->Aura) + { + CastSpell(this, aura, true, nullptr, nullptr, _resurrectionData->GUID); + return; + } + /// Teleport before resurrecting by player, otherwise the player might get attacked from creatures near his corpse - TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation()); + TeleportTo(_resurrectionData->Location); if (IsBeingTeleported()) { @@ -23487,15 +23570,20 @@ void Player::ResurrectUsingRequestData() return; } + ResurrectUsingRequestDataImpl(); +} + +void Player::ResurrectUsingRequestDataImpl() +{ ResurrectPlayer(0.0f, false); - if (GetMaxHealth() > m_resurrectHealth) - SetHealth(m_resurrectHealth); + if (GetMaxHealth() > _resurrectionData->Health) + SetHealth(_resurrectionData->Health); else SetFullHealth(); - if (GetMaxPower(POWER_MANA) > m_resurrectMana) - SetPower(POWER_MANA, m_resurrectMana); + if (GetMaxPower(POWER_MANA) > _resurrectionData->Mana) + SetPower(POWER_MANA, _resurrectionData->Mana); else SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); @@ -23522,7 +23610,7 @@ void Player::SetClientControl(Unit* target, bool allowMove) void Player::SetMover(Unit* target) { - m_mover->m_movedPlayer = NULL; + m_mover->m_movedPlayer = nullptr; m_mover = target; m_mover->m_movedPlayer = this; } @@ -23567,7 +23655,7 @@ uint32 Player::GetCorpseReclaimDelay(bool pvp) const else if (!sWorld->getBoolConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE)) return 0; - time_t now = time(NULL); + time_t now = time(nullptr); // 0..2 full period // should be ceil(x)-1 but not floor(x) uint64 count = (now < m_deathExpireTime - 1) ? (m_deathExpireTime - 1 - now) / DEATH_EXPIRE_STEP : 0; @@ -23582,7 +23670,7 @@ void Player::UpdateCorpseReclaimDelay() (!pvp && !sWorld->getBoolConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE))) return; - time_t now = time(NULL); + time_t now = time(nullptr); if (now < m_deathExpireTime) { @@ -23598,7 +23686,7 @@ void Player::UpdateCorpseReclaimDelay() m_deathExpireTime = now + DEATH_EXPIRE_STEP; } -int32 Player::CalculateCorpseReclaimDelay(bool load) +int32 Player::CalculateCorpseReclaimDelay(bool load) const { Corpse* corpse = GetCorpse(); @@ -23626,7 +23714,7 @@ int32 Player::CalculateCorpseReclaimDelay(bool load) } time_t expected_time = corpse->GetGhostTime() + copseReclaimDelay[count]; - time_t now = time(NULL); + time_t now = time(nullptr); if (now >= expected_time) return -1; @@ -23639,7 +23727,7 @@ int32 Player::CalculateCorpseReclaimDelay(bool load) return delay * IN_MILLISECONDS; } -void Player::SendCorpseReclaimDelay(uint32 delay) +void Player::SendCorpseReclaimDelay(uint32 delay) const { WorldPacket data(SMSG_CORPSE_RECLAIM_DELAY, 4); data << uint32(delay); @@ -23650,12 +23738,12 @@ Player* Player::GetNextRandomRaidMember(float radius) { Group* group = GetGroup(); if (!group) - return NULL; + return nullptr; std::vector<Player*> nearMembers; nearMembers.reserve(group->GetMembersCount()); - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* Target = itr->GetSource(); @@ -23666,7 +23754,7 @@ Player* Player::GetNextRandomRaidMember(float radius) } if (nearMembers.empty()) - return NULL; + return nullptr; uint32 randTarget = urand(0, nearMembers.size()-1); return nearMembers[randTarget]; @@ -23698,7 +23786,7 @@ PartyResult Player::CanUninviteFromGroup(ObjectGuid guidMember) const return ERR_PARTY_LFG_BOOT_LOOT_ROLLS; /// @todo Should also be sent when anyone has recently left combat, with an aprox ~5 seconds timer. - for (GroupReference const* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + for (GroupReference const* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next()) if (itr->GetSource() && itr->GetSource()->IsInCombat()) return ERR_PARTY_LFG_BOOT_IN_COMBAT; @@ -23722,12 +23810,12 @@ PartyResult Player::CanUninviteFromGroup(ObjectGuid guidMember) const return ERR_PARTY_RESULT_OK; } -bool Player::isUsingLfg() +bool Player::isUsingLfg() const { return sLFGMgr->GetState(GetGUID()) != lfg::LFG_STATE_NONE; } -bool Player::inRandomLfgDungeon() +bool Player::inRandomLfgDungeon() const { if (sLFGMgr->selectedRandomLfgDungeon(GetGUID())) { @@ -23757,12 +23845,12 @@ void Player::RemoveFromBattlegroundOrBattlefieldRaid() m_group.link(group, this); m_group.setSubGroup(GetOriginalSubGroup()); } - SetOriginalGroup(NULL); + SetOriginalGroup(nullptr); } void Player::SetOriginalGroup(Group* group, int8 subgroup) { - if (group == NULL) + if (group == nullptr) m_originalGroup.unlink(); else { @@ -23783,7 +23871,7 @@ void Player::UpdateUnderwaterState(Map* m, float x, float y, float z) if (_lastLiquid && _lastLiquid->SpellId) RemoveAurasDueToSpell(_lastLiquid->SpellId); - _lastLiquid = NULL; + _lastLiquid = nullptr; return; } @@ -23809,7 +23897,7 @@ void Player::UpdateUnderwaterState(Map* m, float x, float y, float z) else if (_lastLiquid && _lastLiquid->SpellId) { RemoveAurasDueToSpell(_lastLiquid->SpellId); - _lastLiquid = NULL; + _lastLiquid = nullptr; } @@ -23864,7 +23952,7 @@ void Player::SetCanBlock(bool value) UpdateBlockPercentage(); } -bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const +bool ItemPosCount::isContainedIn(std::vector<ItemPosCount> const& vec) const { for (ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end(); ++itr) if (itr->pos == pos) @@ -23872,15 +23960,15 @@ bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const return false; } -void Player::StopCastingBindSight() +void Player::StopCastingBindSight() const { if (WorldObject* target = GetViewpoint()) { if (target->isType(TYPEMASK_UNIT)) { - ((Unit*)target)->RemoveAurasByType(SPELL_AURA_BIND_SIGHT, GetGUID()); - ((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, GetGUID()); - ((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, GetGUID()); + static_cast<Unit*>(target)->RemoveAurasByType(SPELL_AURA_BIND_SIGHT, GetGUID()); + static_cast<Unit*>(target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, GetGUID()); + static_cast<Unit*>(target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, GetGUID()); } } } @@ -23889,11 +23977,12 @@ void Player::SetViewpoint(WorldObject* target, bool apply) { if (apply) { - TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player %s created seer %u (TypeId: %u).", GetName().c_str(), target->GetEntry(), target->GetTypeId()); + TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player '%s' (%s) creates seer (Entry: %u, TypeId: %u).", + GetName().c_str(), GetGUID().ToString().c_str(), target->GetEntry(), target->GetTypeId()); if (!AddGuidValue(PLAYER_FARSIGHT, target->GetGUID())) { - TC_LOG_FATAL("entities.player", "Player::CreateViewpoint: Player %s cannot add new viewpoint!", GetName().c_str()); + TC_LOG_FATAL("entities.player", "Player::CreateViewpoint: Player '%s' (%s) cannot add new viewpoint!", GetName().c_str(), GetGUID().ToString().c_str()); return; } @@ -23901,7 +23990,7 @@ void Player::SetViewpoint(WorldObject* target, bool apply) UpdateVisibilityOf(target); if (target->isType(TYPEMASK_UNIT) && target != GetVehicleBase()) - ((Unit*)target)->AddPlayerToVision(this); + static_cast<Unit*>(target)->AddPlayerToVision(this); } else { @@ -23909,12 +23998,12 @@ void Player::SetViewpoint(WorldObject* target, bool apply) if (!RemoveGuidValue(PLAYER_FARSIGHT, target->GetGUID())) { - TC_LOG_FATAL("entities.player", "Player::CreateViewpoint: Player %s cannot remove current viewpoint!", GetName().c_str()); + TC_LOG_FATAL("entities.player", "Player::CreateViewpoint: Player '%s' (%s) cannot remove current viewpoint!", GetName().c_str(), GetGUID().ToString().c_str()); return; } if (target->isType(TYPEMASK_UNIT) && target != GetVehicleBase()) - ((Unit*)target)->RemovePlayerFromVision(this); + static_cast<Unit*>(target)->RemovePlayerFromVision(this); //must immediately set seer back otherwise may crash m_seer = this; @@ -23952,11 +24041,11 @@ void Player::SetViewpoint(WorldObject* target, bool apply) WorldObject* Player::GetViewpoint() const { if (ObjectGuid guid = GetGuidValue(PLAYER_FARSIGHT)) - return (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*this, guid, TYPEMASK_SEER); - return NULL; + return static_cast<WorldObject*>(ObjectAccessor::GetObjectByTypeMask(*this, guid, TYPEMASK_SEER)); + return nullptr; } -bool Player::CanUseBattlegroundObject(GameObject* gameobject) +bool Player::CanUseBattlegroundObject(GameObject* gameobject) const { // It is possible to call this method with a null pointer, only skipping faction check. if (gameobject) @@ -23975,24 +24064,24 @@ bool Player::CanUseBattlegroundObject(GameObject* gameobject) IsAlive()); // Alive } -bool Player::CanCaptureTowerPoint() +bool Player::CanCaptureTowerPoint() const { return (!HasStealthAura() && // not stealthed !HasInvisibilityAura() && // not invisible IsAlive()); // live player } -uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, BarberShopStyleEntry const* newSkin) +uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, BarberShopStyleEntry const* newSkin) const { uint8 level = getLevel(); if (level > GT_MAX_LEVEL) level = GT_MAX_LEVEL; // max level in this dbc - uint8 hairstyle = GetByteValue(PLAYER_BYTES, 2); - uint8 haircolor = GetByteValue(PLAYER_BYTES, 3); - uint8 facialhair = GetByteValue(PLAYER_BYTES_2, 0); - uint8 skincolor = GetByteValue(PLAYER_BYTES, 0); + uint8 hairstyle = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID); + uint8 haircolor = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID); + uint8 facialhair = GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE); + uint8 skincolor = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID); if ((hairstyle == newhairstyle) && (haircolor == newhaircolor) && (facialhair == newfacialhair) && (!newSkin || (newSkin->hair_id == skincolor))) return 0; @@ -24050,7 +24139,7 @@ void Player::SetGlyph(uint8 slot, uint32 glyph) SetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot, glyph); } -bool Player::isTotalImmune() +bool Player::isTotalImmune() const { AuraEffectList const& immune = GetAuraEffectsByType(SPELL_AURA_SCHOOL_IMMUNITY); @@ -24100,7 +24189,7 @@ void Player::SetTitle(CharTitlesEntry const* title, bool lost) GetSession()->SendPacket(&data); } -bool Player::isTotalImmunity() +bool Player::isTotalImmunity() const { AuraEffectList const& immune = GetAuraEffectsByType(SPELL_AURA_SCHOOL_IMMUNITY); @@ -24176,7 +24265,7 @@ void Player::RemoveRunesByAuraEffect(AuraEffect const* aura) if (m_runes->runes[i].ConvertAura == aura) { ConvertRune(i, GetBaseRune(i)); - SetRuneConvertAura(i, NULL); + SetRuneConvertAura(i, nullptr); } } } @@ -24184,11 +24273,11 @@ void Player::RemoveRunesByAuraEffect(AuraEffect const* aura) void Player::RestoreBaseRune(uint8 index) { AuraEffect const* aura = m_runes->runes[index].ConvertAura; - // If rune was converted by a non-pasive aura that still active we should keep it converted + // If rune was converted by a non-passive aura that still active we should keep it converted if (aura && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_PASSIVE)) return; ConvertRune(index, GetBaseRune(index)); - SetRuneConvertAura(index, NULL); + SetRuneConvertAura(index, nullptr); // Don't drop passive talents providing rune convertion if (!aura || aura->GetAuraType() != SPELL_AURA_CONVERT_RUNE) return; @@ -24210,7 +24299,7 @@ void Player::ConvertRune(uint8 index, RuneType newType) GetSession()->SendPacket(&data); } -void Player::ResyncRunes(uint8 count) +void Player::ResyncRunes(uint8 count) const { WorldPacket data(SMSG_RESYNC_RUNES, 4 + count * 2); data << uint32(count); @@ -24222,7 +24311,7 @@ void Player::ResyncRunes(uint8 count) GetSession()->SendPacket(&data); } -void Player::AddRunePower(uint8 index) +void Player::AddRunePower(uint8 index) const { WorldPacket data(SMSG_ADD_RUNE_POWER, 4); data << uint32(1 << index); // mask (0x00-0x3F probably) @@ -24256,7 +24345,7 @@ void Player::InitRunes() SetRuneCooldown(i, 0); // reset cooldowns SetRuneTimer(i, 0xFFFFFFFF); // Reset rune flags SetLastRuneGraceTimer(i, 0); - SetRuneConvertAura(i, NULL); + SetRuneConvertAura(i, nullptr); m_runes->SetRuneState(i); } @@ -24291,7 +24380,7 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, lootItem->itemid, lootItem->count); if (msg != EQUIP_ERR_OK) { - SendEquipError(msg, NULL, NULL, lootItem->itemid); + SendEquipError(msg, nullptr, nullptr, lootItem->itemid); continue; } @@ -24302,15 +24391,15 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons void Player::StoreLootItem(uint8 lootSlot, Loot* loot) { - QuestItem* qitem = NULL; - QuestItem* ffaitem = NULL; - QuestItem* conditem = NULL; + QuestItem* qitem = nullptr; + QuestItem* ffaitem = nullptr; + QuestItem* conditem = nullptr; LootItem* item = loot->LootItemInSlot(lootSlot, this, &qitem, &ffaitem, &conditem); if (!item) { - SendEquipError(EQUIP_ERR_ALREADY_LOOTED, NULL, NULL); + SendEquipError(EQUIP_ERR_ALREADY_LOOTED, nullptr, nullptr); return; } @@ -24377,7 +24466,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) } else - SendEquipError(msg, NULL, NULL, item->itemid); + SendEquipError(msg, nullptr, nullptr, item->itemid); } uint32 Player::CalculateTalentsPoints() const @@ -24430,8 +24519,8 @@ void Player::_LoadSkills(PreparedQueryResult result) SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skill, getRace(), getClass()); if (!rcEntry) { - TC_LOG_ERROR("entities.player", "Character: %s (GUID: %u Race: %u Class: %u) has skill %u not allowed for his race/class combination", - GetName().c_str(), GetGUID().GetCounter(), uint32(getRace()), uint32(getClass()), skill); + TC_LOG_ERROR("entities.player", "Player::_LoadSkills: Player '%s' (%s, Race: %u, Class: %u) has forbidden skill %u for his race/class combination", + GetName().c_str(), GetGUID().ToString().c_str(), uint32(getRace()), uint32(getClass()), skill); mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(0, SKILL_DELETED))); continue; @@ -24454,7 +24543,8 @@ void Player::_LoadSkills(PreparedQueryResult result) if (value == 0) { - TC_LOG_ERROR("entities.player", "Character %u has skill %u with value 0. Skill will be deleted.", GetGUID().GetCounter(), skill); + TC_LOG_ERROR("entities.player", "Player::_LoadSkills: Player '%s' (%s) has skill %u with value 0, deleted.", + GetName().c_str(), GetGUID().ToString().c_str(), skill); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL); @@ -24491,7 +24581,8 @@ void Player::_LoadSkills(PreparedQueryResult result) if (count >= PLAYER_MAX_SKILLS) // client limit { - TC_LOG_ERROR("entities.player", "Character %u has more than %u skills.", GetGUID().GetCounter(), PLAYER_MAX_SKILLS); + TC_LOG_ERROR("entities.player", "Player::_LoadSkills: Player '%s' (%s) has more than %u skills.", + GetName().c_str(), GetGUID().ToString().c_str(), PLAYER_MAX_SKILLS); break; } } @@ -24758,30 +24849,13 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) uint32 tTab = talentInfo->TalentTab; if (talentInfo->Row > 0) - { - uint32 numRows = sTalentStore.GetNumRows(); - for (uint32 i = 0; i < numRows; i++) // Loop through all talents. - { - // Someday, someone needs to revamp - const TalentEntry* tmpTalent = sTalentStore.LookupEntry(i); - if (tmpTalent) // the way talents are tracked - { + for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++) // Loop through all talents. + if (const TalentEntry* tmpTalent = sTalentStore.LookupEntry(i)) // the way talents are tracked if (tmpTalent->TalentTab == tTab) - { for (uint8 rank = 0; rank < MAX_TALENT_RANK; rank++) - { if (tmpTalent->RankID[rank] != 0) - { if (HasSpell(tmpTalent->RankID[rank])) - { spentPoints += (rank + 1); - } - } - } - } - } - } - } // not have required min points spent in talent tree if (spentPoints < (talentInfo->Row * MAX_TALENT_RANK)) @@ -24791,7 +24865,7 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) uint32 spellid = talentInfo->RankID[talentRank]; if (spellid == 0) { - TC_LOG_ERROR("entities.player", "Talent.dbc contains talent: %u Rank: %u spell id = 0", talentId, talentRank); + TC_LOG_ERROR("entities.player", "Player::LearnTalent: Talent.dbc has no spellInfo for talent: %u (spell id = 0)", talentId); return; } @@ -24803,7 +24877,7 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) LearnSpell(spellid, false); AddTalent(spellid, m_activeSpec, true); - TC_LOG_DEBUG("entities.player", "TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, m_activeSpec); + TC_LOG_DEBUG("misc", "Player::LearnTalent: TalentID: %u Spell: %u Group: %u\n", talentId, spellid, uint32(m_activeSpec)); // update free talent points SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1)); @@ -25255,7 +25329,8 @@ void Player::SetEquipmentSet(uint32 index, EquipmentSet eqset) if (!found) // something wrong... { - TC_LOG_ERROR("entities.player", "Player %s tried to save equipment set " UI64FMTD " (index %u), but that equipment set was not found!", GetName().c_str(), eqset.Guid, index); + TC_LOG_ERROR("entities.player", "Player::SetEquipmentSet: Player '%s' (%s) tried to save nonexistent equipment set " UI64FMTD " (index: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), eqset.Guid, index); return; } } @@ -25285,7 +25360,7 @@ void Player::_SaveEquipmentSets(SQLTransaction& trans) { uint32 index = itr->first; EquipmentSet& eqset = itr->second; - PreparedStatement* stmt = NULL; + PreparedStatement* stmt = nullptr; uint8 j = 0; switch (eqset.state) { @@ -25423,7 +25498,7 @@ void Player::_LoadGlyphs(PreparedQueryResult result) while (result->NextRow()); } -void Player::_SaveGlyphs(SQLTransaction& trans) +void Player::_SaveGlyphs(SQLTransaction& trans) const { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS); stmt->setUInt32(0, GetGUID().GetCounter()); @@ -25507,7 +25582,7 @@ void Player::UpdateSpecCount(uint8 count) ActivateSpec(0); SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = NULL; + PreparedStatement* stmt; // Copy spec data if (count > curCount) @@ -25715,7 +25790,7 @@ uint32 Player::GetReputation(uint32 factionentry) const return GetReputationMgr().GetReputation(sFactionStore.LookupEntry(factionentry)); } -std::string const& Player::GetGuildName() +std::string const& Player::GetGuildName() const { return sGuildMgr->GetGuildById(GetGuildId())->GetName(); } @@ -25923,7 +25998,7 @@ void Player::SendItemRetrievalMail(uint32 itemEntry, uint32 count) MailDraft draft("Recovered Item", "We recovered a lost item in the twisting nether and noted that it was yours.$B$BPlease find said object enclosed."); // This is the text used in Cataclysm, it probably wasn't changed. SQLTransaction trans = CharacterDatabase.BeginTransaction(); - if (Item* item = Item::CreateItem(itemEntry, count, 0)) + if (Item* item = Item::CreateItem(itemEntry, count, nullptr)) { item->SaveToDB(trans); draft.AddItem(item); @@ -25954,7 +26029,7 @@ void Player::_LoadRandomBGStatus(PreparedQueryResult result) m_IsBGRandomWinner = true; } -float Player::GetAverageItemLevel() +float Player::GetAverageItemLevel() const { float sum = 0; uint32 count = 0; @@ -26036,6 +26111,9 @@ bool Player::SetCanFly(bool apply, bool packetOnly /*= false*/) if (!packetOnly && !Unit::SetCanFly(apply)) return false; + if (!apply) + SetFallInformation(0, GetPositionZ()); + WorldPacket data(apply ? SMSG_MOVE_SET_CAN_FLY : SMSG_MOVE_UNSET_CAN_FLY, 12); data << GetPackGUID(); data << uint32(0); //! movement counter @@ -26132,7 +26210,126 @@ float Player::GetCollisionHeight(bool mounted) const } } -std::string Player::GetMapAreaAndZoneString() +void Player::BeginCinematic() +{ + // Sanity check for active camera set + if (m_activeCinematicCameraId == 0) + return; + + auto itr = sFlyByCameraStore.find(m_activeCinematicCameraId); + if (itr != sFlyByCameraStore.end()) + { + // Initialize diff, and set camera + m_cinematicDiff = 0; + m_cinematicCamera = &itr->second; + + auto camitr = m_cinematicCamera->begin(); + if (camitr != m_cinematicCamera->end()) + { + Position pos(camitr->locations.x, camitr->locations.y, camitr->locations.z, camitr->locations.w); + if (!pos.IsPositionValid()) + return; + + m_mapRef->LoadGrid(camitr->locations.x, camitr->locations.y); + m_CinematicObject = SummonCreature(VISUAL_WAYPOINT, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 120000); + if (m_CinematicObject) + { + m_CinematicObject->setActive(true); + SetViewpoint(m_CinematicObject, true); + } + } + } +} + +void Player::EndCinematic() +{ + m_cinematicDiff = 0; + m_cinematicCamera = nullptr; + m_activeCinematicCameraId = 0; + if (m_CinematicObject) + { + if (m_seer && m_seer == m_CinematicObject) + SetViewpoint(m_CinematicObject, false); + m_CinematicObject->AddObjectToRemoveList(); + } +} + +void Player::UpdateCinematicLocation(uint32 /*diff*/) +{ + Position lastPosition; + uint32 lastTimestamp = 0; + Position nextPosition; + uint32 nextTimestamp = 0; + + if (m_cinematicCamera->size() == 0) + return; + + // Obtain direction of travel + for (FlyByCamera cam : *m_cinematicCamera) + { + if (cam.timeStamp > m_cinematicDiff) + { + nextPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); + nextTimestamp = cam.timeStamp; + break; + } + lastPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); + lastTimestamp = cam.timeStamp; + } + float angle = lastPosition.GetAngle(&nextPosition); + angle -= lastPosition.GetOrientation(); + if (angle < 0) + angle += 2 * float(M_PI); + + // Look for position around 2 second ahead of us. + int32 workDiff = m_cinematicDiff; + + // Modify result based on camera direction (Humans for example, have the camera point behind) + workDiff += static_cast<int32>(float(CINEMATIC_LOOKAHEAD) * cos(angle)); + + // Get an iterator to the last entry in the cameras, to make sure we don't go beyond the end + FlyByCameraCollection::const_reverse_iterator endItr = m_cinematicCamera->rbegin(); + if (endItr != m_cinematicCamera->rend() && workDiff > static_cast<int32>(endItr->timeStamp)) + workDiff = endItr->timeStamp; + + // Never try to go back in time before the start of cinematic! + if (workDiff < 0) + workDiff = m_cinematicDiff; + + // Obtain the previous and next waypoint based on timestamp + for (FlyByCamera cam : *m_cinematicCamera) + { + if (static_cast<int32>(cam.timeStamp) >= workDiff) + { + nextPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); + nextTimestamp = cam.timeStamp; + break; + } + lastPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); + lastTimestamp = cam.timeStamp; + } + + // Never try to go beyond the end of the cinematic + if (workDiff > static_cast<int32>(nextTimestamp)) + workDiff = static_cast<int32>(nextTimestamp); + + // Interpolate the position for this moment in time (or the adjusted moment in time) + uint32 timeDiff = nextTimestamp - lastTimestamp; + uint32 interDiff = workDiff - lastTimestamp; + float xDiff = nextPosition.m_positionX - lastPosition.m_positionX; + float yDiff = nextPosition.m_positionY - lastPosition.m_positionY; + float zDiff = nextPosition.m_positionZ - lastPosition.m_positionZ; + Position interPosition(lastPosition.m_positionX + (xDiff * (float(interDiff)/float(timeDiff))), lastPosition.m_positionY + + (yDiff * (float(interDiff) / float(timeDiff))), lastPosition.m_positionZ + (zDiff * (float(interDiff) / float(timeDiff)))); + + // Advance (at speed) to this position. The remote sight object is used + // to send update information to player in cinematic + if (m_CinematicObject && interPosition.IsPositionValid()) + m_CinematicObject->MonsterMoveWithSpeed(interPosition.m_positionX, interPosition.m_positionY, interPosition.m_positionZ, 200.0f, false, true); +} + + +std::string Player::GetMapAreaAndZoneString() const { uint32 areaId = GetAreaId(); std::string areaName = "Unknown"; @@ -26150,7 +26347,7 @@ std::string Player::GetMapAreaAndZoneString() return str.str(); } -std::string Player::GetCoordsMapAreaAndZoneString() +std::string Player::GetCoordsMapAreaAndZoneString() const { std::ostringstream str; str << Position::ToString() << " " << GetMapAreaAndZoneString(); @@ -26185,31 +26382,31 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy if (duration > 0) pet->SetDuration(duration); - return NULL; + return nullptr; } // petentry == 0 for hunter "call pet" (current pet summoned if any) if (!entry) { delete pet; - return NULL; + return nullptr; } pet->Relocate(x, y, z, ang); if (!pet->IsPositionValid()) { - TC_LOG_ERROR("misc", "Pet (guidlow %d, entry %d) not summoned. Suggested coordinates are not valid (X: %f Y: %f)", pet->GetGUID().GetCounter(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY()); + TC_LOG_ERROR("misc", "Player::SummonPet: Pet (%s, Entry: %d) not summoned. Suggested coordinates aren't valid (X: %f Y: %f)", pet->GetGUID().ToString().c_str(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY()); delete pet; - return NULL; + return nullptr; } Map* map = GetMap(); uint32 pet_number = sObjectMgr->GeneratePetNumber(); if (!pet->Create(map->GenerateLowGuid<HighGuid::Pet>(), map, GetPhaseMask(), entry, pet_number)) { - TC_LOG_ERROR("misc", "No such creature entry %u", entry); + TC_LOG_ERROR("misc", "Player::SummonPet: No such creature entry %u", entry); delete pet; - return NULL; + return nullptr; } pet->SetCreatorGUID(GetGUID()); @@ -26227,12 +26424,12 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy case SUMMON_PET: // this enables pet details window (Shift+P) pet->GetCharmInfo()->SetPetNumber(pet_number, true); - pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048); + pet->SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, CLASS_MAGE); pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); pet->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000); pet->SetFullHealth(); pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA)); - pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped in this case + pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(nullptr))); // cast can't be helped in this case break; default: break; @@ -26276,7 +26473,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy return pet; } -void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) +void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) const { WorldPacket data(SMSG_SUPERCEDED_SPELL, 8); data << uint32(oldSpell) << uint32(newSpell); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 0d6d21c6b28..fd0fac69674 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -117,7 +117,7 @@ struct PlayerTalent // Spell modifier (used for modify other spells) struct SpellModifier { - SpellModifier(Aura* _ownerAura = NULL) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), value(0), mask(), spellId(0), ownerAura(_ownerAura) { } + SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), value(0), mask(), spellId(0), ownerAura(_ownerAura) { } SpellModOp op : 8; SpellModType type : 8; int16 charges : 16; @@ -256,7 +256,7 @@ typedef std::list<PlayerCreateInfoSkill> PlayerCreateInfoSkills; struct PlayerInfo { // existence checked by displayId != 0 - PlayerInfo() : mapId(0), areaId(0), positionX(0.0f), positionY(0.0f), positionZ(0.0f), orientation(0.0f), displayId_m(0), displayId_f(0), levelInfo(NULL) { } + PlayerInfo() : mapId(0), areaId(0), positionX(0.0f), positionY(0.0f), positionZ(0.0f), orientation(0.0f), displayId_m(0), displayId_f(0), levelInfo(nullptr) { } uint32 mapId; uint32 areaId; @@ -287,7 +287,7 @@ struct PvPInfo struct DuelInfo { - DuelInfo() : initiator(NULL), opponent(NULL), startTimer(0), startTime(0), outOfBound(0), isMounted(false) { } + DuelInfo() : initiator(nullptr), opponent(nullptr), startTimer(0), startTime(0), outOfBound(0), isMounted(false) { } Player* initiator; Player* opponent; @@ -315,7 +315,7 @@ enum RuneCooldowns RUNE_MISS_COOLDOWN = 1500 // cooldown applied on runes when the spell misses }; -enum RuneType +enum RuneType : uint8 { RUNE_BLOOD = 0, RUNE_UNHOLY = 1, @@ -349,7 +349,7 @@ struct Runes struct EnchantDuration { - EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { } + EnchantDuration() : item(nullptr), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { } EnchantDuration(Item* _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot), leftduration(_leftduration){ ASSERT(item); } @@ -415,50 +415,48 @@ enum PlayerFlags PLAYER_FLAGS_UNK31 = 0x80000000 }; -// used for PLAYER__FIELD_KNOWN_TITLES field (uint64), (1<<bit_index) without (-1) -// can't use enum for uint64 values -#define PLAYER_TITLE_DISABLED UI64LIT(0x0000000000000000) -#define PLAYER_TITLE_NONE UI64LIT(0x0000000000000001) -#define PLAYER_TITLE_PRIVATE UI64LIT(0x0000000000000002) // 1 -#define PLAYER_TITLE_CORPORAL UI64LIT(0x0000000000000004) // 2 -#define PLAYER_TITLE_SERGEANT_A UI64LIT(0x0000000000000008) // 3 -#define PLAYER_TITLE_MASTER_SERGEANT UI64LIT(0x0000000000000010) // 4 -#define PLAYER_TITLE_SERGEANT_MAJOR UI64LIT(0x0000000000000020) // 5 -#define PLAYER_TITLE_KNIGHT UI64LIT(0x0000000000000040) // 6 -#define PLAYER_TITLE_KNIGHT_LIEUTENANT UI64LIT(0x0000000000000080) // 7 -#define PLAYER_TITLE_KNIGHT_CAPTAIN UI64LIT(0x0000000000000100) // 8 -#define PLAYER_TITLE_KNIGHT_CHAMPION UI64LIT(0x0000000000000200) // 9 -#define PLAYER_TITLE_LIEUTENANT_COMMANDER UI64LIT(0x0000000000000400) // 10 -#define PLAYER_TITLE_COMMANDER UI64LIT(0x0000000000000800) // 11 -#define PLAYER_TITLE_MARSHAL UI64LIT(0x0000000000001000) // 12 -#define PLAYER_TITLE_FIELD_MARSHAL UI64LIT(0x0000000000002000) // 13 -#define PLAYER_TITLE_GRAND_MARSHAL UI64LIT(0x0000000000004000) // 14 -#define PLAYER_TITLE_SCOUT UI64LIT(0x0000000000008000) // 15 -#define PLAYER_TITLE_GRUNT UI64LIT(0x0000000000010000) // 16 -#define PLAYER_TITLE_SERGEANT_H UI64LIT(0x0000000000020000) // 17 -#define PLAYER_TITLE_SENIOR_SERGEANT UI64LIT(0x0000000000040000) // 18 -#define PLAYER_TITLE_FIRST_SERGEANT UI64LIT(0x0000000000080000) // 19 -#define PLAYER_TITLE_STONE_GUARD UI64LIT(0x0000000000100000) // 20 -#define PLAYER_TITLE_BLOOD_GUARD UI64LIT(0x0000000000200000) // 21 -#define PLAYER_TITLE_LEGIONNAIRE UI64LIT(0x0000000000400000) // 22 -#define PLAYER_TITLE_CENTURION UI64LIT(0x0000000000800000) // 23 -#define PLAYER_TITLE_CHAMPION UI64LIT(0x0000000001000000) // 24 -#define PLAYER_TITLE_LIEUTENANT_GENERAL UI64LIT(0x0000000002000000) // 25 -#define PLAYER_TITLE_GENERAL UI64LIT(0x0000000004000000) // 26 -#define PLAYER_TITLE_WARLORD UI64LIT(0x0000000008000000) // 27 -#define PLAYER_TITLE_HIGH_WARLORD UI64LIT(0x0000000010000000) // 28 -#define PLAYER_TITLE_GLADIATOR UI64LIT(0x0000000020000000) // 29 -#define PLAYER_TITLE_DUELIST UI64LIT(0x0000000040000000) // 30 -#define PLAYER_TITLE_RIVAL UI64LIT(0x0000000080000000) // 31 -#define PLAYER_TITLE_CHALLENGER UI64LIT(0x0000000100000000) // 32 -#define PLAYER_TITLE_SCARAB_LORD UI64LIT(0x0000000200000000) // 33 -#define PLAYER_TITLE_CONQUEROR UI64LIT(0x0000000400000000) // 34 -#define PLAYER_TITLE_JUSTICAR UI64LIT(0x0000000800000000) // 35 -#define PLAYER_TITLE_CHAMPION_OF_THE_NAARU UI64LIT(0x0000001000000000) // 36 -#define PLAYER_TITLE_MERCILESS_GLADIATOR UI64LIT(0x0000002000000000) // 37 -#define PLAYER_TITLE_OF_THE_SHATTERED_SUN UI64LIT(0x0000004000000000) // 38 -#define PLAYER_TITLE_HAND_OF_ADAL UI64LIT(0x0000008000000000) // 39 -#define PLAYER_TITLE_VENGEFUL_GLADIATOR UI64LIT(0x0000010000000000) // 40 +enum PlayerBytesOffsets +{ + PLAYER_BYTES_OFFSET_SKIN_ID = 0, + PLAYER_BYTES_OFFSET_FACE_ID = 1, + PLAYER_BYTES_OFFSET_HAIR_STYLE_ID = 2, + PLAYER_BYTES_OFFSET_HAIR_COLOR_ID = 3 +}; + +enum PlayerBytes2Offsets +{ + PLAYER_BYTES_2_OFFSET_FACIAL_STYLE = 0, + PLAYER_BYTES_2_OFFSET_PARTY_TYPE = 1, + PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS = 2, + PLAYER_BYTES_2_OFFSET_REST_STATE = 3 +}; + +enum PlayerBytes3Offsets +{ + PLAYER_BYTES_3_OFFSET_GENDER = 0, + PLAYER_BYTES_3_OFFSET_INEBRIATION = 1, + PLAYER_BYTES_3_OFFSET_PVP_TITLE = 2, + PLAYER_BYTES_3_OFFSET_ARENA_FACTION = 3 +}; + +enum PlayerFieldBytesOffsets +{ + PLAYER_FIELD_BYTES_OFFSET_FLAGS = 0, + PLAYER_FIELD_BYTES_OFFSET_RAF_GRANTABLE_LEVEL = 1, + PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES = 2, + PLAYER_FIELD_BYTES_OFFSET_LIFETIME_MAX_PVP_RANK = 3 +}; + +enum PlayerFieldBytes2Offsets +{ + PLAYER_FIELD_BYTES_2_OFFSET_OVERRIDE_SPELLS_ID = 0, // uint16! + PLAYER_FIELD_BYTES_2_OFFSET_IGNORE_POWER_REGEN_PREDICTION_MASK = 2, + PLAYER_FIELD_BYTES_2_OFFSET_AURA_VISION = 3 +}; + +static_assert((PLAYER_FIELD_BYTES_2_OFFSET_OVERRIDE_SPELLS_ID & 1) == 0, "PLAYER_FIELD_BYTES_2_OFFSET_OVERRIDE_SPELLS_ID must be aligned to 2 byte boundary"); + +#define PLAYER_BYTES_2_OVERRIDE_SPELLS_UINT16_OFFSET (PLAYER_FIELD_BYTES_2_OFFSET_OVERRIDE_SPELLS_ID / 2) #define KNOWN_TITLES_SIZE 3 #define MAX_TITLE_INDEX (KNOWN_TITLES_SIZE*64) // 3 uint64 fields @@ -584,7 +582,7 @@ enum PlayerSlots #define INVENTORY_SLOT_BAG_0 255 -enum EquipmentSlots // 19 slots +enum EquipmentSlots : uint8 // 19 slots { EQUIPMENT_SLOT_START = 0, EQUIPMENT_SLOT_HEAD = 0, @@ -609,13 +607,13 @@ enum EquipmentSlots // 19 slots EQUIPMENT_SLOT_END = 19 }; -enum InventorySlots // 4 slots +enum InventorySlots : uint8 // 4 slots { INVENTORY_SLOT_BAG_START = 19, INVENTORY_SLOT_BAG_END = 23 }; -enum InventoryPackSlots // 16 slots +enum InventoryPackSlots : uint8 // 16 slots { INVENTORY_SLOT_ITEM_START = 23, INVENTORY_SLOT_ITEM_END = 39 @@ -640,7 +638,7 @@ enum BuyBackSlots // 12 slots BUYBACK_SLOT_END = 86 }; -enum KeyRingSlots // 32 slots +enum KeyRingSlots : uint8 // 32 slots { KEYRING_SLOT_START = 86, KEYRING_SLOT_END = 118 @@ -750,7 +748,7 @@ enum TeleportToOptions }; /// Type of environmental damages -enum EnviromentalDamage +enum EnviromentalDamage : uint8 { DAMAGE_EXHAUSTED = 0, DAMAGE_DROWNING = 1, @@ -833,7 +831,7 @@ enum PlayerDelayedOperations // Player summoning auto-decline time (in secs) #define MAX_PLAYER_SUMMON_DELAY (2*MINUTE) // Maximum money amount : 2^31 - 1 -extern uint32 const MAX_MONEY_AMOUNT; +TC_GAME_API extern uint32 const MAX_MONEY_AMOUNT; enum BindExtensionState { @@ -855,7 +853,7 @@ struct InstancePlayerBind EXTENDED - won't be promoted to EXPIRED at next reset period, will instead be promoted to NORMAL */ BindExtensionState extendState; - InstancePlayerBind() : save(NULL), perm(false), extendState(EXTEND_STATE_NORMAL) { } + InstancePlayerBind() : save(nullptr), perm(false), extendState(EXTEND_STATE_NORMAL) { } }; struct AccessRequirement @@ -902,7 +900,7 @@ enum ReferAFriendError ERR_REFER_A_FRIEND_SUMMON_OFFLINE_S = 0x0D }; -enum PlayerRestState +enum PlayerRestState : uint8 { REST_STATE_RESTED = 0x01, REST_STATE_NOT_RAF_LINKED = 0x02, @@ -919,7 +917,7 @@ enum PlayerCommandStates CHEAT_WATERWALK = 0x10 }; -class PlayerTaxi +class TC_GAME_API PlayerTaxi { public: PlayerTaxi(); @@ -1014,7 +1012,18 @@ struct TradeStatusInfo uint8 Slot; }; -class Player : public Unit, public GridObject<Player> +struct ResurrectionData +{ + ObjectGuid GUID; + WorldLocation Location; + uint32 Health; + uint32 Mana; + uint32 Aura; +}; + +#define SPELL_DK_RAISE_ALLY 46619 + +class TC_GAME_API Player : public Unit, public GridObject<Player> { friend class WorldSession; friend void Item::AddToUpdateQueueOf(Player* player); @@ -1061,12 +1070,12 @@ class Player : public Unit, public GridObject<Player> void SendInitialPacketsBeforeAddToMap(); void SendInitialPacketsAfterAddToMap(); - void SendSupercededSpell(uint32 oldSpell, uint32 newSpell); - void SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 arg = 0); - void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time, bool welcome); + void SendSupercededSpell(uint32 oldSpell, uint32 newSpell) const; + void SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 arg = 0) const; + void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time, bool welcome) const; - bool CanInteractWithQuestGiver(Object* questGiver); - Creature* GetNPCIfCanInteractWith(ObjectGuid const& guid, uint32 npcflagmask); + bool CanInteractWithQuestGiver(Object* questGiver) const; + Creature* GetNPCIfCanInteractWith(ObjectGuid const& guid, uint32 npcflagmask) const; GameObject* GetGameObjectIfCanInteractWith(ObjectGuid const& guid) const; GameObject* GetGameObjectIfCanInteractWith(ObjectGuid const& guid, GameobjectTypes type) const; @@ -1077,16 +1086,16 @@ class Player : public Unit, public GridObject<Player> uint8 GetChatTag() const; std::string autoReplyMsg; - uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, BarberShopStyleEntry const* newSkin=NULL); + uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, BarberShopStyleEntry const* newSkin = nullptr) const; - PlayerSocial *GetSocial() { return m_social; } + PlayerSocial *GetSocial() const { return m_social; } PlayerTaxi m_taxi; void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), getLevel()); } - bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = NULL, uint32 spellid = 0); + bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = nullptr, uint32 spellid = 0); bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0); void CleanupAfterTaxiFlight(); - void ContinueTaxiFlight(); + void ContinueTaxiFlight() const; // mount_id can be used in scripting calls bool isAcceptWhispers() const { return (m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS) != 0; } void SetAcceptWhispers(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; } @@ -1153,8 +1162,8 @@ class Player : public Unit, public GridObject<Player> void SetVirtualItemSlot(uint8 i, Item* item); void SetSheath(SheathState sheathed) override; // overwrite Unit version uint8 FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const; - uint32 GetItemCount(uint32 item, bool inBankAlso = false, Item* skipItem = NULL) const; - uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem = NULL) const; + uint32 GetItemCount(uint32 item, bool inBankAlso = false, Item* skipItem = nullptr) const; + uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem = nullptr) const; Item* GetItemByGuid(ObjectGuid guid) const; Item* GetItemByEntry(uint32 entry) const; Item* GetItemByPos(uint16 pos) const; @@ -1172,18 +1181,18 @@ class Player : public Unit, public GridObject<Player> static bool IsBagPos(uint16 pos); static bool IsBankPos(uint16 pos) { return IsBankPos(pos >> 8, pos & 255); } static bool IsBankPos(uint8 bag, uint8 slot); - bool IsValidPos(uint16 pos, bool explicit_pos) { return IsValidPos(pos >> 8, pos & 255, explicit_pos); } - bool IsValidPos(uint8 bag, uint8 slot, bool explicit_pos); - uint8 GetBankBagSlotCount() const { return GetByteValue(PLAYER_BYTES_2, 2); } - void SetBankBagSlotCount(uint8 count) { SetByteValue(PLAYER_BYTES_2, 2, count); } + bool IsValidPos(uint16 pos, bool explicit_pos) const { return IsValidPos(pos >> 8, pos & 255, explicit_pos); } + bool IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) const; + uint8 GetBankBagSlotCount() const { return GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS); } + void SetBankBagSlotCount(uint8 count) { SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS, count); } bool HasItemCount(uint32 item, uint32 count = 1, bool inBankAlso = false) const; - bool HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem = NULL) const; + bool HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem = nullptr) const; bool CanNoReagentCast(SpellInfo const* spellInfo) const; bool HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot = NULL_SLOT) const; bool HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot = NULL_SLOT) const; InventoryResult CanTakeMoreSimilarItems(Item* pItem, uint32* itemLimitCategory = NULL) const { return CanTakeMoreSimilarItems(pItem->GetEntry(), pItem->GetCount(), pItem, NULL, itemLimitCategory); } InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count, uint32* itemLimitCategory = NULL) const { return CanTakeMoreSimilarItems(entry, count, NULL, NULL, itemLimitCategory); } - InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = NULL) const; + InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = nullptr) const; InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap = false) const; InventoryResult CanStoreItems(Item** items, int count, uint32* itemLimitCategory) const; InventoryResult CanEquipNewItem(uint8 slot, uint16& dest, uint32 item, bool swap) const; @@ -1210,7 +1219,7 @@ class Player : public Unit, public GridObject<Player> void StoreLootItem(uint8 lootSlot, Loot* loot); InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL, uint32* itemLimitCategory = NULL) const; - InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item* pItem = NULL, bool swap = false, uint32* no_space_count = NULL) const; + InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item* pItem = nullptr, bool swap = false, uint32* no_space_count = nullptr) const; void AddRefundReference(ObjectGuid it); void DeleteRefundReference(ObjectGuid it); @@ -1241,9 +1250,9 @@ class Player : public Unit, public GridObject<Player> Item* GetItemFromBuyBackSlot(uint32 slot); void RemoveItemFromBuyBackSlot(uint32 slot, bool del); uint32 GetMaxKeyringSize() const { return KEYRING_SLOT_END-KEYRING_SLOT_START; } - void SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2 = NULL, uint32 itemid = 0); - void SendBuyError(BuyResult msg, Creature* creature, uint32 item, uint32 param); - void SendSellError(SellResult msg, Creature* creature, ObjectGuid guid, uint32 param); + void SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2 = nullptr, uint32 itemid = 0) const; + void SendBuyError(BuyResult msg, Creature* creature, uint32 item, uint32 param) const; + void SendSellError(SellResult msg, Creature* creature, ObjectGuid guid, uint32 param) const; void AddWeaponProficiency(uint32 newflag) { m_WeaponProficiency |= newflag; } void AddArmorProficiency(uint32 newflag) { m_ArmorProficiency |= newflag; } uint32 GetWeaponProficiency() const { return m_WeaponProficiency; } @@ -1305,10 +1314,10 @@ class Player : public Unit, public GridObject<Player> void PrepareQuestMenu(ObjectGuid guid); void SendPreparedQuest(ObjectGuid guid); bool IsActiveQuest(uint32 quest_id) const; - Quest const* GetNextQuest(ObjectGuid guid, Quest const* quest); + Quest const* GetNextQuest(ObjectGuid guid, Quest const* quest) const; bool CanSeeStartQuest(Quest const* quest); bool CanTakeQuest(Quest const* quest, bool msg); - bool CanAddQuest(Quest const* quest, bool msg); + bool CanAddQuest(Quest const* quest, bool msg) const; bool CanCompleteQuest(uint32 quest_id); bool CanCompleteRepeatableQuest(Quest const* quest); bool CanRewardQuest(Quest const* quest, bool msg); @@ -1320,19 +1329,19 @@ class Player : public Unit, public GridObject<Player> void RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce = true); void FailQuest(uint32 quest_id); bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const; - bool SatisfyQuestLevel(Quest const* qInfo, bool msg); - bool SatisfyQuestLog(bool msg); + bool SatisfyQuestLevel(Quest const* qInfo, bool msg) const; + bool SatisfyQuestLog(bool msg) const; bool SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg); bool SatisfyQuestClass(Quest const* qInfo, bool msg) const; - bool SatisfyQuestRace(Quest const* qInfo, bool msg); + bool SatisfyQuestRace(Quest const* qInfo, bool msg) const; bool SatisfyQuestReputation(Quest const* qInfo, bool msg); - bool SatisfyQuestStatus(Quest const* qInfo, bool msg); + bool SatisfyQuestStatus(Quest const* qInfo, bool msg) const; bool SatisfyQuestConditions(Quest const* qInfo, bool msg); - bool SatisfyQuestTimed(Quest const* qInfo, bool msg); + bool SatisfyQuestTimed(Quest const* qInfo, bool msg) const; bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg); - bool SatisfyQuestNextChain(Quest const* qInfo, bool msg); + bool SatisfyQuestNextChain(Quest const* qInfo, bool msg) const; bool SatisfyQuestPrevChain(Quest const* qInfo, bool msg); - bool SatisfyQuestDay(Quest const* qInfo, bool msg); + bool SatisfyQuestDay(Quest const* qInfo, bool msg) const; bool SatisfyQuestWeek(Quest const* qInfo, bool msg); bool SatisfyQuestMonth(Quest const* qInfo, bool msg); bool SatisfyQuestSeasonal(Quest const* qInfo, bool msg); @@ -1367,7 +1376,7 @@ class Player : public Unit, public GridObject<Player> void SetQuestSlotTimer(uint16 slot, uint32 timer); void SwapQuestSlot(uint16 slot1, uint16 slot2); - uint16 GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry); + uint16 GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry) const; void AreaExploredOrEventHappens(uint32 questId); void GroupEventHappens(uint32 questId, WorldObject const* pEventObject); void ItemAddedQuestCheck(uint32 entry, uint32 count); @@ -1385,14 +1394,14 @@ class Player : public Unit, public GridObject<Player> void UpdateForQuestWorldObjects(); bool CanShareQuest(uint32 questId) const; - void SendQuestComplete(uint32 questId); - void SendQuestReward(Quest const* quest, uint32 XP); - void SendQuestFailed(uint32 questId, InventoryResult reason = EQUIP_ERR_OK); - void SendQuestTimerFailed(uint32 questId); + void SendQuestComplete(uint32 questId) const; + void SendQuestReward(Quest const* quest, uint32 XP) const; + void SendQuestFailed(uint32 questId, InventoryResult reason = EQUIP_ERR_OK) const; + void SendQuestTimerFailed(uint32 questId) const; void SendCanTakeQuestResponse(QuestFailedReason msg) const; - void SendQuestConfirmAccept(Quest const* quest, Player* pReceiver); - void SendPushToPartyResponse(Player* player, uint8 msg); - void SendQuestUpdateAddItem(Quest const* quest, uint32 itemIdx, uint16 count); + void SendQuestConfirmAccept(Quest const* quest, Player* pReceiver) const; + void SendPushToPartyResponse(Player* player, uint8 msg) const; + void SendQuestUpdateAddItem(Quest const* quest, uint32 itemIdx, uint16 count) const; void SendQuestUpdateAddCreatureOrGo(Quest const* quest, ObjectGuid guid, uint32 creatureOrGOIdx, uint16 oldCount, uint16 addCount); void SendQuestUpdateAddPlayer(Quest const* quest, uint16 oldCount, uint16 addCount); @@ -1430,10 +1439,9 @@ class Player : public Unit, public GridObject<Player> void SaveToDB(bool create = false); void SaveInventoryAndGoldToDB(SQLTransaction& trans); // fast save function for item/money cheating preventing - void SaveGoldToDB(SQLTransaction& trans); + void SaveGoldToDB(SQLTransaction& trans) const; static void SetUInt32ValueInArray(Tokenizer& data, uint16 index, uint32 value); - static void SetFloatValueInArray(Tokenizer& data, uint16 index, float value); static void Customize(CharacterCustomizeInfo const* customizeInfo, SQLTransaction& trans); static void SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, SQLTransaction& trans); @@ -1444,10 +1452,9 @@ class Player : public Unit, public GridObject<Player> bool m_mailsLoaded; bool m_mailsUpdated; - void SetBindPoint(ObjectGuid guid); - void SendTalentWipeConfirm(ObjectGuid guid); + void SetBindPoint(ObjectGuid guid) const; + void SendTalentWipeConfirm(ObjectGuid guid) const; void ResetPetTalents(); - void CalcRage(uint32 damage, bool attacker); void RegenerateAll(); void Regenerate(Powers power); void RegenerateHealth(); @@ -1475,13 +1482,13 @@ class Player : public Unit, public GridObject<Player> uint8 GetComboPoints() const { return m_comboPoints; } ObjectGuid GetComboTarget() const { return m_comboTarget; } - void AddComboPoints(Unit* target, int8 count, Spell* spell = NULL); + void AddComboPoints(Unit* target, int8 count, Spell* spell = nullptr); void GainSpellComboPoints(int8 count); void ClearComboPoints(); void SendComboPoints(); - void SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError = 0, ObjectGuid::LowType item_guid = 0, uint32 item_count = 0); - void SendNewMail(); + void SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError = 0, ObjectGuid::LowType item_guid = 0, uint32 item_count = 0) const; + void SendNewMail() const; void UpdateNextMailTimeAndUnreads(); void AddNewMailDeliverTime(time_t deliver_time); bool IsMailsLoaded() const { return m_mailsLoaded; } @@ -1512,19 +1519,19 @@ class Player : public Unit, public GridObject<Player> void AddMItem(Item* it); bool RemoveMItem(uint32 id); - void SendOnCancelExpectedVehicleRideAura(); + void SendOnCancelExpectedVehicleRideAura() const; void PetSpellInitialize(); void CharmSpellInitialize(); void PossessSpellInitialize(); void VehicleSpellInitialize(); - void SendRemoveControlBar(); + void SendRemoveControlBar() const; bool HasSpell(uint32 spell) const override; bool HasActiveSpell(uint32 spell) const; // show in spellbook TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const; bool IsSpellFitByClassAndRace(uint32 spell_id) const; bool IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const; - void SendProficiency(ItemClass itemClass, uint32 itemSubclassMask); + void SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) const; void SendInitialSpells(); bool AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, uint32 fromSkill = 0); void LearnSpell(uint32 spell_id, bool dependent, uint32 fromSkill = 0); @@ -1540,7 +1547,7 @@ class Player : public Unit, public GridObject<Player> void RemoveTemporarySpell(uint32 spellId); void SetReputation(uint32 factionentry, uint32 value); uint32 GetReputation(uint32 factionentry) const; - std::string const& GetGuildName(); + std::string const& GetGuildName() const; uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); } void SetFreeTalentPoints(uint32 points); bool ResetTalents(bool no_cost = false); @@ -1579,26 +1586,39 @@ class Player : public Unit, public GridObject<Player> PlayerSpellMap & GetSpellMap() { return m_spells; } void AddSpellMod(SpellModifier* mod, bool apply); - bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = NULL); - template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell* spell = NULL); + bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr) const; + template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell* spell = nullptr); void RemoveSpellMods(Spell* spell); - void RestoreSpellMods(Spell* spell, uint32 ownerAuraId = 0, Aura* aura = NULL); - void RestoreAllSpellMods(uint32 ownerAuraId = 0, Aura* aura = NULL); + void RestoreSpellMods(Spell* spell, uint32 ownerAuraId = 0, Aura* aura = nullptr); + void RestoreAllSpellMods(uint32 ownerAuraId = 0, Aura* aura = nullptr); void DropModCharge(SpellModifier* mod, Spell* spell); void SetSpellModTakingSpell(Spell* spell, bool apply); void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns = false); uint32 GetLastPotionId() const { return m_lastPotionId; } void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; } - void UpdatePotionCooldown(Spell* spell = NULL); + void UpdatePotionCooldown(Spell* spell = nullptr); + + void SetResurrectRequestData(Unit* caster, uint32 health, uint32 mana, uint32 appliedAura); + + void ClearResurrectRequestData() + { + _resurrectionData.reset(); + } + + bool IsResurrectRequestedBy(ObjectGuid const& guid) const + { + if (!IsResurrectRequested()) + return false; - void setResurrectRequestData(ObjectGuid guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana); - void clearResurrectRequestData(); - bool isResurrectRequestedBy(ObjectGuid guid) const { return !m_resurrectGUID.IsEmpty() && m_resurrectGUID == guid; } - bool isResurrectRequested() const { return !m_resurrectGUID.IsEmpty(); } + return !_resurrectionData->GUID.IsEmpty() && _resurrectionData->GUID == guid; + } + + bool IsResurrectRequested() const { return _resurrectionData.get() != nullptr; } void ResurrectUsingRequestData(); + void ResurrectUsingRequestDataImpl(); - uint8 getCinematic() { return m_cinematic; } + uint8 getCinematic() const { return m_cinematic; } void setCinematic(uint8 cine) { m_cinematic = cine; } ActionButton* addActionButton(uint8 button, uint32 action, uint8 type); @@ -1606,11 +1626,11 @@ class Player : public Unit, public GridObject<Player> ActionButton const* GetActionButton(uint8 button); void SendInitialActionButtons() const { SendActionButtons(1); } void SendActionButtons(uint32 state) const; - bool IsActionButtonDataValid(uint8 button, uint32 action, uint8 type); + bool IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) const; PvPInfo pvpInfo; void UpdatePvPState(bool onlyFFA = false); - void SetPvP(bool state); + void SetPvP(bool state) override; void UpdatePvP(bool state, bool override=false); void UpdateZone(uint32 newZone, uint32 newArea); void UpdateArea(uint32 newArea); @@ -1636,7 +1656,7 @@ class Player : public Unit, public GridObject<Player> bool IsInSameGroupWith(Player const* p) const; bool IsInSameRaidWith(Player const* p) const; void UninviteFromGroup(); - static void RemoveFromGroup(Group* group, ObjectGuid guid, RemoveMethod method = GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker = ObjectGuid::Empty, const char* reason = NULL); + static void RemoveFromGroup(Group* group, ObjectGuid guid, RemoveMethod method = GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker = ObjectGuid::Empty, const char* reason = nullptr); void RemoveFromGroup(RemoveMethod method = GROUP_REMOVEMETHOD_DEFAULT) { RemoveFromGroup(GetGroup(), GetGUID(), method); } void SendUpdateToOutOfRangeGroupMembers(); @@ -1703,13 +1723,13 @@ class Player : public Unit, public GridObject<Player> void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override; void UpdateDefenseBonusesMod(); - inline void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);} - float GetMeleeCritFromAgility(); - void GetDodgeFromAgility(float &diminishing, float &nondiminishing); + void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);} + float GetMeleeCritFromAgility() const; + void GetDodgeFromAgility(float &diminishing, float &nondiminishing) const; float GetMissPercentageFromDefence() const; - float GetSpellCritFromIntellect(); - float OCTRegenHPPerSpirit(); - float OCTRegenMPPerSpirit(); + float GetSpellCritFromIntellect() const; + float OCTRegenHPPerSpirit() const; + float OCTRegenMPPerSpirit() const; float GetRatingMultiplier(CombatRating cr) const; float GetRatingBonusValue(CombatRating cr) const; uint32 GetBaseSpellPowerBonus() const { return m_baseSpellPower; } @@ -1747,26 +1767,26 @@ class Player : public Unit, public GridObject<Player> void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override; void DestroyForPlayer(Player* target, bool onDeath = false) const override; - void SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend = false, float group_rate=1.0f); + void SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend = false, float group_rate=1.0f) const; // notifiers - void SendAttackSwingCantAttack(); - void SendAttackSwingCancelAttack(); - void SendAttackSwingDeadTarget(); - void SendAttackSwingNotInRange(); - void SendAttackSwingBadFacingAttack(); + void SendAttackSwingCantAttack() const; + void SendAttackSwingCancelAttack() const; + void SendAttackSwingDeadTarget() const; + void SendAttackSwingNotInRange() const; + void SendAttackSwingBadFacingAttack() const; void SendAutoRepeatCancel(Unit* target); - void SendExplorationExperience(uint32 Area, uint32 Experience); + void SendExplorationExperience(uint32 Area, uint32 Experience) const; - void SendDungeonDifficulty(bool IsInGroup); - void SendRaidDifficulty(bool IsInGroup, int32 forcedDifficulty = -1); + void SendDungeonDifficulty(bool IsInGroup) const; + void SendRaidDifficulty(bool IsInGroup, int32 forcedDifficulty = -1) const; void ResetInstances(uint8 method, bool isRaid); - void SendResetInstanceSuccess(uint32 MapId); - void SendResetInstanceFailed(uint32 reason, uint32 MapId); - void SendResetFailedNotify(uint32 mapid); + void SendResetInstanceSuccess(uint32 MapId) const; + void SendResetInstanceFailed(uint32 reason, uint32 MapId) const; + void SendResetFailedNotify(uint32 mapid) const; - virtual bool UpdatePosition(float x, float y, float z, float orientation, bool teleport = false) override; - bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } + bool UpdatePosition(float x, float y, float z, float orientation, bool teleport = false) override; + bool UpdatePosition(const Position &pos, bool teleport = false) override { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } void UpdateUnderwaterState(Map* m, float x, float y, float z) override; void SendMessageToSet(WorldPacket* data, bool self) override { SendMessageToSetInRange(data, GetVisibilityRange(), self); } @@ -1787,14 +1807,7 @@ class Player : public Unit, public GridObject<Player> void ResurrectPlayer(float restore_percent, bool applySickness = false); void BuildPlayerRepop(); void RepopAtGraveyard(); - void SendGhoulResurrectRequest(Player* target); - bool IsValidGhoulResurrectRequest(ObjectGuid guid) - { - return !m_ghoulResurrectPlayerGUID.IsEmpty() && m_ghoulResurrectPlayerGUID == guid; - } - void GhoulResurrect(); - void SetGhoulResurrectGhoulGUID(ObjectGuid guid) { m_ghoulResurrectGhoulGUID = guid; } - ObjectGuid GetGhoulResurrectGhoulGUID() { return m_ghoulResurrectGhoulGUID; } + void RemoveGhoul(); void DurabilityLossAll(double percent, bool inventory); @@ -1807,11 +1820,11 @@ class Player : public Unit, public GridObject<Player> void UpdateMirrorTimers(); void StopMirrorTimers(); - bool IsMirrorTimerActive(MirrorTimerType type); + bool IsMirrorTimerActive(MirrorTimerType type) const; void SetMovement(PlayerMovementType pType); - bool CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone); + bool CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone) const; void JoinedChannel(Channel* c); void LeftChannel(Channel* c); @@ -1896,14 +1909,14 @@ class Player : public Unit, public GridObject<Player> //End of PvP System void SetDrunkValue(uint8 newDrunkValue, uint32 itemId = 0); - uint8 GetDrunkValue() const { return GetByteValue(PLAYER_BYTES_3, 1); } + uint8 GetDrunkValue() const { return GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_INEBRIATION); } static DrunkenState GetDrunkenstateByValue(uint8 value); uint32 GetDeathTimer() const { return m_deathTimer; } uint32 GetCorpseReclaimDelay(bool pvp) const; void UpdateCorpseReclaimDelay(); - int32 CalculateCorpseReclaimDelay(bool load = false); - void SendCorpseReclaimDelay(uint32 delay); + int32 CalculateCorpseReclaimDelay(bool load = false) const; + void SendCorpseReclaimDelay(uint32 delay) const; uint32 GetShieldBlockValue() const override; // overwrite Unit version (virtual) bool CanParry() const { return m_canParry; } @@ -1936,7 +1949,7 @@ class Player : public Unit, public GridObject<Player> void _ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply, bool only_level_scale = false); void _ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv, bool apply); void _ApplyAmmoBonuses(); - bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot); + bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) const; void ToggleMetaGemsActive(uint8 exceptslot, bool apply); void CorrectMetaGemEnchants(uint8 slot, bool apply); void InitDataForForm(bool reapplyMods = false); @@ -1953,21 +1966,21 @@ class Player : public Unit, public GridObject<Player> void DeleteEquipmentSet(uint64 setGuid); void SendInitWorldStates(uint32 zone, uint32 area); - void SendUpdateWorldState(uint32 Field, uint32 Value); - void SendDirectMessage(WorldPacket* data); - void SendBGWeekendWorldStates(); - void SendBattlefieldWorldStates(); + void SendUpdateWorldState(uint32 Field, uint32 Value) const; + void SendDirectMessage(WorldPacket const* data) const; + void SendBGWeekendWorldStates() const; + void SendBattlefieldWorldStates() const; - void SendAurasForTarget(Unit* target); + void SendAurasForTarget(Unit* target) const; PlayerMenu* PlayerTalkClass; std::vector<ItemSetEffect*> ItemSetEff; void SendLoot(ObjectGuid guid, LootType loot_type); - void SendLootError(ObjectGuid guid, LootError error); - void SendLootRelease(ObjectGuid guid); - void SendNotifyLootItemRemoved(uint8 lootSlot); - void SendNotifyLootMoneyRemoved(); + void SendLootError(ObjectGuid guid, LootError error) const; + void SendLootRelease(ObjectGuid guid) const; + void SendNotifyLootItemRemoved(uint8 lootSlot) const; + void SendNotifyLootMoneyRemoved() const; /*********************************************************/ /*** BATTLEGROUND SYSTEM ***/ @@ -1988,7 +2001,7 @@ class Player : public Unit, public GridObject<Player> void SetBattlegroundId(uint32 val, BattlegroundTypeId bgTypeId); uint32 AddBattlegroundQueueId(BattlegroundQueueTypeId val); - bool HasFreeBattlegroundQueueId(); + bool HasFreeBattlegroundQueueId() const; void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val); void SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId); bool IsInvitedForBattlegroundInstance(uint32 instanceId) const; @@ -2005,10 +2018,10 @@ class Player : public Unit, public GridObject<Player> void ClearAfkReports() { m_bgData.bgAfkReporter.clear(); } bool GetBGAccessByLevel(BattlegroundTypeId bgTypeId) const; - bool isTotalImmunity(); - bool CanUseBattlegroundObject(GameObject* gameobject); - bool isTotalImmune(); - bool CanCaptureTowerPoint(); + bool isTotalImmunity() const; + bool CanUseBattlegroundObject(GameObject* gameobject) const; + bool isTotalImmune() const; + bool CanCaptureTowerPoint() const; bool GetRandomWinner() const { return m_IsBGRandomWinner; } void SetRandomWinner(bool isWinner); @@ -2019,13 +2032,13 @@ class Player : public Unit, public GridObject<Player> OutdoorPvP* GetOutdoorPvP() const; // returns true if the player is in active state for outdoor pvp objective capturing, false otherwise - bool IsOutdoorPvPActive(); + bool IsOutdoorPvPActive() const; /*********************************************************/ /*** ENVIROMENTAL SYSTEM ***/ /*********************************************************/ - bool IsImmuneToEnvironmentalDamage(); + bool IsImmuneToEnvironmentalDamage() const; uint32 EnvironmentalDamage(EnviromentalDamage type, uint32 damage); /*********************************************************/ @@ -2055,7 +2068,7 @@ class Player : public Unit, public GridObject<Player> void SetViewpoint(WorldObject* target, bool apply); WorldObject* GetViewpoint() const; void StopCastingCharm(); - void StopCastingBindSight(); + void StopCastingBindSight() const; uint32 GetSaveTimer() const { return m_nextSave; } void SetSaveTimer(uint32 timer) { m_nextSave = timer; } @@ -2082,13 +2095,13 @@ class Player : public Unit, public GridObject<Player> // currently visible objects at player client GuidUnorderedSet m_clientGUIDs; - bool HaveAtClient(WorldObject const* u) const; + bool HaveAtClient(Object const* u) const; bool IsNeverVisible() const override; bool IsVisibleGloballyFor(Player const* player) const; - void SendInitialVisiblePackets(Unit* target); + void SendInitialVisiblePackets(Unit* target) const; void UpdateObjectVisibility(bool forced = true) override; void UpdateVisibilityForPlayer(); void UpdateVisibilityOf(WorldObject* target); @@ -2103,8 +2116,8 @@ class Player : public Unit, public GridObject<Player> void SetAtLoginFlag(AtLoginFlags f) { m_atLoginFlags |= f; } void RemoveAtLoginFlag(AtLoginFlags flags, bool persist = false); - bool isUsingLfg(); - bool inRandomLfgDungeon(); + bool isUsingLfg() const; + bool inRandomLfgDungeon() const; typedef std::set<uint32> DFQuestsDoneList; DFQuestsDoneList m_DFQuests; @@ -2117,7 +2130,7 @@ class Player : public Unit, public GridObject<Player> bool IsPetNeedBeTemporaryUnsummoned() const; void SendCinematicStart(uint32 CinematicSequenceId); - void SendMovieStart(uint32 MovieId); + void SendMovieStart(uint32 MovieId) const; /*********************************************************/ /*** INSTANCE SYSTEM ***/ @@ -2155,10 +2168,10 @@ class Player : public Unit, public GridObject<Player> /*** GROUP SYSTEM ***/ /*********************************************************/ - Group* GetGroupInvite() { return m_groupInvite; } + Group* GetGroupInvite() const { return m_groupInvite; } void SetGroupInvite(Group* group) { m_groupInvite = group; } Group* GetGroup() { return m_group.getTarget(); } - const Group* GetGroup() const { return (const Group*)m_group.getTarget(); } + Group const* GetGroup() const { return const_cast<Group const*>(m_group.getTarget()); } GroupReference& GetGroupRef() { return m_group; } void SetGroup(Group* group, int8 subgroup = -1); uint8 GetSubGroup() const { return m_group.getSubGroup(); } @@ -2172,7 +2185,7 @@ class Player : public Unit, public GridObject<Player> // Battleground / Battlefield Group System void SetBattlegroundOrBattlefieldRaid(Group* group, int8 subgroup = -1); void RemoveFromBattlegroundOrBattlefieldRaid(); - Group* GetOriginalGroup() { return m_originalGroup.getTarget(); } + Group* GetOriginalGroup() const { return m_originalGroup.getTarget(); } GroupReference& GetOriginalGroupRef() { return m_originalGroup; } uint8 GetOriginalSubGroup() const { return m_originalGroup.getSubGroup(); } void SetOriginalGroup(Group* group, int8 subgroup = -1); @@ -2205,8 +2218,8 @@ class Player : public Unit, public GridObject<Player> void RemoveRunesByAuraEffect(AuraEffect const* aura); void RestoreBaseRune(uint8 index); void ConvertRune(uint8 index, RuneType newType); - void ResyncRunes(uint8 count); - void AddRunePower(uint8 index); + void ResyncRunes(uint8 count) const; + void AddRunePower(uint8 index) const; void InitRunes(); void SendRespondInspectAchievements(Player* player) const; @@ -2230,7 +2243,7 @@ class Player : public Unit, public GridObject<Player> void SetChampioningFaction(uint32 faction) { m_ChampioningFaction = faction; } Spell* m_spellModTakingSpell; - float GetAverageItemLevel(); + float GetAverageItemLevel() const; bool isDebugAreaTriggers; void ClearWhisperWhiteList() { WhisperList.clear(); } @@ -2249,6 +2262,17 @@ class Player : public Unit, public GridObject<Player> //! Return collision height sent to client float GetCollisionHeight(bool mounted) const; + std::string GetMapAreaAndZoneString() const; + std::string GetCoordsMapAreaAndZoneString() const; + + // Cinematic camera data and remote sight functions + uint32 GetActiveCinematicCamera() const { return m_activeCinematicCameraId; } + void SetActiveCinematicCamera(uint32 cinematicCameraId = 0) { m_activeCinematicCameraId = cinematicCameraId; } + bool IsOnCinematic() const { return (m_cinematicCamera != nullptr); } + void BeginCinematic(); + void EndCinematic(); + void UpdateCinematicLocation(uint32 diff); + std::string GetMapAreaAndZoneString(); std::string GetCoordsMapAreaAndZoneString(); @@ -2341,9 +2365,9 @@ class Player : public Unit, public GridObject<Player> void _SaveSpells(SQLTransaction& trans); void _SaveEquipmentSets(SQLTransaction& trans); void _SaveBGData(SQLTransaction& trans); - void _SaveGlyphs(SQLTransaction& trans); + void _SaveGlyphs(SQLTransaction& trans) const; void _SaveTalents(SQLTransaction& trans); - void _SaveStats(SQLTransaction& trans); + void _SaveStats(SQLTransaction& trans) const; void _SaveInstanceTimeRestrictions(SQLTransaction& trans); /*********************************************************/ @@ -2353,7 +2377,7 @@ class Player : public Unit, public GridObject<Player> void SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen); void StopMirrorTimer(MirrorTimerType Type); void HandleDrowning(uint32 time_diff); - int32 getMaxTimer(MirrorTimerType timer); + int32 getMaxTimer(MirrorTimerType timer) const; /*********************************************************/ /*** HONOR SYSTEM ***/ @@ -2424,13 +2448,7 @@ class Player : public Unit, public GridObject<Player> void ResetTimeSync(); void SendTimeSync(); - ObjectGuid m_resurrectGUID; - uint32 m_resurrectMap; - float m_resurrectX, m_resurrectY, m_resurrectZ; - uint32 m_resurrectHealth, m_resurrectMana; - - ObjectGuid m_ghoulResurrectPlayerGUID; - ObjectGuid m_ghoulResurrectGhoulGUID; + std::unique_ptr<ResurrectionData> _resurrectionData; WorldSession* m_session; @@ -2583,10 +2601,18 @@ class Player : public Unit, public GridObject<Player> uint32 manaBeforeDuel; WorldLocation _corpseLocation; + + // Remote location information + uint32 m_cinematicDiff; + uint32 m_lastCinematicCheck; + uint32 m_activeCinematicCameraId; + FlyByCameraCollection* m_cinematicCamera; + Position m_remoteSightPosition; + Creature* m_CinematicObject; }; -void AddItemsSetItem(Player* player, Item* item); -void RemoveItemsSetItem(Player* player, ItemTemplate const* proto); +TC_GAME_API void AddItemsSetItem(Player* player, Item* item); +TC_GAME_API void RemoveItemsSetItem(Player* player, ItemTemplate const* proto); // "the bodies of template functions must be made available in a header file" template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell* spell) diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp index ffb2d8a7dd8..809bdd0bf6f 100644 --- a/src/server/game/Entities/Player/SocialMgr.cpp +++ b/src/server/game/Entities/Player/SocialMgr.cpp @@ -195,6 +195,12 @@ SocialMgr::SocialMgr() { } SocialMgr::~SocialMgr() { } +SocialMgr* SocialMgr::instance() +{ + static SocialMgr instance; + return &instance; +} + void SocialMgr::GetFriendInfo(Player* player, ObjectGuid::LowType friendGUID, FriendInfo &friendInfo) { if (!player) diff --git a/src/server/game/Entities/Player/SocialMgr.h b/src/server/game/Entities/Player/SocialMgr.h index 8f8ed04b5fb..803301b95c7 100644 --- a/src/server/game/Entities/Player/SocialMgr.h +++ b/src/server/game/Entities/Player/SocialMgr.h @@ -99,7 +99,7 @@ enum FriendsResult #define SOCIALMGR_FRIEND_LIMIT 50 #define SOCIALMGR_IGNORE_LIMIT 50 -class PlayerSocial +class TC_GAME_API PlayerSocial { friend class SocialMgr; public: @@ -128,11 +128,7 @@ class SocialMgr ~SocialMgr(); public: - static SocialMgr* instance() - { - static SocialMgr instance; - return &instance; - } + static SocialMgr* instance(); // Misc void RemovePlayerSocial(ObjectGuid::LowType guid) { m_socialMap.erase(guid); } diff --git a/src/server/game/Entities/Player/TradeData.h b/src/server/game/Entities/Player/TradeData.h index 276e6f3db1c..396d784fee7 100644 --- a/src/server/game/Entities/Player/TradeData.h +++ b/src/server/game/Entities/Player/TradeData.h @@ -31,7 +31,7 @@ enum TradeSlots class Item; class Player; -class TradeData +class TC_GAME_API TradeData { public: TradeData(Player* player, Player* trader) : diff --git a/src/server/game/Entities/Totem/Totem.h b/src/server/game/Entities/Totem/Totem.h index bbe7943f4b6..42be4525a0c 100644 --- a/src/server/game/Entities/Totem/Totem.h +++ b/src/server/game/Entities/Totem/Totem.h @@ -32,7 +32,7 @@ enum TotemType #define SENTRY_TOTEM_ENTRY 3968 -class Totem : public Minion +class TC_GAME_API Totem : public Minion { public: Totem(SummonPropertiesEntry const* properties, Unit* owner); diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index 987fbf70739..4cd20c8b613 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -25,7 +25,7 @@ struct CreatureData; -class Transport : public GameObject, public TransportBase +class TC_GAME_API Transport : public GameObject, public TransportBase { friend Transport* TransportMgr::CreateTransport(uint32, ObjectGuid::LowType, Map*); diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index a8e13a9f7db..82792a49c96 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -1152,7 +1152,7 @@ bool Guardian::UpdateStats(Stats stat) if (itr != ToPet()->m_spells.end()) // If pet has Wild Hunt { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value AddPct(mod, spellInfo->Effects[EFFECT_0].CalcValue()); } } @@ -1321,7 +1321,7 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) if (itr != ToPet()->m_spells.end()) // If pet has Wild Hunt { - SpellInfo const* sProto = sSpellMgr->EnsureSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value + SpellInfo const* sProto = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value mod += CalculatePct(1.0f, sProto->Effects[1].CalcValue()); } } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e2b0e1f01eb..b7f05a7fefa 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -8715,7 +8715,7 @@ void Unit::setPowerType(Powers new_powertype) if (getPowerType() == new_powertype) return; - SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE, new_powertype); if (GetTypeId() == TYPEID_PLAYER) { @@ -9052,10 +9052,10 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) if (GetTypeId() == TYPEID_UNIT && !IsPet()) { // should not let player enter combat by right clicking target - doesn't helps + AddThreat(victim, 0.0f); SetInCombatWith(victim); if (victim->GetTypeId() == TYPEID_PLAYER) victim->SetInCombatWith(this); - AddThreat(victim, 0.0f); ToCreature()->SendAIReaction(AI_REACTION_HOSTILE); ToCreature()->CallAssistance(); @@ -9106,7 +9106,7 @@ bool Unit::AttackStop() if (creature->HasSearchedAssistance()) { creature->SetNoSearchAssistance(false); - UpdateSpeed(MOVE_RUN, false); + UpdateSpeed(MOVE_RUN); } } @@ -9299,7 +9299,7 @@ Unit* Unit::GetCharmer() const if (ObjectGuid charmerGUID = GetCharmerGUID()) return ObjectAccessor::GetUnit(*this, charmerGUID); - return NULL; + return nullptr; } Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() const @@ -9440,7 +9440,7 @@ void Unit::SetMinion(Minion *minion, bool apply) // FIXME: hack, speed must be set only at follow if (GetTypeId() == TYPEID_PLAYER && minion->IsPet()) for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) - minion->SetSpeed(UnitMoveType(i), m_speed_rate[i], true); + minion->SetSpeedRate(UnitMoveType(i), m_speed_rate[i]); // Ghoul pets have energy instead of mana (is anywhere better place for this code?) if (minion->IsPetGhoul() || minion->IsRisenAlly()) @@ -11870,9 +11870,9 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy) if (IsPet()) { - UpdateSpeed(MOVE_RUN, true); - UpdateSpeed(MOVE_SWIM, true); - UpdateSpeed(MOVE_FLIGHT, true); + UpdateSpeed(MOVE_RUN); + UpdateSpeed(MOVE_SWIM); + UpdateSpeed(MOVE_FLIGHT); } if (!(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_MOUNTED_COMBAT)) @@ -11916,7 +11916,7 @@ void Unit::ClearInCombat() if (Unit* owner = GetOwner()) for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) if (owner->GetSpeedRate(UnitMoveType(i)) > GetSpeedRate(UnitMoveType(i))) - SetSpeed(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i)), true); + SetSpeedRate(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i))); } else if (!IsCharmed()) return; @@ -12003,25 +12003,26 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo || target->GetReactionTo(this) > REP_NEUTRAL) return false; + Player const* playerAffectingAttacker = HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr; + Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr; + // Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar) - if (GetReactionTo(target) == REP_NEUTRAL && - target->GetReactionTo(this) <= REP_NEUTRAL) + if ( + (playerAffectingAttacker && !playerAffectingTarget) || + (!playerAffectingAttacker && playerAffectingTarget) + ) { - if (!(target->GetTypeId() == TYPEID_PLAYER && GetTypeId() == TYPEID_PLAYER) && - !(target->GetTypeId() == TYPEID_UNIT && GetTypeId() == TYPEID_UNIT)) - { - Player const* player = target->GetTypeId() == TYPEID_PLAYER ? target->ToPlayer() : ToPlayer(); - Unit const* creature = target->GetTypeId() == TYPEID_UNIT ? target : this; + Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget; + Unit const* creature = playerAffectingAttacker ? target : this; - if (FactionTemplateEntry const* factionTemplate = creature->GetFactionTemplateEntry()) - { - if (!(player->GetReputationMgr().GetForcedRankIfAny(factionTemplate))) - if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->faction)) - if (FactionState const* repState = player->GetReputationMgr().GetState(factionEntry)) - if (!(repState->Flags & FACTION_FLAG_AT_WAR)) - return false; + if (FactionTemplateEntry const* factionTemplate = creature->GetFactionTemplateEntry()) + { + if (!(player->GetReputationMgr().GetForcedRankIfAny(factionTemplate))) + if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->faction)) + if (FactionState const* repState = player->GetReputationMgr().GetState(factionEntry)) + if (!(repState->Flags & FACTION_FLAG_AT_WAR)) + return false; - } } } @@ -12029,9 +12030,6 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo if (creatureAttacker && creatureAttacker->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_PARTY_MEMBER) return false; - Player const* playerAffectingAttacker = HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : NULL; - Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : NULL; - // check duel - before sanctuary checks if (playerAffectingAttacker && playerAffectingTarget) if (playerAffectingAttacker->duel && playerAffectingAttacker->duel->opponent == playerAffectingTarget && playerAffectingAttacker->duel->startTime != 0) @@ -12302,7 +12300,7 @@ void Unit::SetVisible(bool x) UpdateObjectVisibility(); } -void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) +void Unit::UpdateSpeed(UnitMoveType mtype) { int32 main_speed_mod = 0; float stack_bonus = 1.0f; @@ -12365,7 +12363,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) // Update speed for vehicle if available if (GetTypeId() == TYPEID_PLAYER && GetVehicle()) - GetVehicleBase()->UpdateSpeed(MOVE_FLIGHT, true); + GetVehicleBase()->UpdateSpeed(MOVE_FLIGHT); break; } default: @@ -12447,7 +12445,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) speed = min_speed; } - SetSpeed(mtype, speed, forced); + SetSpeedRate(mtype, speed); } float Unit::GetSpeed(UnitMoveType mtype) const @@ -12455,7 +12453,12 @@ float Unit::GetSpeed(UnitMoveType mtype) const return m_speed_rate[mtype]*(IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]); } -void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) +void Unit::SetSpeed(UnitMoveType mtype, float newValue) +{ + SetSpeedRate(mtype, newValue / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype])); +} + +void Unit::SetSpeedRate(UnitMoveType mtype, float rate) { if (rate < 0) rate = 0.0f; @@ -12468,102 +12471,67 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) propagateSpeedChange(); - WorldPacket data; - if (!forced) + // Spline packets are for units controlled by AI. "Force speed change" (wrongly named opcodes) and "move set speed" packets are for units controlled by a player. + static Opcodes const moveTypeToOpcode[MAX_MOVE_TYPE][3] = + { + {SMSG_SPLINE_SET_WALK_SPEED, SMSG_FORCE_WALK_SPEED_CHANGE, MSG_MOVE_SET_WALK_SPEED }, + {SMSG_SPLINE_SET_RUN_SPEED, SMSG_FORCE_RUN_SPEED_CHANGE, MSG_MOVE_SET_RUN_SPEED }, + {SMSG_SPLINE_SET_RUN_BACK_SPEED, SMSG_FORCE_RUN_BACK_SPEED_CHANGE, MSG_MOVE_SET_RUN_BACK_SPEED }, + {SMSG_SPLINE_SET_SWIM_SPEED, SMSG_FORCE_SWIM_SPEED_CHANGE, MSG_MOVE_SET_SWIM_SPEED }, + {SMSG_SPLINE_SET_SWIM_BACK_SPEED, SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, MSG_MOVE_SET_SWIM_BACK_SPEED }, + {SMSG_SPLINE_SET_TURN_RATE, SMSG_FORCE_TURN_RATE_CHANGE, MSG_MOVE_SET_TURN_RATE }, + {SMSG_SPLINE_SET_FLIGHT_SPEED, SMSG_FORCE_FLIGHT_SPEED_CHANGE, MSG_MOVE_SET_FLIGHT_SPEED }, + {SMSG_SPLINE_SET_FLIGHT_BACK_SPEED, SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, MSG_MOVE_SET_FLIGHT_BACK_SPEED }, + {SMSG_SPLINE_SET_PITCH_RATE, SMSG_FORCE_PITCH_RATE_CHANGE, MSG_MOVE_SET_PITCH_RATE }, + }; + + if (GetTypeId() == TYPEID_PLAYER) { - switch (mtype) - { - case MOVE_WALK: - data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_RUN: - data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_RUN_BACK: - data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_SWIM: - data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_SWIM_BACK: - data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_TURN_RATE: - data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_FLIGHT: - data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_FLIGHT_BACK: - data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_PITCH_RATE: - data.Initialize(MSG_MOVE_SET_PITCH_RATE, 8+4+2+4+4+4+4+4+4+4); - break; - default: - TC_LOG_ERROR("entities.unit", "Unit::SetSpeed: Unsupported move type (%d), data not sent to client.", mtype); - return; - } + // register forced speed changes for WorldSession::HandleForceSpeedChangeAck + // and do it only for real sent packets and use run for run/mounted as client expected + ++ToPlayer()->m_forced_speed_changes[mtype]; + + if (!IsInCombat()) + if (Pet* pet = ToPlayer()->GetPet()) + pet->SetSpeedRate(mtype, m_speed_rate[mtype]); + } + if (m_movedPlayer) // unit controlled by a player. + { + // Send notification to self. this packet is only sent to one client (the client of the player concerned by the change). + WorldPacket self; + self.Initialize(moveTypeToOpcode[mtype][1], mtype != MOVE_RUN ? 8 + 4 + 4 : 8 + 4 + 1 + 4); + self << GetPackGUID(); + self << (uint32)0; // Movement counter. Unimplemented at the moment! NUM_PMOVE_EVTS = 0x39Z. + if (mtype == MOVE_RUN) + self << uint8(1); // unknown byte added in 2.1.0 + self << float(GetSpeed(mtype)); + m_movedPlayer->GetSession()->SendPacket(&self); + + // Send notification to other players. sent to every clients (if in range) except one: the client of the player concerned by the change. + WorldPacket data; + data.Initialize(moveTypeToOpcode[mtype][2], 8 + 30 + 4); + data << GetPackGUID(); BuildMovementPacket(&data); data << float(GetSpeed(mtype)); - SendMessageToSet(&data, true); + SendMessageToSet(&data, false); } - else + else // unit controlled by AI. { - if (GetTypeId() == TYPEID_PLAYER) - { - // register forced speed changes for WorldSession::HandleForceSpeedChangeAck - // and do it only for real sent packets and use run for run/mounted as client expected - ++ToPlayer()->m_forced_speed_changes[mtype]; - - if (!IsInCombat()) - if (Pet* pet = ToPlayer()->GetPet()) - pet->SetSpeed(mtype, m_speed_rate[mtype], forced); - } - - switch (mtype) - { - case MOVE_WALK: - data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16); - break; - case MOVE_RUN: - data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 17); - break; - case MOVE_RUN_BACK: - data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16); - break; - case MOVE_SWIM: - data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16); - break; - case MOVE_SWIM_BACK: - data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16); - break; - case MOVE_TURN_RATE: - data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16); - break; - case MOVE_FLIGHT: - data.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE, 16); - break; - case MOVE_FLIGHT_BACK: - data.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, 16); - break; - case MOVE_PITCH_RATE: - data.Initialize(SMSG_FORCE_PITCH_RATE_CHANGE, 16); - break; - default: - TC_LOG_ERROR("entities.unit", "Unit::SetSpeed: Unsupported move type (%d), data not sent to client.", mtype); - return; - } + // send notification to every clients. + WorldPacket data; + data.Initialize(moveTypeToOpcode[mtype][0], 8 + 4); data << GetPackGUID(); - data << (uint32)0; // moveEvent, NUM_PMOVE_EVTS = 0x39 - if (mtype == MOVE_RUN) - data << uint8(0); // new 2.1.0 data << float(GetSpeed(mtype)); - SendMessageToSet(&data, true); + SendMessageToSet(&data, false); } } +bool Unit::IsGhouled() const +{ + return HasAura(SPELL_DK_RAISE_ALLY); +} + void Unit::setDeathState(DeathState s) { // Death state needs to be updated before RemoveAllAurasOnDeath() is called, to prevent entering combat @@ -13724,28 +13692,76 @@ void Unit::CleanupsBeforeDelete(bool finalCleanup) void Unit::UpdateCharmAI() { - if (GetTypeId() == TYPEID_PLAYER) - return; - - if (i_disabledAI) // disabled AI must be primary AI + switch (GetTypeId()) { - if (!IsCharmed()) - { - delete i_AI; - i_AI = i_disabledAI; - i_disabledAI = NULL; - } - } - else - { - if (IsCharmed()) + case TYPEID_UNIT: + if (i_disabledAI) // disabled AI must be primary AI + { + if (!IsCharmed()) + { + delete i_AI; + i_AI = i_disabledAI; + i_disabledAI = nullptr; + } + } + else + { + if (IsCharmed()) + { + i_disabledAI = i_AI; + if (isPossessed() || IsVehicle()) + i_AI = new PossessedAI(ToCreature()); + else + i_AI = new PetAI(ToCreature()); + } + } + break; + case TYPEID_PLAYER: { - i_disabledAI = i_AI; - if (isPossessed() || IsVehicle()) - i_AI = new PossessedAI(ToCreature()); + if (IsCharmed()) // if we are currently being charmed, then we should apply charm AI + { + i_disabledAI = i_AI; + + UnitAI* newAI = nullptr; + // first, we check if the creature's own AI specifies an override playerai for its owned players + if (Unit* charmer = GetCharmer()) + { + if (Creature* creatureCharmer = charmer->ToCreature()) + { + if (PlayerAI* charmAI = creatureCharmer->IsAIEnabled ? creatureCharmer->AI()->GetAIForCharmedPlayer(ToPlayer()) : nullptr) + newAI = charmAI; + } + else + { + TC_LOG_ERROR("misc", "Attempt to assign charm AI to player %s who is charmed by non-creature %s.", GetGUID().ToString().c_str(), GetCharmerGUID().ToString().c_str()); + } + } + if (!newAI) // otherwise, we default to the generic one + newAI = new SimpleCharmedPlayerAI(ToPlayer()); + i_AI = newAI; + } else - i_AI = new PetAI(ToCreature()); + { + if (i_AI) + { + // we allow the charmed PlayerAI to clean up + i_AI->OnCharmed(false); + // then delete it + delete i_AI; + } + else + { + TC_LOG_ERROR("misc", "Attempt to remove charm AI from player %s who doesn't currently have charm AI.", GetGUID().ToString().c_str()); + } + // and restore our previous PlayerAI (if we had one) + i_AI = i_disabledAI; + i_disabledAI = nullptr; + // IsAIEnabled gets handled in the caller + } + break; } + default: + TC_LOG_ERROR("misc", "Attempt to update charm AI for unit %s, which is neither player nor creature.", GetGUID().ToString().c_str()); } } @@ -14669,7 +14685,7 @@ void Unit::SendMovementFlagUpdate(bool self /* = false */) bool Unit::IsSitState() const { - uint8 s = getStandState(); + uint8 s = GetStandState(); return s == UNIT_STAND_STATE_SIT_CHAIR || s == UNIT_STAND_STATE_SIT_LOW_CHAIR || s == UNIT_STAND_STATE_SIT_MEDIUM_CHAIR || s == UNIT_STAND_STATE_SIT_HIGH_CHAIR || @@ -14678,7 +14694,7 @@ bool Unit::IsSitState() const bool Unit::IsStandState() const { - uint8 s = getStandState(); + uint8 s = GetStandState(); return !IsSitState() && s != UNIT_STAND_STATE_SLEEP && s != UNIT_STAND_STATE_KNEEL; } @@ -14715,7 +14731,7 @@ void Unit::SetDisplayId(uint32 modelId) SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId); // Set Gender by modelId if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(modelId)) - SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, minfo->gender); } void Unit::RestoreDisplayId() @@ -15979,15 +15995,11 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au if (player->isAFK()) player->ToggleAFK(); - if (Creature* creatureCharmer = charmer->ToCreature()) // we are charmed by a creature + if (charmer->GetTypeId() == TYPEID_UNIT) // we are charmed by a creature { - IsAIEnabled = true; - i_disabledAI = i_AI; - // set our AI to the charmer's custom charm AI if applicable - if (PlayerAI* charmAI = creatureCharmer->AI()->GetAIForCharmedPlayer(player)) - i_AI = charmAI; - else // otherwise use the default charmed player AI - i_AI = new SimpleCharmedPlayerAI(player); + // change AI to charmed AI on next Update tick + NeedChangeAI = true; + IsAIEnabled = false; } player->SetClientControl(this, false); } @@ -16030,7 +16042,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au if (cinfo && cinfo->type == CREATURE_TYPE_DEMON) { // to prevent client crash - SetByteValue(UNIT_FIELD_BYTES_0, 1, (uint8)CLASS_MAGE); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, (uint8)CLASS_MAGE); // just to enable stat window if (GetCharmInfo()) @@ -16132,7 +16144,7 @@ void Unit::RemoveCharmedBy(Unit* charmer) CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate(); if (cinfo && cinfo->type == CREATURE_TYPE_DEMON) { - SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class)); + SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, uint8(cinfo->unit_class)); if (GetCharmInfo()) GetCharmInfo()->SetPetNumber(0, true); else @@ -16149,18 +16161,8 @@ void Unit::RemoveCharmedBy(Unit* charmer) { if (charmer->GetTypeId() == TYPEID_UNIT) // charmed by a creature, this means we had PlayerAI { - if (i_AI) - { - // allow charmed player AI to clean up - i_AI->OnCharmed(false); - // then delete it - delete i_AI; - // and restore our previous playerAI (if we had one) - if ((i_AI = i_disabledAI)) - i_disabledAI = nullptr; - else - IsAIEnabled = false; - } + NeedChangeAI = true; + IsAIEnabled = false; } player->SetClientControl(this, true); } @@ -16660,7 +16662,7 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const // Based on Hair color if (getRace() == RACE_NIGHTELF) { - uint8 hairColor = GetByteValue(PLAYER_BYTES, 3); + uint8 hairColor = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID); switch (hairColor) { case 7: // Violet @@ -16681,7 +16683,7 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const // Based on Skin color else if (getRace() == RACE_TAUREN) { - uint8 skinColor = GetByteValue(PLAYER_BYTES, 0); + uint8 skinColor = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID); // Male if (getGender() == GENDER_MALE) { @@ -16740,7 +16742,7 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const // Based on Hair color if (getRace() == RACE_NIGHTELF) { - uint8 hairColor = GetByteValue(PLAYER_BYTES, 3); + uint8 hairColor = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID); switch (hairColor) { case 0: // Green @@ -16760,7 +16762,7 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const // Based on Skin color else if (getRace() == RACE_TAUREN) { - uint8 skinColor = GetByteValue(PLAYER_BYTES, 0); + uint8 skinColor = GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID); // Male if (getGender() == GENDER_MALE) { diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 19fd4089168..a0973aac279 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -190,6 +190,30 @@ enum UnitStandFlags UNIT_STAND_FLAGS_ALL = 0xFF }; +enum UnitBytes0Offsets +{ + UNIT_BYTES_0_OFFSET_RACE = 0, + UNIT_BYTES_0_OFFSET_CLASS = 1, + UNIT_BYTES_0_OFFSET_GENDER = 2, + UNIT_BYTES_0_OFFSET_POWER_TYPE = 3, +}; + +enum UnitBytes1Offsets +{ + UNIT_BYTES_1_OFFSET_STAND_STATE = 0, + UNIT_BYTES_1_OFFSET_PET_TALENTS = 1, + UNIT_BYTES_1_OFFSET_VIS_FLAG = 2, + UNIT_BYTES_1_OFFSET_ANIM_TIER = 3 +}; + +enum UnitBytes2Offsets +{ + UNIT_BYTES_2_OFFSET_SHEATH_STATE = 0, + UNIT_BYTES_2_OFFSET_PVP_FLAG = 1, + UNIT_BYTES_2_OFFSET_PET_FLAG = 2, + UNIT_BYTES_2_OFFSET_SHAPESHIFT = 3, +}; + // byte flags value (UNIT_FIELD_BYTES_1, 3) enum UnitBytes1_Flags { @@ -533,10 +557,10 @@ enum UnitMoveType #define MAX_MOVE_TYPE 9 -extern float baseMoveSpeed[MAX_MOVE_TYPE]; -extern float playerBaseMoveSpeed[MAX_MOVE_TYPE]; +TC_GAME_API extern float baseMoveSpeed[MAX_MOVE_TYPE]; +TC_GAME_API extern float playerBaseMoveSpeed[MAX_MOVE_TYPE]; -enum WeaponAttackType +enum WeaponAttackType : uint8 { BASE_ATTACK = 0, OFF_ATTACK = 1, @@ -586,7 +610,7 @@ enum DamageEffectType }; // Value masks for UNIT_FIELD_FLAGS -enum UnitFlags +enum UnitFlags : uint32 { UNIT_FLAG_SERVER_CONTROLLED = 0x00000001, // set only when unit movement is controlled by server - by SPLINE/MONSTER_MOVE packets, together with UNIT_FLAG_STUNNED; only set to units controlled by client; client function CGUnit_C::IsClientControlled returns false when set for owner UNIT_FLAG_NON_ATTACKABLE = 0x00000002, // not attackable @@ -826,7 +850,7 @@ struct CleanDamage struct CalcDamageInfo; -class DamageInfo +class TC_GAME_API DamageInfo { private: Unit* const m_attacker; @@ -889,7 +913,7 @@ public: SpellSchoolMask GetSchoolMask() const { return _schoolMask; }; }; -class ProcEventInfo +class TC_GAME_API ProcEventInfo { public: ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, @@ -947,7 +971,7 @@ struct CalcDamageInfo }; // Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode -struct SpellNonMeleeDamage +struct TC_GAME_API SpellNonMeleeDamage { SpellNonMeleeDamage(Unit* _attacker, Unit* _target, uint32 _SpellID, uint32 _schoolMask) : target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask), @@ -1043,7 +1067,7 @@ enum ReactStates REACT_AGGRESSIVE = 2 }; -enum CommandStates +enum CommandStates : uint8 { COMMAND_STAY = 0, COMMAND_FOLLOW = 1, @@ -1108,7 +1132,7 @@ enum ActionBarIndex #define MAX_UNIT_ACTION_BAR_INDEX (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START) -struct CharmInfo +struct TC_GAME_API CharmInfo { public: explicit CharmInfo(Unit* unit); @@ -1210,7 +1234,7 @@ enum PlayerTotemType struct SpellProcEventEntry; // used only privately -class Unit : public WorldObject +class TC_GAME_API Unit : public WorldObject { public: typedef std::set<Unit*> AttackerSet; @@ -1276,7 +1300,7 @@ class Unit : public WorldObject void _removeAttacker(Unit* pAttacker); // must be called only from Unit::AttackStop() Unit* getAttackerForHelper() const; // If someone wants to help, who to give them bool Attack(Unit* victim, bool meleeAttack); - void MustReacquireTarget() { m_shouldReacquireTarget = true; } // flags the Unit for forced target reacquisition in the next ::Attack call + void MustReacquireTarget() { m_shouldReacquireTarget = true; } // flags the Unit for forced (client displayed) target reacquisition in the next ::Attack call void CastStop(uint32 except_spellid = 0); bool AttackStop(); void RemoveAllAttackers(); @@ -1314,11 +1338,11 @@ class Unit : public WorldObject uint8 getLevel() const { return uint8(GetUInt32Value(UNIT_FIELD_LEVEL)); } uint8 getLevelForTarget(WorldObject const* /*target*/) const override { return getLevel(); } void SetLevel(uint8 lvl); - uint8 getRace() const { return GetByteValue(UNIT_FIELD_BYTES_0, 0); } + uint8 getRace() const { return GetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_RACE); } uint32 getRaceMask() const { return 1 << (getRace()-1); } - uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, 1); } + uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS); } uint32 getClassMask() const { return 1 << (getClass()-1); } - uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, 2); } + uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER); } float GetStat(Stats stat) const { return float(GetUInt32Value(UNIT_FIELD_STAT0+stat)); } void SetStat(Stats stat, int32 val) { SetStatInt32Value(UNIT_FIELD_STAT0+stat, val); } @@ -1347,7 +1371,7 @@ class Unit : public WorldObject int32 ModifyHealth(int32 val); int32 GetHealthGain(int32 dVal); - Powers getPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, 3)); } + Powers getPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE)); } void setPowerType(Powers power); uint32 GetPower(Powers power) const { return GetUInt32Value(UNIT_FIELD_POWER1 +power); } uint32 GetMaxPower(Powers power) const { return GetUInt32Value(UNIT_FIELD_MAXPOWER1+power); } @@ -1383,11 +1407,12 @@ class Unit : public WorldObject bool IsContestedGuard() const; bool IsPvP() const { return HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); } bool IsFFAPvP() const { return HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); } - void SetPvP(bool state); + virtual void SetPvP(bool state); + uint32 GetCreatureType() const; uint32 GetCreatureTypeMask() const; - uint8 getStandState() const { return GetByteValue(UNIT_FIELD_BYTES_1, 0); } + uint8 GetStandState() const { return GetByteValue(UNIT_FIELD_BYTES_1, 0); } bool IsSitState() const; bool IsStandState() const; void SetStandState(uint8 state); @@ -1561,7 +1586,7 @@ class Unit : public WorldObject void SendTeleportPacket(Position& pos); virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport = false); // returns true if unit's position really changed - bool UpdatePosition(const Position &pos, bool teleport = false); + virtual bool UpdatePosition(const Position &pos, bool teleport = false); void UpdateOrientation(float orientation); void UpdateHeight(float newZ); @@ -1601,7 +1626,7 @@ class Unit : public WorldObject bool IsAlive() const { return (m_deathState == ALIVE); } bool isDying() const { return (m_deathState == JUST_DIED); } bool isDead() const { return (m_deathState == DEAD || m_deathState == CORPSE); } - bool IsGhouled() const { return HasAura(46619 /*SPELL_DK_RAISE_ALLY*/); } + bool IsGhouled() const; DeathState getDeathState() const { return m_deathState; } virtual void setDeathState(DeathState s); // overwrited in Creature/Player/Pet @@ -1993,10 +2018,11 @@ class Unit : public WorldObject void CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo = NULL); void CalcHealAbsorb(Unit* victim, SpellInfo const* spellInfo, uint32& healAmount, uint32& absorb); - void UpdateSpeed(UnitMoveType mtype, bool forced); + void UpdateSpeed(UnitMoveType mtype); float GetSpeed(UnitMoveType mtype) const; float GetSpeedRate(UnitMoveType mtype) const { return m_speed_rate[mtype]; } - void SetSpeed(UnitMoveType mtype, float rate, bool forced = false); + void SetSpeed(UnitMoveType mtype, float newValue); + void SetSpeedRate(UnitMoveType mtype, float rate); float ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index, float value) const; int32 CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effect_index, int32 const* basePoints = NULL) const; diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h index cd28c4082d4..f8992708a46 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.h +++ b/src/server/game/Entities/Vehicle/Vehicle.h @@ -29,7 +29,7 @@ struct VehicleEntry; class Unit; class VehicleJoinEvent; -class Vehicle : public TransportBase +class TC_GAME_API Vehicle : public TransportBase { protected: friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry); @@ -118,7 +118,7 @@ class Vehicle : public TransportBase PendingJoinEventContainer _pendingJoinEvents; ///< Collection of delayed join events for prospective passengers }; -class VehicleJoinEvent : public BasicEvent +class TC_GAME_API VehicleJoinEvent : public BasicEvent { friend class Vehicle; protected: diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 79584c6261e..bb8e89d4829 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -29,6 +29,12 @@ #include "UnitAI.h" #include "GameObjectAI.h" +GameEventMgr* GameEventMgr::instance() +{ + static GameEventMgr instance; + return &instance; +} + bool GameEventMgr::CheckOneGameEvent(uint16 entry) const { switch (mGameEvent[entry].state) diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index b8d281dfdd7..44ed2fb1332 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -93,18 +93,14 @@ class Player; class Creature; class Quest; -class GameEventMgr +class TC_GAME_API GameEventMgr { private: GameEventMgr(); ~GameEventMgr() { } public: - static GameEventMgr* instance() - { - static GameEventMgr instance; - return &instance; - } + static GameEventMgr* instance(); typedef std::set<uint16> ActiveEvents; typedef std::vector<GameEventData> GameEventDataMap; @@ -186,8 +182,8 @@ class GameEventMgr #define sGameEventMgr GameEventMgr::instance() -bool IsHolidayActive(HolidayIds id); -bool IsEventActive(uint16 event_id); +TC_GAME_API bool IsHolidayActive(HolidayIds id); +TC_GAME_API bool IsEventActive(uint16 event_id); #endif diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index 762c9b9c28e..247c4943113 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -34,6 +34,53 @@ #include <boost/thread/shared_mutex.hpp> #include <boost/thread/locks.hpp> +template<class T> +void HashMapHolder<T>::Insert(T* o) +{ + boost::unique_lock<boost::shared_mutex> lock(*GetLock()); + + GetContainer()[o->GetGUID()] = o; +} + +template<class T> +void HashMapHolder<T>::Remove(T* o) +{ + boost::unique_lock<boost::shared_mutex> lock(*GetLock()); + + GetContainer().erase(o->GetGUID()); +} + +template<class T> +T* HashMapHolder<T>::Find(ObjectGuid guid) +{ + boost::shared_lock<boost::shared_mutex> lock(*GetLock()); + + typename MapType::iterator itr = GetContainer().find(guid); + return (itr != GetContainer().end()) ? itr->second : NULL; +} + +template<class T> +auto HashMapHolder<T>::GetContainer() -> MapType& +{ + static MapType _objectMap; + return _objectMap; +} + +template<class T> +boost::shared_mutex* HashMapHolder<T>::GetLock() +{ + static boost::shared_mutex _lock; + return &_lock; +} + +HashMapHolder<Player>::MapType const& ObjectAccessor::GetPlayers() +{ + return HashMapHolder<Player>::GetContainer(); +} + +template class TC_GAME_API HashMapHolder<Player>; +template class TC_GAME_API HashMapHolder<Transport>; + WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, ObjectGuid const& guid) { switch (guid.GetHigh()) @@ -206,11 +253,6 @@ Player* ObjectAccessor::FindConnectedPlayerByName(std::string const& name) return NULL; } -HashMapHolder<Player>::MapType const& ObjectAccessor::GetPlayers() -{ - return HashMapHolder<Player>::GetContainer(); -} - void ObjectAccessor::SaveAllPlayers() { boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock()); @@ -219,14 +261,3 @@ void ObjectAccessor::SaveAllPlayers() for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) itr->second->SaveToDB(); } - -/// Define the static members of HashMapHolder - -template <class T> typename HashMapHolder<T>::MapType HashMapHolder<T>::_objectMap; -template <class T> boost::shared_mutex HashMapHolder<T>::_lock; - -/// Global definitions for the hashmap storage - -template class HashMapHolder<Player>; - -template class HashMapHolder<Transport>; diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index d8466dbb1bc..be7066c84a9 100644 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -42,76 +42,56 @@ class WorldRunnable; class Transport; template <class T> -class HashMapHolder +class TC_GAME_API HashMapHolder { - public: - static_assert(std::is_same<Player, T>::value - || std::is_same<Transport, T>::value, - "Only Player and Transport can be registered in global HashMapHolder"); + //Non instanceable only static + HashMapHolder() { } - typedef std::unordered_map<ObjectGuid, T*> MapType; +public: + static_assert(std::is_same<Player, T>::value + || std::is_same<Transport, T>::value, + "Only Player and Transport can be registered in global HashMapHolder"); - static void Insert(T* o) - { - boost::unique_lock<boost::shared_mutex> lock(_lock); + typedef std::unordered_map<ObjectGuid, T*> MapType; - _objectMap[o->GetGUID()] = o; - } + static void Insert(T* o); - static void Remove(T* o) - { - boost::unique_lock<boost::shared_mutex> lock(_lock); + static void Remove(T* o); - _objectMap.erase(o->GetGUID()); - } + static T* Find(ObjectGuid guid); - static T* Find(ObjectGuid guid) - { - boost::shared_lock<boost::shared_mutex> lock(_lock); + static MapType& GetContainer(); - typename MapType::iterator itr = _objectMap.find(guid); - return (itr != _objectMap.end()) ? itr->second : NULL; - } - - static MapType& GetContainer() { return _objectMap; } - - static boost::shared_mutex* GetLock() { return &_lock; } - - private: - //Non instanceable only static - HashMapHolder() { } - - static boost::shared_mutex _lock; - static MapType _objectMap; + static boost::shared_mutex* GetLock(); }; namespace ObjectAccessor { // these functions return objects only if in map of specified object - WorldObject* GetWorldObject(WorldObject const&, ObjectGuid const&); - Object* GetObjectByTypeMask(WorldObject const&, ObjectGuid const&, uint32 typemask); - Corpse* GetCorpse(WorldObject const& u, ObjectGuid const& guid); - GameObject* GetGameObject(WorldObject const& u, ObjectGuid const& guid); - Transport* GetTransport(WorldObject const& u, ObjectGuid const& guid); - DynamicObject* GetDynamicObject(WorldObject const& u, ObjectGuid const& guid); - Unit* GetUnit(WorldObject const&, ObjectGuid const& guid); - Creature* GetCreature(WorldObject const& u, ObjectGuid const& guid); - Pet* GetPet(WorldObject const&, ObjectGuid const& guid); - Player* GetPlayer(Map const*, ObjectGuid const& guid); - Player* GetPlayer(WorldObject const&, ObjectGuid const& guid); - Creature* GetCreatureOrPetOrVehicle(WorldObject const&, ObjectGuid const&); + TC_GAME_API WorldObject* GetWorldObject(WorldObject const&, ObjectGuid const&); + TC_GAME_API Object* GetObjectByTypeMask(WorldObject const&, ObjectGuid const&, uint32 typemask); + TC_GAME_API Corpse* GetCorpse(WorldObject const& u, ObjectGuid const& guid); + TC_GAME_API GameObject* GetGameObject(WorldObject const& u, ObjectGuid const& guid); + TC_GAME_API Transport* GetTransport(WorldObject const& u, ObjectGuid const& guid); + TC_GAME_API DynamicObject* GetDynamicObject(WorldObject const& u, ObjectGuid const& guid); + TC_GAME_API Unit* GetUnit(WorldObject const&, ObjectGuid const& guid); + TC_GAME_API Creature* GetCreature(WorldObject const& u, ObjectGuid const& guid); + TC_GAME_API Pet* GetPet(WorldObject const&, ObjectGuid const& guid); + TC_GAME_API Player* GetPlayer(Map const*, ObjectGuid const& guid); + TC_GAME_API Player* GetPlayer(WorldObject const&, ObjectGuid const& guid); + TC_GAME_API Creature* GetCreatureOrPetOrVehicle(WorldObject const&, ObjectGuid const&); // these functions return objects if found in whole world // ACCESS LIKE THAT IS NOT THREAD SAFE - Player* FindPlayer(ObjectGuid const&); - Player* FindPlayerByName(std::string const& name); + TC_GAME_API Player* FindPlayer(ObjectGuid const&); + TC_GAME_API Player* FindPlayerByName(std::string const& name); // this returns Player even if he is not in world, for example teleporting - Player* FindConnectedPlayer(ObjectGuid const&); - Player* FindConnectedPlayerByName(std::string const& name); + TC_GAME_API Player* FindConnectedPlayer(ObjectGuid const&); + TC_GAME_API Player* FindConnectedPlayerByName(std::string const& name); // when using this, you must use the hashmapholder's lock - HashMapHolder<Player>::MapType const& GetPlayers(); + TC_GAME_API HashMapHolder<Player>::MapType const& GetPlayers(); template<class T> void AddObject(T* object) @@ -125,7 +105,8 @@ namespace ObjectAccessor HashMapHolder<T>::Remove(object); } - void SaveAllPlayers(); + TC_GAME_API void SaveAllPlayers(); }; #endif + diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index f45634e9684..3efeb1ca273 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -235,6 +235,12 @@ ObjectMgr::ObjectMgr(): } } +ObjectMgr* ObjectMgr::instance() +{ + static ObjectMgr instance; + return &instance; +} + ObjectMgr::~ObjectMgr() { for (QuestMap::iterator i = _questTemplates.begin(); i != _questTemplates.end(); ++i) @@ -4709,7 +4715,7 @@ void ObjectMgr::LoadScripts(ScriptsType type) if (tableName.empty()) return; - if (sScriptMgr->IsScriptScheduled()) // function cannot be called when scripts are in use. + if (sMapMgr->IsScriptScheduled()) // function cannot be called when scripts are in use. return; TC_LOG_INFO("server.loading", "Loading %s...", tableName.c_str()); @@ -5156,7 +5162,7 @@ void ObjectMgr::LoadSpellScriptNames() while (spellInfo) { - _spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, GetScriptId(scriptName))); + _spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, std::make_pair(GetScriptId(scriptName), true))); spellInfo = spellInfo->GetNextRankSpell(); } } @@ -5165,7 +5171,7 @@ void ObjectMgr::LoadSpellScriptNames() if (spellInfo->IsRanked()) TC_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) is ranked spell. Perhaps not all ranks are assigned to this script.", scriptName.c_str(), spellId); - _spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, GetScriptId(scriptName))); + _spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, std::make_pair(GetScriptId(scriptName), true))); } ++count; @@ -5187,45 +5193,59 @@ void ObjectMgr::ValidateSpellScripts() uint32 count = 0; - for (SpellScriptsContainer::iterator itr = _spellScriptsStore.begin(); itr != _spellScriptsStore.end();) + for (auto spell : _spellScriptsStore) { - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(itr->first); - std::vector<std::pair<SpellScriptLoader *, SpellScriptsContainer::iterator> > SpellScriptLoaders; - sScriptMgr->CreateSpellScriptLoaders(itr->first, SpellScriptLoaders); - itr = _spellScriptsStore.upper_bound(itr->first); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spell.first); - for (std::vector<std::pair<SpellScriptLoader *, SpellScriptsContainer::iterator> >::iterator sitr = SpellScriptLoaders.begin(); sitr != SpellScriptLoaders.end(); ++sitr) + auto const bounds = sObjectMgr->GetSpellScriptsBounds(spell.first); + + for (auto itr = bounds.first; itr != bounds.second; ++itr) { - SpellScript* spellScript = sitr->first->GetSpellScript(); - AuraScript* auraScript = sitr->first->GetAuraScript(); - bool valid = true; - if (!spellScript && !auraScript) - { - TC_LOG_ERROR("scripts", "Functions GetSpellScript() and GetAuraScript() of script `%s` do not return objects - script skipped", GetScriptName(sitr->second->second).c_str()); - valid = false; - } - if (spellScript) - { - spellScript->_Init(&sitr->first->GetName(), spellEntry->Id); - spellScript->_Register(); - if (!spellScript->_Validate(spellEntry)) - valid = false; - delete spellScript; - } - if (auraScript) - { - auraScript->_Init(&sitr->first->GetName(), spellEntry->Id); - auraScript->_Register(); - if (!auraScript->_Validate(spellEntry)) - valid = false; - delete auraScript; - } - if (!valid) + if (SpellScriptLoader* spellScriptLoader = sScriptMgr->GetSpellScriptLoader(itr->second.first)) { - _spellScriptsStore.erase(sitr->second); + ++count; + + std::unique_ptr<SpellScript> spellScript(spellScriptLoader->GetSpellScript()); + std::unique_ptr<AuraScript> auraScript(spellScriptLoader->GetAuraScript()); + + if (!spellScript && !auraScript) + { + TC_LOG_ERROR("scripts", "Functions GetSpellScript() and GetAuraScript() of script `%s` do not return objects - script skipped", GetScriptName(itr->second.first).c_str()); + + itr->second.second = false; + continue; + } + + if (spellScript) + { + spellScript->_Init(&spellScriptLoader->GetName(), spellEntry->Id); + spellScript->_Register(); + + if (!spellScript->_Validate(spellEntry)) + { + itr->second.second = false; + continue; + } + } + + if (auraScript) + { + auraScript->_Init(&spellScriptLoader->GetName(), spellEntry->Id); + auraScript->_Register(); + + if (!auraScript->_Validate(spellEntry)) + { + itr->second.second = false; + continue; + } + } + + // Enable the script when all checks passed + itr->second.second = true; } + else + itr->second.second = false; } - ++count; } TC_LOG_INFO("server.loading", ">> Validated %u scripts in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); @@ -6502,7 +6522,12 @@ uint32 ObjectMgr::GenerateMailID() uint32 ObjectMgr::GeneratePetNumber() { - return ++_hiPetNumber; + if (_hiPetNumber >= 0xFFFFFFFE) + { + TC_LOG_ERROR("misc", "_hiPetNumber Id overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return _hiPetNumber++; } uint32 ObjectMgr::GenerateCreatureSpawnId() @@ -8560,6 +8585,8 @@ void ObjectMgr::LoadScriptNames() { uint32 oldMSTime = getMSTime(); + // We insert an empty placeholder here so we can use the + // script id 0 as dummy for "no script found". _scriptNamesStore.emplace_back(""); QueryResult result = WorldDatabase.Query( @@ -8601,18 +8628,18 @@ void ObjectMgr::LoadScriptNames() std::sort(_scriptNamesStore.begin(), _scriptNamesStore.end()); -#ifdef SCRIPTS - for (size_t i = 1; i < _scriptNamesStore.size(); ++i) - UnusedScriptNames.push_back(_scriptNamesStore[i]); -#endif - TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " ScriptNames in %u ms", _scriptNamesStore.size(), GetMSTimeDiffToNow(oldMSTime)); } +ObjectMgr::ScriptNameContainer const& ObjectMgr::GetAllScriptNames() const +{ + return _scriptNamesStore; +} + std::string const& ObjectMgr::GetScriptName(uint32 id) const { static std::string const empty = ""; - return id < _scriptNamesStore.size() ? _scriptNamesStore[id] : empty; + return (id < _scriptNamesStore.size()) ? _scriptNamesStore[id] : empty; } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index ae1258713f5..576a8d2ccac 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -370,17 +370,17 @@ struct ScriptInfo typedef std::multimap<uint32, ScriptInfo> ScriptMap; typedef std::map<uint32, ScriptMap > ScriptMapMap; -typedef std::multimap<uint32, uint32> SpellScriptsContainer; +typedef std::multimap<uint32 /*spell id*/, std::pair<uint32 /*script id*/, bool /*enabled*/>> SpellScriptsContainer; typedef std::pair<SpellScriptsContainer::iterator, SpellScriptsContainer::iterator> SpellScriptsBounds; -extern ScriptMapMap sSpellScripts; -extern ScriptMapMap sEventScripts; -extern ScriptMapMap sWaypointScripts; +TC_GAME_API extern ScriptMapMap sSpellScripts; +TC_GAME_API extern ScriptMapMap sEventScripts; +TC_GAME_API extern ScriptMapMap sWaypointScripts; std::string GetScriptsTableNameByType(ScriptsType type); ScriptMapMap* GetScriptsMapByType(ScriptsType type); std::string GetScriptCommandName(ScriptCommands command); -struct SpellClickInfo +struct TC_GAME_API SpellClickInfo { uint32 spellId; uint8 castFlags; @@ -637,7 +637,7 @@ SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry); #define MAX_PET_NAME 12 // max allowed by client name length #define MAX_CHARTER_NAME 24 // max allowed by client name length -bool normalizePlayerName(std::string& name); +TC_GAME_API bool normalizePlayerName(std::string& name); struct LanguageDesc { @@ -646,7 +646,7 @@ struct LanguageDesc uint32 skill_id; }; -extern LanguageDesc lang_description[LANGUAGES_COUNT]; +TC_GAME_API extern LanguageDesc lang_description[LANGUAGES_COUNT]; LanguageDesc const* GetLanguageDescByID(uint32 lang); enum EncounterCreditType @@ -671,7 +671,7 @@ typedef std::unordered_map<uint32, DungeonEncounterList> DungeonEncounterContain class PlayerDumpReader; -class ObjectMgr +class TC_GAME_API ObjectMgr { friend class PlayerDumpReader; @@ -680,11 +680,13 @@ class ObjectMgr ~ObjectMgr(); public: - static ObjectMgr* instance() - { - static ObjectMgr instance; - return &instance; - } + ObjectMgr(ObjectMgr const&) = delete; + ObjectMgr(ObjectMgr&&) = delete; + + ObjectMgr& operator= (ObjectMgr const&) = delete; + ObjectMgr& operator= (ObjectMgr&&) = delete; + + static ObjectMgr* instance(); typedef std::unordered_map<uint32, Item*> ItemMap; @@ -1270,6 +1272,7 @@ class ObjectMgr bool IsVendorItemValid(uint32 vendor_entry, uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* player = NULL, std::set<uint32>* skip_vendors = NULL, uint32 ORnpcflag = 0) const; void LoadScriptNames(); + ScriptNameContainer const& GetAllScriptNames() const; std::string const& GetScriptName(uint32 id) const; uint32 GetScriptId(std::string const& name); diff --git a/src/server/game/Grids/GridReference.h b/src/server/game/Grids/GridReference.h index b1f2e92a840..f5766382822 100644 --- a/src/server/game/Grids/GridReference.h +++ b/src/server/game/Grids/GridReference.h @@ -28,18 +28,18 @@ template<class OBJECT> class GridReference : public Reference<GridRefManager<OBJECT>, OBJECT> { protected: - void targetObjectBuildLink() + void targetObjectBuildLink() override { // called from link() this->getTarget()->insertFirst(this); this->getTarget()->incSize(); } - void targetObjectDestroyLink() + void targetObjectDestroyLink() override { // called from unlink() if (this->isValid()) this->getTarget()->decSize(); } - void sourceObjectDestroyLink() + void sourceObjectDestroyLink() override { // called from invalidate() this->getTarget()->decSize(); diff --git a/src/server/game/Grids/GridStates.h b/src/server/game/Grids/GridStates.h index 9420bef4b9d..b567da43b69 100644 --- a/src/server/game/Grids/GridStates.h +++ b/src/server/game/Grids/GridStates.h @@ -24,32 +24,32 @@ class Map; -class GridState +class TC_GAME_API GridState { public: virtual ~GridState() { }; virtual void Update(Map &, NGridType&, GridInfo &, uint32 t_diff) const = 0; }; -class InvalidState : public GridState +class TC_GAME_API InvalidState : public GridState { public: void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override; }; -class ActiveState : public GridState +class TC_GAME_API ActiveState : public GridState { public: void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override; }; -class IdleState : public GridState +class TC_GAME_API IdleState : public GridState { public: void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override; }; -class RemovalState : public GridState +class TC_GAME_API RemovalState : public GridState { public: void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 6edeadf6b94..84aa29f96b7 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -38,7 +38,7 @@ class Player; namespace Trinity { - struct VisibleNotifier + struct TC_GAME_API VisibleNotifier { Player &i_player; UpdateData i_data; @@ -61,7 +61,7 @@ namespace Trinity void Visit(DynamicObjectMapType &); }; - struct PlayerRelocationNotifier : public VisibleNotifier + struct TC_GAME_API PlayerRelocationNotifier : public VisibleNotifier { PlayerRelocationNotifier(Player &player) : VisibleNotifier(player) { } @@ -70,7 +70,7 @@ namespace Trinity void Visit(PlayerMapType &); }; - struct CreatureRelocationNotifier + struct TC_GAME_API CreatureRelocationNotifier { Creature &i_creature; CreatureRelocationNotifier(Creature &c) : i_creature(c) { } @@ -79,7 +79,7 @@ namespace Trinity void Visit(PlayerMapType &); }; - struct DelayedUnitRelocation + struct TC_GAME_API DelayedUnitRelocation { Map &i_map; Cell &cell; @@ -92,7 +92,7 @@ namespace Trinity void Visit(PlayerMapType &); }; - struct AIRelocationNotifier + struct TC_GAME_API AIRelocationNotifier { Unit &i_unit; bool isCreature; @@ -120,7 +120,7 @@ namespace Trinity void Visit(CorpseMapType &m) { updateObjects<Corpse>(m); } }; - struct MessageDistDeliverer + struct TC_GAME_API MessageDistDeliverer { WorldObject* i_source; WorldPacket* i_message; @@ -566,7 +566,7 @@ namespace Trinity // WorldObject check classes - class AnyDeadUnitObjectInRangeCheck + class TC_GAME_API AnyDeadUnitObjectInRangeCheck { public: AnyDeadUnitObjectInRangeCheck(Unit* searchObj, float range) : i_searchObj(searchObj), i_range(range) { } @@ -579,7 +579,7 @@ namespace Trinity float i_range; }; - class AnyDeadUnitSpellTargetInRangeCheck : public AnyDeadUnitObjectInRangeCheck + class TC_GAME_API AnyDeadUnitSpellTargetInRangeCheck : public AnyDeadUnitObjectInRangeCheck { public: AnyDeadUnitSpellTargetInRangeCheck(Unit* searchObj, float range, SpellInfo const* spellInfo, SpellTargetCheckTypes check) diff --git a/src/server/game/Grids/ObjectGridLoader.h b/src/server/game/Grids/ObjectGridLoader.h index 9dc4c7e048b..f2893da609e 100644 --- a/src/server/game/Grids/ObjectGridLoader.h +++ b/src/server/game/Grids/ObjectGridLoader.h @@ -27,7 +27,7 @@ class ObjectWorldLoader; -class ObjectGridLoader +class TC_GAME_API ObjectGridLoader { friend class ObjectWorldLoader; @@ -55,7 +55,7 @@ class ObjectGridLoader }; //Stop the creatures before unloading the NGrid -class ObjectGridStoper +class TC_GAME_API ObjectGridStoper { public: void Visit(CreatureMapType &m); @@ -63,7 +63,7 @@ class ObjectGridStoper }; //Move the foreign creatures back to respawn positions before unloading the NGrid -class ObjectGridEvacuator +class TC_GAME_API ObjectGridEvacuator { public: void Visit(CreatureMapType &m); diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 42fd9b582e8..18b8119246f 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -158,7 +158,7 @@ struct InstanceGroupBind /** request member stats checken **/ /// @todo uninvite people that not accepted invite -class Group +class TC_GAME_API Group { public: struct MemberSlot diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp index 0fd2e7c7095..a5aa432aadc 100644 --- a/src/server/game/Groups/GroupMgr.cpp +++ b/src/server/game/Groups/GroupMgr.cpp @@ -92,6 +92,12 @@ ObjectGuid::LowType GroupMgr::GenerateGroupId() return NextGroupId++; } +GroupMgr* GroupMgr::instance() +{ + static GroupMgr instance; + return &instance; +} + Group* GroupMgr::GetGroupByGUID(ObjectGuid::LowType groupId) const { GroupContainer::const_iterator itr = GroupStore.find(groupId); diff --git a/src/server/game/Groups/GroupMgr.h b/src/server/game/Groups/GroupMgr.h index 9afdddd0f18..14ff3519aa6 100644 --- a/src/server/game/Groups/GroupMgr.h +++ b/src/server/game/Groups/GroupMgr.h @@ -20,18 +20,14 @@ #include "Group.h" -class GroupMgr +class TC_GAME_API GroupMgr { private: GroupMgr(); ~GroupMgr(); public: - static GroupMgr* instance() - { - static GroupMgr instance; - return &instance; - } + static GroupMgr* instance(); typedef std::map<ObjectGuid::LowType, Group*> GroupContainer; typedef std::vector<Group*> GroupDbContainer; diff --git a/src/server/game/Groups/GroupReference.h b/src/server/game/Groups/GroupReference.h index 4718dda1832..6e7373de7d7 100644 --- a/src/server/game/Groups/GroupReference.h +++ b/src/server/game/Groups/GroupReference.h @@ -24,7 +24,7 @@ class Group; class Player; -class GroupReference : public Reference<Group, Player> +class TC_GAME_API GroupReference : public Reference<Group, Player> { protected: uint8 iSubGroup; diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 2bc57a70671..e25a3201957 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -223,7 +223,7 @@ enum GuildMemberFlags }; // Emblem info -class EmblemInfo +class TC_GAME_API EmblemInfo { public: EmblemInfo() : m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { } @@ -279,7 +279,7 @@ typedef std::vector <GuildBankRightsAndSlots> GuildBankRightsAndSlotsVec; typedef std::set <uint8> SlotIds; -class Guild +class TC_GAME_API Guild { private: // Class representing guild member diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 2d4fb849fb5..a4d245cbc9b 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -79,6 +79,12 @@ std::string GuildMgr::GetGuildNameById(ObjectGuid::LowType guildId) const return ""; } +GuildMgr* GuildMgr::instance() +{ + static GuildMgr instance; + return &instance; +} + Guild* GuildMgr::GetGuildByLeader(ObjectGuid guid) const { for (GuildContainer::const_iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) diff --git a/src/server/game/Guilds/GuildMgr.h b/src/server/game/Guilds/GuildMgr.h index a97a59cafe0..ad2555c2e71 100644 --- a/src/server/game/Guilds/GuildMgr.h +++ b/src/server/game/Guilds/GuildMgr.h @@ -20,18 +20,14 @@ #include "Guild.h" -class GuildMgr +class TC_GAME_API GuildMgr { private: GuildMgr(); ~GuildMgr(); public: - static GuildMgr* instance() - { - static GuildMgr instance; - return &instance; - } + static GuildMgr* instance(); Guild* GetGuildByLeader(ObjectGuid guid) const; Guild* GetGuildById(ObjectGuid::LowType guildId) const; diff --git a/src/server/game/Handlers/AddonHandler.cpp b/src/server/game/Handlers/AddonHandler.cpp index ad44e0993e4..c72fc08982c 100644 --- a/src/server/game/Handlers/AddonHandler.cpp +++ b/src/server/game/Handlers/AddonHandler.cpp @@ -21,6 +21,12 @@ #include "Opcodes.h" #include "Log.h" +AddonHandler* AddonHandler::instance() +{ + static AddonHandler instance; + return &instance; +} + bool AddonHandler::BuildAddonPacket(WorldPacket* source, WorldPacket* target) { ByteBuffer AddOnPacked; diff --git a/src/server/game/Handlers/AddonHandler.h b/src/server/game/Handlers/AddonHandler.h index 1e8081e0913..0113695895a 100644 --- a/src/server/game/Handlers/AddonHandler.h +++ b/src/server/game/Handlers/AddonHandler.h @@ -26,11 +26,7 @@ class AddonHandler { public: - static AddonHandler* instance() - { - static AddonHandler instance; - return &instance; - } + static AddonHandler* instance(); bool BuildAddonPacket(WorldPacket* Source, WorldPacket* Target); diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 540eeba0752..1a654335714 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -700,7 +700,7 @@ void WorldSession::HandleSetSavedInstanceExtend(WorldPacket& recvData) InstancePlayerBind* instanceBind = player->GetBoundInstance(mapId, Difficulty(difficulty), toggleExtend == 1); // include expired instances if we are toggling extend on if (!instanceBind || !instanceBind->save || !instanceBind->perm) return; - + BindExtensionState newState; if (!toggleExtend || instanceBind->extendState == EXTEND_STATE_EXPIRED) newState = EXTEND_STATE_NORMAL; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index e0d790312d2..19638ec1bf8 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -228,11 +228,11 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result) if (Player::BuildEnumData(result, &data)) { // Do not allow banned characters to log in - if (!(*result)[20].GetUInt32()) + if (!(*result)[23].GetUInt32()) _legitCharacters.insert(guid); if (!sWorld->HasCharacterInfo(guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet. - sWorld->AddCharacterInfo(guid, GetAccountId(), (*result)[1].GetString(), (*result)[4].GetUInt8(), (*result)[2].GetUInt8(), (*result)[3].GetUInt8(), (*result)[7].GetUInt8()); + sWorld->AddCharacterInfo(guid, GetAccountId(), (*result)[1].GetString(), (*result)[4].GetUInt8(), (*result)[2].GetUInt8(), (*result)[3].GetUInt8(), (*result)[10].GetUInt8()); ++num; } } @@ -627,13 +627,13 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); stmt->setUInt32(0, GetAccountId()); - stmt->setUInt32(1, realmID); + stmt->setUInt32(1, realm.Id.Realm); trans->Append(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS); stmt->setUInt32(0, createInfo->CharCount); stmt->setUInt32(1, GetAccountId()); - stmt->setUInt32(2, realmID); + stmt->setUInt32(2, realm.Id.Realm); trans->Append(stmt); LoginDatabase.CommitTransaction(trans); @@ -642,7 +642,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte TC_LOG_INFO("entities.player.character", "Account: %d (IP: %s) Create Character:[%s] (GUID: %u)", GetAccountId(), GetRemoteAddress().c_str(), createInfo->Name.c_str(), newChar.GetGUID().GetCounter()); sScriptMgr->OnPlayerCreate(&newChar); - sWorld->AddCharacterInfo(newChar.GetGUID(), GetAccountId(), newChar.GetName(), newChar.GetByteValue(PLAYER_BYTES_3, 0), newChar.getRace(), newChar.getClass(), newChar.getLevel()); + sWorld->AddCharacterInfo(newChar.GetGUID(), GetAccountId(), newChar.GetName(), newChar.GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER), newChar.getRace(), newChar.getClass(), newChar.getLevel()); newChar.CleanupsBeforeDelete(); delete createInfo; @@ -1242,20 +1242,25 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData) BarberShopStyleEntry const* bs_hair = sBarberShopStyleStore.LookupEntry(Hair); - if (!bs_hair || bs_hair->type != 0 || bs_hair->race != _player->getRace() || bs_hair->gender != _player->GetByteValue(PLAYER_BYTES_3, 0)) + if (!bs_hair || bs_hair->type != 0 || bs_hair->race != _player->getRace() || bs_hair->gender != _player->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER)) return; BarberShopStyleEntry const* bs_facialHair = sBarberShopStyleStore.LookupEntry(FacialHair); - if (!bs_facialHair || bs_facialHair->type != 2 || bs_facialHair->race != _player->getRace() || bs_facialHair->gender != _player->GetByteValue(PLAYER_BYTES_3, 0)) + if (!bs_facialHair || bs_facialHair->type != 2 || bs_facialHair->race != _player->getRace() || bs_facialHair->gender != _player->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER)) return; BarberShopStyleEntry const* bs_skinColor = sBarberShopStyleStore.LookupEntry(SkinColor); - if (bs_skinColor && (bs_skinColor->type != 3 || bs_skinColor->race != _player->getRace() || bs_skinColor->gender != _player->GetByteValue(PLAYER_BYTES_3, 0))) + if (bs_skinColor && (bs_skinColor->type != 3 || bs_skinColor->race != _player->getRace() || bs_skinColor->gender != _player->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER))) return; - if (!Player::ValidateAppearance(_player->getRace(), _player->getClass(), _player->GetByteValue(PLAYER_BYTES_3, 0), bs_hair->hair_id, Color, _player->GetByteValue(PLAYER_BYTES, 1), bs_facialHair->hair_id, bs_skinColor ? bs_skinColor->hair_id : _player->GetByteValue(PLAYER_BYTES, 0))) + if (!Player::ValidateAppearance(_player->getRace(), _player->getClass(), _player->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER), + bs_hair->hair_id, + Color, + _player->GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID), + bs_facialHair->hair_id, + bs_skinColor ? bs_skinColor->hair_id : _player->GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID))) return; GameObject* go = _player->FindNearestGameObjectOfType(GAMEOBJECT_TYPE_BARBER_CHAIR, 5.0f); @@ -1265,7 +1270,7 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData) return; } - if (_player->getStandState() != UNIT_STAND_STATE_SIT_LOW_CHAIR + go->GetGOInfo()->barberChair.chairheight) + if (_player->GetStandState() != UNIT_STAND_STATE_SIT_LOW_CHAIR + go->GetGOInfo()->barberChair.chairheight) { SendBarberShopResult(BARBER_SHOP_RESULT_NOT_ON_CHAIR); return; @@ -1287,11 +1292,11 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData) _player->ModifyMoney(-int32(cost)); // it isn't free _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, cost); - _player->SetByteValue(PLAYER_BYTES, 2, uint8(bs_hair->hair_id)); - _player->SetByteValue(PLAYER_BYTES, 3, uint8(Color)); - _player->SetByteValue(PLAYER_BYTES_2, 0, uint8(bs_facialHair->hair_id)); + _player->SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID, uint8(bs_hair->hair_id)); + _player->SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID, uint8(Color)); + _player->SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE, uint8(bs_facialHair->hair_id)); if (bs_skinColor) - _player->SetByteValue(PLAYER_BYTES, 0, uint8(bs_skinColor->hair_id)); + _player->SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID, uint8(bs_skinColor->hair_id)); _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 45cee59aec9..467d3730ab2 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -284,7 +284,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) continue; uint32 pzoneid = target->GetZoneId(); - uint8 gender = target->GetByteValue(PLAYER_BYTES_3, 0); + uint8 gender = target->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER); bool z_show = true; for (uint32 i = 0; i < zones_count; ++i) @@ -405,7 +405,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recvData*/) // not set flags if player can't free move to prevent lost state at logout cancel if (GetPlayer()->CanFreeMove()) { - if (GetPlayer()->getStandState() == UNIT_STAND_STATE_STAND) + if (GetPlayer()->GetStandState() == UNIT_STAND_STATE_STAND) GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT); WorldPacket data(SMSG_FORCE_MOVE_ROOT, (8+4)); // guess size @@ -569,7 +569,7 @@ void WorldSession::HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std team = Player::TeamForRace(fields[1].GetUInt8()); friendAccountId = fields[2].GetUInt32(); - if (HasPermission(rbac::RBAC_PERM_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realmID))) + if (HasPermission(rbac::RBAC_PERM_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realm.Id.Realm))) { if (friendGuid) { @@ -773,17 +773,11 @@ void WorldSession::HandleResurrectResponseOpcode(WorldPacket& recvData) if (status == 0) { - GetPlayer()->clearResurrectRequestData(); // reject + GetPlayer()->ClearResurrectRequestData(); // reject return; } - if (GetPlayer()->IsValidGhoulResurrectRequest(guid)) - { - GetPlayer()->GhoulResurrect(); - return; - } - - if (!GetPlayer()->isResurrectRequestedBy(guid)) + if (!GetPlayer()->IsResurrectRequestedBy(guid)) return; GetPlayer()->ResurrectUsingRequestData(); @@ -933,7 +927,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recvData) default: break; } - + if (reviveAtTrigger) // check if the player is touching the areatrigger leading to the map his corpse is on if (!player->IsAlive() && player->HasCorpse()) if (player->GetCorpseLocation().GetMapId() == at->target_mapId) @@ -1062,12 +1056,14 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recvData) void WorldSession::HandleCompleteCinematic(WorldPacket& /*recvData*/) { - TC_LOG_DEBUG("network", "WORLD: Received CMSG_COMPLETE_CINEMATIC"); + // If player has sight bound to visual waypoint NPC we should remove it + GetPlayer()->EndCinematic(); } void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recvData*/) { - TC_LOG_DEBUG("network", "WORLD: Received CMSG_NEXT_CINEMATIC_CAMERA"); + // Sent by client when cinematic actually begun. So we begin the server side process + GetPlayer()->BeginCinematic(); } void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recvData) @@ -1163,7 +1159,7 @@ void WorldSession::HandleSetActionBarToggles(WorldPacket& recvData) return; } - GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, actionBar); + GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES, actionBar); } void WorldSession::HandlePlayedTime(WorldPacket& recvData) diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 02702fc5622..64f927a987f 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -473,7 +473,7 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recvData) { TC_LOG_ERROR("network", "%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value", move_type_name[move_type], _player->GetName().c_str(), _player->GetSpeed(move_type), newspeed); - _player->SetSpeed(move_type, _player->GetSpeedRate(move_type), true); + _player->SetSpeedRate(move_type, _player->GetSpeedRate(move_type)); } else // must be lesser - cheating { diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 6be1fd30ae3..e07e10ab00c 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -594,11 +594,11 @@ void WorldSession::HandleMirrorImageDataRequest(WorldPacket& recvData) if (creator->GetTypeId() == TYPEID_PLAYER) { Player* player = creator->ToPlayer(); - data << uint8(player->GetByteValue(PLAYER_BYTES, 0)); // skin - data << uint8(player->GetByteValue(PLAYER_BYTES, 1)); // face - data << uint8(player->GetByteValue(PLAYER_BYTES, 2)); // hair - data << uint8(player->GetByteValue(PLAYER_BYTES, 3)); // haircolor - data << uint8(player->GetByteValue(PLAYER_BYTES_2, 0)); // facialhair + data << uint8(player->GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID)); + data << uint8(player->GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID)); + data << uint8(player->GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID)); + data << uint8(player->GetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID)); + data << uint8(player->GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE)); data << uint32(player->GetGuildId()); // unk static EquipmentSlots const itemSlots[] = diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index 3538262ed35..2fbf50cb020 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -38,6 +38,12 @@ InstanceSaveManager::~InstanceSaveManager() { } +InstanceSaveManager* InstanceSaveManager::instance() +{ + static InstanceSaveManager instance; + return &instance; +} + void InstanceSaveManager::Unload() { lock_instLists = true; @@ -447,7 +453,7 @@ time_t InstanceSaveManager::GetSubsequentResetTime(uint32 mapid, Difficulty diff TC_LOG_ERROR("misc", "InstanceSaveManager::GetSubsequentResetTime: not valid difficulty or no reset delay for map %u", mapid); return 0; } - + time_t diff = sWorld->getIntConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR; time_t period = uint32(((mapDiff->resetTime * sWorld->getRate(RATE_INSTANCE_RESET_TIME)) / DAY) * DAY); if (period < DAY) diff --git a/src/server/game/Instances/InstanceSaveMgr.h b/src/server/game/Instances/InstanceSaveMgr.h index d2b3237b3cf..18e22602e07 100644 --- a/src/server/game/Instances/InstanceSaveMgr.h +++ b/src/server/game/Instances/InstanceSaveMgr.h @@ -41,7 +41,7 @@ class Group; - player-instance binds for permanent heroic/raid saves - group-instance binds (both solo and permanent) cache the player binds for the group leader */ -class InstanceSave +class TC_GAME_API InstanceSave { friend class InstanceSaveManager; public: @@ -147,7 +147,7 @@ class InstanceSave typedef std::unordered_map<uint32 /*PAIR32(map, difficulty)*/, time_t /*resetTime*/> ResetTimeByMapDifficultyMap; -class InstanceSaveManager +class TC_GAME_API InstanceSaveManager { friend class InstanceSave; @@ -158,11 +158,7 @@ class InstanceSaveManager public: typedef std::unordered_map<uint32 /*InstanceId*/, InstanceSave*> InstanceSaveHashMap; - static InstanceSaveManager* instance() - { - static InstanceSaveManager instance; - return &instance; - } + static InstanceSaveManager* instance(); void Unload(); diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 1575b50098f..0887d183a8b 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -29,6 +29,8 @@ #include "Pet.h" #include "WorldSession.h" #include "Opcodes.h" +#include "ScriptReloadMgr.h" +#include "ScriptMgr.h" BossBoundaryData::~BossBoundaryData() { @@ -36,6 +38,18 @@ BossBoundaryData::~BossBoundaryData() delete it->Boundary; } +InstanceScript::InstanceScript(Map* map) : instance(map), completedEncounters(0) +{ +#ifdef TRINITY_API_USE_DYNAMIC_LINKING + uint32 scriptId = sObjectMgr->GetInstanceTemplate(map->GetId())->ScriptId; + auto const scriptname = sObjectMgr->GetScriptName(scriptId); + ASSERT(!scriptname.empty()); + // Acquire a strong reference from the script module + // to keep it loaded until this object is destroyed. + module_reference = sScriptMgr->AcquireModuleReferenceOfScriptName(scriptname); +#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING +} + void InstanceScript::SaveToDB() { std::string data = GetSaveData(); diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index ce83061e162..3814afe2f4b 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -36,6 +36,7 @@ class Unit; class Player; class GameObject; class Creature; +class ModuleReference; enum EncounterFrameType { @@ -79,7 +80,7 @@ struct BossBoundaryEntry AreaBoundary const* Boundary; }; -struct BossBoundaryData +struct TC_GAME_API BossBoundaryData { typedef std::vector<BossBoundaryEntry> StorageType; typedef StorageType::const_iterator const_iterator; @@ -134,10 +135,10 @@ typedef std::map<uint32 /*entry*/, MinionInfo> MinionInfoMap; typedef std::map<uint32 /*type*/, ObjectGuid /*guid*/> ObjectGuidMap; typedef std::map<uint32 /*entry*/, uint32 /*type*/> ObjectInfoMap; -class InstanceScript : public ZoneScript +class TC_GAME_API InstanceScript : public ZoneScript { public: - explicit InstanceScript(Map* map) : instance(map), completedEncounters(0) { } + explicit InstanceScript(Map* map); virtual ~InstanceScript() { } @@ -289,6 +290,11 @@ class InstanceScript : public ZoneScript ObjectInfoMap _gameObjectInfo; ObjectGuidMap _objectGuids; uint32 completedEncounters; // completed encounter mask, bit indexes are DungeonEncounter.dbc boss numbers, used for packets + + #ifdef TRINITY_API_USE_DYNAMIC_LINKING + // Strong reference to the associated script module + std::shared_ptr<ModuleReference> module_reference; + #endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING }; template<class AI, class T> diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 19dc210ea5b..5cede9a32d5 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -1871,3 +1871,20 @@ void LoadLootTemplates_Reference() TC_LOG_INFO("server.loading", ">> Loaded refence loot templates in %u ms", GetMSTimeDiffToNow(oldMSTime)); } + +void LoadLootTables() +{ + LoadLootTemplates_Creature(); + LoadLootTemplates_Fishing(); + LoadLootTemplates_Gameobject(); + LoadLootTemplates_Item(); + LoadLootTemplates_Mail(); + LoadLootTemplates_Milling(); + LoadLootTemplates_Pickpocketing(); + LoadLootTemplates_Skinning(); + LoadLootTemplates_Disenchant(); + LoadLootTemplates_Prospecting(); + LoadLootTemplates_Spell(); + + LoadLootTemplates_Reference(); +} diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index af6f3e56707..0afb327d7f0 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -54,7 +54,7 @@ enum RollMask #define MAX_NR_QUEST_ITEMS 32 // unrelated to the number of quest items shown, just for reserve -enum LootMethod +enum LootMethod : uint8 { FREE_FOR_ALL = 0, ROUND_ROBIN = 1, @@ -74,7 +74,7 @@ enum PermissionTypes NONE_PERMISSION = 6 }; -enum LootType +enum LootType : uint8 { LOOT_NONE = 0, @@ -122,7 +122,7 @@ enum LootSlotType class Player; class LootStore; -struct LootStoreItem +struct TC_GAME_API LootStoreItem { uint32 itemid; // id of the item uint32 reference; // referenced TemplateleId @@ -148,7 +148,7 @@ struct LootStoreItem typedef std::set<ObjectGuid::LowType> AllowedLooterSet; -struct LootItem +struct TC_GAME_API LootItem { uint32 itemid; uint32 randomSuffix; @@ -203,7 +203,7 @@ typedef std::unordered_map<uint32, LootTemplate*> LootTemplateMap; typedef std::set<uint32> LootIdSet; -class LootStore +class TC_GAME_API LootStore { public: explicit LootStore(char const* name, char const* entryName, bool ratesAllowed) @@ -239,7 +239,7 @@ class LootStore bool m_ratesAllowed; }; -class LootTemplate +class TC_GAME_API LootTemplate { class LootGroup; // A set of loot definitions for items (refs are not allowed inside) typedef std::vector<LootGroup*> LootGroups; @@ -307,7 +307,7 @@ struct LootView; ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li); ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv); -struct Loot +struct TC_GAME_API Loot { friend ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv); @@ -409,48 +409,33 @@ struct LootView : loot(_loot), viewer(_viewer), permission(_permission) { } }; -extern LootStore LootTemplates_Creature; -extern LootStore LootTemplates_Fishing; -extern LootStore LootTemplates_Gameobject; -extern LootStore LootTemplates_Item; -extern LootStore LootTemplates_Mail; -extern LootStore LootTemplates_Milling; -extern LootStore LootTemplates_Pickpocketing; -extern LootStore LootTemplates_Reference; -extern LootStore LootTemplates_Skinning; -extern LootStore LootTemplates_Disenchant; -extern LootStore LootTemplates_Prospecting; -extern LootStore LootTemplates_Spell; - -void LoadLootTemplates_Creature(); -void LoadLootTemplates_Fishing(); -void LoadLootTemplates_Gameobject(); -void LoadLootTemplates_Item(); -void LoadLootTemplates_Mail(); -void LoadLootTemplates_Milling(); -void LoadLootTemplates_Pickpocketing(); -void LoadLootTemplates_Skinning(); -void LoadLootTemplates_Disenchant(); -void LoadLootTemplates_Prospecting(); - -void LoadLootTemplates_Spell(); -void LoadLootTemplates_Reference(); - -inline void LoadLootTables() -{ - LoadLootTemplates_Creature(); - LoadLootTemplates_Fishing(); - LoadLootTemplates_Gameobject(); - LoadLootTemplates_Item(); - LoadLootTemplates_Mail(); - LoadLootTemplates_Milling(); - LoadLootTemplates_Pickpocketing(); - LoadLootTemplates_Skinning(); - LoadLootTemplates_Disenchant(); - LoadLootTemplates_Prospecting(); - LoadLootTemplates_Spell(); - - LoadLootTemplates_Reference(); -} +TC_GAME_API extern LootStore LootTemplates_Creature; +TC_GAME_API extern LootStore LootTemplates_Fishing; +TC_GAME_API extern LootStore LootTemplates_Gameobject; +TC_GAME_API extern LootStore LootTemplates_Item; +TC_GAME_API extern LootStore LootTemplates_Mail; +TC_GAME_API extern LootStore LootTemplates_Milling; +TC_GAME_API extern LootStore LootTemplates_Pickpocketing; +TC_GAME_API extern LootStore LootTemplates_Reference; +TC_GAME_API extern LootStore LootTemplates_Skinning; +TC_GAME_API extern LootStore LootTemplates_Disenchant; +TC_GAME_API extern LootStore LootTemplates_Prospecting; +TC_GAME_API extern LootStore LootTemplates_Spell; + +TC_GAME_API void LoadLootTemplates_Creature(); +TC_GAME_API void LoadLootTemplates_Fishing(); +TC_GAME_API void LoadLootTemplates_Gameobject(); +TC_GAME_API void LoadLootTemplates_Item(); +TC_GAME_API void LoadLootTemplates_Mail(); +TC_GAME_API void LoadLootTemplates_Milling(); +TC_GAME_API void LoadLootTemplates_Pickpocketing(); +TC_GAME_API void LoadLootTemplates_Skinning(); +TC_GAME_API void LoadLootTemplates_Disenchant(); +TC_GAME_API void LoadLootTemplates_Prospecting(); + +TC_GAME_API void LoadLootTemplates_Spell(); +TC_GAME_API void LoadLootTemplates_Reference(); + +TC_GAME_API void LoadLootTables(); #endif diff --git a/src/server/game/Mails/Mail.h b/src/server/game/Mails/Mail.h index 407edf2badb..ee1a0aae2c9 100644 --- a/src/server/game/Mails/Mail.h +++ b/src/server/game/Mails/Mail.h @@ -79,7 +79,7 @@ enum MailShowFlags MAIL_SHOW_RETURN = 0x0010 }; -class MailSender +class TC_GAME_API MailSender { public: // Constructors MailSender(MailMessageType messageType, ObjectGuid::LowType sender_guidlow_or_entry, MailStationery stationery = MAIL_STATIONERY_DEFAULT) @@ -100,7 +100,7 @@ class MailSender MailStationery m_stationery; }; -class MailReceiver +class TC_GAME_API MailReceiver { public: // Constructors explicit MailReceiver(ObjectGuid::LowType receiver_lowguid) : m_receiver(NULL), m_receiver_lowguid(receiver_lowguid) { } @@ -114,7 +114,7 @@ class MailReceiver ObjectGuid::LowType m_receiver_lowguid; }; -class MailDraft +class TC_GAME_API MailDraft { typedef std::map<ObjectGuid::LowType, Item*> MailItemMap; @@ -162,7 +162,7 @@ struct MailItemInfo }; typedef std::vector<MailItemInfo> MailItemInfoVec; -struct Mail +struct TC_GAME_API Mail { uint32 messageID; uint8 messageType; diff --git a/src/server/game/Maps/AreaBoundary.h b/src/server/game/Maps/AreaBoundary.h index a134b783ca6..0973d1a6e86 100644 --- a/src/server/game/Maps/AreaBoundary.h +++ b/src/server/game/Maps/AreaBoundary.h @@ -20,7 +20,7 @@ #include "Position.h" -class AreaBoundary +class TC_GAME_API AreaBoundary { public: enum BoundaryType @@ -40,7 +40,7 @@ class AreaBoundary { double d_positionX, d_positionY, d_positionZ; DoublePosition(double x = 0.0, double y = 0.0, double z = 0.0, float o = 0.0f) - : Position(x, y, z, o), d_positionX(x), d_positionY(y), d_positionZ(z) { } + : Position(float(x), float(y), float(z), o), d_positionX(x), d_positionY(y), d_positionZ(z) { } DoublePosition(float x, float y = 0.0f, float z = 0.0f, float o = 0.0f) : Position(x, y, z, o), d_positionX(x), d_positionY(y), d_positionZ(z) { } DoublePosition(const Position& pos) @@ -66,7 +66,7 @@ class AreaBoundary bool m_isInvertedBoundary; }; -class RectangleBoundary : public AreaBoundary +class TC_GAME_API RectangleBoundary : public AreaBoundary { public: // X axis is north/south, Y axis is east/west, larger values are northwest @@ -79,7 +79,7 @@ class RectangleBoundary : public AreaBoundary const float _minX, _maxX, _minY, _maxY; }; -class CircleBoundary : public AreaBoundary +class TC_GAME_API CircleBoundary : public AreaBoundary { public: CircleBoundary(Position const& center, double radius, bool isInverted = false); @@ -95,7 +95,7 @@ class CircleBoundary : public AreaBoundary const double _radiusSq; }; -class EllipseBoundary : public AreaBoundary +class TC_GAME_API EllipseBoundary : public AreaBoundary { public: EllipseBoundary(Position const& center, double radiusX, double radiusY, bool isInverted = false); @@ -109,7 +109,7 @@ class EllipseBoundary : public AreaBoundary const double _radiusYSq, _scaleXSq; }; -class TriangleBoundary : public AreaBoundary +class TC_GAME_API TriangleBoundary : public AreaBoundary { public: TriangleBoundary(Position const& pointA, Position const& pointB, Position const& pointC, bool isInverted = false); @@ -123,7 +123,7 @@ class TriangleBoundary : public AreaBoundary const double _abx, _bcx, _cax, _aby, _bcy, _cay; }; -class ParallelogramBoundary : public AreaBoundary +class TC_GAME_API ParallelogramBoundary : public AreaBoundary { public: // Note: AB must be orthogonal to AD @@ -138,7 +138,7 @@ class ParallelogramBoundary : public AreaBoundary const double _abx, _dax, _aby, _day; }; -class ZRangeBoundary : public AreaBoundary +class TC_GAME_API ZRangeBoundary : public AreaBoundary { public: ZRangeBoundary(float minZ, float maxZ, bool isInverted = false); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 5d2952a6a50..794be12ee7c 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -17,6 +17,7 @@ */ #include "Map.h" +#include "MapManager.h" #include "Battleground.h" #include "MMapFactory.h" #include "CellImpl.h" @@ -64,7 +65,7 @@ Map::~Map() } if (!m_scriptSchedule.empty()) - sScriptMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size()); + sMapMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size()); MMAP::MMapFactory::createOrGetMMapManager()->unloadMapInstance(GetId(), i_InstanceId); } @@ -129,9 +130,9 @@ void Map::LoadMMap(int gx, int gy) bool mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap((sWorld->GetDataPath() + "mmaps").c_str(), GetId(), gx, gy); if (mmapLoadResult) - TC_LOG_DEBUG("maps", "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); + TC_LOG_DEBUG("mmaps", "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); else - TC_LOG_ERROR("maps", "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); + TC_LOG_ERROR("mmaps", "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); } void Map::LoadVMap(int gx, int gy) @@ -209,6 +210,13 @@ void Map::LoadMapAndVMap(int gx, int gy) } } +void Map::LoadAllCells() +{ + for (uint32 cellX = 0; cellX < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellX++) + for (uint32 cellY = 0; cellY < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellY++) + LoadGrid((cellX + 0.5f - CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL, (cellY + 0.5f - CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL); +} + void Map::InitStateMachine() { si_GridStates[GRID_STATE_INVALID] = new InvalidState; @@ -594,7 +602,7 @@ bool Map::AddToMap(T* obj) //something, such as vehicle, needs to be update immediately //also, trigger needs to cast spell, if not update, cannot see visual - obj->UpdateObjectVisibility(true); + obj->UpdateObjectVisibilityOnCreate(); return true; } @@ -706,6 +714,15 @@ void Map::Update(const uint32 t_diff) VisitNearbyCellsOf(player, grid_object_update, world_object_update); + // If player is using far sight, visit that object too + if (WorldObject* viewPoint = player->GetViewpoint()) + { + if (Creature* viewCreature = viewPoint->ToCreature()) + VisitNearbyCellsOf(viewCreature, grid_object_update, world_object_update); + else if (DynamicObject* viewObject = viewPoint->ToDynObject()) + VisitNearbyCellsOf(viewObject, grid_object_update, world_object_update); + } + // Handle updates for creatures in combat with player and are more than 60 yards away if (player->IsInCombat()) { @@ -2650,8 +2667,8 @@ void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellCoord cellpa cell.SetNoCreate(); TypeContainerVisitor<Trinity::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier); TypeContainerVisitor<Trinity::VisibleNotifier, GridTypeMapContainer > grid_notifier(notifier); - cell.Visit(cellpair, world_notifier, *this, *player, player->GetSightRange()); - cell.Visit(cellpair, grid_notifier, *this, *player, player->GetSightRange()); + cell.Visit(cellpair, world_notifier, *this, *player->m_seer, player->GetSightRange()); + cell.Visit(cellpair, grid_notifier, *this, *player->m_seer, player->GetSightRange()); // send data notifier.SendToSelf(); @@ -2986,15 +3003,15 @@ void Map::RemoveFromActive(DynamicObject* obj) RemoveFromActiveHelper(obj); } -template bool Map::AddToMap(Corpse*); -template bool Map::AddToMap(Creature*); -template bool Map::AddToMap(GameObject*); -template bool Map::AddToMap(DynamicObject*); +template TC_GAME_API bool Map::AddToMap(Corpse*); +template TC_GAME_API bool Map::AddToMap(Creature*); +template TC_GAME_API bool Map::AddToMap(GameObject*); +template TC_GAME_API bool Map::AddToMap(DynamicObject*); -template void Map::RemoveFromMap(Corpse*, bool); -template void Map::RemoveFromMap(Creature*, bool); -template void Map::RemoveFromMap(GameObject*, bool); -template void Map::RemoveFromMap(DynamicObject*, bool); +template TC_GAME_API void Map::RemoveFromMap(Corpse*, bool); +template TC_GAME_API void Map::RemoveFromMap(Creature*, bool); +template TC_GAME_API void Map::RemoveFromMap(GameObject*, bool); +template TC_GAME_API void Map::RemoveFromMap(DynamicObject*, bool); /* ******* Dungeon Instance Maps ******* */ diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index bc2bf72f271..5f134613e85 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -154,7 +154,7 @@ struct LiquidData float depth_level; }; -class GridMap +class TC_GAME_API GridMap { uint32 _flags; union{ @@ -253,7 +253,7 @@ typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHol typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap; -class Map : public GridRefManager<NGridType> +class TC_GAME_API Map : public GridRefManager<NGridType> { friend class MapReference; public: @@ -277,6 +277,7 @@ class Map : public GridRefManager<NGridType> virtual bool AddPlayerToMap(Player*); virtual void RemovePlayerFromMap(Player*, bool); + template<class T> bool AddToMap(T *); template<class T> void RemoveFromMap(T *, bool); @@ -292,7 +293,8 @@ class Map : public GridRefManager<NGridType> void GameObjectRelocation(GameObject* go, float x, float y, float z, float orientation, bool respawnRelocationOnFail = true); void DynamicObjectRelocation(DynamicObject* go, float x, float y, float z, float orientation); - template<class T, class CONTAINER> void Visit(const Cell& cell, TypeContainerVisitor<T, CONTAINER> &visitor); + template<class T, class CONTAINER> + void Visit(const Cell& cell, TypeContainerVisitor<T, CONTAINER> &visitor); bool IsRemovalGrid(float x, float y) const { @@ -308,6 +310,7 @@ class Map : public GridRefManager<NGridType> bool GetUnloadLock(const GridCoord &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } void SetUnloadLock(const GridCoord &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } void LoadGrid(float x, float y); + void LoadAllCells(); bool UnloadGrid(NGridType& ngrid, bool pForce); virtual void UnloadAll(); @@ -753,7 +756,7 @@ enum InstanceResetMethod INSTANCE_RESET_RESPAWN_DELAY }; -class InstanceMap : public Map +class TC_GAME_API InstanceMap : public Map { public: InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent); @@ -785,7 +788,7 @@ class InstanceMap : public Map uint32 i_script_id; }; -class BattlegroundMap : public Map +class TC_GAME_API BattlegroundMap : public Map { public: BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, uint8 spawnMode); diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 47b9b376b1e..58decc05354 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -230,6 +230,9 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, bool load_data = save != NULL; map->CreateInstanceData(load_data); + if (sWorld->getBoolConfig(CONFIG_INSTANCEMAP_LOAD_GRIDS)) + map->LoadAllCells(); + m_InstancedMaps[InstanceId] = map; return map; } diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h index 7fa66bde06a..eea54e1f013 100644 --- a/src/server/game/Maps/MapInstanced.h +++ b/src/server/game/Maps/MapInstanced.h @@ -23,7 +23,7 @@ #include "InstanceSaveMgr.h" #include "DBCEnums.h" -class MapInstanced : public Map +class TC_GAME_API MapInstanced : public Map { friend class MapManager; public: diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index e5f364e39f4..79a8b3855e8 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -38,10 +38,10 @@ #include "AchievementMgr.h" MapManager::MapManager() + : _nextInstanceId(0), _scheduledScripts(0) { i_gridCleanUpDelay = sWorld->getIntConfig(CONFIG_INTERVAL_GRIDCLEAN); i_timer.SetInterval(sWorld->getIntConfig(CONFIG_INTERVAL_MAPUPDATE)); - _nextInstanceId = 0; } MapManager::~MapManager() { } @@ -62,6 +62,12 @@ void MapManager::InitializeVisibilityDistanceInfo() (*iter).second->InitVisibilityDistance(); } +MapManager* MapManager::instance() +{ + static MapManager instance; + return &instance; +} + Map* MapManager::CreateBaseMap(uint32 id) { Map* map = FindBaseMap(id); diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 7f9621593d4..a7fdc37d324 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -28,14 +28,10 @@ class Transport; struct TransportCreatureProto; -class MapManager +class TC_GAME_API MapManager { public: - static MapManager* instance() - { - static MapManager instance; - return &instance; - } + static MapManager* instance(); Map* CreateBaseMap(uint32 mapId); Map* FindBaseNonInstanceMap(uint32 mapId) const; @@ -130,6 +126,11 @@ class MapManager template<typename Worker> void DoForAllMapsWithMapId(uint32 mapId, Worker&& worker); + uint32 IncreaseScheduledScriptsCount() { return ++_scheduledScripts; } + uint32 DecreaseScheduledScriptCount() { return --_scheduledScripts; } + uint32 DecreaseScheduledScriptCount(size_t count) { return _scheduledScripts -= count; } + bool IsScriptScheduled() const { return _scheduledScripts > 0; } + private: typedef std::unordered_map<uint32, Map*> MapMapType; typedef std::vector<bool> InstanceIds; @@ -154,6 +155,9 @@ class MapManager InstanceIds _instanceIds; uint32 _nextInstanceId; MapUpdater m_updater; + + // atomic op counter for active scripts amount + std::atomic<uint32> _scheduledScripts; }; template<typename Worker> diff --git a/src/server/game/Scripting/MapScripts.cpp b/src/server/game/Maps/MapScripts.cpp index a01c109b9ca..c5d7bdc64ce 100644 --- a/src/server/game/Scripting/MapScripts.cpp +++ b/src/server/game/Maps/MapScripts.cpp @@ -21,6 +21,7 @@ #include "GridNotifiersImpl.h" #include "GossipDef.h" #include "Map.h" +#include "MapManager.h" #include "ObjectMgr.h" #include "Pet.h" #include "Item.h" @@ -58,7 +59,7 @@ void Map::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, O if (iter->first == 0) immedScript = true; - sScriptMgr->IncreaseScheduledScriptsCount(); + sMapMgr->IncreaseScheduledScriptsCount(); } ///- If one of the effects should be immediate, launch the script execution if (/*start &&*/ immedScript && !i_scriptLock) @@ -86,7 +87,7 @@ void Map::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* sou sa.script = &script; m_scriptSchedule.insert(ScriptScheduleMap::value_type(time_t(sWorld->GetGameTime() + delay), sa)); - sScriptMgr->IncreaseScheduledScriptsCount(); + sMapMgr->IncreaseScheduledScriptsCount(); ///- If effects should be immediate, launch the script execution if (delay == 0 && !i_scriptLock) @@ -878,6 +879,6 @@ void Map::ScriptsProcess() m_scriptSchedule.erase(iter); iter = m_scriptSchedule.begin(); - sScriptMgr->DecreaseScheduledScriptCount(); + sMapMgr->DecreaseScheduledScriptCount(); } } diff --git a/src/server/game/Maps/MapUpdater.h b/src/server/game/Maps/MapUpdater.h index 3d0f0b9e7e8..d95011d5a42 100644 --- a/src/server/game/Maps/MapUpdater.h +++ b/src/server/game/Maps/MapUpdater.h @@ -28,7 +28,7 @@ class MapUpdateRequest; class Map; -class MapUpdater +class TC_GAME_API MapUpdater { public: diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index afbddc5e686..c94dd860dea 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -36,6 +36,12 @@ TransportMgr::TransportMgr() { } TransportMgr::~TransportMgr() { } +TransportMgr* TransportMgr::instance() +{ + static TransportMgr instance; + return &instance; +} + void TransportMgr::Unload() { _transportTemplates.clear(); diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index 0bfb5b7a410..229fea882a4 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -82,7 +82,7 @@ struct TransportTemplate typedef std::map<uint32, TransportAnimationEntry const*> TransportPathContainer; typedef std::map<uint32, TransportRotationEntry const*> TransportPathRotationContainer; -struct TransportAnimation +struct TC_GAME_API TransportAnimation { TransportAnimation() : TotalTime(0) { } @@ -96,16 +96,12 @@ struct TransportAnimation typedef std::map<uint32, TransportAnimation> TransportAnimationContainer; -class TransportMgr +class TC_GAME_API TransportMgr { - friend void LoadDBCStores(std::string const&); + friend TC_GAME_API void LoadDBCStores(std::string const&); public: - static TransportMgr* instance() - { - static TransportMgr instance; - return &instance; - } + static TransportMgr* instance(); void Unload(); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 62c2a3a1981..ca63137ac93 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -208,7 +208,9 @@ enum TrinityStrings LANG_INVALID_GAMEOBJECT_TYPE = 176, LANG_GAMEOBJECT_DAMAGED = 177, LANG_GRID_POSITION = 178, - // Room for more level 1 179-199 not used + // 179-185 used in 6.x branch + LANG_TRANSPORT_POSITION = 186, + // Room for more level 1 187-199 not used // level 2 chat LANG_NO_SELECTION = 200, @@ -885,7 +887,9 @@ enum TrinityStrings LANG_CHARACTER_DELETED_LIST_LINE_CHAT = 1026, LANG_SQLDRIVER_QUERY_LOGGING_ENABLED = 1027, LANG_SQLDRIVER_QUERY_LOGGING_DISABLED = 1028, - // Room for more level 4 1029-1099 not used + LANG_ACCOUNT_INVALID_BNET_NAME = 1029, // 6.x ONLY + LANG_ACCOUNT_USE_BNET_COMMANDS = 1030, // 6.x enum value name but different text in DB + // Room for more level 4 1031-1099 not used // Level 3 (continue) LANG_ACCOUNT_SETADDON = 1100, diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 77d6f739da6..aa45c5024e6 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -23,7 +23,7 @@ #include "DetourNavMesh.h" #include <cassert> -enum SpellEffIndex +enum SpellEffIndex : uint8 { EFFECT_0 = 0, EFFECT_1 = 1, diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 2a57524cb3c..b01ddcb060d 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -302,6 +302,27 @@ void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generate } } +void MotionMaster::MoveCloserAndStop(uint32 id, Unit* target, float distance) +{ + float distanceToTravel = _owner->GetExactDist2d(target) - distance; + if (distanceToTravel > 0.0f) + { + float angle = _owner->GetAngle(target); + float destx = _owner->GetPositionX() + distanceToTravel * std::cos(angle); + float desty = _owner->GetPositionY() + distanceToTravel * std::sin(angle); + MovePoint(id, destx, desty, target->GetPositionZ()); + } + else + { + // we are already close enough. We just need to turn toward the target without changing position. + Movement::MoveSplineInit init(_owner); + init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZMinusOffset()); + init.SetFacing(target); + init.Launch(); + Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE); + } +} + void MotionMaster::MoveLand(uint32 id, Position const& pos) { float x, y, z; diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 76ae12986d5..7d6d512e88d 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -79,7 +79,7 @@ enum RotateDirection // assume it is 25 yard per 0.6 second #define SPEED_CHARGE 42.0f -class MotionMaster //: private std::stack<MovementGenerator *> +class TC_GAME_API MotionMaster //: private std::stack<MovementGenerator *> { private: //typedef std::stack<MovementGenerator *> Impl; @@ -173,6 +173,12 @@ class MotionMaster //: private std::stack<MovementGenerator *> { MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ, generatePath); } void MovePoint(uint32 id, float x, float y, float z, bool generatePath = true); + /* Makes the unit move toward the target until it is at a certain distance from it. The unit then stops. + Only works in 2D. + This method doesn't account for any movement done by the target. in other words, it only works if the target is stationary. + */ + void MoveCloserAndStop(uint32 id, Unit* target, float distance); + // These two movement types should only be used with creatures having landing/takeoff animations void MoveLand(uint32 id, Position const& pos); void MoveTakeoff(uint32 id, Position const& pos); diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h index 56e5dc7058a..d9dd17fabc2 100755 --- a/src/server/game/Movement/MovementGenerator.h +++ b/src/server/game/Movement/MovementGenerator.h @@ -27,7 +27,7 @@ class Unit; -class MovementGenerator +class TC_GAME_API MovementGenerator { public: virtual ~MovementGenerator(); diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h index 9aa778c5651..161f9e3e970 100755 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h @@ -32,7 +32,7 @@ class IdleMovementGenerator : public MovementGenerator MovementGeneratorType GetMovementGeneratorType() const override { return IDLE_MOTION_TYPE; } }; -extern IdleMovementGenerator si_idleMovement; +TC_GAME_API extern IdleMovementGenerator si_idleMovement; class RotateMovementGenerator : public MovementGenerator { diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index b595059557a..d3c6c70c4ed 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -265,9 +265,9 @@ void FollowMovementGenerator<Creature>::_updateSpeed(Creature* owner) if (!owner->IsPet() || !owner->IsInWorld() || !i_target.isValid() || i_target->GetGUID() != owner->GetOwnerGUID()) return; - owner->UpdateSpeed(MOVE_RUN, true); - owner->UpdateSpeed(MOVE_WALK, true); - owner->UpdateSpeed(MOVE_SWIM, true); + owner->UpdateSpeed(MOVE_RUN); + owner->UpdateSpeed(MOVE_WALK); + owner->UpdateSpeed(MOVE_SWIM); } template<> diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h index 7103eaace55..9250b666484 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h @@ -50,7 +50,7 @@ class TargetedMovementGeneratorMedium : public MovementGeneratorMedium< T, D >, bool DoUpdate(T*, uint32); Unit* GetTarget() const { return i_target.getTarget(); } - void unitSpeedChanged() { i_recalculateTravel = true; } + void unitSpeedChanged() override { i_recalculateTravel = true; } bool IsReachable() const { return (i_path) ? (i_path->GetPathType() & PATHFIND_NORMAL) : true; } protected: void _setTargetLocation(T* owner, bool updateDestination); diff --git a/src/server/game/Movement/PathGenerator.h b/src/server/game/Movement/PathGenerator.h index 71e0e88f0b2..3cad62abf25 100644 --- a/src/server/game/Movement/PathGenerator.h +++ b/src/server/game/Movement/PathGenerator.h @@ -49,7 +49,7 @@ enum PathType PATHFIND_SHORT = 0x20, // path is longer or equal to its limited path length }; -class PathGenerator +class TC_GAME_API PathGenerator { public: explicit PathGenerator(Unit const* owner); diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h index 209f978d658..0e62862cecc 100644 --- a/src/server/game/Movement/Spline/MoveSpline.h +++ b/src/server/game/Movement/Spline/MoveSpline.h @@ -37,7 +37,7 @@ namespace Movement // MoveSpline represents smooth catmullrom or linear curve and point that moves belong it // curve can be cyclic - in this case movement will be cyclic // point can have vertical acceleration motion componemt(used in fall, parabolic movement) - class MoveSpline + class TC_GAME_API MoveSpline { public: typedef Spline<int32> MySpline; diff --git a/src/server/game/Movement/Spline/MoveSplineInit.h b/src/server/game/Movement/Spline/MoveSplineInit.h index a94c84d92f3..3f38da97916 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.h +++ b/src/server/game/Movement/Spline/MoveSplineInit.h @@ -35,7 +35,7 @@ namespace Movement }; // Transforms coordinates from global to transport offsets - class TransportPathTransform + class TC_GAME_API TransportPathTransform { public: TransportPathTransform(Unit* owner, bool transformForTransport) @@ -49,7 +49,7 @@ namespace Movement /* Initializes and launches spline movement */ - class MoveSplineInit + class TC_GAME_API MoveSplineInit { public: diff --git a/src/server/game/Movement/Spline/MovementTypedefs.h b/src/server/game/Movement/Spline/MovementTypedefs.h index 031ec729949..c87fea47a82 100644 --- a/src/server/game/Movement/Spline/MovementTypedefs.h +++ b/src/server/game/Movement/Spline/MovementTypedefs.h @@ -69,8 +69,8 @@ namespace Movement typedef counter<uint32, 0xFFFFFFFF> UInt32Counter; - extern float gravity; - extern UInt32Counter splineIdGen; + TC_GAME_API extern float gravity; + TC_GAME_API extern UInt32Counter splineIdGen; } #endif // TRINITYSERVER_TYPEDEFS_H diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp index e0639e38e77..dc935263927 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.cpp +++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp @@ -94,6 +94,12 @@ void WaypointMgr::Load() TC_LOG_INFO("server.loading", ">> Loaded %u waypoints in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +WaypointMgr* WaypointMgr::instance() +{ + static WaypointMgr instance; + return &instance; +} + void WaypointMgr::ReloadPath(uint32 id) { WaypointPathContainer::iterator itr = _waypointStore.find(id); diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h index d519eee4793..63dc4184308 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.h +++ b/src/server/game/Movement/Waypoints/WaypointManager.h @@ -44,14 +44,10 @@ struct WaypointData typedef std::vector<WaypointData*> WaypointPath; typedef std::unordered_map<uint32, WaypointPath> WaypointPathContainer; -class WaypointMgr +class TC_GAME_API WaypointMgr { public: - static WaypointMgr* instance() - { - static WaypointMgr instance; - return &instance; - } + static WaypointMgr* instance(); // Attempts to reload a single path from database void ReloadPath(uint32 id); diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.h b/src/server/game/OutdoorPvP/OutdoorPvP.h index 79f34ff10ea..255f3cd0f99 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.h +++ b/src/server/game/OutdoorPvP/OutdoorPvP.h @@ -84,7 +84,7 @@ class Unit; struct GossipMenuItems; class OutdoorPvP; -class OPvPCapturePoint +class TC_GAME_API OPvPCapturePoint { public: @@ -185,7 +185,7 @@ class OPvPCapturePoint }; // base class for specific outdoor pvp handlers -class OutdoorPvP : public ZoneScript +class TC_GAME_API OutdoorPvP : public ZoneScript { friend class OutdoorPvPMgr; diff --git a/src/server/game/OutdoorPvP/OutdoorPvPMgr.cpp b/src/server/game/OutdoorPvP/OutdoorPvPMgr.cpp index 8296cdfb7ea..aa00d211d6e 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvPMgr.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvPMgr.cpp @@ -33,8 +33,20 @@ void OutdoorPvPMgr::Die() for (OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr) delete *itr; + m_OutdoorPvPSet.clear(); + for (OutdoorPvPDataMap::iterator itr = m_OutdoorPvPDatas.begin(); itr != m_OutdoorPvPDatas.end(); ++itr) delete itr->second; + + m_OutdoorPvPDatas.clear(); + + m_OutdoorPvPMap.clear(); +} + +OutdoorPvPMgr* OutdoorPvPMgr::instance() +{ + static OutdoorPvPMgr instance; + return &instance; } void OutdoorPvPMgr::InitOutdoorPvP() diff --git a/src/server/game/OutdoorPvP/OutdoorPvPMgr.h b/src/server/game/OutdoorPvP/OutdoorPvPMgr.h index 8a113987882..e53a78ac271 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvPMgr.h +++ b/src/server/game/OutdoorPvP/OutdoorPvPMgr.h @@ -35,18 +35,14 @@ struct OutdoorPvPData }; // class to handle player enter / leave / areatrigger / GO use events -class OutdoorPvPMgr +class TC_GAME_API OutdoorPvPMgr { private: OutdoorPvPMgr(); ~OutdoorPvPMgr() { }; public: - static OutdoorPvPMgr* instance() - { - static OutdoorPvPMgr instance; - return &instance; - } + static OutdoorPvPMgr* instance(); // create outdoor pvp events void InitOutdoorPvP(); diff --git a/src/server/game/Pools/PoolMgr.cpp b/src/server/game/Pools/PoolMgr.cpp index 12fb8a06b62..812d8ea3940 100644 --- a/src/server/game/Pools/PoolMgr.cpp +++ b/src/server/game/Pools/PoolMgr.cpp @@ -60,6 +60,11 @@ bool ActivePoolData::IsActiveObject<Quest>(uint32 quest_id) const return mActiveQuests.find(quest_id) != mActiveQuests.end(); } +template TC_GAME_API bool ActivePoolData::IsActiveObject<Creature>(uint32) const; +template TC_GAME_API bool ActivePoolData::IsActiveObject<GameObject>(uint32) const; +template TC_GAME_API bool ActivePoolData::IsActiveObject<Pool>(uint32) const; +template TC_GAME_API bool ActivePoolData::IsActiveObject<Quest>(uint32) const; + template<> void ActivePoolData::ActivateObject<Creature>(uint32 db_guid, uint32 pool_id) { @@ -570,6 +575,12 @@ void PoolMgr::Initialize() mCreatureSearchMap.clear(); } +PoolMgr* PoolMgr::instance() +{ + static PoolMgr instance; + return &instance; +} + void PoolMgr::LoadFromDB() { // Pool templates diff --git a/src/server/game/Pools/PoolMgr.h b/src/server/game/Pools/PoolMgr.h index 51e0bcb4cac..f1af3a3530e 100644 --- a/src/server/game/Pools/PoolMgr.h +++ b/src/server/game/Pools/PoolMgr.h @@ -43,7 +43,7 @@ class Pool // for Pool of Pool typedef std::set<ObjectGuid::LowType> ActivePoolObjects; typedef std::map<uint32, uint32> ActivePoolPools; -class ActivePoolData +class TC_GAME_API ActivePoolData { public: template<typename T> @@ -66,7 +66,7 @@ class ActivePoolData }; template <class T> -class PoolGroup +class TC_GAME_API PoolGroup { typedef std::vector<PoolObject> PoolObjectList; public: @@ -101,18 +101,14 @@ typedef std::multimap<uint32, uint32> PooledQuestRelation; typedef std::pair<PooledQuestRelation::const_iterator, PooledQuestRelation::const_iterator> PooledQuestRelationBounds; typedef std::pair<PooledQuestRelation::iterator, PooledQuestRelation::iterator> PooledQuestRelationBoundsNC; -class PoolMgr +class TC_GAME_API PoolMgr { private: PoolMgr(); ~PoolMgr() { }; public: - static PoolMgr* instance() - { - static PoolMgr instance; - return &instance; - } + static PoolMgr* instance(); void LoadFromDB(); void LoadQuestPools(); diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index a502fef6140..5e3bb4889ab 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -60,7 +60,7 @@ enum QuestFailedReason INVALIDREASON_DAILY_QUEST_COMPLETED_TODAY = 29 // You have completed that daily quest today. }; -enum QuestShareMessages +enum QuestShareMessages : uint8 { QUEST_PARTY_MSG_SHARING_QUEST = 0, QUEST_PARTY_MSG_CANT_TAKE_QUEST = 1, @@ -190,7 +190,7 @@ struct QuestLocale // This Quest class provides a convenient way to access a few pretotaled (cached) quest details, // all base quest information, and any utility functions such as generating the amount of // xp to give -class Quest +class TC_GAME_API Quest { friend class ObjectMgr; public: diff --git a/src/server/game/Reputation/ReputationMgr.h b/src/server/game/Reputation/ReputationMgr.h index 6f319a39b0c..5a51c9eb383 100644 --- a/src/server/game/Reputation/ReputationMgr.h +++ b/src/server/game/Reputation/ReputationMgr.h @@ -61,7 +61,7 @@ typedef std::map<uint32, ReputationRank> ForcedReactions; class Player; -class ReputationMgr +class TC_GAME_API ReputationMgr { public: // constructors and global modifiers explicit ReputationMgr(Player* owner) : _player(owner), diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp deleted file mode 100644 index 07ac1a2ed5b..00000000000 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "ScriptLoader.h" -#include "World.h" - -void AddSpellsScripts(); -void AddSC_SmartScripts(); -void AddCommandsScripts(); - -#ifdef SCRIPTS -void AddWorldScripts(); -void AddEasternKingdomsScripts(); -void AddKalimdorScripts(); -void AddOutlandScripts(); -void AddNorthrendScripts(); -void AddEventsScripts(); -void AddPetScripts(); -void AddOutdoorPvPScripts(); -void AddCustomScripts(); -#endif - -void AddScripts() -{ - AddSpellsScripts(); - AddSC_SmartScripts(); - AddCommandsScripts(); -#ifdef SCRIPTS - AddWorldScripts(); - AddEasternKingdomsScripts(); - AddKalimdorScripts(); - AddOutlandScripts(); - AddNorthrendScripts(); - AddEventsScripts(); - AddPetScripts(); - AddOutdoorPvPScripts(); - AddCustomScripts(); -#endif -} diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 4b26ba96c9b..ca1cd71363e 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -17,15 +17,16 @@ */ #include "ScriptMgr.h" +#include "ScriptReloadMgr.h" #include "Config.h" #include "DatabaseEnv.h" #include "DBCStores.h" #include "ObjectMgr.h" #include "OutdoorPvPMgr.h" -#include "ScriptLoader.h" #include "ScriptSystem.h" #include "Transport.h" #include "Vehicle.h" +#include "SmartAI.h" #include "SpellInfo.h" #include "SpellScript.h" #include "GossipDef.h" @@ -34,11 +35,9 @@ #include "WorldPacket.h" #include "WorldSession.h" #include "Chat.h" - -// namespace -// { - UnusedScriptNamesContainer UnusedScriptNames; -// } +#include "MapManager.h" +#include "LFGScripts.h" +#include "InstanceScript.h" // Trait which indicates whether this script type // must be assigned in the database. @@ -67,6 +66,10 @@ struct is_script_database_bound<GameObjectScript> : std::true_type { }; template<> +struct is_script_database_bound<VehicleScript> + : std::true_type { }; + +template<> struct is_script_database_bound<AreaTriggerScript> : std::true_type { }; @@ -94,143 +97,846 @@ template<> struct is_script_database_bound<AchievementCriteriaScript> : std::true_type { }; +enum Spells +{ + SPELL_HOTSWAP_VISUAL_SPELL_EFFECT = 40162 // 59084 +}; + +class ScriptRegistryInterface +{ +public: + ScriptRegistryInterface() { } + virtual ~ScriptRegistryInterface() { } + + ScriptRegistryInterface(ScriptRegistryInterface const&) = delete; + ScriptRegistryInterface(ScriptRegistryInterface&&) = delete; + + ScriptRegistryInterface& operator= (ScriptRegistryInterface const&) = delete; + ScriptRegistryInterface& operator= (ScriptRegistryInterface&&) = delete; + + /// Removes all scripts associated with the given script context. + /// Requires ScriptRegistryBase::SwapContext to be called after all transfers have finished. + virtual void ReleaseContext(std::string const& context) = 0; + + /// Injects and updates the changed script objects. + virtual void SwapContext(bool initialize) = 0; + + /// Removes the scripts used by this registry from the given container. + /// Used to find unused script names. + virtual void RemoveUsedScriptsFromContainer(std::unordered_set<std::string>& scripts) = 0; + + /// Unloads the script registry. + virtual void Unload() = 0; +}; + +template<class> +class ScriptRegistry; + +class ScriptRegistryCompositum + : public ScriptRegistryInterface +{ + ScriptRegistryCompositum() { } + + template<class> + friend class ScriptRegistry; + + /// Type erasure wrapper for objects + class DeleteableObjectBase + { + public: + DeleteableObjectBase() { } + virtual ~DeleteableObjectBase() { } + + DeleteableObjectBase(DeleteableObjectBase const&) = delete; + DeleteableObjectBase& operator= (DeleteableObjectBase const&) = delete; + }; + + template<typename T> + class DeleteableObject + : public DeleteableObjectBase + { + public: + DeleteableObject(T&& object) + : _object(std::forward<T>(object)) { } + + private: + T _object; + }; + +public: + void SetScriptNameInContext(std::string const& scriptname, std::string const& context) + { + ASSERT(_scriptnames_to_context.find(scriptname) == _scriptnames_to_context.end(), + "Scriptname was assigned to this context already!"); + _scriptnames_to_context.insert(std::make_pair(scriptname, context)); + } + + std::string const& GetScriptContextOfScriptName(std::string const& scriptname) const + { + auto itr = _scriptnames_to_context.find(scriptname); + ASSERT(itr != _scriptnames_to_context.end() && + "Given scriptname doesn't exist!"); + return itr->second; + } + + void ReleaseContext(std::string const& context) final override + { + for (auto const registry : _registries) + registry->ReleaseContext(context); + + // Clear the script names in context after calling the release hooks + // since it's possible that new references to a shared library + // are acquired when releasing. + for (auto itr = _scriptnames_to_context.begin(); + itr != _scriptnames_to_context.end();) + if (itr->second == context) + itr = _scriptnames_to_context.erase(itr); + else + ++itr; + } + + void SwapContext(bool initialize) final override + { + for (auto const registry : _registries) + registry->SwapContext(initialize); + + DoDelayedDelete(); + } + + void RemoveUsedScriptsFromContainer(std::unordered_set<std::string>& scripts) final override + { + for (auto const registry : _registries) + registry->RemoveUsedScriptsFromContainer(scripts); + } + + void Unload() final override + { + for (auto const registry : _registries) + registry->Unload(); + } + + template<typename T> + void QueueForDelayedDelete(T&& any) + { + _delayed_delete_queue.push_back( + Trinity::make_unique< + DeleteableObject<typename std::decay<T>::type> + >(std::forward<T>(any)) + ); + } + + static ScriptRegistryCompositum* Instance() + { + static ScriptRegistryCompositum instance; + return &instance; + } + +private: + void Register(ScriptRegistryInterface* registry) + { + _registries.insert(registry); + } + + void DoDelayedDelete() + { + _delayed_delete_queue.clear(); + } + + std::unordered_set<ScriptRegistryInterface*> _registries; + + std::vector<std::unique_ptr<DeleteableObjectBase>> _delayed_delete_queue; + + std::unordered_map< + std::string /*script name*/, + std::string /*context*/ + > _scriptnames_to_context; +}; + +#define sScriptRegistryCompositum ScriptRegistryCompositum::Instance() + +template<typename /*ScriptType*/, bool /*IsDatabaseBound*/> +class SpecializedScriptRegistry; + // This is the global static registry of scripts. -template<class TScript> -class ScriptRegistry +template<class ScriptType> +class ScriptRegistry final + : public SpecializedScriptRegistry< + ScriptType, is_script_database_bound<ScriptType>::value> +{ + ScriptRegistry() + { + sScriptRegistryCompositum->Register(this); + } + +public: + static ScriptRegistry* Instance() + { + static ScriptRegistry instance; + return &instance; + } + + void LogDuplicatedScriptPointerError(ScriptType const* first, ScriptType const* second) + { + // See if the script is using the same memory as another script. If this happens, it means that + // someone forgot to allocate new memory for a script. + TC_LOG_ERROR("scripts", "Script '%s' has same memory pointer as '%s'.", + first->GetName().c_str(), second->GetName().c_str()); + } +}; + +class ScriptRegistrySwapHookBase +{ +public: + ScriptRegistrySwapHookBase() { } + virtual ~ScriptRegistrySwapHookBase() { } + + ScriptRegistrySwapHookBase(ScriptRegistrySwapHookBase const&) = delete; + ScriptRegistrySwapHookBase(ScriptRegistrySwapHookBase&&) = delete; + + ScriptRegistrySwapHookBase& operator= (ScriptRegistrySwapHookBase const&) = delete; + ScriptRegistrySwapHookBase& operator= (ScriptRegistrySwapHookBase&&) = delete; + + /// Called before the actual context release happens + virtual void BeforeReleaseContext(std::string const& /*context*/) { } + + /// Called before SwapContext + virtual void BeforeSwapContext(bool /*initialize*/) { } + + /// Called before Unload + virtual void BeforeUnload() { } +}; + +template<typename ScriptType, typename Base> +class ScriptRegistrySwapHooks + : public ScriptRegistrySwapHookBase +{ +}; + +/// This hook is responsible for swapping OutdoorPvP's +template<typename Base> +class UnsupportedScriptRegistrySwapHooks + : public ScriptRegistrySwapHookBase +{ +public: + void BeforeReleaseContext(std::string const& context) final override + { + auto const bounds = static_cast<Base*>(this)->_ids_of_contexts.equal_range(context); + ASSERT(bounds.first == bounds.second); + } +}; + +/// This hook is responsible for swapping Creature and GameObject AI's +template<typename ObjectType, typename ScriptType, typename Base> +class CreatureGameObjectScriptRegistrySwapHooks + : public ScriptRegistrySwapHookBase { + template<typename W> + class AIFunctionMapWorker + { public: + template<typename T> + AIFunctionMapWorker(T&& worker) + : _worker(std::forward<T>(worker)) { } - typedef std::map<uint32, TScript*> ScriptMap; - typedef typename ScriptMap::iterator ScriptMapIterator; + void Visit(std::unordered_map<ObjectGuid, ObjectType*>& objects) + { + _worker(objects); + } - // The actual list of scripts. This will be accessed concurrently, so it must not be modified - // after server startup. - static ScriptMap ScriptPointerList; - static std::vector<TScript*> Scripts; + template<typename O> + void Visit(std::unordered_map<ObjectGuid, O*>&) { } - static void AddScript(TScript* const script, bool addToDeleteContainer = true) + private: + W _worker; + }; + + class AsyncCastHotswapEffectEvent : public BasicEvent + { + public: + explicit AsyncCastHotswapEffectEvent(Unit* owner) : owner_(owner) { } + + bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override + { + owner_->CastSpell(owner_, SPELL_HOTSWAP_VISUAL_SPELL_EFFECT, true); + return true; + } + + private: + Unit* owner_; + }; + + // Hook which is called before a creature is swapped + static void UnloadStage1(Creature* creature) + { + if (creature->IsCharmed()) + creature->RemoveCharmedBy(nullptr); + + ASSERT(!creature->IsCharmed(), + "There is a disabled AI which is still loaded."); + + creature->AI()->EnterEvadeMode(); + } + + static void UnloadStage2(Creature* creature) + { + bool const destroyed = creature->AIM_Destroy(); + ASSERT(destroyed, + "Destroying the AI should never fail here!"); + (void)destroyed; + + ASSERT(!creature->AI(), + "The AI should be null here!"); + } + + // Hook which is called before a gameobject is swapped + static void UnloadStage1(GameObject* gameobject) + { + gameobject->AI()->Reset(); + } + + static void UnloadStage2(GameObject* gameobject) + { + gameobject->AIM_Destroy(); + + ASSERT(!gameobject->AI(), + "The AI should be null here!"); + } + + // Hook which is called after a creature was swapped + static void LoadStage1(Creature* creature) + { + ASSERT(!creature->AI(), + "The AI should be null here!"); + + if (creature->IsAlive()) + creature->ClearUnitState(UNIT_STATE_EVADE); + + bool const created = creature->AIM_Initialize(); + ASSERT(created, + "Creating the AI should never fail here!"); + (void)created; + } + + static void LoadStage2(Creature* creature) + { + if (!creature->IsAlive()) + return; + + creature->AI()->EnterEvadeMode(); + + // Cast a dummy visual spell asynchronously here to signal + // that the AI was hot swapped + creature->m_Events.AddEvent(new AsyncCastHotswapEffectEvent(creature), + creature->m_Events.CalculateTime(0)); + } + + // Hook which is called after a gameobject was swapped + static void LoadStage1(GameObject* gameobject) + { + ASSERT(!gameobject->AI(), + "The AI should be null here!"); + + gameobject->AIM_Initialize(); + } + + static void LoadStage2(GameObject* gameobject) + { + gameobject->AI()->Reset(); + } + + template<typename T> + void RunOverAllEntities(T fn) + { + auto evaluator = [&](std::unordered_map<ObjectGuid, ObjectType*>& objects) + { + for (auto object : objects) + fn(object.second); + }; + + AIFunctionMapWorker<typename std::decay<decltype(evaluator)>::type> worker(std::move(evaluator)); + TypeContainerVisitor<decltype(worker), MapStoredObjectTypesContainer> visitor(worker); + + sMapMgr->DoForAllMaps([&](Map* map) + { + // Run the worker over all maps + visitor.Visit(map->GetObjectsStore()); + }); + } + +public: + void BeforeReleaseContext(std::string const& context) final override + { + auto ids_to_remove = static_cast<Base*>(this)->GetScriptIDsToRemove(context); + + std::vector<ObjectType*> stage2; + + RunOverAllEntities([&](ObjectType* object) { - ASSERT(script); + if (ids_to_remove.find(object->GetScriptId()) != ids_to_remove.end()) + { + UnloadStage1(object); + stage2.push_back(object); + } + }); + + for (auto object : stage2) + UnloadStage2(object); + + // Add the new ids which are removed to the global ids to remove set + ids_removed_.insert(ids_to_remove.begin(), ids_to_remove.end()); + } + + void BeforeSwapContext(bool initialize) override + { + // Never swap creature or gameobject scripts when initializing + if (initialize) + return; - // See if the script is using the same memory as another script. If this happens, it means that - // someone forgot to allocate new memory for a script. - for (ScriptMapIterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) + // Add the recently added scripts to the deleted scripts to replace + // default AI's with recently added core scripts. + ids_removed_.insert(static_cast<Base*>(this)->GetRecentlyAddedScriptIDs().begin(), + static_cast<Base*>(this)->GetRecentlyAddedScriptIDs().end()); + + std::vector<ObjectType*> remove; + std::vector<ObjectType*> stage2; + + RunOverAllEntities([&](ObjectType* object) + { + if (ids_removed_.find(object->GetScriptId()) != ids_removed_.end()) { - if (it->second == script) + if (object->AI()) { - TC_LOG_ERROR("scripts", "Script '%s' has same memory pointer as '%s'.", - script->GetName().c_str(), it->second->GetName().c_str()); - - return; + // Overwrite existing (default) AI's which are replaced by a new script + UnloadStage1(object); + remove.push_back(object); } + + stage2.push_back(object); } + }); + + for (auto object : remove) + UnloadStage2(object); + + for (auto object : stage2) + LoadStage1(object); + + for (auto object : stage2) + LoadStage2(object); + + ids_removed_.clear(); + } + + void BeforeUnload() final override + { + ASSERT(ids_removed_.empty()); + } + +private: + std::unordered_set<uint32> ids_removed_; +}; + +// This hook is responsible for swapping CreatureAI's +template<typename Base> +class ScriptRegistrySwapHooks<CreatureScript, Base> + : public CreatureGameObjectScriptRegistrySwapHooks< + Creature, CreatureScript, Base + > { }; + +// This hook is responsible for swapping GameObjectAI's +template<typename Base> +class ScriptRegistrySwapHooks<GameObjectScript, Base> + : public CreatureGameObjectScriptRegistrySwapHooks< + GameObject, GameObjectScript, Base + > { }; + +/// This hook is responsible for swapping BattlegroundScript's +template<typename Base> +class ScriptRegistrySwapHooks<BattlegroundScript, Base> + : public UnsupportedScriptRegistrySwapHooks<Base> { }; + +/// This hook is responsible for swapping OutdoorPvP's +template<typename Base> +class ScriptRegistrySwapHooks<OutdoorPvPScript, Base> + : public ScriptRegistrySwapHookBase +{ +public: + ScriptRegistrySwapHooks() : swapped(false) { } + + void BeforeReleaseContext(std::string const& context) final override + { + auto const bounds = static_cast<Base*>(this)->_ids_of_contexts.equal_range(context); - AddScript(is_script_database_bound<TScript>{}, script); - if (addToDeleteContainer) - Scripts.push_back(script); + if ((!swapped) && (bounds.first != bounds.second)) + { + swapped = true; + sOutdoorPvPMgr->Die(); } + } - // Gets a script by its ID (assigned by ObjectMgr). - static TScript* GetScriptById(uint32 id) + void BeforeSwapContext(bool initialize) override + { + // Never swap outdoor pvp scripts when initializing + if ((!initialize) && swapped) { - ScriptMapIterator it = ScriptPointerList.find(id); - if (it != ScriptPointerList.end()) - return it->second; + sOutdoorPvPMgr->InitOutdoorPvP(); + swapped = false; + } + } + + void BeforeUnload() final override + { + ASSERT(!swapped); + } + +private: + bool swapped; +}; + +/// This hook is responsible for swapping InstanceMapScript's +template<typename Base> +class ScriptRegistrySwapHooks<InstanceMapScript, Base> + : public ScriptRegistrySwapHookBase +{ +public: + ScriptRegistrySwapHooks() : swapped(false) { } + + void BeforeReleaseContext(std::string const& context) final override + { + auto const bounds = static_cast<Base*>(this)->_ids_of_contexts.equal_range(context); + if (bounds.first != bounds.second) + swapped = true; + } + + void BeforeSwapContext(bool /*initialize*/) override + { + swapped = false; + } - return NULL; + void BeforeUnload() final override + { + ASSERT(!swapped); + } + +private: + bool swapped; +}; + +/// This hook is responsible for swapping SpellScriptLoader's +template<typename Base> +class ScriptRegistrySwapHooks<SpellScriptLoader, Base> + : public ScriptRegistrySwapHookBase +{ +public: + ScriptRegistrySwapHooks() : swapped(false) { } + + void BeforeReleaseContext(std::string const& context) final override + { + auto const bounds = static_cast<Base*>(this)->_ids_of_contexts.equal_range(context); + + if (bounds.first != bounds.second) + swapped = true; + } + + void BeforeSwapContext(bool /*initialize*/) override + { + if (swapped) + { + sObjectMgr->ValidateSpellScripts(); + swapped = false; } + } - private: + void BeforeUnload() final override + { + ASSERT(!swapped); + } + +private: + bool swapped; +}; + +// Database bound script registry +template<typename ScriptType> +class SpecializedScriptRegistry<ScriptType, true> + : public ScriptRegistryInterface, + public ScriptRegistrySwapHooks<ScriptType, ScriptRegistry<ScriptType>> +{ + template<typename> + friend class UnsupportedScriptRegistrySwapHooks; + + template<typename, typename> + friend class ScriptRegistrySwapHooks; + + template<typename, typename, typename> + friend class CreatureGameObjectScriptRegistrySwapHooks; + +public: + SpecializedScriptRegistry() { } + + typedef std::unordered_map< + uint32 /*script id*/, + std::unique_ptr<ScriptType> + > ScriptStoreType; - // Adds a database bound script - static void AddScript(std::true_type, TScript* const script) + typedef typename ScriptStoreType::iterator ScriptStoreIteratorType; + + void ReleaseContext(std::string const& context) final override + { + this->BeforeReleaseContext(context); + + auto const bounds = _ids_of_contexts.equal_range(context); + for (auto itr = bounds.first; itr != bounds.second; ++itr) + _scripts.erase(itr->second); + } + + void SwapContext(bool initialize) final override + { + this->BeforeSwapContext(initialize); + + _recently_added_ids.clear(); + } + + void RemoveUsedScriptsFromContainer(std::unordered_set<std::string>& scripts) final override + { + for (auto const& script : _scripts) + scripts.erase(script.second->GetName()); + } + + void Unload() final override + { + this->BeforeUnload(); + + ASSERT(_recently_added_ids.empty(), + "Recently added script ids should be empty here!"); + + _scripts.clear(); + _ids_of_contexts.clear(); + } + + // Adds a database bound script + void AddScript(ScriptType* script) + { + ASSERT(script, + "Tried to call AddScript with a nullpointer!"); + ASSERT(!sScriptMgr->GetCurrentScriptContext().empty(), + "Tried to register a script without being in a valid script context!"); + + std::unique_ptr<ScriptType> script_ptr(script); + + // Get an ID for the script. An ID only exists if it's a script that is assigned in the database + // through a script name (or similar). + if (uint32 const id = sObjectMgr->GetScriptId(script->GetName())) { - // Get an ID for the script. An ID only exists if it's a script that is assigned in the database - // through a script name (or similar). - uint32 id = sObjectMgr->GetScriptId(script->GetName()); - if (id) + // Try to find an existing script. + for (auto const& stored_script : _scripts) { - // Try to find an existing script. - bool existing = false; - for (ScriptMapIterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) - { - // If the script names match... - if (it->second->GetName() == script->GetName()) - { - // ... It exists. - existing = true; - break; - } - } - - // If the script isn't assigned -> assign it! - if (!existing) - { - ScriptPointerList[id] = script; - sScriptMgr->IncrementScriptCount(); - - #ifdef SCRIPTS - UnusedScriptNamesContainer::iterator itr = std::lower_bound(UnusedScriptNames.begin(), UnusedScriptNames.end(), script->GetName()); - if (itr != UnusedScriptNames.end() && *itr == script->GetName()) - UnusedScriptNames.erase(itr); - #endif - } - else + // If the script names match... + if (stored_script.second->GetName() == script->GetName()) { // If the script is already assigned -> delete it! - TC_LOG_ERROR("scripts", "Script '%s' already assigned with the same script name, so the script can't work.", - script->GetName().c_str()); + TC_LOG_ERROR("scripts", "Script '%s' already assigned with the same script name, " + "so the script can't work.", script->GetName().c_str()); - ABORT(); // Error that should be fixed ASAP. + // Error that should be fixed ASAP. + sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr)); + ABORT(); + return; } } - else - { - // The script uses a script name from database, but isn't assigned to anything. - TC_LOG_ERROR("sql.sql", "Script named '%s' does not have a script name assigned in database.", script->GetName().c_str()); - } - } - // Adds a non database bound script - static void AddScript(std::false_type, TScript* const script) + // If the script isn't assigned -> assign it! + _scripts.insert(std::make_pair(id, std::move(script_ptr))); + _ids_of_contexts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), id)); + _recently_added_ids.insert(id); + + sScriptRegistryCompositum->SetScriptNameInContext(script->GetName(), + sScriptMgr->GetCurrentScriptContext()); + } + else { - // We're dealing with a code-only script; just add it. - ScriptPointerList[_scriptIdCounter++] = script; - sScriptMgr->IncrementScriptCount(); + // The script uses a script name from database, but isn't assigned to anything. + TC_LOG_ERROR("sql.sql", "Script named '%s' does not have a script name assigned in database.", + script->GetName().c_str()); + + // Avoid calling "delete script;" because we are currently in the script constructor + // In a valid scenario this will not happen because every script has a name assigned in the database + sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr)); + return; } + } + + // Gets a script by its ID (assigned by ObjectMgr). + ScriptType* GetScriptById(uint32 id) + { + auto const itr = _scripts.find(id); + if (itr != _scripts.end()) + return itr->second.get(); + + return nullptr; + } + + ScriptStoreType& GetScripts() + { + return _scripts; + } + +protected: + // Returns the script id's which are registered to a certain context + std::unordered_set<uint32> GetScriptIDsToRemove(std::string const& context) const + { + // Create a set of all ids which are removed + std::unordered_set<uint32> scripts_to_remove; + + auto const bounds = _ids_of_contexts.equal_range(context); + for (auto itr = bounds.first; itr != bounds.second; ++itr) + scripts_to_remove.insert(itr->second); + + return scripts_to_remove; + } + + std::unordered_set<uint32> const& GetRecentlyAddedScriptIDs() const + { + return _recently_added_ids; + } - // Counter used for code-only scripts. - static uint32 _scriptIdCounter; +private: + ScriptStoreType _scripts; + + // Scripts of a specific context + std::unordered_multimap<std::string /*context*/, uint32 /*id*/> _ids_of_contexts; + + // Script id's which were registered recently + std::unordered_set<uint32> _recently_added_ids; +}; + +/// This hook is responsible for swapping CommandScript's +template<typename Base> +class ScriptRegistrySwapHooks<CommandScript, Base> + : public ScriptRegistrySwapHookBase +{ +public: + void BeforeReleaseContext(std::string const& /*context*/) final override + { + ChatHandler::invalidateCommandTable(); + } + + void BeforeSwapContext(bool /*initialize*/) override + { + ChatHandler::invalidateCommandTable(); + } + + void BeforeUnload() final override + { + ChatHandler::invalidateCommandTable(); + } +}; + +// Database unbound script registry +template<typename ScriptType> +class SpecializedScriptRegistry<ScriptType, false> + : public ScriptRegistryInterface, + public ScriptRegistrySwapHooks<ScriptType, ScriptRegistry<ScriptType>> +{ + template<typename, typename> + friend class ScriptRegistrySwapHooks; + +public: + typedef std::unordered_multimap<std::string /*context*/, std::unique_ptr<ScriptType>> ScriptStoreType; + typedef typename ScriptStoreType::iterator ScriptStoreIteratorType; + + SpecializedScriptRegistry() { } + + void ReleaseContext(std::string const& context) final override + { + this->BeforeReleaseContext(context); + + _scripts.erase(context); + } + + void SwapContext(bool initialize) final override + { + this->BeforeSwapContext(initialize); + } + + void RemoveUsedScriptsFromContainer(std::unordered_set<std::string>& scripts) final override + { + for (auto const& script : _scripts) + scripts.erase(script.second->GetName()); + } + + void Unload() final override + { + this->BeforeUnload(); + + _scripts.clear(); + } + + // Adds a non database bound script + void AddScript(ScriptType* script) + { + ASSERT(script, + "Tried to call AddScript with a nullpointer!"); + ASSERT(!sScriptMgr->GetCurrentScriptContext().empty(), + "Tried to register a script without being in a valid script context!"); + + std::unique_ptr<ScriptType> script_ptr(script); + + for (auto const& entry : _scripts) + if (entry.second.get() == script) + { + static_cast<ScriptRegistry<ScriptType>*>(this)-> + LogDuplicatedScriptPointerError(script, entry.second.get()); + + sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr)); + return; + } + + // We're dealing with a code-only script, just add it. + _scripts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), std::move(script_ptr))); + } + + ScriptStoreType& GetScripts() + { + return _scripts; + } + +private: + ScriptStoreType _scripts; }; // Utility macros to refer to the script registry. -#define SCR_REG_MAP(T) ScriptRegistry<T>::ScriptMap -#define SCR_REG_ITR(T) ScriptRegistry<T>::ScriptMapIterator -#define SCR_REG_LST(T) ScriptRegistry<T>::ScriptPointerList -#define SCR_REG_VEC(T) ScriptRegistry<T>::Scripts +#define SCR_REG_MAP(T) ScriptRegistry<T>::ScriptStoreType +#define SCR_REG_ITR(T) ScriptRegistry<T>::ScriptStoreIteratorType +#define SCR_REG_LST(T) ScriptRegistry<T>::Instance()->GetScripts() // Utility macros for looping over scripts. #define FOR_SCRIPTS(T, C, E) \ if (SCR_REG_LST(T).empty()) \ return; \ + \ for (SCR_REG_ITR(T) C = SCR_REG_LST(T).begin(); \ C != SCR_REG_LST(T).end(); ++C) + #define FOR_SCRIPTS_RET(T, C, E, R) \ if (SCR_REG_LST(T).empty()) \ return R; \ + \ for (SCR_REG_ITR(T) C = SCR_REG_LST(T).begin(); \ C != SCR_REG_LST(T).end(); ++C) + #define FOREACH_SCRIPT(T) \ FOR_SCRIPTS(T, itr, end) \ - itr->second + itr->second // Utility macros for finding specific scripts. #define GET_SCRIPT(T, I, V) \ - T* V = ScriptRegistry<T>::GetScriptById(I); \ + T* V = ScriptRegistry<T>::Instance()->GetScriptById(I); \ if (!V) \ return; + #define GET_SCRIPT_RET(T, I, V, R) \ - T* V = ScriptRegistry<T>::GetScriptById(I); \ + T* V = ScriptRegistry<T>::Instance()->GetScriptById(I); \ if (!V) \ return R; @@ -240,14 +946,34 @@ struct TSpellSummary uint8 Effects; // set of enum SelectEffect } *SpellSummary; -ScriptMgr::ScriptMgr() : _scriptCount(0), _scheduledScripts(0) +ScriptObject::ScriptObject(const char* name) : _name(name) +{ + sScriptMgr->IncreaseScriptCount(); +} + +ScriptObject::~ScriptObject() +{ + sScriptMgr->DecreaseScriptCount(); +} + +ScriptMgr::ScriptMgr() + : _scriptCount(0), _script_loader_callback(nullptr) { } ScriptMgr::~ScriptMgr() { } +ScriptMgr* ScriptMgr::instance() +{ + static ScriptMgr instance; + return &instance; +} + void ScriptMgr::Initialize() { + ASSERT(sSpellMgr->GetSpellInfo(SPELL_HOTSWAP_VISUAL_SPELL_EFFECT) + && "Reload hotswap spell effect for creatures isn't valid!"); + uint32 oldMSTime = getMSTime(); LoadDatabase(); @@ -255,54 +981,86 @@ void ScriptMgr::Initialize() TC_LOG_INFO("server.loading", "Loading C++ scripts"); FillSpellSummary(); - AddScripts(); -#ifdef SCRIPTS - for (std::string const& scriptName : UnusedScriptNames) + // Load core scripts + SetScriptContext("___static___"); + + // SmartAI + AddSC_SmartScripts(); + + // LFGScripts + lfg::AddSC_LFGScripts(); + + // Load all static linked scripts through the script loader function. + ASSERT(_script_loader_callback, + "Script loader callback wasn't registered!"); + _script_loader_callback(); + + // Initialize all dynamic scripts + // and finishes the context switch to do + // bulk loading + sScriptReloadMgr->Initialize(); + + // Loads all scripts from the current context + sScriptMgr->SwapScriptContext(true); + + // Print unused script names. + std::unordered_set<std::string> unusedScriptNames( + sObjectMgr->GetAllScriptNames().begin(), + sObjectMgr->GetAllScriptNames().end()); + + // Remove the used scripts from the given container. + sScriptRegistryCompositum->RemoveUsedScriptsFromContainer(unusedScriptNames); + + for (std::string const& scriptName : unusedScriptNames) { - TC_LOG_ERROR("sql.sql", "ScriptName '%s' exists in database, but no core script found!", scriptName.c_str()); + // Avoid complaining about empty script names since the + // script name container contains a placeholder as the 0 element. + if (scriptName.empty()) + continue; + + TC_LOG_ERROR("sql.sql", "ScriptName '%s' exists in database, " + "but no core script found!", scriptName.c_str()); } -#endif - TC_LOG_INFO("server.loading", ">> Loaded %u C++ scripts in %u ms", GetScriptCount(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u C++ scripts in %u ms", + GetScriptCount(), GetMSTimeDiffToNow(oldMSTime)); +} + +void ScriptMgr::SetScriptContext(std::string const& context) +{ + _currentContext = context; +} + +void ScriptMgr::SwapScriptContext(bool initialize) +{ + sScriptRegistryCompositum->SwapContext(initialize); + _currentContext.clear(); +} + +void ScriptMgr::ReleaseScriptContext(std::string const& context) +{ + sScriptRegistryCompositum->ReleaseContext(context); +} + +std::shared_ptr<ModuleReference> + ScriptMgr::AcquireModuleReferenceOfScriptName(std::string const& scriptname) const +{ +#ifdef TRINITY_API_USE_DYNAMIC_LINKING + // Returns the reference to the module of the given scriptname + return ScriptReloadMgr::AcquireModuleReferenceOfContext( + sScriptRegistryCompositum->GetScriptContextOfScriptName(scriptname)); +#else + (void)scriptname; + // Something went wrong when this function is used in + // a static linked context. + WPAbort(); +#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING } void ScriptMgr::Unload() { - #define SCR_CLEAR(T) \ - for (T* scr : SCR_REG_VEC(T)) \ - delete scr; \ - SCR_REG_VEC(T).clear(); - - // Clear scripts for every script type. - SCR_CLEAR(SpellScriptLoader); - SCR_CLEAR(ServerScript); - SCR_CLEAR(WorldScript); - SCR_CLEAR(FormulaScript); - SCR_CLEAR(WorldMapScript); - SCR_CLEAR(InstanceMapScript); - SCR_CLEAR(BattlegroundMapScript); - SCR_CLEAR(ItemScript); - SCR_CLEAR(CreatureScript); - SCR_CLEAR(GameObjectScript); - SCR_CLEAR(AreaTriggerScript); - SCR_CLEAR(BattlegroundScript); - SCR_CLEAR(OutdoorPvPScript); - SCR_CLEAR(CommandScript); - SCR_CLEAR(WeatherScript); - SCR_CLEAR(AuctionHouseScript); - SCR_CLEAR(ConditionScript); - SCR_CLEAR(VehicleScript); - SCR_CLEAR(DynamicObjectScript); - SCR_CLEAR(TransportScript); - SCR_CLEAR(AchievementCriteriaScript); - SCR_CLEAR(PlayerScript); - SCR_CLEAR(AccountScript); - SCR_CLEAR(GuildScript); - SCR_CLEAR(GroupScript); - SCR_CLEAR(UnitScript); - - #undef SCR_CLEAR + sScriptRegistryCompositum->Unload(); delete[] SpellSummary; delete[] UnitAI::AISpellInfo; @@ -400,38 +1158,22 @@ void ScriptMgr::FillSpellSummary() } } -void ScriptMgr::CreateSpellScripts(uint32 spellId, std::list<SpellScript*>& scriptVector) +template<typename T, typename F> +void CreateSpellOrAuraScripts(uint32 spellId, std::list<T*>& scriptVector, F&& extractor) { SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(spellId); for (SpellScriptsContainer::iterator itr = bounds.first; itr != bounds.second; ++itr) { - SpellScriptLoader* tmpscript = ScriptRegistry<SpellScriptLoader>::GetScriptById(itr->second); - if (!tmpscript) - continue; - - SpellScript* script = tmpscript->GetSpellScript(); - - if (!script) + // When the script is disabled continue with the next one + if (!itr->second.second) continue; - script->_Init(&tmpscript->GetName(), spellId); - - scriptVector.push_back(script); - } -} - -void ScriptMgr::CreateAuraScripts(uint32 spellId, std::list<AuraScript*>& scriptVector) -{ - SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(spellId); - - for (SpellScriptsContainer::iterator itr = bounds.first; itr != bounds.second; ++itr) - { - SpellScriptLoader* tmpscript = ScriptRegistry<SpellScriptLoader>::GetScriptById(itr->second); + SpellScriptLoader* tmpscript = sScriptMgr->GetSpellScriptLoader(itr->second.first); if (!tmpscript) continue; - AuraScript* script = tmpscript->GetAuraScript(); + T* script = (*tmpscript.*extractor)(); if (!script) continue; @@ -442,19 +1184,19 @@ void ScriptMgr::CreateAuraScripts(uint32 spellId, std::list<AuraScript*>& script } } -void ScriptMgr::CreateSpellScriptLoaders(uint32 spellId, std::vector<std::pair<SpellScriptLoader*, SpellScriptsContainer::iterator> >& scriptVector) +void ScriptMgr::CreateSpellScripts(uint32 spellId, std::list<SpellScript*>& scriptVector) { - SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(spellId); - scriptVector.reserve(std::distance(bounds.first, bounds.second)); + CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetSpellScript); +} - for (SpellScriptsContainer::iterator itr = bounds.first; itr != bounds.second; ++itr) - { - SpellScriptLoader* tmpscript = ScriptRegistry<SpellScriptLoader>::GetScriptById(itr->second); - if (!tmpscript) - continue; +void ScriptMgr::CreateAuraScripts(uint32 spellId, std::list<AuraScript*>& scriptVector) +{ + CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetAuraScript); +} - scriptVector.push_back(std::make_pair(tmpscript, itr)); - } +SpellScriptLoader* ScriptMgr::GetSpellScriptLoader(uint32 scriptId) +{ + return ScriptRegistry<SpellScriptLoader>::Instance()->GetScriptById(scriptId); } void ScriptMgr::OnNetworkStart() @@ -501,17 +1243,6 @@ void ScriptMgr::OnPacketSend(WorldSession* session, WorldPacket const& packet) FOREACH_SCRIPT(ServerScript)->OnPacketSend(session, copy); } -void ScriptMgr::OnUnknownPacketReceive(WorldSession* session, WorldPacket const& packet) -{ - ASSERT(session); - - if (SCR_REG_LST(ServerScript).empty()) - return; - - WorldPacket copy(packet); - FOREACH_SCRIPT(ServerScript)->OnUnknownPacketReceive(session, copy); -} - void ScriptMgr::OnOpenStateChange(bool open) { FOREACH_SCRIPT(WorldScript)->OnOpenStateChange(open); @@ -1493,56 +2224,62 @@ void ScriptMgr::OnGroupDisband(Group* group) void ScriptMgr::OnHeal(Unit* healer, Unit* reciever, uint32& gain) { FOREACH_SCRIPT(UnitScript)->OnHeal(healer, reciever, gain); + FOREACH_SCRIPT(PlayerScript)->OnHeal(healer, reciever, gain); } void ScriptMgr::OnDamage(Unit* attacker, Unit* victim, uint32& damage) { FOREACH_SCRIPT(UnitScript)->OnDamage(attacker, victim, damage); + FOREACH_SCRIPT(PlayerScript)->OnDamage(attacker, victim, damage); } void ScriptMgr::ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage) { FOREACH_SCRIPT(UnitScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage); + FOREACH_SCRIPT(PlayerScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage); } void ScriptMgr::ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage) { FOREACH_SCRIPT(UnitScript)->ModifyMeleeDamage(target, attacker, damage); + FOREACH_SCRIPT(PlayerScript)->ModifyMeleeDamage(target, attacker, damage); } void ScriptMgr::ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage) { FOREACH_SCRIPT(UnitScript)->ModifySpellDamageTaken(target, attacker, damage); + FOREACH_SCRIPT(PlayerScript)->ModifySpellDamageTaken(target, attacker, damage); } SpellScriptLoader::SpellScriptLoader(const char* name) : ScriptObject(name) { - ScriptRegistry<SpellScriptLoader>::AddScript(this); + ScriptRegistry<SpellScriptLoader>::Instance()->AddScript(this); } ServerScript::ServerScript(const char* name) : ScriptObject(name) { - ScriptRegistry<ServerScript>::AddScript(this); + ScriptRegistry<ServerScript>::Instance()->AddScript(this); } WorldScript::WorldScript(const char* name) : ScriptObject(name) { - ScriptRegistry<WorldScript>::AddScript(this); + ScriptRegistry<WorldScript>::Instance()->AddScript(this); } FormulaScript::FormulaScript(const char* name) : ScriptObject(name) { - ScriptRegistry<FormulaScript>::AddScript(this); + ScriptRegistry<FormulaScript>::Instance()->AddScript(this); } UnitScript::UnitScript(const char* name, bool addToScripts) : ScriptObject(name) { - ScriptRegistry<UnitScript>::AddScript(this, addToScripts); + if (addToScripts) + ScriptRegistry<UnitScript>::Instance()->AddScript(this); } WorldMapScript::WorldMapScript(const char* name, uint32 mapId) @@ -1551,7 +2288,7 @@ WorldMapScript::WorldMapScript(const char* name, uint32 mapId) if (GetEntry() && !GetEntry()->IsWorldMap()) TC_LOG_ERROR("scripts", "WorldMapScript for map %u is invalid.", mapId); - ScriptRegistry<WorldMapScript>::AddScript(this); + ScriptRegistry<WorldMapScript>::Instance()->AddScript(this); } InstanceMapScript::InstanceMapScript(const char* name, uint32 mapId) @@ -1560,7 +2297,7 @@ InstanceMapScript::InstanceMapScript(const char* name, uint32 mapId) if (GetEntry() && !GetEntry()->IsDungeon()) TC_LOG_ERROR("scripts", "InstanceMapScript for map %u is invalid.", mapId); - ScriptRegistry<InstanceMapScript>::AddScript(this); + ScriptRegistry<InstanceMapScript>::Instance()->AddScript(this); } BattlegroundMapScript::BattlegroundMapScript(const char* name, uint32 mapId) @@ -1569,156 +2306,141 @@ BattlegroundMapScript::BattlegroundMapScript(const char* name, uint32 mapId) if (GetEntry() && !GetEntry()->IsBattleground()) TC_LOG_ERROR("scripts", "BattlegroundMapScript for map %u is invalid.", mapId); - ScriptRegistry<BattlegroundMapScript>::AddScript(this); + ScriptRegistry<BattlegroundMapScript>::Instance()->AddScript(this); } ItemScript::ItemScript(const char* name) : ScriptObject(name) { - ScriptRegistry<ItemScript>::AddScript(this); + ScriptRegistry<ItemScript>::Instance()->AddScript(this); } CreatureScript::CreatureScript(const char* name) : UnitScript(name, false) { - ScriptRegistry<CreatureScript>::AddScript(this); + ScriptRegistry<CreatureScript>::Instance()->AddScript(this); } GameObjectScript::GameObjectScript(const char* name) : ScriptObject(name) { - ScriptRegistry<GameObjectScript>::AddScript(this); + ScriptRegistry<GameObjectScript>::Instance()->AddScript(this); } AreaTriggerScript::AreaTriggerScript(const char* name) : ScriptObject(name) { - ScriptRegistry<AreaTriggerScript>::AddScript(this); + ScriptRegistry<AreaTriggerScript>::Instance()->AddScript(this); } BattlegroundScript::BattlegroundScript(const char* name) : ScriptObject(name) { - ScriptRegistry<BattlegroundScript>::AddScript(this); + ScriptRegistry<BattlegroundScript>::Instance()->AddScript(this); } OutdoorPvPScript::OutdoorPvPScript(const char* name) : ScriptObject(name) { - ScriptRegistry<OutdoorPvPScript>::AddScript(this); + ScriptRegistry<OutdoorPvPScript>::Instance()->AddScript(this); } CommandScript::CommandScript(const char* name) : ScriptObject(name) { - ScriptRegistry<CommandScript>::AddScript(this); + ScriptRegistry<CommandScript>::Instance()->AddScript(this); } WeatherScript::WeatherScript(const char* name) : ScriptObject(name) { - ScriptRegistry<WeatherScript>::AddScript(this); + ScriptRegistry<WeatherScript>::Instance()->AddScript(this); } AuctionHouseScript::AuctionHouseScript(const char* name) : ScriptObject(name) { - ScriptRegistry<AuctionHouseScript>::AddScript(this); + ScriptRegistry<AuctionHouseScript>::Instance()->AddScript(this); } ConditionScript::ConditionScript(const char* name) : ScriptObject(name) { - ScriptRegistry<ConditionScript>::AddScript(this); + ScriptRegistry<ConditionScript>::Instance()->AddScript(this); } VehicleScript::VehicleScript(const char* name) : ScriptObject(name) { - ScriptRegistry<VehicleScript>::AddScript(this); + ScriptRegistry<VehicleScript>::Instance()->AddScript(this); } DynamicObjectScript::DynamicObjectScript(const char* name) : ScriptObject(name) { - ScriptRegistry<DynamicObjectScript>::AddScript(this); + ScriptRegistry<DynamicObjectScript>::Instance()->AddScript(this); } TransportScript::TransportScript(const char* name) : ScriptObject(name) { - ScriptRegistry<TransportScript>::AddScript(this); + ScriptRegistry<TransportScript>::Instance()->AddScript(this); } AchievementCriteriaScript::AchievementCriteriaScript(const char* name) : ScriptObject(name) { - ScriptRegistry<AchievementCriteriaScript>::AddScript(this); + ScriptRegistry<AchievementCriteriaScript>::Instance()->AddScript(this); } PlayerScript::PlayerScript(const char* name) : UnitScript(name, false) { - ScriptRegistry<PlayerScript>::AddScript(this); + ScriptRegistry<PlayerScript>::Instance()->AddScript(this); } AccountScript::AccountScript(const char* name) : ScriptObject(name) { - ScriptRegistry<AccountScript>::AddScript(this); + ScriptRegistry<AccountScript>::Instance()->AddScript(this); } GuildScript::GuildScript(const char* name) : ScriptObject(name) { - ScriptRegistry<GuildScript>::AddScript(this); + ScriptRegistry<GuildScript>::Instance()->AddScript(this); } GroupScript::GroupScript(const char* name) : ScriptObject(name) { - ScriptRegistry<GroupScript>::AddScript(this); + ScriptRegistry<GroupScript>::Instance()->AddScript(this); } -// Instantiate static members of ScriptRegistry. -template<class TScript> std::map<uint32, TScript*> ScriptRegistry<TScript>::ScriptPointerList; -template<class TScript> std::vector<TScript*> ScriptRegistry<TScript>::Scripts; -template<class TScript> uint32 ScriptRegistry<TScript>::_scriptIdCounter = 0; - // Specialize for each script type class like so: -template class ScriptRegistry<SpellScriptLoader>; -template class ScriptRegistry<ServerScript>; -template class ScriptRegistry<WorldScript>; -template class ScriptRegistry<FormulaScript>; -template class ScriptRegistry<WorldMapScript>; -template class ScriptRegistry<InstanceMapScript>; -template class ScriptRegistry<BattlegroundMapScript>; -template class ScriptRegistry<ItemScript>; -template class ScriptRegistry<CreatureScript>; -template class ScriptRegistry<GameObjectScript>; -template class ScriptRegistry<AreaTriggerScript>; -template class ScriptRegistry<BattlegroundScript>; -template class ScriptRegistry<OutdoorPvPScript>; -template class ScriptRegistry<CommandScript>; -template class ScriptRegistry<WeatherScript>; -template class ScriptRegistry<AuctionHouseScript>; -template class ScriptRegistry<ConditionScript>; -template class ScriptRegistry<VehicleScript>; -template class ScriptRegistry<DynamicObjectScript>; -template class ScriptRegistry<TransportScript>; -template class ScriptRegistry<AchievementCriteriaScript>; -template class ScriptRegistry<PlayerScript>; -template class ScriptRegistry<GuildScript>; -template class ScriptRegistry<GroupScript>; -template class ScriptRegistry<UnitScript>; -template class ScriptRegistry<AccountScript>; - -// Undefine utility macros. -#undef GET_SCRIPT_RET -#undef GET_SCRIPT -#undef FOREACH_SCRIPT -#undef FOR_SCRIPTS_RET -#undef FOR_SCRIPTS -#undef SCR_REG_LST -#undef SCR_REG_ITR -#undef SCR_REG_MAP +template class TC_GAME_API ScriptRegistry<SpellScriptLoader>; +template class TC_GAME_API ScriptRegistry<ServerScript>; +template class TC_GAME_API ScriptRegistry<WorldScript>; +template class TC_GAME_API ScriptRegistry<FormulaScript>; +template class TC_GAME_API ScriptRegistry<WorldMapScript>; +template class TC_GAME_API ScriptRegistry<InstanceMapScript>; +template class TC_GAME_API ScriptRegistry<BattlegroundMapScript>; +template class TC_GAME_API ScriptRegistry<ItemScript>; +template class TC_GAME_API ScriptRegistry<CreatureScript>; +template class TC_GAME_API ScriptRegistry<GameObjectScript>; +template class TC_GAME_API ScriptRegistry<AreaTriggerScript>; +template class TC_GAME_API ScriptRegistry<BattlegroundScript>; +template class TC_GAME_API ScriptRegistry<OutdoorPvPScript>; +template class TC_GAME_API ScriptRegistry<CommandScript>; +template class TC_GAME_API ScriptRegistry<WeatherScript>; +template class TC_GAME_API ScriptRegistry<AuctionHouseScript>; +template class TC_GAME_API ScriptRegistry<ConditionScript>; +template class TC_GAME_API ScriptRegistry<VehicleScript>; +template class TC_GAME_API ScriptRegistry<DynamicObjectScript>; +template class TC_GAME_API ScriptRegistry<TransportScript>; +template class TC_GAME_API ScriptRegistry<AchievementCriteriaScript>; +template class TC_GAME_API ScriptRegistry<PlayerScript>; +template class TC_GAME_API ScriptRegistry<GuildScript>; +template class TC_GAME_API ScriptRegistry<GroupScript>; +template class TC_GAME_API ScriptRegistry<UnitScript>; +template class TC_GAME_API ScriptRegistry<AccountScript>; diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 8a00305b4da..cc1b65fa593 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -46,6 +46,7 @@ class InstanceMap; class InstanceScript; class Item; class Map; +class ModuleReference; class OutdoorPvP; class Player; class Quest; @@ -147,7 +148,7 @@ struct OutdoorPvPData; event on all registered scripts of that type. */ -class ScriptObject +class TC_GAME_API ScriptObject { friend class ScriptMgr; @@ -157,14 +158,8 @@ class ScriptObject protected: - ScriptObject(const char* name) - : _name(name) - { - } - - virtual ~ScriptObject() - { - } + ScriptObject(const char* name); + virtual ~ScriptObject(); private: @@ -186,7 +181,7 @@ template<class TObject> class UpdatableScript virtual void OnUpdate(TObject* /*obj*/, uint32 /*diff*/) { } }; -class SpellScriptLoader : public ScriptObject +class TC_GAME_API SpellScriptLoader : public ScriptObject { protected: @@ -201,7 +196,7 @@ class SpellScriptLoader : public ScriptObject virtual AuraScript* GetAuraScript() const { return NULL; } }; -class ServerScript : public ScriptObject +class TC_GAME_API ServerScript : public ScriptObject { protected: @@ -229,13 +224,9 @@ class ServerScript : public ScriptObject // Called when a (valid) packet is received by a client. The packet object is a copy of the original packet, so // reading and modifying it is safe. Make sure to check WorldSession pointer before usage, it might be null in case of auth packets virtual void OnPacketReceive(WorldSession* /*session*/, WorldPacket& /*packet*/) { } - - // Called when an invalid (unknown opcode) packet is received by a client. The packet is a reference to the orignal - // packet; not a copy. This allows you to actually handle unknown packets (for whatever purpose). - virtual void OnUnknownPacketReceive(WorldSession* /*session*/, WorldPacket& /*packet*/) { } }; -class WorldScript : public ScriptObject +class TC_GAME_API WorldScript : public ScriptObject { protected: @@ -268,7 +259,7 @@ class WorldScript : public ScriptObject virtual void OnShutdown() { } }; -class FormulaScript : public ScriptObject +class TC_GAME_API FormulaScript : public ScriptObject { protected: @@ -335,14 +326,15 @@ template<class TMap> class MapScript : public UpdatableScript<TMap> virtual void OnPlayerLeave(TMap* /*map*/, Player* /*player*/) { } }; -class WorldMapScript : public ScriptObject, public MapScript<Map> +class TC_GAME_API WorldMapScript : public ScriptObject, public MapScript<Map> { protected: WorldMapScript(const char* name, uint32 mapId); }; -class InstanceMapScript : public ScriptObject, public MapScript<InstanceMap> +class TC_GAME_API InstanceMapScript + : public ScriptObject, public MapScript<InstanceMap> { protected: @@ -354,14 +346,14 @@ class InstanceMapScript : public ScriptObject, public MapScript<InstanceMap> virtual InstanceScript* GetInstanceScript(InstanceMap* /*map*/) const { return NULL; } }; -class BattlegroundMapScript : public ScriptObject, public MapScript<BattlegroundMap> +class TC_GAME_API BattlegroundMapScript : public ScriptObject, public MapScript<BattlegroundMap> { protected: BattlegroundMapScript(const char* name, uint32 mapId); }; -class ItemScript : public ScriptObject +class TC_GAME_API ItemScript : public ScriptObject { protected: @@ -385,7 +377,7 @@ class ItemScript : public ScriptObject virtual bool OnRemove(Player* /*player*/, Item* /*item*/) { return false; } }; -class UnitScript : public ScriptObject +class TC_GAME_API UnitScript : public ScriptObject { protected: @@ -408,7 +400,7 @@ class UnitScript : public ScriptObject virtual void ModifySpellDamageTaken(Unit* /*target*/, Unit* /*attacker*/, int32& /*damage*/) { } }; -class CreatureScript : public UnitScript, public UpdatableScript<Creature> +class TC_GAME_API CreatureScript : public UnitScript, public UpdatableScript<Creature> { protected: @@ -444,7 +436,7 @@ class CreatureScript : public UnitScript, public UpdatableScript<Creature> virtual CreatureAI* GetAI(Creature* /*creature*/) const { return NULL; } }; -class GameObjectScript : public ScriptObject, public UpdatableScript<GameObject> +class TC_GAME_API GameObjectScript : public ScriptObject, public UpdatableScript<GameObject> { protected: @@ -489,7 +481,7 @@ class GameObjectScript : public ScriptObject, public UpdatableScript<GameObject> virtual GameObjectAI* GetAI(GameObject* /*go*/) const { return NULL; } }; -class AreaTriggerScript : public ScriptObject +class TC_GAME_API AreaTriggerScript : public ScriptObject { protected: @@ -501,7 +493,7 @@ class AreaTriggerScript : public ScriptObject virtual bool OnTrigger(Player* /*player*/, AreaTriggerEntry const* /*trigger*/) { return false; } }; -class BattlegroundScript : public ScriptObject +class TC_GAME_API BattlegroundScript : public ScriptObject { protected: @@ -513,7 +505,7 @@ class BattlegroundScript : public ScriptObject virtual Battleground* GetBattleground() const = 0; }; -class OutdoorPvPScript : public ScriptObject +class TC_GAME_API OutdoorPvPScript : public ScriptObject { protected: @@ -525,7 +517,7 @@ class OutdoorPvPScript : public ScriptObject virtual OutdoorPvP* GetOutdoorPvP() const = 0; }; -class CommandScript : public ScriptObject +class TC_GAME_API CommandScript : public ScriptObject { protected: @@ -537,7 +529,7 @@ class CommandScript : public ScriptObject virtual std::vector<ChatCommand> GetCommands() const = 0; }; -class WeatherScript : public ScriptObject, public UpdatableScript<Weather> +class TC_GAME_API WeatherScript : public ScriptObject, public UpdatableScript<Weather> { protected: @@ -549,7 +541,7 @@ class WeatherScript : public ScriptObject, public UpdatableScript<Weather> virtual void OnChange(Weather* /*weather*/, WeatherState /*state*/, float /*grade*/) { } }; -class AuctionHouseScript : public ScriptObject +class TC_GAME_API AuctionHouseScript : public ScriptObject { protected: @@ -570,7 +562,7 @@ class AuctionHouseScript : public ScriptObject virtual void OnAuctionExpire(AuctionHouseObject* /*ah*/, AuctionEntry* /*entry*/) { } }; -class ConditionScript : public ScriptObject +class TC_GAME_API ConditionScript : public ScriptObject { protected: @@ -582,7 +574,7 @@ class ConditionScript : public ScriptObject virtual bool OnConditionCheck(Condition const* /*condition*/, ConditionSourceInfo& /*sourceInfo*/) { return true; } }; -class VehicleScript : public ScriptObject +class TC_GAME_API VehicleScript : public ScriptObject { protected: @@ -609,14 +601,14 @@ class VehicleScript : public ScriptObject virtual void OnRemovePassenger(Vehicle* /*veh*/, Unit* /*passenger*/) { } }; -class DynamicObjectScript : public ScriptObject, public UpdatableScript<DynamicObject> +class TC_GAME_API DynamicObjectScript : public ScriptObject, public UpdatableScript<DynamicObject> { protected: DynamicObjectScript(const char* name); }; -class TransportScript : public ScriptObject, public UpdatableScript<Transport> +class TC_GAME_API TransportScript : public ScriptObject, public UpdatableScript<Transport> { protected: @@ -637,7 +629,7 @@ class TransportScript : public ScriptObject, public UpdatableScript<Transport> virtual void OnRelocate(Transport* /*transport*/, uint32 /*waypointId*/, uint32 /*mapId*/, float /*x*/, float /*y*/, float /*z*/) { } }; -class AchievementCriteriaScript : public ScriptObject +class TC_GAME_API AchievementCriteriaScript : public ScriptObject { protected: @@ -649,7 +641,7 @@ class AchievementCriteriaScript : public ScriptObject virtual bool OnCheck(Player* source, Unit* target) = 0; }; -class PlayerScript : public UnitScript +class TC_GAME_API PlayerScript : public UnitScript { protected: @@ -746,7 +738,7 @@ class PlayerScript : public UnitScript virtual void OnQuestStatusChange(Player* /*player*/, uint32 /*questId*/, QuestStatus /*status*/) { } }; -class AccountScript : public ScriptObject +class TC_GAME_API AccountScript : public ScriptObject { protected: @@ -773,7 +765,7 @@ class AccountScript : public ScriptObject virtual void OnFailedPasswordChange(uint32 /*accountId*/) {} }; -class GuildScript : public ScriptObject +class TC_GAME_API GuildScript : public ScriptObject { protected: @@ -814,7 +806,7 @@ class GuildScript : public ScriptObject virtual void OnBankEvent(Guild* /*guild*/, uint8 /*eventType*/, uint8 /*tabId*/, ObjectGuid::LowType /*playerGuid*/, uint32 /*itemOrMoney*/, uint16 /*itemStackCount*/, uint8 /*destTabId*/) { } }; -class GroupScript : public ScriptObject +class TC_GAME_API GroupScript : public ScriptObject { protected: @@ -838,17 +830,8 @@ class GroupScript : public ScriptObject virtual void OnDisband(Group* /*group*/) { } }; -// Placed here due to ScriptRegistry::AddScript dependency. -#define sScriptMgr ScriptMgr::instance() - -// namespace -// { - typedef std::list<std::string> UnusedScriptNamesContainer; - extern UnusedScriptNamesContainer UnusedScriptNames; -// } - // Manages registration, loading, and execution of scripts. -class ScriptMgr +class TC_GAME_API ScriptMgr { friend class ScriptObject; @@ -856,22 +839,49 @@ class ScriptMgr ScriptMgr(); virtual ~ScriptMgr(); + void FillSpellSummary(); + void LoadDatabase(); + + void IncreaseScriptCount() { ++_scriptCount; } + void DecreaseScriptCount() { --_scriptCount; } + public: /* Initialization */ - static ScriptMgr* instance() - { - static ScriptMgr instance; - return &instance; - } + static ScriptMgr* instance(); void Initialize(); - void LoadDatabase(); - void FillSpellSummary(); - const char* ScriptsVersion() const { return "Integrated Trinity Scripts"; } - - void IncrementScriptCount() { ++_scriptCount; } uint32 GetScriptCount() const { return _scriptCount; } + typedef void(*ScriptLoaderCallbackType)(); + + /// Sets the script loader callback which is invoked to load scripts + /// (Workaround for circular dependency game <-> scripts) + void SetScriptLoader(ScriptLoaderCallbackType script_loader_callback) + { + _script_loader_callback = script_loader_callback; + } + + public: /* Script contexts */ + /// Set the current script context, which allows the ScriptMgr + /// to accept new scripts in this context. + /// Requires a SwapScriptContext() call afterwards to load the new scripts. + void SetScriptContext(std::string const& context); + /// Returns the current script context. + std::string const& GetCurrentScriptContext() const { return _currentContext; } + /// Releases all scripts associated with the given script context immediately. + /// Requires a SwapScriptContext() call afterwards to finish the unloading. + void ReleaseScriptContext(std::string const& context); + /// Executes all changed introduced by SetScriptContext and ReleaseScriptContext. + /// It is possible to combine multiple SetScriptContext and ReleaseScriptContext + /// calls for better performance (bulk changes). + void SwapScriptContext(bool initialize = false); + + /// Acquires a strong module reference to the module containing the given script name, + /// which prevents the shared library which contains the script from unloading. + /// The shared library is lazy unloaded as soon as all references to it are released. + std::shared_ptr<ModuleReference> AcquireModuleReferenceOfScriptName( + std::string const& scriptname) const; + public: /* Unloading */ void Unload(); @@ -880,7 +890,7 @@ class ScriptMgr void CreateSpellScripts(uint32 spellId, std::list<SpellScript*>& scriptVector); void CreateAuraScripts(uint32 spellId, std::list<AuraScript*>& scriptVector); - void CreateSpellScriptLoaders(uint32 spellId, std::vector<std::pair<SpellScriptLoader*, std::multimap<uint32, uint32>::iterator> >& scriptVector); + SpellScriptLoader* GetSpellScriptLoader(uint32 scriptId); public: /* ServerScript */ @@ -890,7 +900,6 @@ class ScriptMgr void OnSocketClose(std::shared_ptr<WorldSocket> socket); void OnPacketReceive(WorldSession* session, WorldPacket const& packet); void OnPacketSend(WorldSession* session, WorldPacket const& packet); - void OnUnknownPacketReceive(WorldSession* session, WorldPacket const& packet); public: /* WorldScript */ @@ -1094,19 +1103,14 @@ class ScriptMgr void ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage); void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage); - public: /* Scheduled scripts */ - - uint32 IncreaseScheduledScriptsCount() { return ++_scheduledScripts; } - uint32 DecreaseScheduledScriptCount() { return --_scheduledScripts; } - uint32 DecreaseScheduledScriptCount(size_t count) { return _scheduledScripts -= count; } - bool IsScriptScheduled() const { return _scheduledScripts > 0; } - private: - uint32 _scriptCount; - //atomic op counter for active scripts amount - std::atomic<uint32> _scheduledScripts; + ScriptLoaderCallbackType _script_loader_callback; + + std::string _currentContext; }; +#define sScriptMgr ScriptMgr::instance() + #endif diff --git a/src/server/game/Scripting/ScriptReloadMgr.cpp b/src/server/game/Scripting/ScriptReloadMgr.cpp new file mode 100644 index 00000000000..aac0e26f02b --- /dev/null +++ b/src/server/game/Scripting/ScriptReloadMgr.cpp @@ -0,0 +1,1520 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptReloadMgr.h" +#include "Errors.h" + +#ifndef TRINITY_API_USE_DYNAMIC_LINKING + +// This method should never be called +std::shared_ptr<ModuleReference> + ScriptReloadMgr::AcquireModuleReferenceOfContext(std::string const& /*context*/) +{ + WPAbort(); +} + +// Returns the empty implemented ScriptReloadMgr +ScriptReloadMgr* ScriptReloadMgr::instance() +{ + static ScriptReloadMgr instance; + return &instance; +} + +#else + +#include <algorithm> +#include <regex> +#include <vector> +#include <future> +#include <memory> +#include <fstream> +#include <type_traits> +#include <unordered_set> +#include <unordered_map> + +#include <boost/algorithm/string/replace.hpp> +#include <boost/filesystem.hpp> +#include <boost/system/system_error.hpp> + +#include "efsw/efsw.hpp" + +#include "Log.h" +#include "Config.h" +#include "BuiltInConfig.h" +#include "ScriptMgr.h" +#include "StartProcess.h" +#include "MPSCQueue.h" +#include "GitRevision.h" + +namespace fs = boost::filesystem; + +#ifdef _WIN32 + #include <windows.h> +#else // Posix + #include <dlfcn.h> +#endif + +// Promote the sScriptReloadMgr to a HotSwapScriptReloadMgr +// in this compilation unit. +#undef sScriptReloadMgr +#define sScriptReloadMgr static_cast<HotSwapScriptReloadMgr*>(ScriptReloadMgr::instance()) + +// Returns "" on Windows and "lib" on posix. +static char const* GetSharedLibraryPrefix() +{ +#ifdef _WIN32 + return ""; +#else // Posix + return "lib"; +#endif +} + +// Returns "dll" on Windows and "so" on posix. +static char const* GetSharedLibraryExtension() +{ +#ifdef _WIN32 + return "dll"; +#else // Posix + return "so"; +#endif +} + +#ifdef _WIN32 +typedef HMODULE HandleType; +#else // Posix +typedef void* HandleType; +#endif + +class SharedLibraryUnloader +{ +public: + SharedLibraryUnloader() + : _path() { } + explicit SharedLibraryUnloader(fs::path const& path) + : _path(path) { } + + void operator() (HandleType handle) const + { + // Unload the associated shared library. +#ifdef _WIN32 + bool success = (FreeLibrary(handle) != 0); +#else // Posix + bool success = (dlclose(handle) == 0); +#endif + + if (!success) + { + TC_LOG_ERROR("scripts.hotswap", "Failed to unload (syscall) the shared library \"%s\".", + _path.generic_string().c_str()); + + return; + } + + boost::system::error_code error; + if (fs::remove(_path, error)) + { + TC_LOG_TRACE("scripts.hotswap", "Lazy unloaded and deleted the shared library \"%s\".", + _path.generic_string().c_str()); + } + else + { + TC_LOG_ERROR("scripts.hotswap", "Failed to delete the shared library \"%s\" (%s).", + _path.generic_string().c_str(), error.message().c_str()); + } + } + +private: + fs::path _path; +}; + +typedef std::unique_ptr<typename std::remove_pointer<HandleType>::type, SharedLibraryUnloader> HandleHolder; + +typedef char const* (*GetScriptModuleRevisionHashType)(); +typedef void (*AddScriptsType)(); +typedef char const* (*GetScriptModuleType)(); +typedef char const* (*GetBuildDirectiveType)(); + +class ScriptModule + : public ModuleReference +{ +public: + explicit ScriptModule(HandleHolder handle, GetScriptModuleRevisionHashType getScriptModuleRevisionHash, + AddScriptsType addScripts, GetScriptModuleType getScriptModule, + GetBuildDirectiveType getBuildDirective, fs::path const& path) + : _handle(std::forward<HandleHolder>(handle)), _getScriptModuleRevisionHash(getScriptModuleRevisionHash), + _addScripts(addScripts), _getScriptModule(getScriptModule), + _getBuildDirective(getBuildDirective), _path(path) { } + + ScriptModule(ScriptModule const&) = delete; + ScriptModule(ScriptModule&& right) = delete; + + ScriptModule& operator= (ScriptModule const&) = delete; + ScriptModule& operator= (ScriptModule&& right) = delete; + + static Optional<std::shared_ptr<ScriptModule>> CreateFromPath(fs::path const& path); + + char const* GetScriptModuleRevisionHash() const override + { + return _getScriptModuleRevisionHash(); + } + + void AddScripts() const + { + return _addScripts(); + } + + char const* GetScriptModule() const override + { + return _getScriptModule(); + } + + char const* GetBuildDirective() const + { + return _getBuildDirective(); + } + + fs::path const& GetModulePath() const override + { + return _path; + } + +private: + HandleHolder _handle; + + GetScriptModuleRevisionHashType _getScriptModuleRevisionHash; + AddScriptsType _addScripts; + GetScriptModuleType _getScriptModule; + GetBuildDirectiveType _getBuildDirective; + + fs::path _path; +}; + +template<typename Fn> +static bool GetFunctionFromSharedLibrary(HandleType handle, std::string const& name, Fn& fn) +{ +#ifdef _WIN32 + fn = reinterpret_cast<Fn>(GetProcAddress(handle, name.c_str())); +#else // Posix + fn = reinterpret_cast<Fn>(dlsym(handle, name.c_str())); +#endif + return fn != nullptr; +} + +// Load a shared library from the given path. +Optional<std::shared_ptr<ScriptModule>> ScriptModule::CreateFromPath(fs::path const& path) +{ +#ifdef _WIN32 + HandleType handle = LoadLibrary(path.generic_string().c_str()); +#else // Posix + HandleType handle = dlopen(path.c_str(), RTLD_LAZY); +#endif + + if (!handle) + { + TC_LOG_ERROR("scripts.hotswap", "Could not load the shared library \"%s\" for reading.", + path.generic_string().c_str()); + return boost::none; + } + + // Use RAII to release the library on failure. + HandleHolder holder(handle, SharedLibraryUnloader(path)); + + GetScriptModuleRevisionHashType getScriptModuleRevisionHash; + AddScriptsType addScripts; + GetScriptModuleType getScriptModule; + GetBuildDirectiveType getBuildDirective; + + if (GetFunctionFromSharedLibrary(handle, "GetScriptModuleRevisionHash", getScriptModuleRevisionHash) && + GetFunctionFromSharedLibrary(handle, "AddScripts", addScripts) && + GetFunctionFromSharedLibrary(handle, "GetScriptModule", getScriptModule) && + GetFunctionFromSharedLibrary(handle, "GetBuildDirective", getBuildDirective)) + return std::make_shared<ScriptModule>(std::move(holder), getScriptModuleRevisionHash, + addScripts, getScriptModule, getBuildDirective, path); + else + { + TC_LOG_ERROR("scripts.hotswap", "Could not extract all required functions from the shared library \"%s\"!", + path.generic_string().c_str()); + + return boost::none; + } +} + +static bool HasValidScriptModuleName(std::string const& name) +{ + // Detects scripts_NAME.dll's / .so's + static std::regex const regex( + Trinity::StringFormat("^%s[sS]cripts_[a-zA-Z0-9_]+\\.%s$", + GetSharedLibraryPrefix(), + GetSharedLibraryExtension())); + + return std::regex_match(name, regex); +} + +/// File watcher responsible for watching shared libraries +class LibraryUpdateListener : public efsw::FileWatchListener +{ +public: + LibraryUpdateListener() { } + virtual ~LibraryUpdateListener() { } + + void handleFileAction(efsw::WatchID /*watchid*/, std::string const& dir, + std::string const& filename, efsw::Action action, std::string oldFilename = "") final override; +}; + +static LibraryUpdateListener libraryUpdateListener; + +/// File watcher responsible for watching source files +class SourceUpdateListener : public efsw::FileWatchListener +{ + fs::path const path_; + + std::string const script_module_name_; + + efsw::WatchID const watcher_id_; + +public: + explicit SourceUpdateListener(fs::path path, std::string script_module_name); + + virtual ~SourceUpdateListener(); + + void handleFileAction(efsw::WatchID /*watchid*/, std::string const& dir, + std::string const& filename, efsw::Action action, std::string oldFilename = "") final override; +}; + +namespace std +{ + template <> + struct hash<fs::path> + { + hash<string> hasher; + + std::size_t operator()(fs::path const& key) const + { + return hasher(key.generic_string()); + } + }; +} + +/// Invokes a synchronous CMake process with the given arguments +template<typename... T> +static int InvokeCMakeCommand(T&&... args) +{ + auto const executable = BuiltInConfig::GetCMakeCommand(); + return Trinity::StartProcess(executable, { + executable, + std::forward<T>(args)... + }, "scripts.hotswap"); +} + +/// Invokes an asynchronous CMake process with the given arguments +template<typename... T> +static std::shared_ptr<Trinity::AsyncProcessResult> InvokeAsyncCMakeCommand(T&&... args) +{ + auto const executable = BuiltInConfig::GetCMakeCommand(); + return Trinity::StartAsyncProcess(executable, { + executable, + std::forward<T>(args)... + }, "scripts.hotswap"); +} + +/// Calculates the C++ project name of the given module which is +/// the lowercase string of scripts_${module}. +static std::string CalculateScriptModuleProjectName(std::string const& module) +{ + std::string module_project = "scripts_" + module; + std::transform(module_project.begin(), module_project.end(), + module_project.begin(), ::tolower); + + return module_project; +} + +/// Returns false when there isn't any attached debugger to the process which +/// could block the rebuild of new shared libraries. +static bool IsDebuggerBlockingRebuild() +{ +#ifdef _WIN32 + if (IsDebuggerPresent()) + return true; +#endif + return false; +} + +/// ScriptReloadMgr which is used when dynamic linking is enabled +/// +/// This class manages shared library loading/unloading through watching +/// the script module directory. Loaded shared libraries are mirrored +/// into a .cache subdirectory to allow lazy unloading as long as +/// the shared library is still used which is useful for scripts +/// which can't be instantly replaced like spells or instances. +/// Several modules which reference different versions can be kept loaded +/// to serve scripts of different versions to entities and spells. +/// +/// Also this class invokes rebuilds as soon as the source of loaded +/// scripts change and installs the modules correctly through CMake. +class HotSwapScriptReloadMgr final + : public ScriptReloadMgr +{ + friend class ScriptReloadMgr; + friend class SourceUpdateListener; + + /// Reflects a queued change on a shared library or shared library + /// which is waiting for processing + enum class ChangeStateRequest : uint8 + { + CHANGE_REQUEST_ADDED, + CHANGE_REQUEST_MODIFIED, + CHANGE_REQUEST_REMOVED + }; + + /// Reflects a running job of an invoked asynchronous external process + enum class BuildJobType : uint8 + { + BUILD_JOB_NONE, + BUILD_JOB_RERUN_CMAKE, + BUILD_JOB_COMPILE, + BUILD_JOB_INSTALL, + }; + + // Represents a job which was invoked through a source or shared library change + class BuildJob + { + // Script module which is processed in the current running job + std::string script_module_name_; + // The C++ project name of the module which is processed + std::string script_module_project_name_; + // The build directive of the current module which is processed + // like "Release" or "Debug". The build directive from the + // previous same module is used if there was any. + std::string script_module_build_directive_; + + // Type of the current running job + BuildJobType type_; + // The async process result of the current job + std::shared_ptr<Trinity::AsyncProcessResult> async_result_; + + public: + explicit BuildJob(std::string script_module_name, std::string script_module_project_name, + std::string script_module_build_directive) + : script_module_name_(std::move(script_module_name)), + script_module_project_name_(std::move(script_module_project_name)), + script_module_build_directive_(std::move(script_module_build_directive)), + type_(BuildJobType::BUILD_JOB_NONE) { } + + bool IsValid() const + { + return type_ != BuildJobType::BUILD_JOB_NONE; + } + + std::string const& GetModuleName() const { return script_module_name_; } + + std::string const& GetProjectName() const { return script_module_project_name_; } + + std::string const& GetBuildDirective() const { return script_module_build_directive_; } + + BuildJobType GetType() const { return type_; } + + std::shared_ptr<Trinity::AsyncProcessResult> const& GetProcess() const + { + ASSERT(async_result_, "Tried to access an empty process handle!"); + return async_result_; + } + + /// Updates the current running job with the given type and async result + void UpdateCurrentJob(BuildJobType type, + std::shared_ptr<Trinity::AsyncProcessResult> async_result) + { + ASSERT(type != BuildJobType::BUILD_JOB_NONE, "None isn't allowed here!"); + ASSERT(async_result, "The async result must not be empty!"); + + type_ = type; + async_result_ = std::move(async_result); + } + }; + + /// Base class for lockfree asynchronous messages to the script reloader + class ScriptReloaderMessage + { + public: + virtual ~ScriptReloaderMessage() { } + + /// Invoke this function to run a message thread safe on the reloader + virtual void operator() (HotSwapScriptReloadMgr* reloader) = 0; + }; + + /// Implementation class which wraps functional types and dispatches + /// it in the overwritten implementation of the reloader messages. + template<typename T> + class ScriptReloaderMessageImplementation + : public ScriptReloaderMessage + { + T dispatcher_; + + public: + explicit ScriptReloaderMessageImplementation(T dispatcher) + : dispatcher_(std::move(dispatcher)) { } + + void operator() (HotSwapScriptReloadMgr* reloader) final override + { + dispatcher_(reloader); + } + }; + + /// Uses the given functional type and creates a asynchronous reloader + /// message on the heap, which requires deletion. + template<typename T> + auto MakeMessage(T&& dispatcher) + -> ScriptReloaderMessageImplementation<typename std::decay<T>::type>* + { + return new ScriptReloaderMessageImplementation<typename std::decay<T>::type> + (std::forward<T>(dispatcher)); + } + +public: + HotSwapScriptReloadMgr() + : _libraryWatcher(-1), _unique_library_name_counter(0), + _last_time_library_changed(0), _last_time_sources_changed(0), + _last_time_user_informed(0), terminate_early(false) { } + + virtual ~HotSwapScriptReloadMgr() + { + // Delete all messages + ScriptReloaderMessage* message; + while (_messages.Dequeue(message)) + delete message; + } + + /// Returns the absolute path to the script module directory + static fs::path GetLibraryDirectory() + { + return fs::absolute(sConfigMgr->GetStringDefault("HotSwap.ScriptDir", "scripts")); + } + + /// Returns the absolute path to the scripts directory in the source tree. + static fs::path GetSourceDirectory() + { + fs::path dir = BuiltInConfig::GetSourceDirectory(); + dir /= "src"; + dir /= "server"; + dir /= "scripts"; + return dir; + } + + /// Initializes the file watchers and loads all existing shared libraries + /// into the running server. + void Initialize() final override + { + if (!sWorld->getBoolConfig(CONFIG_HOTSWAP_ENABLED)) + return; + + if (BuiltInConfig::GetBuildDirectory().find(" ") != std::string::npos) + { + TC_LOG_ERROR("scripts.hotswap", "Your build directory path \"%s\" " + "contains spaces, which isn't allowed for compatibility reasons! " + "You need to create a build directory which doesn't contain any space character " + "in it's path!", + BuiltInConfig::GetBuildDirectory().c_str()); + + return; + } + + { + auto const library_directory = GetLibraryDirectory(); + if (!fs::exists(library_directory) || !fs::is_directory(library_directory)) + { + TC_LOG_ERROR("scripts.hotswap", "Library directory \"%s\" doesn't exist!.", + library_directory.generic_string().c_str()); + return; + } + } + + // Get the cache directory path + fs::path const cache_path = [] + { + auto path = fs::absolute(sScriptReloadMgr->GetLibraryDirectory()); + path /= ".cache"; + return path; + }(); + + // We use the boost filesystem function versions which accept + // an error code to prevent it from throwing exceptions. + boost::system::error_code code; + if ((!fs::exists(cache_path, code) || (fs::remove_all(cache_path, code) > 0)) && + !fs::create_directory(cache_path, code)) + { + TC_LOG_ERROR("scripts.hotswap", "Couldn't create the cache directory \"%s\".", + cache_path.generic_string().c_str()); + return; + } + + // Used to silent compiler warnings + (void)code; + + // Correct the CMake prefix when needed + if (sWorld->getBoolConfig(CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED)) + DoCMakePrefixCorrectionIfNeeded(); + + InitializeDefaultLibraries(); + InitializeFileWatchers(); + } + + /// Needs to be called periodically from the worldserver loop + /// to invoke queued actions like module loading/unloading and script + /// compilation. + /// This method should be invoked from a thread safe point to + /// prevent misbehavior. + void Update() final override + { + // Consume all messages + ScriptReloaderMessage* message; + while (_messages.Dequeue(message)) + { + (*message)(this); + delete message; + } + + DispatchRunningBuildJobs(); + DispatchModuleChanges(); + } + + /// Unloads the manager and cancels all runnings jobs immediately + void Unload() final override + { + if (_libraryWatcher >= 0) + { + _fileWatcher.removeWatch(_libraryWatcher); + _libraryWatcher = -1; + } + + // If a build is in progress cancel it + if (_build_job) + { + _build_job->GetProcess()->Terminate(); + _build_job.reset(); + } + + // Release all strong references to script modules + // to trigger unload actions as early as possible, + // otherwise the worldserver will crash on exit. + _running_script_modules.clear(); + } + + /// Queue's a thread safe message to the reloader which is executed on + /// the next world server update tick. + template<typename T> + void QueueMessage(T&& message) + { + _messages.Enqueue(MakeMessage(std::forward<T>(message))); + } + + /// Queues an action which marks the given shared library as changed + /// which will add, unload or reload it at the next world update tick. + /// This method is thread safe. + void QueueSharedLibraryChanged(fs::path const& path) + { + _last_time_library_changed = getMSTime(); + _libraries_changed.insert(path); + } + + /// Queues a notification that a source file was added + /// This method is thread unsafe. + void QueueAddSourceFile(std::string const& module_name, fs::path const& path) + { + UpdateSourceChangeRequest(module_name, path, ChangeStateRequest::CHANGE_REQUEST_ADDED); + } + + /// Queues a notification that a source file was modified + /// This method is thread unsafe. + void QueueModifySourceFile(std::string const& module_name, fs::path const& path) + { + UpdateSourceChangeRequest(module_name, path, ChangeStateRequest::CHANGE_REQUEST_MODIFIED); + } + + /// Queues a notification that a source file was removed + /// This method is thread unsafe. + void QueueRemoveSourceFile(std::string const& module_name, fs::path const& path) + { + UpdateSourceChangeRequest(module_name, path, ChangeStateRequest::CHANGE_REQUEST_REMOVED); + } + +private: + // Loads all shared libraries which are contained in the + // scripts directory on startup. + void InitializeDefaultLibraries() + { + fs::path const libraryDirectory(GetLibraryDirectory()); + fs::directory_iterator const dir_end; + + uint32 count = 0; + + // Iterate through all shared libraries in the script directory and load it + for (fs::directory_iterator dir_itr(libraryDirectory); dir_itr != dir_end ; ++dir_itr) + if (fs::is_regular_file(dir_itr->path()) && HasValidScriptModuleName(dir_itr->path().filename().generic_string())) + { + TC_LOG_INFO("scripts.hotswap", "Loading script module \"%s\"...", + dir_itr->path().filename().generic_string().c_str()); + + // Don't swap the script context to do bulk loading + ProcessLoadScriptModule(dir_itr->path(), false); + ++count; + } + + TC_LOG_INFO("scripts.hotswap", ">> Loaded %u script modules.", count); + } + + // Initialize all enabled file watchers. + // Needs to be called after InitializeDefaultLibraries()! + void InitializeFileWatchers() + { + _libraryWatcher = _fileWatcher.addWatch(GetLibraryDirectory().generic_string(), &libraryUpdateListener, false); + if (_libraryWatcher >= 0) + { + TC_LOG_INFO("scripts.hotswap", ">> Library reloader is listening on \"%s\".", + GetLibraryDirectory().generic_string().c_str()); + } + else + { + TC_LOG_ERROR("scripts.hotswap", "Failed to initialize the library reloader on \"%s\".", + GetLibraryDirectory().generic_string().c_str()); + } + + _fileWatcher.watch(); + } + + /// Updates the current state of the given source path + void UpdateSourceChangeRequest(std::string const& module_name, + fs::path const& path, + ChangeStateRequest state) + { + _last_time_sources_changed = getMSTime(); + + // Write when there is no module with the given name known + auto module_itr = _sources_changed.find(module_name); + + // When the file was modified it's enough to mark the module as + // dirty by initializing the associated map. + if (module_itr == _sources_changed.end()) + module_itr = _sources_changed.insert(std::make_pair( + module_name, decltype(_sources_changed)::mapped_type{})).first; + + // Leave when the file was just modified as explained above + if (state == ChangeStateRequest::CHANGE_REQUEST_MODIFIED) + return; + + // Insert when the given path isn't existent + auto const itr = module_itr->second.find(path); + if (itr == module_itr->second.end()) + { + module_itr->second.insert(std::make_pair(path, state)); + return; + } + + ASSERT((itr->second == ChangeStateRequest::CHANGE_REQUEST_ADDED) + || (itr->second == ChangeStateRequest::CHANGE_REQUEST_REMOVED), + "Stored value is invalid!"); + + ASSERT((state == ChangeStateRequest::CHANGE_REQUEST_ADDED) + || (state == ChangeStateRequest::CHANGE_REQUEST_REMOVED), + "The given state is invalid!"); + + ASSERT(state != itr->second, + "Tried to apply a state which is stored already!"); + + module_itr->second.erase(itr); + } + + /// Called periodically on the worldserver tick to process all + /// load/unload/reload requests of shared libraries. + void DispatchModuleChanges() + { + // When there are no libraries to change return + if (_libraries_changed.empty()) + return; + + // Wait some time after changes to catch bulk changes + if (GetMSTimeDiffToNow(_last_time_library_changed) < 500) + return; + + for (auto const& path : _libraries_changed) + { + bool const is_running = + _running_script_module_names.find(path) != _running_script_module_names.end(); + + bool const exists = fs::exists(path); + + if (is_running) + { + if (exists) + ProcessReloadScriptModule(path); + else + ProcessUnloadScriptModule(path); + } + else if (exists) + ProcessLoadScriptModule(path); + } + + _libraries_changed.clear(); + } + + void ProcessLoadScriptModule(fs::path const& path, bool swap_context = true) + { + ASSERT(_running_script_module_names.find(path) == _running_script_module_names.end(), + "Can't load a module which is running already!"); + + // Create the cache path and increment the library counter to use an unique name for each library + fs::path cache_path = fs::absolute(sScriptReloadMgr->GetLibraryDirectory()); + cache_path /= ".cache"; + cache_path /= Trinity::StringFormat("%s.%u%s", + path.stem().generic_string().c_str(), + _unique_library_name_counter++, + path.extension().generic_string().c_str()); + + if ([&] + { + boost::system::error_code code; + fs::copy_file(path, cache_path, fs::copy_option::fail_if_exists, code); + return code; + }()) + { + TC_LOG_FATAL("scripts.hotswap", ">> Failed to create cache entry for module \"%s\"!", + path.filename().generic_string().c_str()); + + // Find a better solution for this but it's much better + // to start the core without scripts + std::this_thread::sleep_for(std::chrono::seconds(5)); + ABORT(); + return; + } + + auto module = ScriptModule::CreateFromPath(cache_path); + if (!module) + { + TC_LOG_FATAL("scripts.hotswap", ">> Failed to load script module \"%s\"!", + path.filename().generic_string().c_str()); + + // Find a better solution for this but it's much better + // to start the core without scripts + std::this_thread::sleep_for(std::chrono::seconds(5)); + ABORT(); + return; + } + + // Limit the git revision hash to 7 characters. + std::string module_revision((*module)->GetScriptModuleRevisionHash()); + if (module_revision.size() >= 7) + module_revision = module_revision.substr(0, 7); + + std::string const module_name = (*module)->GetScriptModule(); + TC_LOG_INFO("scripts.hotswap", ">> Loaded script module \"%s\" (\"%s\" - %s).", + path.filename().generic_string().c_str(), module_name.c_str(), module_revision.c_str()); + + if (module_revision.empty()) + { + TC_LOG_WARN("scripts.hotswap", ">> Script module \"%s\" has an empty revision hash!", + path.filename().generic_string().c_str()); + } + else + { + // Trim the revision hash + std::string my_revision_hash = GitRevision::GetHash(); + std::size_t const trim = std::min(module_revision.size(), my_revision_hash.size()); + my_revision_hash = my_revision_hash.substr(0, trim); + module_revision = module_revision.substr(0, trim); + + if (my_revision_hash != module_revision) + { + TC_LOG_WARN("scripts.hotswap", ">> Script module \"%s\" has a different revision hash! " + "Binary incompatibility could lead to unknown behaviour!", path.filename().generic_string().c_str()); + } + } + + { + auto const itr = _running_script_modules.find(module_name); + if (itr != _running_script_modules.end()) + { + TC_LOG_ERROR("scripts.hotswap", ">> Attempt to load a module twice \"%s\" (loaded module is at %s)!", + path.generic_string().c_str(), itr->second.first->GetModulePath().generic_string().c_str()); + + return; + } + } + + sScriptMgr->SetScriptContext(module_name); + (*module)->AddScripts(); + TC_LOG_TRACE("scripts.hotswap", ">> Registered all scripts of module %s.", module_name.c_str()); + + if (swap_context) + sScriptMgr->SwapScriptContext(); + + // Create the source listener + auto listener = Trinity::make_unique<SourceUpdateListener>( + sScriptReloadMgr->GetSourceDirectory() / module_name, + module_name); + + // Store the module + _known_modules_build_directives.insert(std::make_pair(module_name, (*module)->GetBuildDirective())); + _running_script_modules.insert(std::make_pair(module_name, + std::make_pair(std::move(*module), std::move(listener)))); + _running_script_module_names.insert(std::make_pair(path, module_name)); + } + + void ProcessReloadScriptModule(fs::path const& path) + { + ProcessUnloadScriptModule(path, false); + ProcessLoadScriptModule(path); + } + + void ProcessUnloadScriptModule(fs::path const& path, bool finish = true) + { + auto const itr = _running_script_module_names.find(path); + + ASSERT(itr != _running_script_module_names.end(), + "Can't unload a module which isn't running!"); + + // Unload the script context + sScriptMgr->ReleaseScriptContext(itr->second); + + if (finish) + sScriptMgr->SwapScriptContext(); + + TC_LOG_INFO("scripts.hotswap", "Released script module \"%s\" (\"%s\")...", + path.filename().generic_string().c_str(), itr->second.c_str()); + + // Unload the script module + auto ref = _running_script_modules.find(itr->second); + ASSERT(ref != _running_script_modules.end() && + "Expected the script reference to be present!"); + + // Yield a message when there are other owning references to + // the module which prevents it from unloading. + // The module will be unloaded once all scripts provided from the module + // are destroyed. + if (!ref->second.first.unique()) + { + TC_LOG_INFO("scripts.hotswap", + "Script module %s is still used by %lu spell, aura or instance scripts. " + "Will lazy unload the module once all scripts stopped using it, " + "to use the latest version of an edited script unbind yourself from " + "the instance or re-cast the spell.", + ref->second.first->GetScriptModule(), ref->second.first.use_count() - 1); + } + + // Remove the owning reference from the reloader + _running_script_modules.erase(ref); + _running_script_module_names.erase(itr); + } + + /// Called periodically on the worldserver tick to process all recompile + /// requests. This method invokes one build or install job at the time + void DispatchRunningBuildJobs() + { + if (_build_job) + { + // Terminate the current build job when an associated source was changed + // while compiling and the terminate early option is enabled. + if (sWorld->getBoolConfig(CONFIG_HOTSWAP_EARLY_TERMINATION_ENABLED)) + { + if (!terminate_early && _sources_changed.find(_build_job->GetModuleName()) != _sources_changed.end()) + { + /* + FIXME: Currently crashes the server + TC_LOG_INFO("scripts.hotswap", "Terminating the running build of module \"%s\"...", + _build_job->GetModuleName().c_str()); + + _build_job->GetProcess()->Terminate(); + _build_job.reset(); + + // Continue with the default execution path + DispatchRunningBuildJobs(); + return; + */ + + terminate_early = true; + return; + } + } + + // Wait for the current build job to finish, if the job finishes in time + // evaluate it and continue with the next one. + if (_build_job->GetProcess()->GetFutureResult(). + wait_for(std::chrono::seconds(0)) == std::future_status::ready) + ProcessReadyBuildJob(); + else + return; // Return when the job didn't finish in time + + // Skip this cycle when the previous job scheduled a new one + if (_build_job) + return; + } + + // Avoid burst updates through waiting for a short time after changes + if ((_last_time_sources_changed != 0) && + (GetMSTimeDiffToNow(_last_time_sources_changed) < 500)) + return; + + // If the changed sources are empty do nothing + if (_sources_changed.empty()) + return; + + // Wait until are attached debugger were detached. + if (IsDebuggerBlockingRebuild()) + { + if ((_last_time_user_informed == 0) || + (GetMSTimeDiffToNow(_last_time_user_informed) > 7500)) + { + _last_time_user_informed = getMSTime(); + + // Informs the user that the attached debugger is blocking the automatic script rebuild. + TC_LOG_INFO("scripts.hotswap", "Your attached debugger is blocking the TrinityCore " + "automatic script rebuild, please detach it!"); + } + + return; + } + + // Find all source files of a changed script module and removes + // it from the changed source list, invoke the build afterwards. + bool rebuild_buildfiles; + auto module_name = [&] + { + auto itr = _sources_changed.begin(); + auto name = itr->first; + rebuild_buildfiles = !itr->second.empty(); + + if (sLog->ShouldLog("scripts.hotswap", LogLevel::LOG_LEVEL_TRACE)) + for (auto const& entry : itr->second) + { + TC_LOG_TRACE("scripts.hotswap", "Source file %s was %s.", + entry.first.generic_string().c_str(), + ((entry.second == ChangeStateRequest::CHANGE_REQUEST_ADDED) ? + "added" : "removed")); + } + + _sources_changed.erase(itr); + return name; + }(); + + // Erase the added delete history all modules when we + // invoke a cmake rebuild since we add all + // added files of other modules to the build as well + if (rebuild_buildfiles) + { + for (auto& entry : _sources_changed) + entry.second.clear(); + } + + ASSERT(!module_name.empty(), + "The current module name is invalid!"); + + TC_LOG_INFO("scripts.hotswap", "Recompiling Module \"%s\"...", + module_name.c_str()); + + // Calculate the project name of the script module + auto project_name = CalculateScriptModuleProjectName(module_name); + + // Find the best build directive for the module + auto build_directive = [&] () -> std::string + { + auto directive = sConfigMgr->GetStringDefault("HotSwap.ReCompilerBuildType", ""); + if (!directive.empty()) + return directive; + + auto const itr = _known_modules_build_directives.find(module_name); + if (itr != _known_modules_build_directives.end()) + return itr->second; + else // If no build directive of the module was found use the one from the game library + return _BUILD_DIRECTIVE; + }(); + + // Initiate the new build job + _build_job = BuildJob(std::move(module_name), + std::move(project_name), std::move(build_directive)); + + // Rerun CMake when we need to recreate the build files + if (rebuild_buildfiles + && sWorld->getBoolConfig(CONFIG_HOTSWAP_BUILD_FILE_RECREATION_ENABLED)) + DoRerunCMake(); + else + DoCompileCurrentProcessedModule(); + } + + void ProcessReadyBuildJob() + { + ASSERT(_build_job->IsValid(), "Invalid build job!"); + + // Retrieve the result + auto const error = _build_job->GetProcess()->GetFutureResult().get(); + + if (terminate_early) + { + _build_job.reset(); + terminate_early = false; + return; + } + + switch (_build_job->GetType()) + { + case BuildJobType::BUILD_JOB_RERUN_CMAKE: + { + if (!error) + { + TC_LOG_INFO("scripts.hotswap", ">> Successfully updated the build files!"); + } + else + { + TC_LOG_INFO("scripts.hotswap", ">> Failed to update the build files at \"%s\", " + "it's possible that recently added sources are not included " + "in your next builds, rerun CMake manually.", + BuiltInConfig::GetBuildDirectory().c_str()); + } + // Continue with building the changes sources + DoCompileCurrentProcessedModule(); + return; + } + case BuildJobType::BUILD_JOB_COMPILE: + { + if (!error) // Build was successful + { + if (sWorld->getBoolConfig(CONFIG_HOTSWAP_INSTALL_ENABLED)) + { + // Continue with the installation when it's enabled + TC_LOG_INFO("scripts.hotswap", + ">> Successfully build module %s, continue with installing...", + _build_job->GetModuleName().c_str()); + + DoInstallCurrentProcessedModule(); + return; + } + + // Skip the installation because it's disabled in config + TC_LOG_INFO("scripts.hotswap", + ">> Successfully build module %s, skipped the installation.", + _build_job->GetModuleName().c_str()); + } + else // Build wasn't successful + { + TC_LOG_ERROR("scripts.hotswap", + ">> The build of module %s failed! See the log for details.", + _build_job->GetModuleName().c_str()); + } + break; + } + case BuildJobType::BUILD_JOB_INSTALL: + { + if (!error) + { + // Installation was successful + TC_LOG_INFO("scripts.hotswap", ">> Successfully installed module %s.", + _build_job->GetModuleName().c_str()); + } + else + { + // Installation wasn't successful + TC_LOG_INFO("scripts.hotswap", + ">> The installation of module %s failed! See the log for details.", + _build_job->GetModuleName().c_str()); + } + break; + } + default: + break; + } + + // Clear the current job + _build_job.reset(); + } + + /// Reruns CMake asynchronously over the build directory + void DoRerunCMake() + { + ASSERT(_build_job, "There isn't any active build job!"); + + TC_LOG_INFO("scripts.hotswap", "Rerunning CMake because there were sources added or removed..."); + + _build_job->UpdateCurrentJob(BuildJobType::BUILD_JOB_RERUN_CMAKE, + InvokeAsyncCMakeCommand(BuiltInConfig::GetBuildDirectory())); + } + + /// Invokes a new build of the current active module job + void DoCompileCurrentProcessedModule() + { + ASSERT(_build_job, "There isn't any active build job!"); + + TC_LOG_INFO("scripts.hotswap", "Starting asynchronous build job for module %s...", + _build_job->GetModuleName().c_str()); + + _build_job->UpdateCurrentJob(BuildJobType::BUILD_JOB_COMPILE, + InvokeAsyncCMakeCommand( + "--build", BuiltInConfig::GetBuildDirectory(), + "--target", _build_job->GetProjectName(), + "--config", _build_job->GetBuildDirective())); + } + + /// Invokes a new asynchronous install of the current active module job + void DoInstallCurrentProcessedModule() + { + ASSERT(_build_job, "There isn't any active build job!"); + + TC_LOG_INFO("scripts.hotswap", "Starting asynchronous install job for module %s...", + _build_job->GetModuleName().c_str()); + + _build_job->UpdateCurrentJob(BuildJobType::BUILD_JOB_INSTALL, + InvokeAsyncCMakeCommand( + "-DCOMPONENT=" + _build_job->GetProjectName(), + "-DBUILD_TYPE=" + _build_job->GetBuildDirective(), + "-P", fs::absolute("cmake_install.cmake", + BuiltInConfig::GetBuildDirectory()).generic_string())); + } + + /// Sets the CMAKE_INSTALL_PREFIX variable in the CMake cache + /// to point to the current worldserver position, + /// since most users will forget this. + void DoCMakePrefixCorrectionIfNeeded() + { + TC_LOG_INFO("scripts.hotswap", "Correcting your CMAKE_INSTALL_PREFIX in \"%s\"...", + BuiltInConfig::GetBuildDirectory().c_str()); + + auto const cmake_cache_path = fs::absolute("CMakeCache.txt", + BuiltInConfig::GetBuildDirectory()); + + // Stop when the CMakeCache wasn't found + if (![&] + { + boost::system::error_code error; + if (!fs::exists(cmake_cache_path, error)) + { + TC_LOG_ERROR("scripts.hotswap", ">> CMake cache \"%s\" doesn't exist, " + "set the \"BuildDirectory\" option in your worldserver.conf to point" + "to your build directory!", + cmake_cache_path.generic_string().c_str()); + + return false; + } + else + return true; + }()) + return; + + TC_LOG_TRACE("scripts.hotswap", "Checking CMake cache (\"%s\") " + "for the correct CMAKE_INSTALL_PREFIX location...", + cmake_cache_path.generic_string().c_str()); + + std::string cmake_cache_content; + { + std::ifstream in(cmake_cache_path.generic_string()); + if (!in.is_open()) + { + TC_LOG_ERROR("scripts.hotswap", ">> Failed to read the CMake cache at \"%s\"!", + cmake_cache_path.generic_string().c_str()); + + return; + } + + std::ostringstream ss; + ss << in.rdbuf(); + cmake_cache_content = ss.str(); + + in.close(); + } + + static std::string const prefix_key = "CMAKE_INSTALL_PREFIX:PATH="; + + // Extract the value of CMAKE_INSTALL_PREFIX + auto begin = cmake_cache_content.find(prefix_key); + if (begin != std::string::npos) + { + begin += prefix_key.length(); + auto const end = cmake_cache_content.find("\n", begin); + if (end != std::string::npos) + { + fs::path value = cmake_cache_content.substr(begin, end - begin); + + auto current_path = fs::current_path(); + + #ifndef _WIN32 + // The worldserver location is ${CMAKE_INSTALL_PREFIX}/bin + // on all other platforms then windows + current_path = current_path.remove_leaf(); + #endif + + if (value != current_path) + { + // Prevent correction of the install prefix + // when we are starting the core from inside the build tree + bool const is_in_path = [&] + { + fs::path base = BuiltInConfig::GetBuildDirectory(); + fs::path branch = value; + while (!branch.empty()) + { + if (base == branch) + return true; + + branch = branch.remove_leaf(); + } + + return false; + }(); + + if (is_in_path) + return; + + TC_LOG_INFO("scripts.hotswap", ">> Found outdated CMAKE_INSTALL_PREFIX (\"%s\"), " + "worldserver is currently installed at %s...", + value.generic_string().c_str(), current_path.generic_string().c_str()); + } + else + { + TC_LOG_INFO("scripts.hotswap", ">> CMAKE_INSTALL_PREFIX is equal to the current path of execution."); + return; + } + } + } + + TC_LOG_INFO("scripts.hotswap", "Invoking CMake cache correction..."); + + auto const error = InvokeCMakeCommand( + "-DCMAKE_INSTALL_PREFIX:PATH=" + fs::current_path().generic_string(), + BuiltInConfig::GetBuildDirectory()); + + if (error) + { + TC_LOG_ERROR("scripts.hotswap", ">> Failed to update the CMAKE_INSTALL_PREFIX! " + "This could lead to unexpected behaviour!"); + } + else + { + TC_LOG_ERROR("scripts.hotswap", ">> Successfully corrected your CMAKE_INSTALL_PREFIX variable" + "to point at your current path of execution."); + } + } + + // File watcher instance and watcher ID's + efsw::FileWatcher _fileWatcher; + efsw::WatchID _libraryWatcher; + + // Unique library name counter which is used to + // generate unique names for every shared library version. + uint32 _unique_library_name_counter; + + // Queue which is used for thread safe message processing + MPSCQueue<ScriptReloaderMessage> _messages; + + // Change requests to load or unload shared libraries + std::unordered_set<fs::path /*path*/> _libraries_changed; + // The timestamp which indicates the last time a library was changed + uint32 _last_time_library_changed; + + // Contains all running script modules + // The associated shared libraries are unloaded immediately + // on loosing ownership through RAII. + std::unordered_map<std::string /*module name*/, + std::pair<std::shared_ptr<ScriptModule>, std::unique_ptr<SourceUpdateListener>> + > _running_script_modules; + // Container which maps the path of a shared library to it's module name + std::unordered_map<fs::path, std::string /*module name*/> _running_script_module_names; + // Container which maps the module name to it's last known build directive + std::unordered_map<std::string /*module name*/, std::string /*build directive*/> _known_modules_build_directives; + + // Modules which were changed and are queued for recompilation + std::unordered_map<std::string /*module*/, + std::unordered_map<fs::path /*path*/, ChangeStateRequest /*state*/>> _sources_changed; + // Tracks the time since the last module has changed to avoid burst updates + uint32 _last_time_sources_changed; + + // Tracks the last timestamp the user was informed about a certain repeating event. + uint32 _last_time_user_informed; + + // Represents the current build job which is in progress + Optional<BuildJob> _build_job; + + // Is true when the build job dispatcher should stop after + // the current job has finished + bool terminate_early; +}; + +/// Maps efsw actions to strings +static char const* ActionToString(efsw::Action action) +{ + switch (action) + { + case efsw::Action::Add: + return "added"; + case efsw::Action::Delete: + return "deleted"; + case efsw::Action::Moved: + return "moved"; + default: + return "modified"; + } +} + +void LibraryUpdateListener::handleFileAction(efsw::WatchID watchid, std::string const& dir, + std::string const& filename, efsw::Action action, std::string oldFilename) +{ + // TC_LOG_TRACE("scripts.hotswap", "Library listener detected change on possible module \"%s\ (%s)".", filename.c_str(), ActionToString(action)); + + // Split moved actions into a delete and an add action + if (action == efsw::Action::Moved) + { + ASSERT(!oldFilename.empty(), "Old filename doesn't exist!"); + handleFileAction(watchid, dir, oldFilename, efsw::Action::Delete); + handleFileAction(watchid, dir, filename, efsw::Action::Add); + return; + } + + sScriptReloadMgr->QueueMessage([=](HotSwapScriptReloadMgr* reloader) mutable + { + auto const path = fs::absolute( + filename, + sScriptReloadMgr->GetLibraryDirectory()); + + if (!HasValidScriptModuleName(filename)) + return; + + switch (action) + { + case efsw::Actions::Add: + TC_LOG_TRACE("scripts.hotswap", ">> Loading \"%s\" (%s)...", + path.generic_string().c_str(), ActionToString(action)); + reloader->QueueSharedLibraryChanged(path); + break; + case efsw::Actions::Delete: + TC_LOG_TRACE("scripts.hotswap", ">> Unloading \"%s\" (%s)...", + path.generic_string().c_str(), ActionToString(action)); + reloader->QueueSharedLibraryChanged(path); + break; + case efsw::Actions::Modified: + TC_LOG_TRACE("scripts.hotswap", ">> Reloading \"%s\" (%s)...", + path.generic_string().c_str(), ActionToString(action)); + reloader->QueueSharedLibraryChanged(path); + break; + default: + WPAbort(); + break; + } + }); +} + +/// Returns true when the given path has a known C++ file extension +static bool HasCXXSourceFileExtension(fs::path const& path) +{ + static std::regex const regex("^\\.(h|hpp|c|cc|cpp)$"); + return std::regex_match(path.extension().generic_string(), regex); +} + +SourceUpdateListener::SourceUpdateListener(fs::path path, std::string script_module_name) + : path_(std::move(path)), script_module_name_(std::move(script_module_name)), + watcher_id_(sScriptReloadMgr->_fileWatcher.addWatch(path_.generic_string(), this, true)) +{ + if (watcher_id_ >= 0) + { + TC_LOG_TRACE("scripts.hotswap", ">> Attached the source recompiler to \"%s\".", + path_.generic_string().c_str()); + } + else + { + TC_LOG_ERROR("scripts.hotswap", "Failed to initialize thesource recompiler on \"%s\".", + path_.generic_string().c_str()); + } +} + +SourceUpdateListener::~SourceUpdateListener() +{ + if (watcher_id_ >= 0) + { + sScriptReloadMgr->_fileWatcher.removeWatch(watcher_id_); + + TC_LOG_TRACE("scripts.hotswap", ">> Detached the source recompiler from \"%s\".", + path_.generic_string().c_str()); + } +} + +void SourceUpdateListener::handleFileAction(efsw::WatchID watchid, std::string const& dir, + std::string const& filename, efsw::Action action, std::string oldFilename) +{ + // TC_LOG_TRACE("scripts.hotswap", "Source listener detected change on possible file \"%s/%s\" (%s).", dir.c_str(), filename.c_str(), ActionToString(action)); + + // Skip the file change notification if the recompiler is disabled + if (!sWorld->getBoolConfig(CONFIG_HOTSWAP_RECOMPILER_ENABLED)) + return; + + // Split moved actions into a delete and an add action + if (action == efsw::Action::Moved) + { + ASSERT(!oldFilename.empty(), "Old filename doesn't exist!"); + handleFileAction(watchid, dir, oldFilename, efsw::Action::Delete); + handleFileAction(watchid, dir, filename, efsw::Action::Add); + return; + } + + auto const path = fs::absolute( + filename, + dir); + + // Check if the file is a C/C++ source file. + if (!path.has_extension() || !HasCXXSourceFileExtension(path)) + return; + + /// Thread safe part + sScriptReloadMgr->QueueMessage([=](HotSwapScriptReloadMgr* reloader) + { + TC_LOG_TRACE("scripts.hotswap", "Detected source change on module \"%s\", " + "queued for recompilation...", script_module_name_.c_str()); + + switch (action) + { + case efsw::Actions::Add: + TC_LOG_TRACE("scripts.hotswap", "Source file %s of module %s was added.", + path.generic_string().c_str(), script_module_name_.c_str()); + reloader->QueueAddSourceFile(script_module_name_, path); + break; + case efsw::Actions::Delete: + TC_LOG_TRACE("scripts.hotswap", "Source file %s of module %s was deleted.", + path.generic_string().c_str(), script_module_name_.c_str()); + reloader->QueueRemoveSourceFile(script_module_name_, path); + break; + case efsw::Actions::Modified: + TC_LOG_TRACE("scripts.hotswap", "Source file %s of module %s was modified.", + path.generic_string().c_str(), script_module_name_.c_str()); + reloader->QueueModifySourceFile(script_module_name_, path); + break; + default: + WPAbort(); + break; + } + }); +} + +// Returns the module reference of the given context +std::shared_ptr<ModuleReference> + ScriptReloadMgr::AcquireModuleReferenceOfContext(std::string const& context) +{ + auto const itr = sScriptReloadMgr->_running_script_modules.find(context); + if (itr != sScriptReloadMgr->_running_script_modules.end()) + return itr->second.first; + else + return { }; +} + +// Returns the full hot swap implemented ScriptReloadMgr +ScriptReloadMgr* ScriptReloadMgr::instance() +{ + static HotSwapScriptReloadMgr instance; + return &instance; +} + +#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING diff --git a/src/server/game/Scripting/ScriptReloadMgr.h b/src/server/game/Scripting/ScriptReloadMgr.h new file mode 100644 index 00000000000..f9b388f8eb0 --- /dev/null +++ b/src/server/game/Scripting/ScriptReloadMgr.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SCRIPT_RELOADER_H +#define SCRIPT_RELOADER_H + +#include <memory> +#include <string> +#include "Define.h" +#include <boost/filesystem/path.hpp> + +/// Represents a strong reference to a dynamic library which +/// provides C++ scripts. As long as one reference to the library exists +/// the library is kept loaded in the server, which makes it possible to lazy +/// unload several script types on demand (like SpellScripts), and to +/// provide multiple versions of the same script to the script factories. +/// +/// Acquire a new reference through using: +/// `ScriptReloadMgr::AcquireModuleReferenceOfContext` +class ModuleReference +{ +public: + virtual ~ModuleReference() { } + + /// Returns the git revision hash of the referenced script module + virtual char const* GetScriptModuleRevisionHash() const = 0; + /// Returns the name of the referenced script module + virtual char const* GetScriptModule() const = 0; + /// Returns the path to the script module + virtual boost::filesystem::path const& GetModulePath() const = 0; +}; + +/// Provides the whole physical dynamic library unloading capability. +/// Loads, Reloads and Unloads dynamic libraries on changes and +/// informs the ScriptMgr about changes which were made. +/// The ScriptReloadMgr is also responsible for watching the source directory +/// and to invoke a build on changes. +class TC_GAME_API ScriptReloadMgr +{ +protected: + ScriptReloadMgr() { } + +public: + virtual ~ScriptReloadMgr() { } + + /// Initializes the ScriptReloadMgr + virtual void Initialize() { } + + /// Needs to be called periodically to check for updates on script modules. + /// Expects to be invoked in a thread safe way which means it's required that + /// the current thread is the only one which accesses the world data. + virtual void Update() { } + + /// Unloads the ScriptReloadMgr + virtual void Unload() { } + + /// Returns an owning reference to the current module of the given context + static std::shared_ptr<ModuleReference> AcquireModuleReferenceOfContext( + std::string const& context); + + /// Returns the unique ScriptReloadMgr singleton instance + static ScriptReloadMgr* instance(); +}; + +#define sScriptReloadMgr ScriptReloadMgr::instance() + +#endif // SCRIPT_RELOADER_H diff --git a/src/server/game/Scripting/ScriptSystem.cpp b/src/server/game/Scripting/ScriptSystem.cpp index e828830ec0f..52c5c1640af 100644 --- a/src/server/game/Scripting/ScriptSystem.cpp +++ b/src/server/game/Scripting/ScriptSystem.cpp @@ -21,7 +21,13 @@ #include "DatabaseEnv.h" #include "ScriptMgr.h" -ScriptPointVector const SystemMgr::_empty; +TC_GAME_API ScriptPointVector const SystemMgr::_empty; + +SystemMgr* SystemMgr::instance() +{ + static SystemMgr instance; + return &instance; +} void SystemMgr::LoadScriptWaypoints() { diff --git a/src/server/game/Scripting/ScriptSystem.h b/src/server/game/Scripting/ScriptSystem.h index 74c51e5b136..7cf8ffc85b0 100644 --- a/src/server/game/Scripting/ScriptSystem.h +++ b/src/server/game/Scripting/ScriptSystem.h @@ -45,18 +45,14 @@ struct ScriptPointMove typedef std::vector<ScriptPointMove> ScriptPointVector; -class SystemMgr +class TC_GAME_API SystemMgr { private: SystemMgr() { } ~SystemMgr() { } public: - static SystemMgr* instance() - { - static SystemMgr instance; - return &instance; - } + static SystemMgr* instance(); typedef std::unordered_map<uint32, ScriptPointVector> PointMoveMap; diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 0d30134aa9f..48ed03004ea 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -1373,7 +1373,7 @@ struct OpcodeHandler void (WorldSession::*handler)(WorldPacket& recvPacket); }; -extern OpcodeHandler opcodeTable[NUM_MSG_TYPES]; +TC_GAME_API extern OpcodeHandler opcodeTable[NUM_MSG_TYPES]; #pragma pack(pop) diff --git a/src/server/game/Server/Protocol/PacketLog.cpp b/src/server/game/Server/Protocol/PacketLog.cpp index 57b76304a77..11a02828998 100644 --- a/src/server/game/Server/Protocol/PacketLog.cpp +++ b/src/server/game/Server/Protocol/PacketLog.cpp @@ -69,6 +69,12 @@ PacketLog::~PacketLog() _file = NULL; } +PacketLog* PacketLog::instance() +{ + static PacketLog instance; + return &instance; +} + void PacketLog::Initialize() { std::string logsDir = sConfigMgr->GetStringDefault("LogsDir", ""); diff --git a/src/server/game/Server/Protocol/PacketLog.h b/src/server/game/Server/Protocol/PacketLog.h index 45a3f0a4655..5e7661a884b 100644 --- a/src/server/game/Server/Protocol/PacketLog.h +++ b/src/server/game/Server/Protocol/PacketLog.h @@ -31,7 +31,7 @@ enum Direction class WorldPacket; -class PacketLog +class TC_GAME_API PacketLog { private: PacketLog(); @@ -40,11 +40,7 @@ class PacketLog std::once_flag _initializeFlag; public: - static PacketLog* instance() - { - static PacketLog instance; - return &instance; - } + static PacketLog* instance(); void Initialize(); bool CanLogPacket() const { return (_file != NULL); } diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index c380c1a5627..ddcc10b53dd 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -187,7 +187,7 @@ ObjectGuid::LowType WorldSession::GetGUIDLow() const } /// Send a packet to the client -void WorldSession::SendPacket(WorldPacket* packet) +void WorldSession::SendPacket(WorldPacket const* packet) { if (!m_Socket) return; @@ -272,119 +272,99 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) WorldPacket* packet = NULL; //! Delete packet after processing by default bool deletePacket = true; - //! To prevent infinite loop - WorldPacket* firstDelayedPacket = NULL; - //! If _recvQueue.peek() == firstDelayedPacket it means that in this Update call, we've processed all - //! *properly timed* packets, and we're now at the part of the queue where we find - //! delayed packets that were re-enqueued due to improper timing. To prevent an infinite - //! loop caused by re-enqueueing the same packets over and over again, we stop updating this session - //! and continue updating others. The re-enqueued packets will be handled in the next Update call for this session. + std::vector<WorldPacket*> requeuePackets; uint32 processedPackets = 0; time_t currentTime = time(NULL); - while (m_Socket && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) + while (m_Socket && _recvQueue.next(packet, updater)) { - if (packet->GetOpcode() >= NUM_MSG_TYPES) + OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()]; + try { - TC_LOG_ERROR("network.opcode", "Received non-existed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() - , GetPlayerInfo().c_str()); - sScriptMgr->OnUnknownPacketReceive(this, *packet); - } - else - { - OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; - try + switch (opHandle.status) { - switch (opHandle.status) - { - case STATUS_LOGGEDIN: - if (!_player) - { - // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets - //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize - //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later. - if (!m_playerRecentlyLogout) - { - //! Prevent infinite loop - if (!firstDelayedPacket) - firstDelayedPacket = packet; - //! Because checking a bool is faster than reallocating memory - deletePacket = false; - QueuePacket(packet); - //! Log - TC_LOG_DEBUG("network", "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. " - "Player is currently not in world yet.", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()); - } - } - else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime)) - { - sScriptMgr->OnPacketReceive(this, *packet); - (this->*opHandle.handler)(*packet); - LogUnprocessedTail(packet); - } - // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer - break; - case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: - if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout - LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT", - "the player has not logged in yet and not recently logout"); - else if (AntiDOS.EvaluateOpcode(*packet, currentTime)) - { - // not expected _player or must checked in packet handler - sScriptMgr->OnPacketReceive(this, *packet); - (this->*opHandle.handler)(*packet); - LogUnprocessedTail(packet); - } - break; - case STATUS_TRANSFER: - if (!_player) - LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet"); - else if (_player->IsInWorld()) - LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world"); - else if (AntiDOS.EvaluateOpcode(*packet, currentTime)) - { - sScriptMgr->OnPacketReceive(this, *packet); - (this->*opHandle.handler)(*packet); - LogUnprocessedTail(packet); - } - break; - case STATUS_AUTHED: - // prevent cheating with skip queue wait - if (m_inQueue) + case STATUS_LOGGEDIN: + if (!_player) + { + // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets + //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize + //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later. + if (!m_playerRecentlyLogout) { - LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet"); - break; + requeuePackets.push_back(packet); + deletePacket = false; + TC_LOG_DEBUG("network", "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. " + "Player is currently not in world yet.", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()); } - - // some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes - // however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process. - if (packet->GetOpcode() == CMSG_CHAR_ENUM) - m_playerRecentlyLogout = false; - - if (AntiDOS.EvaluateOpcode(*packet, currentTime)) - { - sScriptMgr->OnPacketReceive(this, *packet); - (this->*opHandle.handler)(*packet); - LogUnprocessedTail(packet); - } - break; - case STATUS_NEVER: - TC_LOG_ERROR("network.opcode", "Received not allowed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() - , GetPlayerInfo().c_str()); - break; - case STATUS_UNHANDLED: - TC_LOG_DEBUG("network.opcode", "Received not handled opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() - , GetPlayerInfo().c_str()); + } + else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime)) + { + sScriptMgr->OnPacketReceive(this, *packet); + (this->*opHandle.handler)(*packet); + LogUnprocessedTail(packet); + } + // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer + break; + case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: + if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout + LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT", + "the player has not logged in yet and not recently logout"); + else if (AntiDOS.EvaluateOpcode(*packet, currentTime)) + { + // not expected _player or must checked in packet hanlder + sScriptMgr->OnPacketReceive(this, *packet); + (this->*opHandle.handler)(*packet); + LogUnprocessedTail(packet); + } + break; + case STATUS_TRANSFER: + if (!_player) + LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet"); + else if (_player->IsInWorld()) + LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world"); + else if (AntiDOS.EvaluateOpcode(*packet, currentTime)) + { + sScriptMgr->OnPacketReceive(this, *packet); + (this->*opHandle.handler)(*packet); + LogUnprocessedTail(packet); + } + break; + case STATUS_AUTHED: + // prevent cheating with skip queue wait + if (m_inQueue) + { + LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet"); break; - } - } - catch (ByteBufferException const&) - { - TC_LOG_ERROR("misc", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", - packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); - packet->hexlike(); + } + + // some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes + // however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process. + if (packet->GetOpcode() == CMSG_CHAR_ENUM) + m_playerRecentlyLogout = false; + + if (AntiDOS.EvaluateOpcode(*packet, currentTime)) + { + sScriptMgr->OnPacketReceive(this, *packet); + (this->*opHandle.handler)(*packet); + LogUnprocessedTail(packet); + } + break; + case STATUS_NEVER: + TC_LOG_ERROR("network.opcode", "Received not allowed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() + , GetPlayerInfo().c_str()); + break; + case STATUS_UNHANDLED: + TC_LOG_DEBUG("network.opcode", "Received not handled opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() + , GetPlayerInfo().c_str()); + break; } } + catch (ByteBufferException const&) + { + TC_LOG_ERROR("network", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", + packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); + packet->hexlike(); + } if (deletePacket) delete packet; @@ -400,6 +380,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) break; } + _recvQueue.readd(requeuePackets.begin(), requeuePackets.end()); + if (m_Socket && m_Socket->IsOpen() && _warden) _warden->Update(); @@ -1220,7 +1202,7 @@ void WorldSession::LoadPermissions() uint32 id = GetAccountId(); uint8 secLevel = GetSecurity(); - _RBACData = new rbac::RBACData(id, _accountName, realmID, secLevel); + _RBACData = new rbac::RBACData(id, _accountName, realm.Id.Realm, secLevel); _RBACData->LoadFromDB(); } @@ -1230,9 +1212,9 @@ PreparedQueryResultFuture WorldSession::LoadPermissionsAsync() uint8 secLevel = GetSecurity(); TC_LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]", - id, _accountName.c_str(), realmID, secLevel); + id, _accountName.c_str(), realm.Id.Realm, secLevel); - _RBACData = new rbac::RBACData(id, _accountName, realmID, secLevel); + _RBACData = new rbac::RBACData(id, _accountName, realm.Id.Realm, secLevel); return _RBACData->LoadFromDBAsync(); } @@ -1310,7 +1292,7 @@ bool WorldSession::HasPermission(uint32 permission) bool hasPermission = _RBACData->HasPermission(permission); TC_LOG_DEBUG("rbac", "WorldSession::HasPermission [AccountId: %u, Name: %s, realmId: %d]", - _RBACData->GetId(), _RBACData->GetName().c_str(), realmID); + _RBACData->GetId(), _RBACData->GetName().c_str(), realm.Id.Realm); return hasPermission; } @@ -1318,7 +1300,7 @@ bool WorldSession::HasPermission(uint32 permission) void WorldSession::InvalidateRBACData() { TC_LOG_DEBUG("rbac", "WorldSession::Invalidaterbac::RBACData [AccountId: %u, Name: %s, realmId: %d]", - _RBACData->GetId(), _RBACData->GetName().c_str(), realmID); + _RBACData->GetId(), _RBACData->GetName().c_str(), realm.Id.Realm); delete _RBACData; _RBACData = NULL; } diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 2253b6bc684..584367bd375 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -246,7 +246,7 @@ struct PacketCounter }; /// Player session in the World -class WorldSession +class TC_GAME_API WorldSession { public: WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); @@ -264,7 +264,7 @@ class WorldSession void ReadMovementInfo(WorldPacket& data, MovementInfo* mi); void WriteMovementInfo(WorldPacket* data, MovementInfo* mi); - void SendPacket(WorldPacket* packet); + void SendPacket(WorldPacket const* packet); void SendNotification(const char *format, ...) ATTR_PRINTF(2, 3); void SendNotification(uint32 string_id, ...); void SendPetNameInvalid(uint32 error, std::string const& name, DeclinedName *declinedName); diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 36029113055..e3c6179a34a 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -414,7 +414,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Get the account information from the auth database PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); - stmt->setInt32(0, int32(realmID)); + stmt->setInt32(0, int32(realm.Id.Realm)); stmt->setString(1, authSession->Account); _queryCallback = std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1); @@ -457,10 +457,11 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes return; } - if (authSession->RealmID != realmID) + if (authSession->RealmID != realm.Id.Realm) { SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm)."); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s requested connecting with realm id %u but this realm has id %u set in config.", + GetRemoteIpAddress().to_string().c_str(), authSession->RealmID, realm.Id.Realm); DelayedCloseSocket(); return; } diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 08a5b185cf1..3874b60b0bb 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -29,7 +29,6 @@ #include "MPSCQueue.h" #include <chrono> #include <boost/asio/ip/tcp.hpp> -#include <boost/asio/buffer.hpp> using boost::asio::ip::tcp; class EncryptablePacket; @@ -49,7 +48,7 @@ struct ClientPktHeader struct AuthSession; -class WorldSocket : public Socket<WorldSocket> +class TC_GAME_API WorldSocket : public Socket<WorldSocket> { typedef Socket<WorldSocket> BaseSocket; diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp index e8f8c59f4af..2faf0704d4f 100644 --- a/src/server/game/Server/WorldSocketMgr.cpp +++ b/src/server/game/Server/WorldSocketMgr.cpp @@ -47,7 +47,13 @@ WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _socketSendBufferSize(-1), m { } -bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) +WorldSocketMgr& WorldSocketMgr::Instance() +{ + static WorldSocketMgr instance; + return instance; +} + +bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port, int threadCount) { _tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true); @@ -65,7 +71,7 @@ bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string return false; } - BaseSocketMgr::StartNetwork(service, bindIp, port); + BaseSocketMgr::StartNetwork(service, bindIp, port, threadCount); _acceptor->SetSocketFactory(std::bind(&BaseSocketMgr::GetSocketForAccept, this)); diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h index 38e2e7abb69..a5aee344bf7 100644 --- a/src/server/game/Server/WorldSocketMgr.h +++ b/src/server/game/Server/WorldSocketMgr.h @@ -30,19 +30,15 @@ class WorldSocket; /// Manages all sockets connected to peers and network threads -class WorldSocketMgr : public SocketMgr<WorldSocket> +class TC_GAME_API WorldSocketMgr : public SocketMgr<WorldSocket> { typedef SocketMgr<WorldSocket> BaseSocketMgr; public: - static WorldSocketMgr& Instance() - { - static WorldSocketMgr instance; - return instance; - } + static WorldSocketMgr& Instance(); /// Start network, listen at address:port . - bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) override; + bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port, int networkThreads) override; /// Stops all network threads, It will wait for all running threads . void StopNetwork() override; diff --git a/src/server/game/Skills/SkillDiscovery.h b/src/server/game/Skills/SkillDiscovery.h index b7fe1cdc8b2..c2020e5b075 100644 --- a/src/server/game/Skills/SkillDiscovery.h +++ b/src/server/game/Skills/SkillDiscovery.h @@ -23,8 +23,9 @@ class Player; -void LoadSkillDiscoveryTable(); -uint32 GetSkillDiscoverySpell(uint32 skillId, uint32 spellId, Player* player); -bool HasDiscoveredAllSpells(uint32 spellId, Player* player); -uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player); +TC_GAME_API void LoadSkillDiscoveryTable(); +TC_GAME_API uint32 GetSkillDiscoverySpell(uint32 skillId, uint32 spellId, Player* player); +TC_GAME_API bool HasDiscoveredAllSpells(uint32 spellId, Player* player); +TC_GAME_API uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player); + #endif diff --git a/src/server/game/Skills/SkillExtraItems.h b/src/server/game/Skills/SkillExtraItems.h index 2889b221600..5a477b65f0b 100644 --- a/src/server/game/Skills/SkillExtraItems.h +++ b/src/server/game/Skills/SkillExtraItems.h @@ -23,12 +23,14 @@ // predef classes used in functions class Player; + // returns true and sets the appropriate info if the player can create a perfect item with the given spellId -bool CanCreatePerfectItem(Player* player, uint32 spellId, float &perfectCreateChance, uint32 &perfectItemType); +TC_GAME_API bool CanCreatePerfectItem(Player* player, uint32 spellId, float &perfectCreateChance, uint32 &perfectItemType); // load perfection proc info from DB -void LoadSkillPerfectItemTable(); +TC_GAME_API void LoadSkillPerfectItemTable(); // returns true and sets the appropriate info if the player can create extra items with the given spellId -bool CanCreateExtraItems(Player* player, uint32 spellId, float &additionalChance, uint8 &additionalMax); +TC_GAME_API bool CanCreateExtraItems(Player* player, uint32 spellId, float &additionalChance, uint8 &additionalMax); // function to load the extra item creation info from DB -void LoadSkillExtraItemTable(); +TC_GAME_API void LoadSkillExtraItemTable(); + #endif diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 207908c6d51..a8adda3ad58 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1325,7 +1325,7 @@ void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode { // apply glow vision if (target->GetTypeId() == TYPEID_PLAYER) - target->SetByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); + target->SetByteFlag(PLAYER_FIELD_BYTES2, PLAYER_FIELD_BYTES_2_OFFSET_AURA_VISION, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); target->m_invisibility.AddFlag(type); target->m_invisibility.AddValue(type, GetAmount()); @@ -1337,7 +1337,7 @@ void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode // if not have different invisibility auras. // remove glow vision if (target->GetTypeId() == TYPEID_PLAYER) - target->RemoveByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); + target->RemoveByteFlag(PLAYER_FIELD_BYTES2, PLAYER_FIELD_BYTES_2_OFFSET_AURA_VISION, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); target->m_invisibility.DelFlag(type); } @@ -1409,7 +1409,7 @@ void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, boo target->SetStandFlags(UNIT_STAND_FLAGS_CREEP); if (target->GetTypeId() == TYPEID_PLAYER) - target->SetByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_STEALTH); + target->SetByteFlag(PLAYER_FIELD_BYTES2, PLAYER_FIELD_BYTES_2_OFFSET_AURA_VISION, PLAYER_FIELD_BYTE2_STEALTH); } else { @@ -1421,7 +1421,7 @@ void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, boo target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP); if (target->GetTypeId() == TYPEID_PLAYER) - target->RemoveByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_STEALTH); + target->RemoveByteFlag(PLAYER_FIELD_BYTES2, PLAYER_FIELD_BYTES_2_OFFSET_AURA_VISION, PLAYER_FIELD_BYTE2_STEALTH); } } @@ -2400,7 +2400,7 @@ void AuraEffect::HandleAuraTrackStealthed(AuraApplication const* aurApp, uint8 m if (target->HasAuraType(GetAuraType())) return; } - target->ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_TRACK_STEALTHED, apply); + target->ApplyModByteFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_FLAGS, PLAYER_FIELD_BYTE_TRACK_STEALTHED, apply); } void AuraEffect::HandleAuraModStalked(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -2915,7 +2915,7 @@ void AuraEffect::HandleAuraModIncreaseSpeed(AuraApplication const* aurApp, uint8 Unit* target = aurApp->GetTarget(); - target->UpdateSpeed(MOVE_RUN, true); + target->UpdateSpeed(MOVE_RUN); } void AuraEffect::HandleAuraModIncreaseMountedSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -2930,7 +2930,7 @@ void AuraEffect::HandleAuraModIncreaseFlightSpeed(AuraApplication const* aurApp, Unit* target = aurApp->GetTarget(); if (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK) - target->UpdateSpeed(MOVE_FLIGHT, true); + target->UpdateSpeed(MOVE_FLIGHT); //! Update ability to fly if (GetAuraType() == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) @@ -2965,7 +2965,7 @@ void AuraEffect::HandleAuraModIncreaseSwimSpeed(AuraApplication const* aurApp, u Unit* target = aurApp->GetTarget(); - target->UpdateSpeed(MOVE_SWIM, true); + target->UpdateSpeed(MOVE_SWIM); } void AuraEffect::HandleAuraModDecreaseSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const @@ -2975,12 +2975,12 @@ void AuraEffect::HandleAuraModDecreaseSpeed(AuraApplication const* aurApp, uint8 Unit* target = aurApp->GetTarget(); - target->UpdateSpeed(MOVE_RUN, true); - target->UpdateSpeed(MOVE_SWIM, true); - target->UpdateSpeed(MOVE_FLIGHT, true); - target->UpdateSpeed(MOVE_RUN_BACK, true); - target->UpdateSpeed(MOVE_SWIM_BACK, true); - target->UpdateSpeed(MOVE_FLIGHT_BACK, true); + target->UpdateSpeed(MOVE_RUN); + target->UpdateSpeed(MOVE_SWIM); + target->UpdateSpeed(MOVE_FLIGHT); + target->UpdateSpeed(MOVE_RUN_BACK); + target->UpdateSpeed(MOVE_SWIM_BACK); + target->UpdateSpeed(MOVE_FLIGHT_BACK); } void AuraEffect::HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const @@ -2990,9 +2990,9 @@ void AuraEffect::HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint Unit* target = aurApp->GetTarget(); - target->UpdateSpeed(MOVE_RUN, true); - target->UpdateSpeed(MOVE_SWIM, true); - target->UpdateSpeed(MOVE_FLIGHT, true); + target->UpdateSpeed(MOVE_RUN); + target->UpdateSpeed(MOVE_SWIM); + target->UpdateSpeed(MOVE_FLIGHT); } /*********************************************************/ @@ -4808,7 +4808,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool uint32 spellId = 24659; if (apply && caster) { - SpellInfo const* spell = sSpellMgr->EnsureSpellInfo(spellId); + SpellInfo const* spell = sSpellMgr->AssertSpellInfo(spellId); for (uint32 i = 0; i < spell->StackAmount; ++i) caster->CastSpell(target, spell->Id, true, NULL, NULL, GetCasterGUID()); @@ -4823,7 +4823,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool uint32 spellId = 24662; if (apply && caster) { - SpellInfo const* spell = sSpellMgr->EnsureSpellInfo(spellId); + SpellInfo const* spell = sSpellMgr->AssertSpellInfo(spellId); for (uint32 i = 0; i < spell->StackAmount; ++i) caster->CastSpell(target, spell->Id, true, NULL, NULL, GetCasterGUID()); break; @@ -5248,7 +5248,7 @@ void AuraEffect::HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 m if (apply) { - target->SetUInt16Value(PLAYER_FIELD_BYTES2, 0, overrideId); + target->SetUInt16Value(PLAYER_FIELD_BYTES2, PLAYER_BYTES_2_OVERRIDE_SPELLS_UINT16_OFFSET, overrideId); if (OverrideSpellDataEntry const* overrideSpells = sOverrideSpellDataStore.LookupEntry(overrideId)) for (uint8 i = 0; i < MAX_OVERRIDE_SPELL; ++i) if (uint32 spellId = overrideSpells->spellId[i]) @@ -5256,7 +5256,7 @@ void AuraEffect::HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 m } else { - target->SetUInt16Value(PLAYER_FIELD_BYTES2, 0, 0); + target->SetUInt16Value(PLAYER_FIELD_BYTES2, PLAYER_BYTES_2_OVERRIDE_SPELLS_UINT16_OFFSET, 0); if (OverrideSpellDataEntry const* overrideSpells = sOverrideSpellDataStore.LookupEntry(overrideId)) for (uint8 i = 0; i < MAX_OVERRIDE_SPELL; ++i) if (uint32 spellId = overrideSpells->spellId[i]) @@ -5302,9 +5302,9 @@ void AuraEffect::HandlePreventResurrection(AuraApplication const* aurApp, uint8 return; if (apply) - aurApp->GetTarget()->RemoveByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_RELEASE_TIMER); + aurApp->GetTarget()->RemoveByteFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_FLAGS, PLAYER_FIELD_BYTE_RELEASE_TIMER); else if (!aurApp->GetTarget()->GetBaseMap()->Instanceable()) - aurApp->GetTarget()->SetByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_RELEASE_TIMER); + aurApp->GetTarget()->SetByteFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_FLAGS, PLAYER_FIELD_BYTE_RELEASE_TIMER); } void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const @@ -5974,14 +5974,14 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c caster->CalcAbsorbResist(target, GetSpellInfo()->GetSchoolMask(), DOT, damage, &absorb, &resist, m_spellInfo); - if (target->GetHealth() < damage) - damage = uint32(target->GetHealth()); - TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s health leech of %s for %u dmg inflicted by %u abs is %u", GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb); caster->SendSpellNonMeleeDamageLog(target, GetId(), damage, GetSpellInfo()->GetSchoolMask(), absorb, resist, false, 0, crit); + if (target->GetHealth() < damage) + damage = uint32(target->GetHealth()); + // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index b400520a08a..32a7b97fff2 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -27,7 +27,7 @@ class Aura; typedef void(AuraEffect::*pAuraEffectHandler)(AuraApplication const* aurApp, uint8 mode, bool apply) const; -class AuraEffect +class TC_GAME_API AuraEffect { friend void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount); friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID); diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 2180f524194..750110dc146 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -39,7 +39,7 @@ class ChargeDropEvent; // update aura target map every 500 ms instead of every update - reduce amount of grid searcher calls #define UPDATE_TARGET_MAP_INTERVAL 500 -class AuraApplication +class TC_GAME_API AuraApplication { friend void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask); friend void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode); @@ -82,7 +82,7 @@ class AuraApplication void ClientUpdate(bool remove = false); }; -class Aura +class TC_GAME_API Aura { friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); public: @@ -273,7 +273,7 @@ class Aura Unit::AuraApplicationList m_removedApplications; }; -class UnitAura : public Aura +class TC_GAME_API UnitAura : public Aura { friend Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); protected: @@ -294,7 +294,7 @@ class UnitAura : public Aura DiminishingGroup m_AuraDRGroup:8; // Diminishing }; -class DynObjAura : public Aura +class TC_GAME_API DynObjAura : public Aura { friend Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); protected: @@ -305,12 +305,12 @@ class DynObjAura : public Aura void FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) override; }; -class ChargeDropEvent : public BasicEvent +class TC_GAME_API ChargeDropEvent : public BasicEvent { friend class Aura; protected: ChargeDropEvent(Aura* base, AuraRemoveMode mode) : _base(base), _mode(mode) { } - bool Execute(uint64 /*e_time*/, uint32 /*p_time*/); + bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override; private: Aura* _base; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 23e2f144ff2..fff69ae48df 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -602,7 +602,7 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO //Auto Shot & Shoot (wand) m_autoRepeat = m_spellInfo->IsAutoRepeatRangedSpell(); - + m_isDelayedInstantCast = false; m_runesState = 0; @@ -3811,7 +3811,7 @@ void Spell::SendSpellStart() if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell) castFlags |= CAST_FLAG_PENDING; - if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO)) + if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA)) castFlags |= CAST_FLAG_AMMO; if ((m_caster->GetTypeId() == TYPEID_PLAYER || (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet())) @@ -3864,7 +3864,7 @@ void Spell::SendSpellGo() if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell) castFlags |= CAST_FLAG_PENDING; - if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO)) + if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA)) castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual if ((m_caster->GetTypeId() == TYPEID_PLAYER || @@ -4831,6 +4831,10 @@ SpellCastResult Spell::CheckCast(bool strict) m_customError = SpellCustomErrors(condInfo.mLastFailedCondition->ErrorTextId); return SpellCastResult(condInfo.mLastFailedCondition->ErrorType); } + + if (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) + return SPELL_FAILED_DONT_REPORT; + if (!condInfo.mLastFailedCondition || !condInfo.mLastFailedCondition->ConditionTarget) return SPELL_FAILED_CASTER_AURASTATE; return SPELL_FAILED_BAD_TARGETS; @@ -5702,27 +5706,37 @@ bool Spell::CanAutoCast(Unit* target) { ObjectGuid targetguid = target->GetGUID(); - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + // check if target already has the same or a more powerful aura + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if (m_spellInfo->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA) + if (!GetSpellInfo()->Effects[i].IsAura()) + continue; + + AuraType const& auraType = AuraType(GetSpellInfo()->Effects[i].ApplyAuraName); + Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(auraType); + for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt) { - if (m_spellInfo->StackAmount <= 1) + if (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id) + return false; + + switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo())) { - if (target->HasAuraEffect(m_spellInfo->Id, j)) + case SPELL_GROUP_STACK_RULE_EXCLUSIVE: return false; - } - else - { - if (AuraEffect* aureff = target->GetAuraEffect(m_spellInfo->Id, j)) - if (aureff->GetBase()->GetStackAmount() >= m_spellInfo->StackAmount) + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER: + if (GetCaster() == (*auraIt)->GetCaster()) return false; + break; + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: // this one has further checks, but i don't think they're necessary for autocast logic + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST: + if (abs(GetSpellInfo()->Effects[i].BasePoints) <= abs((*auraIt)->GetAmount())) + return false; + break; + case SPELL_GROUP_STACK_RULE_DEFAULT: + default: + break; } } - else if (m_spellInfo->Effects[j].IsAreaAuraEffect()) - { - if (target->HasAuraEffect(m_spellInfo->Id, j)) - return false; - } } SpellCastResult result = CheckPetCast(target); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 696d2801645..e634aa62a1c 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -80,7 +80,7 @@ enum SpellRangeFlag SPELL_RANGE_RANGED = 2 //hunter range and ranged weapon }; -struct SpellDestination +struct TC_GAME_API SpellDestination { SpellDestination(); SpellDestination(float x, float y, float z, float orientation = 0.0f, uint32 mapId = MAPID_INVALID); @@ -95,7 +95,7 @@ struct SpellDestination Position _transportOffset; }; -class SpellCastTargets +class TC_GAME_API SpellCastTargets { public: SpellCastTargets(); @@ -218,7 +218,7 @@ enum SpellEffectHandleMode typedef std::list<std::pair<uint32, ObjectGuid>> DispelList; -class Spell +class TC_GAME_API Spell { friend void Unit::SetCurrentCastSpell(Spell* pSpell); friend class SpellScript; @@ -708,7 +708,7 @@ class Spell namespace Trinity { - struct WorldObjectSpellTargetCheck + struct TC_GAME_API WorldObjectSpellTargetCheck { Unit* _caster; Unit* _referer; @@ -723,7 +723,7 @@ namespace Trinity bool operator()(WorldObject* target); }; - struct WorldObjectSpellNearbyTargetCheck : public WorldObjectSpellTargetCheck + struct TC_GAME_API WorldObjectSpellNearbyTargetCheck : public WorldObjectSpellTargetCheck { float _range; Position const* _position; @@ -732,7 +732,7 @@ namespace Trinity bool operator()(WorldObject* target); }; - struct WorldObjectSpellAreaTargetCheck : public WorldObjectSpellTargetCheck + struct TC_GAME_API WorldObjectSpellAreaTargetCheck : public WorldObjectSpellTargetCheck { float _range; Position const* _position; @@ -741,7 +741,7 @@ namespace Trinity bool operator()(WorldObject* target); }; - struct WorldObjectSpellConeTargetCheck : public WorldObjectSpellAreaTargetCheck + struct TC_GAME_API WorldObjectSpellConeTargetCheck : public WorldObjectSpellAreaTargetCheck { float _coneAngle; WorldObjectSpellConeTargetCheck(float coneAngle, float range, Unit* caster, @@ -749,7 +749,7 @@ namespace Trinity bool operator()(WorldObject* target); }; - struct WorldObjectSpellTrajTargetCheck : public WorldObjectSpellAreaTargetCheck + struct TC_GAME_API WorldObjectSpellTrajTargetCheck : public WorldObjectSpellAreaTargetCheck { WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, SpellInfo const* spellInfo); bool operator()(WorldObject* target); @@ -758,7 +758,7 @@ namespace Trinity typedef void(Spell::*pEffect)(SpellEffIndex effIndex); -class SpellEvent : public BasicEvent +class TC_GAME_API SpellEvent : public BasicEvent { public: SpellEvent(Spell* spell); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index f9bf33553cc..3f0ff9a0f19 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -250,13 +250,13 @@ void Spell::EffectResurrectNew(SpellEffIndex effIndex) Player* target = unitTarget->ToPlayer(); - if (target->isResurrectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = damage; uint32 mana = m_spellInfo->Effects[effIndex].MiscValue; ExecuteLogEffectResurrect(effIndex, target); - target->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); + target->SetResurrectRequestData(m_caster, health, mana, 0); SendResurrectRequest(target); } @@ -1830,7 +1830,7 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_BATTLE, avalibleElixirs); for (std::set<uint32>::iterator itr = avalibleElixirs.begin(); itr != avalibleElixirs.end();) { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(*itr); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(*itr); if (spellInfo->SpellLevel < m_spellInfo->SpellLevel || spellInfo->SpellLevel > unitTarget->getLevel()) avalibleElixirs.erase(itr++); else if (sSpellMgr->IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_SHATTRATH)) @@ -2110,8 +2110,7 @@ void Spell::EffectSummonChangeItem(SpellEffIndex effIndex) else if (player->IsBankPos(pos)) { ItemPosCountVec dest; - uint8 msg = player->CanBankItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true); - if (msg == EQUIP_ERR_OK) + if (player->CanBankItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true) == EQUIP_ERR_OK) { player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true); @@ -2133,7 +2132,7 @@ void Spell::EffectSummonChangeItem(SpellEffIndex effIndex) player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true); - uint8 msg = player->CanEquipItem(m_CastItem->GetSlot(), dest, pNewItem, true); + InventoryResult msg = player->CanEquipItem(m_CastItem->GetSlot(), dest, pNewItem, true); if (msg == EQUIP_ERR_OK || msg == EQUIP_ERR_CANT_DO_RIGHT_NOW) { @@ -4536,7 +4535,7 @@ void Spell::EffectResurrect(SpellEffIndex effIndex) Player* target = unitTarget->ToPlayer(); - if (target->isResurrectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = target->CountPctFromMaxHealth(damage); @@ -4544,7 +4543,7 @@ void Spell::EffectResurrect(SpellEffIndex effIndex) ExecuteLogEffectResurrect(effIndex, target); - target->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); + target->SetResurrectRequestData(m_caster, health, mana, 0); SendResurrectRequest(target); } diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index adf5fc47c77..4f74197fed2 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -373,7 +373,7 @@ void SpellHistory::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId / player->SendDirectMessage(&data); if (startCooldown) - StartCooldown(sSpellMgr->EnsureSpellInfo(categoryItr->second->SpellId), itemId, spell); + StartCooldown(sSpellMgr->AssertSpellInfo(categoryItr->second->SpellId), itemId, spell); } WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8); @@ -483,7 +483,7 @@ bool SpellHistory::HasCooldown(SpellInfo const* spellInfo, uint32 itemId /*= 0*/ bool SpellHistory::HasCooldown(uint32 spellId, uint32 itemId /*= 0*/, bool ignoreCategoryCooldown /*= false*/) const { - return HasCooldown(sSpellMgr->EnsureSpellInfo(spellId), itemId, ignoreCategoryCooldown); + return HasCooldown(sSpellMgr->AssertSpellInfo(spellId), itemId, ignoreCategoryCooldown); } uint32 SpellHistory::GetRemainingCooldown(SpellInfo const* spellInfo) const @@ -542,7 +542,7 @@ void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTim WorldPacket spellCooldowns; for (uint32 spellId : knownSpells) { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(spellId); if (spellInfo->IsCooldownStartedOnEvent()) continue; @@ -688,7 +688,7 @@ void SpellHistory::RestoreCooldownStateAfterDuel() // add all profession CDs created while in duel (if any) for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end(); ++itr) { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); if (spellInfo->RecoveryTime > 10 * MINUTE * IN_MILLISECONDS || spellInfo->CategoryRecoveryTime > 10 * MINUTE * IN_MILLISECONDS) diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h index f0a53fe130d..ccc8a7daa96 100644 --- a/src/server/game/Spells/SpellHistory.h +++ b/src/server/game/Spells/SpellHistory.h @@ -31,7 +31,7 @@ class SpellInfo; class Unit; struct SpellCategoryEntry; -class SpellHistory +class TC_GAME_API SpellHistory { public: typedef std::chrono::system_clock Clock; diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index ba658c885fa..1530235174a 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -187,13 +187,14 @@ enum SpellCustomAttributes SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000, SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000, SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET = 0x00040000, + SPELL_ATTR0_CU_NEEDS_AMMO_DATA = 0x00080000, SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2 }; uint32 GetTargetFlagMask(SpellTargetObjectTypes objType); -class SpellImplicitTargetInfo +class TC_GAME_API SpellImplicitTargetInfo { private: Targets _target; @@ -224,7 +225,7 @@ private: static StaticData _data[TOTAL_SPELL_TARGETS]; }; -class SpellEffectInfo +class TC_GAME_API SpellEffectInfo { SpellInfo const* _spellInfo; uint8 _effIndex; @@ -290,7 +291,7 @@ private: static StaticData _data[TOTAL_SPELL_EFFECTS]; }; -class SpellInfo +class TC_GAME_API SpellInfo { public: uint32 Id; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 0f80d83e0ff..50f750f2ca5 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -353,6 +353,12 @@ SpellMgr::~SpellMgr() UnloadSpellInfoStore(); } +SpellMgr* SpellMgr::instance() +{ + static SpellMgr instance; + return &instance; +} + /// Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book, etc bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg) { @@ -3050,6 +3056,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 48246: // Ball of Flame case 36327: // Shoot Arcane Explosion Arrow case 55479: // Force Obedience + case 28560: // Summon Blizzard (Sapphiron) spellInfo->MaxAffectedTargets = 1; break; case 36384: // Skartax Purple Beam @@ -3235,6 +3242,8 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->AttributesEx4 = 0; break; case 8145: // Tremor Totem (instant pulse) + spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; + /*no break*/ case 6474: // Earthbind Totem (instant pulse) spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY; break; diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 651a8cde938..fea7513b092 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -441,7 +441,7 @@ enum EffectRadiusIndex }; // Spell pet auras -class PetAura +class TC_GAME_API PetAura { private: typedef std::unordered_map<uint32, uint32> PetAuraMap; @@ -488,7 +488,7 @@ class PetAura }; typedef std::map<uint32, PetAura> SpellPetAuraMap; -struct SpellArea +struct TC_GAME_API SpellArea { uint32 spellId; uint32 areaId; // zone/subzone/or 0 is not limited to zone @@ -593,13 +593,13 @@ inline bool IsProfessionOrRidingSkill(uint32 skill) bool IsPartOfSkillLine(uint32 skillId, uint32 spellId); // spell diminishing returns -DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, bool triggered); -DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group); -DiminishingLevels GetDiminishingReturnsMaxLevel(DiminishingGroup group); -int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const* spellproto); -bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group); +TC_GAME_API DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, bool triggered); +TC_GAME_API DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group); +TC_GAME_API DiminishingLevels GetDiminishingReturnsMaxLevel(DiminishingGroup group); +TC_GAME_API int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const* spellproto); +TC_GAME_API bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group); -class SpellMgr +class TC_GAME_API SpellMgr { // Constructors private: @@ -608,11 +608,7 @@ class SpellMgr // Accessors (const or static functions) public: - static SpellMgr* instance() - { - static SpellMgr instance; - return &instance; - } + static SpellMgr* instance(); // Spell correctness for client using static bool IsSpellValid(SpellInfo const* spellInfo, Player* player = NULL, bool msg = true); @@ -696,7 +692,7 @@ class SpellMgr // SpellInfo object management SpellInfo const* GetSpellInfo(uint32 spellId) const { return spellId < GetSpellInfoStoreSize() ? mSpellInfoMap[spellId] : NULL; } // Use this only with 100% valid spellIds - SpellInfo const* EnsureSpellInfo(uint32 spellId) const + SpellInfo const* AssertSpellInfo(uint32 spellId) const { ASSERT(spellId < GetSpellInfoStoreSize()); SpellInfo const* spellInfo = mSpellInfoMap[spellId]; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 6876f8fa7ef..e2598386466 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -16,6 +16,7 @@ */ #include "Spell.h" +#include "ScriptMgr.h" #include "SpellAuras.h" #include "SpellScript.h" #include "SpellMgr.h" @@ -50,6 +51,12 @@ void _SpellScript::_Init(std::string const* scriptname, uint32 spellId) m_currentScriptState = SPELL_SCRIPT_STATE_NONE; m_scriptName = scriptname; m_scriptSpellId = spellId; + +#ifdef TRINITY_API_USE_DYNAMIC_LINKING + // Acquire a strong reference to the binary code + // to keep it loaded until all spells are destroyed. + m_moduleReference = sScriptMgr->AcquireModuleReferenceOfScriptName(*scriptname); +#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING } std::string const* _SpellScript::_GetScriptName() const diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 77a993fffae..539bc54cc94 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -22,6 +22,7 @@ #include "SharedDefines.h" #include "SpellAuraDefines.h" #include "Spell.h" +#include "ScriptReloadMgr.h" #include <stack> class Unit; @@ -52,7 +53,7 @@ enum SpellScriptState #define SPELL_SCRIPT_STATE_END SPELL_SCRIPT_STATE_UNLOADING + 1 // helper class from which SpellScript and SpellAura derive, use these classes instead -class _SpellScript +class TC_GAME_API _SpellScript { // internal use classes & functions // DO NOT OVERRIDE THESE IN SCRIPTS @@ -68,7 +69,7 @@ class _SpellScript std::string const* _GetScriptName() const; protected: - class EffectHook + class TC_GAME_API EffectHook { public: EffectHook(uint8 _effIndex); @@ -82,7 +83,7 @@ class _SpellScript uint8 effIndex; }; - class EffectNameCheck + class TC_GAME_API EffectNameCheck { public: EffectNameCheck(uint16 _effName) { effName = _effName; } @@ -92,7 +93,7 @@ class _SpellScript uint16 effName; }; - class EffectAuraNameCheck + class TC_GAME_API EffectAuraNameCheck { public: EffectAuraNameCheck(uint16 _effAurName) { effAurName = _effAurName; } @@ -105,6 +106,16 @@ class _SpellScript uint8 m_currentScriptState; std::string const* m_scriptName; uint32 m_scriptSpellId; + + private: + +#ifdef TRINITY_API_USE_DYNAMIC_LINKING + + // Strong reference to keep the binary code loaded + std::shared_ptr<ModuleReference> m_moduleReference; + +#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING + public: // // SpellScript/AuraScript interface base @@ -149,7 +160,7 @@ enum SpellScriptHookType #define HOOK_SPELL_END SPELL_SCRIPT_HOOK_CHECK_CAST + 1 #define HOOK_SPELL_COUNT HOOK_SPELL_END - HOOK_SPELL_START -class SpellScript : public _SpellScript +class TC_GAME_API SpellScript : public _SpellScript { // internal use classes & functions // DO NOT OVERRIDE THESE IN SCRIPTS @@ -165,7 +176,7 @@ class SpellScript : public _SpellScript SPELLSCRIPT_FUNCTION_TYPE_DEFINES(SpellScript) - class CastHandler + class TC_GAME_API CastHandler { public: CastHandler(SpellCastFnType _pCastHandlerScript); @@ -174,7 +185,7 @@ class SpellScript : public _SpellScript SpellCastFnType pCastHandlerScript; }; - class CheckCastHandler + class TC_GAME_API CheckCastHandler { public: CheckCastHandler(SpellCheckCastFnType checkCastHandlerScript); @@ -183,7 +194,7 @@ class SpellScript : public _SpellScript SpellCheckCastFnType _checkCastHandlerScript; }; - class EffectHandler : public _SpellScript::EffectNameCheck, public _SpellScript::EffectHook + class TC_GAME_API EffectHandler : public _SpellScript::EffectNameCheck, public _SpellScript::EffectHook { public: EffectHandler(SpellEffectFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName); @@ -194,7 +205,7 @@ class SpellScript : public _SpellScript SpellEffectFnType pEffectHandlerScript; }; - class HitHandler + class TC_GAME_API HitHandler { public: HitHandler(SpellHitFnType _pHitHandlerScript); @@ -203,7 +214,7 @@ class SpellScript : public _SpellScript SpellHitFnType pHitHandlerScript; }; - class TargetHook : public _SpellScript::EffectHook + class TC_GAME_API TargetHook : public _SpellScript::EffectHook { public: TargetHook(uint8 _effectIndex, uint16 _targetType, bool _area, bool _dest); @@ -216,7 +227,7 @@ class SpellScript : public _SpellScript bool dest; }; - class ObjectAreaTargetSelectHandler : public TargetHook + class TC_GAME_API ObjectAreaTargetSelectHandler : public TargetHook { public: ObjectAreaTargetSelectHandler(SpellObjectAreaTargetSelectFnType _pObjectAreaTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType); @@ -225,7 +236,7 @@ class SpellScript : public _SpellScript SpellObjectAreaTargetSelectFnType pObjectAreaTargetSelectHandlerScript; }; - class ObjectTargetSelectHandler : public TargetHook + class TC_GAME_API ObjectTargetSelectHandler : public TargetHook { public: ObjectTargetSelectHandler(SpellObjectTargetSelectFnType _pObjectTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType); @@ -234,7 +245,7 @@ class SpellScript : public _SpellScript SpellObjectTargetSelectFnType pObjectTargetSelectHandlerScript; }; - class DestinationTargetSelectHandler : public TargetHook + class TC_GAME_API DestinationTargetSelectHandler : public TargetHook { public: DestinationTargetSelectHandler(SpellDestinationTargetSelectFnType _DestinationTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType); @@ -470,7 +481,7 @@ enum AuraScriptHookType #define HOOK_AURA_EFFECT_END HOOK_AURA_EFFECT_CALC_SPELLMOD + 1 #define HOOK_AURA_EFFECT_COUNT HOOK_AURA_EFFECT_END - HOOK_AURA_EFFECT_START */ -class AuraScript : public _SpellScript +class TC_GAME_API AuraScript : public _SpellScript { // internal use classes & functions // DO NOT OVERRIDE THESE IN SCRIPTS @@ -493,7 +504,7 @@ class AuraScript : public _SpellScript AURASCRIPT_FUNCTION_TYPE_DEFINES(AuraScript) - class CheckAreaTargetHandler + class TC_GAME_API CheckAreaTargetHandler { public: CheckAreaTargetHandler(AuraCheckAreaTargetFnType pHandlerScript); @@ -501,7 +512,7 @@ class AuraScript : public _SpellScript private: AuraCheckAreaTargetFnType pHandlerScript; }; - class AuraDispelHandler + class TC_GAME_API AuraDispelHandler { public: AuraDispelHandler(AuraDispelFnType pHandlerScript); @@ -509,14 +520,14 @@ class AuraScript : public _SpellScript private: AuraDispelFnType pHandlerScript; }; - class EffectBase : public _SpellScript::EffectAuraNameCheck, public _SpellScript::EffectHook + class TC_GAME_API EffectBase : public _SpellScript::EffectAuraNameCheck, public _SpellScript::EffectHook { public: EffectBase(uint8 _effIndex, uint16 _effName); std::string ToString(); bool CheckEffect(SpellInfo const* spellInfo, uint8 effIndex) override; }; - class EffectPeriodicHandler : public EffectBase + class TC_GAME_API EffectPeriodicHandler : public EffectBase { public: EffectPeriodicHandler(AuraEffectPeriodicFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName); @@ -524,7 +535,7 @@ class AuraScript : public _SpellScript private: AuraEffectPeriodicFnType pEffectHandlerScript; }; - class EffectUpdatePeriodicHandler : public EffectBase + class TC_GAME_API EffectUpdatePeriodicHandler : public EffectBase { public: EffectUpdatePeriodicHandler(AuraEffectUpdatePeriodicFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName); @@ -532,7 +543,7 @@ class AuraScript : public _SpellScript private: AuraEffectUpdatePeriodicFnType pEffectHandlerScript; }; - class EffectCalcAmountHandler : public EffectBase + class TC_GAME_API EffectCalcAmountHandler : public EffectBase { public: EffectCalcAmountHandler(AuraEffectCalcAmountFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName); @@ -540,7 +551,7 @@ class AuraScript : public _SpellScript private: AuraEffectCalcAmountFnType pEffectHandlerScript; }; - class EffectCalcPeriodicHandler : public EffectBase + class TC_GAME_API EffectCalcPeriodicHandler : public EffectBase { public: EffectCalcPeriodicHandler(AuraEffectCalcPeriodicFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName); @@ -548,7 +559,7 @@ class AuraScript : public _SpellScript private: AuraEffectCalcPeriodicFnType pEffectHandlerScript; }; - class EffectCalcSpellModHandler : public EffectBase + class TC_GAME_API EffectCalcSpellModHandler : public EffectBase { public: EffectCalcSpellModHandler(AuraEffectCalcSpellModFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName); @@ -556,7 +567,7 @@ class AuraScript : public _SpellScript private: AuraEffectCalcSpellModFnType pEffectHandlerScript; }; - class EffectApplyHandler : public EffectBase + class TC_GAME_API EffectApplyHandler : public EffectBase { public: EffectApplyHandler(AuraEffectApplicationModeFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName, AuraEffectHandleModes _mode); @@ -565,7 +576,7 @@ class AuraScript : public _SpellScript AuraEffectApplicationModeFnType pEffectHandlerScript; AuraEffectHandleModes mode; }; - class EffectAbsorbHandler : public EffectBase + class TC_GAME_API EffectAbsorbHandler : public EffectBase { public: EffectAbsorbHandler(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex); @@ -573,7 +584,7 @@ class AuraScript : public _SpellScript private: AuraEffectAbsorbFnType pEffectHandlerScript; }; - class EffectManaShieldHandler : public EffectBase + class TC_GAME_API EffectManaShieldHandler : public EffectBase { public: EffectManaShieldHandler(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex); @@ -581,7 +592,7 @@ class AuraScript : public _SpellScript private: AuraEffectAbsorbFnType pEffectHandlerScript; }; - class EffectSplitHandler : public EffectBase + class TC_GAME_API EffectSplitHandler : public EffectBase { public: EffectSplitHandler(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex); @@ -589,7 +600,7 @@ class AuraScript : public _SpellScript private: AuraEffectSplitFnType pEffectHandlerScript; }; - class CheckProcHandler + class TC_GAME_API CheckProcHandler { public: CheckProcHandler(AuraCheckProcFnType handlerScript); @@ -597,7 +608,7 @@ class AuraScript : public _SpellScript private: AuraCheckProcFnType _HandlerScript; }; - class AuraProcHandler + class TC_GAME_API AuraProcHandler { public: AuraProcHandler(AuraProcFnType handlerScript); @@ -605,7 +616,7 @@ class AuraScript : public _SpellScript private: AuraProcFnType _HandlerScript; }; - class EffectProcHandler : public EffectBase + class TC_GAME_API EffectProcHandler : public EffectBase { public: EffectProcHandler(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName); @@ -645,7 +656,7 @@ class AuraScript : public _SpellScript AuraApplication const* m_auraApplication; bool m_defaultActionPrevented; - class ScriptStateStore + class TC_GAME_API ScriptStateStore { public: AuraApplication const* _auraApplication; diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index 499f0c9cbf0..d8df3310765 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -72,6 +72,12 @@ class PlayerTextBuilder WorldObject const* _target; }; +CreatureTextMgr* CreatureTextMgr::instance() +{ + static CreatureTextMgr instance; + return &instance; +} + void CreatureTextMgr::LoadCreatureTexts() { uint32 oldMSTime = getMSTime(); diff --git a/src/server/game/Texts/CreatureTextMgr.h b/src/server/game/Texts/CreatureTextMgr.h index 28fd98f21a8..d7953463a97 100644 --- a/src/server/game/Texts/CreatureTextMgr.h +++ b/src/server/game/Texts/CreatureTextMgr.h @@ -75,18 +75,14 @@ typedef std::unordered_map<uint32, CreatureTextHolder> CreatureTextMap; // a typedef std::map<CreatureTextId, CreatureTextLocale> LocaleCreatureTextMap; -class CreatureTextMgr +class TC_GAME_API CreatureTextMgr { private: CreatureTextMgr() { } ~CreatureTextMgr() { } public: - static CreatureTextMgr* instance() - { - static CreatureTextMgr instance; - return &instance; - } + static CreatureTextMgr* instance(); void LoadCreatureTexts(); void LoadCreatureTextLocales(); diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp index 1cf68eec9c7..94e4427fe10 100644 --- a/src/server/game/Tickets/TicketMgr.cpp +++ b/src/server/game/Tickets/TicketMgr.cpp @@ -284,6 +284,12 @@ void TicketMgr::ResetTickets() CharacterDatabase.Execute(stmt); } +TicketMgr* TicketMgr::instance() +{ + static TicketMgr instance; + return &instance; +} + void TicketMgr::LoadTickets() { uint32 oldMSTime = getMSTime(); diff --git a/src/server/game/Tickets/TicketMgr.h b/src/server/game/Tickets/TicketMgr.h index 9cc1d20b122..ff2cd656dce 100644 --- a/src/server/game/Tickets/TicketMgr.h +++ b/src/server/game/Tickets/TicketMgr.h @@ -84,7 +84,7 @@ enum TicketType TICKET_TYPE_CHARACTER_DELETED = 2, }; -class GmTicket +class TC_GAME_API GmTicket { public: GmTicket(); @@ -181,18 +181,14 @@ private: }; typedef std::map<uint32, GmTicket*> GmTicketList; -class TicketMgr +class TC_GAME_API TicketMgr { private: TicketMgr(); ~TicketMgr(); public: - static TicketMgr* instance() - { - static TicketMgr instance; - return &instance; - } + static TicketMgr* instance(); void LoadTickets(); void LoadSurveys(); diff --git a/src/server/game/Tools/CharacterDatabaseCleaner.h b/src/server/game/Tools/CharacterDatabaseCleaner.h index ecbd6d0a790..f1e6900a6bb 100644 --- a/src/server/game/Tools/CharacterDatabaseCleaner.h +++ b/src/server/game/Tools/CharacterDatabaseCleaner.h @@ -30,20 +30,20 @@ namespace CharacterDatabaseCleaner CLEANING_FLAG_QUESTSTATUS = 0x10 }; - void CleanDatabase(); + TC_GAME_API void CleanDatabase(); - void CheckUnique(const char* column, const char* table, bool (*check)(uint32)); + TC_GAME_API void CheckUnique(const char* column, const char* table, bool (*check)(uint32)); - bool AchievementProgressCheck(uint32 criteria); - bool SkillCheck(uint32 skill); - bool SpellCheck(uint32 spell_id); - bool TalentCheck(uint32 talent_id); + TC_GAME_API bool AchievementProgressCheck(uint32 criteria); + TC_GAME_API bool SkillCheck(uint32 skill); + TC_GAME_API bool SpellCheck(uint32 spell_id); + TC_GAME_API bool TalentCheck(uint32 talent_id); - void CleanCharacterAchievementProgress(); - void CleanCharacterSkills(); - void CleanCharacterSpell(); - void CleanCharacterTalent(); - void CleanCharacterQuestStatus(); + TC_GAME_API void CleanCharacterAchievementProgress(); + TC_GAME_API void CleanCharacterSkills(); + TC_GAME_API void CleanCharacterSpell(); + TC_GAME_API void CleanCharacterTalent(); + TC_GAME_API void CleanCharacterQuestStatus(); } #endif diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index 113fea2ea35..4c5ac1dab5e 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -315,10 +315,10 @@ bool PlayerDumpWriter::DumpTable(std::string& dump, ObjectGuid::LowType guid, ch break; case DTT_CHARACTER: { - if (result->GetFieldCount() <= 68) // avoid crashes on next check + if (result->GetFieldCount() <= 73) // avoid crashes on next check TC_LOG_FATAL("misc", "PlayerDumpWriter::DumpTable - Trying to access non-existing or wrong positioned field (`deleteInfos_Account`) in `characters` table."); - if (result->Fetch()[68].GetUInt32()) // characters.deleteInfos_Account - if filled error + if (result->Fetch()[73].GetUInt32()) // characters.deleteInfos_Account - if filled error return false; break; } @@ -549,11 +549,11 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s ROLLBACK(DUMP_FILE_BROKEN); const char null[5] = "NULL"; - if (!ChangeNth(line, 69, null)) // characters.deleteInfos_Account + if (!ChangeNth(line, 74, null)) // characters.deleteInfos_Account ROLLBACK(DUMP_FILE_BROKEN); - if (!ChangeNth(line, 70, null)) // characters.deleteInfos_Name + if (!ChangeNth(line, 75, null)) // characters.deleteInfos_Name ROLLBACK(DUMP_FILE_BROKEN); - if (!ChangeNth(line, 71, null)) // characters.deleteDate + if (!ChangeNth(line, 76, null)) // characters.deleteDate ROLLBACK(DUMP_FILE_BROKEN); break; } diff --git a/src/server/game/Tools/PlayerDump.h b/src/server/game/Tools/PlayerDump.h index 95d6ed2d04b..12cafc6ad48 100644 --- a/src/server/game/Tools/PlayerDump.h +++ b/src/server/game/Tools/PlayerDump.h @@ -62,7 +62,7 @@ enum DumpReturn DUMP_CHARACTER_DELETED }; -class PlayerDump +class TC_GAME_API PlayerDump { public: typedef std::set<ObjectGuid::LowType> DumpGuidSet; @@ -72,7 +72,7 @@ class PlayerDump PlayerDump() { } }; -class PlayerDumpWriter : public PlayerDump +class TC_GAME_API PlayerDumpWriter : public PlayerDump { public: PlayerDumpWriter() { } @@ -90,7 +90,7 @@ class PlayerDumpWriter : public PlayerDump DumpGuidSet items; }; -class PlayerDumpReader : public PlayerDump +class TC_GAME_API PlayerDumpReader : public PlayerDump { public: PlayerDumpReader() { } diff --git a/src/server/game/Warden/Warden.h b/src/server/game/Warden/Warden.h index 35ee18d4c02..b0aa496cbe8 100644 --- a/src/server/game/Warden/Warden.h +++ b/src/server/game/Warden/Warden.h @@ -92,7 +92,7 @@ struct ClientWardenModule class WorldSession; -class Warden +class TC_GAME_API Warden { friend class WardenWin; friend class WardenMac; diff --git a/src/server/game/Warden/WardenCheckMgr.cpp b/src/server/game/Warden/WardenCheckMgr.cpp index 5c4b0fc05b7..13ddae012fe 100644 --- a/src/server/game/Warden/WardenCheckMgr.cpp +++ b/src/server/game/Warden/WardenCheckMgr.cpp @@ -189,6 +189,12 @@ void WardenCheckMgr::LoadWardenOverrides() TC_LOG_INFO("server.loading", ">> Loaded %u warden action overrides.", count); } +WardenCheckMgr* WardenCheckMgr::instance() +{ + static WardenCheckMgr instance; + return &instance; +} + WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 Id) { if (Id < CheckStore.size()) diff --git a/src/server/game/Warden/WardenCheckMgr.h b/src/server/game/Warden/WardenCheckMgr.h index 4107ccc3aff..7349fd5b589 100644 --- a/src/server/game/Warden/WardenCheckMgr.h +++ b/src/server/game/Warden/WardenCheckMgr.h @@ -48,18 +48,14 @@ struct WardenCheckResult BigNumber Result; // MEM_CHECK }; -class WardenCheckMgr +class TC_GAME_API WardenCheckMgr { private: WardenCheckMgr(); ~WardenCheckMgr(); public: - static WardenCheckMgr* instance() - { - static WardenCheckMgr instance; - return &instance; - } + static WardenCheckMgr* instance(); // We have a linear key without any gaps, so we use vector for fast access typedef std::vector<WardenCheck*> CheckContainer; diff --git a/src/server/game/Warden/WardenMac.h b/src/server/game/Warden/WardenMac.h index 26a2d86524e..c7435502f63 100644 --- a/src/server/game/Warden/WardenMac.h +++ b/src/server/game/Warden/WardenMac.h @@ -28,7 +28,7 @@ class WorldSession; class Warden; -class WardenMac : public Warden +class TC_GAME_API WardenMac : public Warden { public: WardenMac(); diff --git a/src/server/game/Warden/WardenWin.h b/src/server/game/Warden/WardenWin.h index 4bf1af77c47..b3e6d7c586c 100644 --- a/src/server/game/Warden/WardenWin.h +++ b/src/server/game/Warden/WardenWin.h @@ -62,7 +62,7 @@ struct WardenInitModuleRequest class WorldSession; class Warden; -class WardenWin : public Warden +class TC_GAME_API WardenWin : public Warden { public: WardenWin(); diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h index c1f029d6264..6a770615308 100644 --- a/src/server/game/Weather/Weather.h +++ b/src/server/game/Weather/Weather.h @@ -62,7 +62,7 @@ enum WeatherState }; /// Weather for one zone -class Weather +class TC_GAME_API Weather { public: diff --git a/src/server/game/Weather/WeatherMgr.h b/src/server/game/Weather/WeatherMgr.h index 97c541fd3c0..e3dd4ac9ec4 100644 --- a/src/server/game/Weather/WeatherMgr.h +++ b/src/server/game/Weather/WeatherMgr.h @@ -30,15 +30,15 @@ class Player; namespace WeatherMgr { - void LoadWeatherData(); + TC_GAME_API void LoadWeatherData(); - Weather* FindWeather(uint32 id); - Weather* AddWeather(uint32 zone_id); - void RemoveWeather(uint32 zone_id); + TC_GAME_API Weather* FindWeather(uint32 id); + TC_GAME_API Weather* AddWeather(uint32 zone_id); + TC_GAME_API void RemoveWeather(uint32 zone_id); - void SendFineWeatherUpdateToPlayer(Player* player); + TC_GAME_API void SendFineWeatherUpdateToPlayer(Player* player); - void Update(uint32 diff); + TC_GAME_API void Update(uint32 diff); } #endif diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index b238b0a356d..4b64ef0bbd8 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -38,6 +38,7 @@ #include "DatabaseEnv.h" #include "DisableMgr.h" #include "GameEventMgr.h" +#include "GameObjectModel.h" #include "GridNotifiersImpl.h" #include "GroupMgr.h" #include "GuildMgr.h" @@ -53,6 +54,7 @@ #include "PoolMgr.h" #include "GitRevision.h" #include "ScriptMgr.h" +#include "ScriptReloadMgr.h" #include "SkillDiscovery.h" #include "SkillExtraItems.h" #include "SmartAI.h" @@ -66,17 +68,18 @@ #include "WorldSession.h" -std::atomic<bool> World::m_stopEvent(false); -uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE; -std::atomic<uint32> World::m_worldLoopCounter(0); +TC_GAME_API std::atomic<bool> World::m_stopEvent(false); +TC_GAME_API uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE; -float World::m_MaxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE; -float World::m_MaxVisibleDistanceInInstances = DEFAULT_VISIBILITY_INSTANCE; -float World::m_MaxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS; +TC_GAME_API std::atomic<uint32> World::m_worldLoopCounter(0); -int32 World::m_visibility_notify_periodOnContinents = DEFAULT_VISIBILITY_NOTIFY_PERIOD; -int32 World::m_visibility_notify_periodInInstances = DEFAULT_VISIBILITY_NOTIFY_PERIOD; -int32 World::m_visibility_notify_periodInBGArenas = DEFAULT_VISIBILITY_NOTIFY_PERIOD; +TC_GAME_API float World::m_MaxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE; +TC_GAME_API float World::m_MaxVisibleDistanceInInstances = DEFAULT_VISIBILITY_INSTANCE; +TC_GAME_API float World::m_MaxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS; + +TC_GAME_API int32 World::m_visibility_notify_periodOnContinents = DEFAULT_VISIBILITY_NOTIFY_PERIOD; +TC_GAME_API int32 World::m_visibility_notify_periodInInstances = DEFAULT_VISIBILITY_NOTIFY_PERIOD; +TC_GAME_API int32 World::m_visibility_notify_periodInBGArenas = DEFAULT_VISIBILITY_NOTIFY_PERIOD; /// World constructor World::World() @@ -139,6 +142,12 @@ World::~World() /// @todo free addSessQueue } +World* World::instance() +{ + static World instance; + return &instance; +} + /// Find a player in a specified zone Player* World::FindPlayerInZone(uint32 zone) { @@ -592,6 +601,18 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_PRESERVE_CUSTOM_CHANNELS] = sConfigMgr->GetBoolDefault("PreserveCustomChannels", false); m_int_configs[CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION] = sConfigMgr->GetIntDefault("PreserveCustomChannelDuration", 14); m_bool_configs[CONFIG_GRID_UNLOAD] = sConfigMgr->GetBoolDefault("GridUnload", true); + m_bool_configs[CONFIG_BASEMAP_LOAD_GRIDS] = sConfigMgr->GetBoolDefault("BaseMapLoadAllGrids", false); + if (m_bool_configs[CONFIG_BASEMAP_LOAD_GRIDS] && m_bool_configs[CONFIG_GRID_UNLOAD]) + { + TC_LOG_ERROR("server.loading", "BaseMapLoadAllGrids enabled, but GridUnload also enabled. GridUnload must be disabled to enable base map pre-loading. Base map pre-loading disabled"); + m_bool_configs[CONFIG_BASEMAP_LOAD_GRIDS] = false; + } + m_bool_configs[CONFIG_INSTANCEMAP_LOAD_GRIDS] = sConfigMgr->GetBoolDefault("InstanceMapLoadAllGrids", false); + if (m_bool_configs[CONFIG_INSTANCEMAP_LOAD_GRIDS] && m_bool_configs[CONFIG_GRID_UNLOAD]) + { + TC_LOG_ERROR("server.loading", "InstanceMapLoadAllGrids enabled, but GridUnload also enabled. GridUnload must be disabled to enable instance map pre-loading. Instance map pre-loading disabled"); + m_bool_configs[CONFIG_INSTANCEMAP_LOAD_GRIDS] = false; + } m_int_configs[CONFIG_INTERVAL_SAVE] = sConfigMgr->GetIntDefault("PlayerSaveInterval", 15 * MINUTE * IN_MILLISECONDS); m_int_configs[CONFIG_INTERVAL_DISCONNECT_TOLERANCE] = sConfigMgr->GetIntDefault("DisconnectToleranceInterval", 0); m_bool_configs[CONFIG_STATS_SAVE_ONLY_ON_LOGOUT] = sConfigMgr->GetBoolDefault("PlayerSave.Stats.SaveOnlyOnLogout", true); @@ -1047,7 +1068,6 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfigMgr->GetBoolDefault("Arena.AutoDistributePoints", false); m_int_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfigMgr->GetIntDefault ("Arena.AutoDistributeInterval", 7); m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetBoolDefault("Arena.QueueAnnouncer.Enable", false); - m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY] = sConfigMgr->GetBoolDefault("Arena.QueueAnnouncer.PlayerOnly", false); m_int_configs[CONFIG_ARENA_SEASON_ID] = sConfigMgr->GetIntDefault ("Arena.ArenaSeason.ID", 1); m_int_configs[CONFIG_ARENA_START_RATING] = sConfigMgr->GetIntDefault ("Arena.ArenaStartRating", 0); m_int_configs[CONFIG_ARENA_START_PERSONAL_RATING] = sConfigMgr->GetIntDefault ("Arena.ArenaStartPersonalRating", 1000); @@ -1300,13 +1320,19 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA] = sConfigMgr->GetBoolDefault("Calculate.Creature.Zone.Area.Data", false); m_bool_configs[CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA] = sConfigMgr->GetBoolDefault("Calculate.Gameoject.Zone.Area.Data", false); + // HotSwap + m_bool_configs[CONFIG_HOTSWAP_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.Enabled", true); + m_bool_configs[CONFIG_HOTSWAP_RECOMPILER_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnableReCompiler", true); + m_bool_configs[CONFIG_HOTSWAP_EARLY_TERMINATION_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnableEarlyTermination", true); + m_bool_configs[CONFIG_HOTSWAP_BUILD_FILE_RECREATION_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnableBuildFileRecreation", true); + m_bool_configs[CONFIG_HOTSWAP_INSTALL_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnableInstall", true); + m_bool_configs[CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnablePrefixCorrection", true); + // call ScriptMgr if we're reloading the configuration if (reload) sScriptMgr->OnConfigLoad(reload); } -extern void LoadGameObjectModelList(std::string const& dataPath); - /// Initialize the World void World::SetInitialWorldSettings() { @@ -1369,7 +1395,7 @@ void World::SetInitialWorldSettings() uint32 server_type = IsFFAPvPRealm() ? uint32(REALM_TYPE_PVP) : getIntConfig(CONFIG_GAME_TYPE); uint32 realm_zone = getIntConfig(CONFIG_REALM_ZONE); - LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID); // One-time query + LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realm.Id.Realm); // One-time query ///- Load the DBC files TC_LOG_INFO("server.loading", "Initialize data stores..."); @@ -1790,7 +1816,7 @@ void World::SetInitialWorldSettings() m_startTime = m_gameTime; LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES(%u, %u, 0, '%s')", - realmID, uint32(m_startTime), GitRevision::GetFullVersion()); // One-time query + realm.Id.Realm, uint32(m_startTime), GitRevision::GetFullVersion()); // One-time query m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS); m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS); @@ -1809,6 +1835,8 @@ void World::SetInitialWorldSettings() m_timers[WUPDATE_PINGDB].SetInterval(getIntConfig(CONFIG_DB_PING_INTERVAL)*MINUTE*IN_MILLISECONDS); // Mysql ping time in minutes + m_timers[WUPDATE_CHECK_FILECHANGES].SetInterval(500); + //to set mailtimer to return mails every day between 4 and 5 am //mailtimer is increased when updating auctions //one second is 1000 -(tested on win system) @@ -1888,6 +1916,19 @@ void World::SetInitialWorldSettings() LoadCharacterInfoStore(); + // Preload all cells, if required for the base maps + if (sWorld->getBoolConfig(CONFIG_BASEMAP_LOAD_GRIDS)) + { + sMapMgr->DoForAllMaps([](Map* map) + { + if (!map->Instanceable()) + { + TC_LOG_INFO("server.loading", "Pre-loading base map data for map %u", map->GetId()); + map->LoadAllCells(); + } + }); + } + uint32 startupDuration = GetMSTimeDiffToNow(startupBegin); TC_LOG_INFO("server.worldserver", "World initialized in %u minutes %u seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000)); @@ -2079,6 +2120,13 @@ void World::Update(uint32 diff) m_timers[WUPDATE_AHBOT].Reset(); } + /// <li> Handle file changes + if (m_timers[WUPDATE_CHECK_FILECHANGES].Passed()) + { + sScriptReloadMgr->Update(); + m_timers[WUPDATE_CHECK_FILECHANGES].Reset(); + } + /// <li> Handle session updates when the timer has passed ResetTimeDiffRecord(); UpdateSessions(diff); @@ -2103,7 +2151,7 @@ void World::Update(uint32 diff) stmt->setUInt32(0, tmpDiff); stmt->setUInt16(1, uint16(maxOnlinePlayers)); - stmt->setUInt32(2, realmID); + stmt->setUInt32(2, realm.Id.Realm); stmt->setUInt32(3, uint32(m_startTime)); LoginDatabase.Execute(stmt); @@ -2826,13 +2874,13 @@ void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount) PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); stmt->setUInt32(0, accountId); - stmt->setUInt32(1, realmID); + stmt->setUInt32(1, realm.Id.Realm); LoginDatabase.Execute(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS); stmt->setUInt8(0, charCount); stmt->setUInt32(1, accountId); - stmt->setUInt32(2, realmID); + stmt->setUInt32(2, realm.Id.Realm); LoginDatabase.Execute(stmt); } } @@ -2960,7 +3008,7 @@ void World::ResetDailyQuests() void World::LoadDBAllowedSecurityLevel() { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL); - stmt->setInt32(0, int32(realmID)); + stmt->setInt32(0, int32(realm.Id.Realm)); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) @@ -3290,3 +3338,4 @@ void World::RemoveOldCorpses() m_timers[WUPDATE_CORPSES].SetCurrent(m_timers[WUPDATE_CORPSES].GetInterval()); } +Realm realm; diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 2f1580d887c..abc0ea452ac 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -29,6 +29,7 @@ #include "SharedDefines.h" #include "QueryResult.h" #include "Callback.h" +#include "Realm/Realm.h" #include <atomic> #include <map> @@ -80,6 +81,7 @@ enum WorldTimers WUPDATE_DELETECHARS, WUPDATE_AHBOT, WUPDATE_PINGDB, + WUPDATE_CHECK_FILECHANGES, WUPDATE_COUNT }; @@ -128,7 +130,6 @@ enum WorldBoolConfigs CONFIG_BG_XP_FOR_KILL, CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS, CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE, - CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY, CONFIG_ARENA_SEASON_IN_PROGRESS, CONFIG_ARENA_LOG_EXTENDED_INFO, CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN, @@ -165,6 +166,14 @@ enum WorldBoolConfigs CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA, CONFIG_RESET_DUEL_COOLDOWNS, CONFIG_RESET_DUEL_HEALTH_MANA, + CONFIG_BASEMAP_LOAD_GRIDS, + CONFIG_INSTANCEMAP_LOAD_GRIDS, + CONFIG_HOTSWAP_ENABLED, + CONFIG_HOTSWAP_RECOMPILER_ENABLED, + CONFIG_HOTSWAP_EARLY_TERMINATION_ENABLED, + CONFIG_HOTSWAP_BUILD_FILE_RECREATION_ENABLED, + CONFIG_HOTSWAP_INSTALL_ENABLED, + CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED, BOOL_CONFIG_VALUE_COUNT }; @@ -446,18 +455,6 @@ enum BillingPlanFlags SESSION_ENABLE_CAIS = 0x80 }; -/// Type of server, this is values from second column of Cfg_Configs.dbc -enum RealmType -{ - REALM_TYPE_NORMAL = 0, - REALM_TYPE_PVP = 1, - REALM_TYPE_NORMAL2 = 4, - REALM_TYPE_RP = 6, - REALM_TYPE_RPPVP = 8, - REALM_TYPE_FFA_PVP = 16 // custom, free for all pvp mode like arena PvP in all zones except rest activated places and sanctuaries - // replaced by REALM_PVP in realm list -}; - enum RealmZone { REALM_ZONE_UNKNOWN = 0, // any language @@ -546,14 +543,10 @@ struct CharacterInfo }; /// The World -class World +class TC_GAME_API World { public: - static World* instance() - { - static World instance; - return &instance; - } + static World* instance(); static std::atomic<uint32> m_worldLoopCounter; @@ -882,8 +875,9 @@ class World std::deque<std::future<PreparedQueryResult>> m_realmCharCallbacks; }; -extern uint32 realmID; +TC_GAME_API extern Realm realm; #define sWorld World::instance() + #endif /// @} diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index ea0b058b91d..31ba073e77d 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -8,148 +8,232 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# Enable precompiled headers when using the GCC compiler. +message("") -if (USE_SCRIPTPCH) - set(scripts_STAT_PCH_HDR PrecompiledHeaders/ScriptPCH.h) - set(scripts_STAT_PCH_SRC PrecompiledHeaders/ScriptPCH.cpp) -endif () +# Make the script module list available in the current scope +GetScriptModuleList(SCRIPT_MODULE_LIST) + +# Make the native install offset available in this scope +GetInstallOffset(INSTALL_OFFSET) -message(STATUS "SCRIPT PREPARATIONS") - -macro(PrepareScripts name out) - file(GLOB_RECURSE found - ${name}/*.h - ${name}/*.cpp - ) - list(APPEND ${out} ${found}) - message(STATUS " -> Prepared: ${name}") -endmacro(PrepareScripts) - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - ../game/AI/ScriptedAI/ScriptedEscortAI.cpp - ../game/AI/ScriptedAI/ScriptedCreature.cpp - ../game/AI/ScriptedAI/ScriptedFollowerAI.cpp - ../game/Maps/AreaBoundary.cpp -) - -PrepareScripts(Spells scripts_STAT_SRCS) -PrepareScripts(Commands scripts_STAT_SRCS) - -if(SCRIPTS) - PrepareScripts(Custom scripts_STAT_SRCS) - PrepareScripts(World scripts_STAT_SRCS) - PrepareScripts(OutdoorPvP scripts_STAT_SRCS) - PrepareScripts(EasternKingdoms scripts_STAT_SRCS) - PrepareScripts(Kalimdor scripts_STAT_SRCS) - PrepareScripts(Outland scripts_STAT_SRCS) - PrepareScripts(Northrend scripts_STAT_SRCS) - PrepareScripts(Events scripts_STAT_SRCS) - PrepareScripts(Pet scripts_STAT_SRCS) +# Sets the SCRIPTS_${SCRIPT_MODULE} variables +# when using predefined templates for script building +# like dynamic, static, minimal-static... +# Sets SCRIPTS_DEFAULT_LINKAGE +if (SCRIPTS MATCHES "dynamic") + set(SCRIPTS_DEFAULT_LINKAGE "dynamic") +elseif(SCRIPTS MATCHES "static") + set(SCRIPTS_DEFAULT_LINKAGE "static") +else() + set(SCRIPTS_DEFAULT_LINKAGE "disabled") +endif() +# Sets SCRIPTS_USE_WHITELIST +# Sets SCRIPTS_WHITELIST +if (SCRIPTS MATCHES "minimal") + set(SCRIPTS_USE_WHITELIST ON) + # Whitelist which is used when minimal is selected + list(APPEND SCRIPTS_WHITELIST Commands Spells) endif() -message(STATUS "SCRIPT PREPARATION COMPLETE") -message("") +# Set the SCRIPTS_${SCRIPT_MODULE} variables from the +# variables set above +foreach(SCRIPT_MODULE ${SCRIPT_MODULE_LIST}) + ScriptModuleNameToVariable(${SCRIPT_MODULE} SCRIPT_MODULE_VARIABLE) + if (${SCRIPT_MODULE_VARIABLE} STREQUAL "default") + if(SCRIPTS_USE_WHITELIST) + list(FIND SCRIPTS_WHITELIST "${SCRIPT_MODULE}" INDEX) + if (${INDEX} GREATER -1) + set(${SCRIPT_MODULE_VARIABLE} ${SCRIPTS_DEFAULT_LINKAGE}) + else() + set(${SCRIPT_MODULE_VARIABLE} "disabled") + endif() + else() + set(${SCRIPT_MODULE_VARIABLE} ${SCRIPTS_DEFAULT_LINKAGE}) + endif() + endif() + # Build the Graph values + if (${SCRIPT_MODULE_VARIABLE} MATCHES "dynamic") + GetProjectNameOfScriptModule(${SCRIPT_MODULE} SCRIPT_MODULE_PROJECT_NAME) + GetNativeSharedLibraryName(${SCRIPT_MODULE_PROJECT_NAME} SCRIPT_PROJECT_LIBRARY) + list(APPEND GRAPH_KEYS ${SCRIPT_MODULE_PROJECT_NAME}) + set(GRAPH_VALUE_DISPLAY_${SCRIPT_MODULE_PROJECT_NAME} ${SCRIPT_PROJECT_LIBRARY}) + list(APPEND GRAPH_VALUE_CONTAINS_MODULES_${SCRIPT_MODULE_PROJECT_NAME} ${SCRIPT_MODULE}) + elseif(${SCRIPT_MODULE_VARIABLE} MATCHES "static") + list(APPEND GRAPH_KEYS worldserver) + set(GRAPH_VALUE_DISPLAY_worldserver worldserver) + list(APPEND GRAPH_VALUE_CONTAINS_MODULES_worldserver ${SCRIPT_MODULE}) + else() + list(APPEND GRAPH_KEYS disabled) + set(GRAPH_VALUE_DISPLAY_disabled disabled) + list(APPEND GRAPH_VALUE_CONTAINS_MODULES_disabled ${SCRIPT_MODULE}) + endif() +endforeach() + +list(SORT GRAPH_KEYS) +list(REMOVE_DUPLICATES GRAPH_KEYS) -include_directories( - ${CMAKE_SOURCE_DIR}/dep/cppformat - ${CMAKE_SOURCE_DIR}/dep/g3dlite/include - ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include - ${CMAKE_SOURCE_DIR}/src/common/ - ${CMAKE_SOURCE_DIR}/src/common/Collision - ${CMAKE_SOURCE_DIR}/src/common/Collision/Management - ${CMAKE_SOURCE_DIR}/src/common/Collision/Maps - ${CMAKE_SOURCE_DIR}/src/common/Collision/Models - ${CMAKE_SOURCE_DIR}/src/common/Configuration - ${CMAKE_SOURCE_DIR}/src/common/Debugging - ${CMAKE_SOURCE_DIR}/src/common/Logging - ${CMAKE_SOURCE_DIR}/src/common/Threading - ${CMAKE_SOURCE_DIR}/src/common/Utilities - ${CMAKE_SOURCE_DIR}/src/server/database/Database - ${CMAKE_SOURCE_DIR}/src/server/game/Accounts - ${CMAKE_SOURCE_DIR}/src/server/game/Achievements - ${CMAKE_SOURCE_DIR}/src/server/game/Addons - ${CMAKE_SOURCE_DIR}/src/server/game/AI - ${CMAKE_SOURCE_DIR}/src/server/game/AI/CoreAI - ${CMAKE_SOURCE_DIR}/src/server/game/AI/PlayerAI - ${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI - ${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts - ${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse - ${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouseBot - ${CMAKE_SOURCE_DIR}/src/server/game/Battlefield - ${CMAKE_SOURCE_DIR}/src/server/game/Battlefield/Zones - ${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds - ${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds/Zones - ${CMAKE_SOURCE_DIR}/src/server/game/Chat - ${CMAKE_SOURCE_DIR}/src/server/game/Chat/Channels - ${CMAKE_SOURCE_DIR}/src/server/game/Combat - ${CMAKE_SOURCE_DIR}/src/server/game/Conditions - ${CMAKE_SOURCE_DIR}/src/server/game/DataStores - ${CMAKE_SOURCE_DIR}/src/server/game/DungeonFinding - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Corpse - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Creature - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/DynamicObject - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/GameObject - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item/Container - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object/Updates - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Pet - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Player - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Transport - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Unit - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Vehicle - ${CMAKE_SOURCE_DIR}/src/server/game/Events - ${CMAKE_SOURCE_DIR}/src/server/game/Globals - ${CMAKE_SOURCE_DIR}/src/server/game/Grids - ${CMAKE_SOURCE_DIR}/src/server/game/Grids/Cells - ${CMAKE_SOURCE_DIR}/src/server/game/Grids/Notifiers - ${CMAKE_SOURCE_DIR}/src/server/game/Groups - ${CMAKE_SOURCE_DIR}/src/server/game/Guilds - ${CMAKE_SOURCE_DIR}/src/server/game/Handlers - ${CMAKE_SOURCE_DIR}/src/server/game/Instances - ${CMAKE_SOURCE_DIR}/src/server/game/Loot - ${CMAKE_SOURCE_DIR}/src/server/game/Mails - ${CMAKE_SOURCE_DIR}/src/server/game/Maps - ${CMAKE_SOURCE_DIR}/src/server/game/Miscellaneous - ${CMAKE_SOURCE_DIR}/src/server/game/Movement - ${CMAKE_SOURCE_DIR}/src/server/game/Movement/MovementGenerators - ${CMAKE_SOURCE_DIR}/src/server/game/Movement/Spline - ${CMAKE_SOURCE_DIR}/src/server/game/Movement/Waypoints - ${CMAKE_SOURCE_DIR}/src/server/game/OutdoorPvP - ${CMAKE_SOURCE_DIR}/src/server/game/Pools - ${CMAKE_SOURCE_DIR}/src/server/game/Quests - ${CMAKE_SOURCE_DIR}/src/server/game/Reputation - ${CMAKE_SOURCE_DIR}/src/server/game/Scripting - ${CMAKE_SOURCE_DIR}/src/server/game/Server - ${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol - ${CMAKE_SOURCE_DIR}/src/server/game/Skills - ${CMAKE_SOURCE_DIR}/src/server/game/Spells - ${CMAKE_SOURCE_DIR}/src/server/game/Spells/Auras - ${CMAKE_SOURCE_DIR}/src/server/game/Texts - ${CMAKE_SOURCE_DIR}/src/server/game/Tickets - ${CMAKE_SOURCE_DIR}/src/server/game/Tools - ${CMAKE_SOURCE_DIR}/src/server/game/Warden - ${CMAKE_SOURCE_DIR}/src/server/game/Weather - ${CMAKE_SOURCE_DIR}/src/server/game/World - ${CMAKE_SOURCE_DIR}/src/server/shared - ${CMAKE_SOURCE_DIR}/src/server/shared/DataStores - ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic - ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference - ${CMAKE_SOURCE_DIR}/src/server/shared/Packets - ${MYSQL_INCLUDE_DIR} - ${VALGRIND_INCLUDE_DIR} -) +# Display the script graph +message("* Script configuration (${SCRIPTS}): + |") + +foreach(GRAPH_KEY ${GRAPH_KEYS}) + if (NOT GRAPH_KEY STREQUAL "disabled") + message(" +- ${GRAPH_VALUE_DISPLAY_${GRAPH_KEY}}") + else() + message(" | ${GRAPH_VALUE_DISPLAY_${GRAPH_KEY}}") + endif() + foreach(GRAPH_PROJECT_ENTRY ${GRAPH_VALUE_CONTAINS_MODULES_${GRAPH_KEY}}) + message(" | +- ${GRAPH_PROJECT_ENTRY}") + endforeach() + message(" |") +endforeach() + +# Base sources which are used by every script project +if (USE_SCRIPTPCH) + set(PRIVATE_PCH_HEADER ScriptPCH.h) + set(PRIVATE_PCH_SOURCE ScriptPCH.cpp) +endif () GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) +# Configures the scriptloader with the given name and stores the output in the LOADER_OUT variable. +# It is possible to expose multiple subdirectories from the same scriptloader through passing +# it to the variable arguments +function(ConfigureScriptLoader SCRIPTLOADER_NAME LOADER_OUT IS_DYNAMIC_SCRIPTLOADER) + # Deduces following variables which are referenced by thge template: + # TRINITY_IS_DYNAMIC_SCRIPTLOADER + # TRINITY_SCRIPTS_FORWARD_DECL + # TRINITY_SCRIPTS_INVOKE + # TRINITY_CURRENT_SCRIPT_PROJECT + + # To generate export macros + set(TRINITY_IS_DYNAMIC_SCRIPTLOADER ${IS_DYNAMIC_SCRIPTLOADER}) + # To generate forward declarations of the loading functions + unset(TRINITY_SCRIPTS_FORWARD_DECL) + unset(TRINITY_SCRIPTS_INVOKE) + # The current script project which is built in + set(TRINITY_CURRENT_SCRIPT_PROJECT ${SCRIPTLOADER_NAME}) + foreach(LOCALE_SCRIPT_MODULE ${ARGN}) + # Determine the loader function ("Add##${NameOfDirectory}##Scripts()") + set(LOADER_FUNCTION + "Add${LOCALE_SCRIPT_MODULE}Scripts()") + # Generate the funciton call and the forward declarations + set(TRINITY_SCRIPTS_FORWARD_DECL + "${TRINITY_SCRIPTS_FORWARD_DECL}void ${LOADER_FUNCTION};\n") + set(TRINITY_SCRIPTS_INVOKE + "${TRINITY_SCRIPTS_INVOKE} ${LOADER_FUNCTION};\n") + endforeach() + set(GENERATED_LOADER ${CMAKE_CURRENT_BINARY_DIR}/gen_scriptloader/${SCRIPTLOADER_NAME}/ScriptLoader.cpp) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ScriptLoader.cpp.in.cmake ${GENERATED_LOADER}) + set(${LOADER_OUT} ${GENERATED_LOADER} PARENT_SCOPE) +endfunction() + +# Generates the actual script projects +# Fills the STATIC_SCRIPT_MODULES and DYNAMIC_SCRIPT_MODULE_PROJECTS variables +# which contain the names which scripts are linked statically/dynamically and +# adds the sources of the static modules to the PRIVATE_SOURCES variable. +foreach(SCRIPT_MODULE ${SCRIPT_MODULE_LIST}) + GetPathToScriptModule(${SCRIPT_MODULE} SCRIPT_MODULE_PATH) + ScriptModuleNameToVariable(${SCRIPT_MODULE} SCRIPT_MODULE_VARIABLE) + + if ((${SCRIPT_MODULE_VARIABLE} STREQUAL "disabled") OR + (${SCRIPT_MODULE_VARIABLE} STREQUAL "static")) + # Uninstall disabled modules + GetProjectNameOfScriptModule(${SCRIPT_MODULE} SCRIPT_MODULE_PROJECT_NAME) + GetNativeSharedLibraryName(${SCRIPT_MODULE_PROJECT_NAME} SCRIPT_MODULE_OUTPUT_NAME) + list(APPEND DISABLED_SCRIPT_MODULE_PROJECTS ${INSTALL_OFFSET}/${SCRIPT_MODULE_OUTPUT_NAME}) + if (${SCRIPT_MODULE_VARIABLE} STREQUAL "static") + # Add the module name to STATIC_SCRIPT_MODULES + list(APPEND STATIC_SCRIPT_MODULES ${SCRIPT_MODULE}) + # Add the module content to the whole static module + CollectSourceFiles(${SCRIPT_MODULE_PATH} PRIVATE_SOURCES) + endif() + elseif(${SCRIPT_MODULE_VARIABLE} STREQUAL "dynamic") + # Generate an own dynamic module which is loadable on runtime + # Add the module content to the whole static module + unset(SCRIPT_MODULE_PRIVATE_SOURCES) + CollectSourceFiles(${SCRIPT_MODULE_PATH} SCRIPT_MODULE_PRIVATE_SOURCES) + # Configure the scriptloader + ConfigureScriptLoader(${SCRIPT_MODULE} SCRIPT_MODULE_PRIVATE_SCRIPTLOADER ON ${SCRIPT_MODULE}) + GetProjectNameOfScriptModule(${SCRIPT_MODULE} SCRIPT_MODULE_PROJECT_NAME) + # Add the module name to DYNAMIC_SCRIPT_MODULES + list(APPEND DYNAMIC_SCRIPT_MODULE_PROJECTS ${SCRIPT_MODULE_PROJECT_NAME}) + # Create the script module project + add_library(${SCRIPT_MODULE_PROJECT_NAME} SHARED + ${PRIVATE_PCH_SOURCE} + ${SCRIPT_MODULE_PRIVATE_SOURCES} + ${SCRIPT_MODULE_PRIVATE_SCRIPTLOADER}) + target_link_libraries(${SCRIPT_MODULE_PROJECT_NAME} + PUBLIC + game) + set_target_properties(${SCRIPT_MODULE_PROJECT_NAME} + PROPERTIES + FOLDER + "scripts") + + if(UNIX) + install(TARGETS ${SCRIPT_MODULE_PROJECT_NAME} + DESTINATION ${INSTALL_OFFSET} + COMPONENT ${SCRIPT_MODULE_PROJECT_NAME}) + elseif(WIN32) + install(TARGETS ${SCRIPT_MODULE_PROJECT_NAME} + RUNTIME DESTINATION ${INSTALL_OFFSET} + COMPONENT ${SCRIPT_MODULE_PROJECT_NAME}) + if(MSVC) + # Place the script modules in the script subdirectory + set_target_properties(${SCRIPT_MODULE_PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/bin/Debug/scripts + RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin/Release/scripts + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}/bin/RelWithDebInfo/scripts + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_BINARY_DIR}/bin/MinSizeRel/scripts) + endif() + endif() + else() + message(FATAL_ERROR "Unknown value \"${${SCRIPT_MODULE_VARIABLE}}\"!") + endif() +endforeach() + +# Add the dynamic script modules to the worldserver as dependency +set(WORLDSERVER_DYNAMIC_SCRIPT_MODULES_DEPENDENCIES ${DYNAMIC_SCRIPT_MODULE_PROJECTS} PARENT_SCOPE) + +ConfigureScriptLoader("static" SCRIPT_MODULE_PRIVATE_SCRIPTLOADER OFF ${STATIC_SCRIPT_MODULES}) + add_library(scripts STATIC - ${scripts_STAT_SRCS} - ${scripts_STAT_PCH_SRC} -) + ScriptLoader.h + ${PRIVATE_PCH_SOURCE} + ${SCRIPT_MODULE_PRIVATE_SCRIPTLOADER} + ${PRIVATE_SOURCES}) + +target_link_libraries(scripts + PUBLIC + game-interface) + +target_include_directories(scripts + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}) + +set_target_properties(scripts + PROPERTIES + FOLDER + "scripts") # Generate precompiled header if (USE_SCRIPTPCH) - add_cxx_pch(scripts ${scripts_STAT_PCH_HDR} ${scripts_STAT_PCH_SRC}) + list(APPEND ALL_SCRIPT_PROJECTS scripts ${DYNAMIC_SCRIPT_MODULE_PROJECTS}) + add_cxx_pch("${ALL_SCRIPT_PROJECTS}" ${PRIVATE_PCH_HEADER} ${PRIVATE_PCH_SOURCE}) +endif() + +# Remove all shared libraries in the installl directory which +# are contained in the static library already. +if (DISABLED_SCRIPT_MODULE_PROJECTS) + install(CODE " + foreach(SCRIPT_TO_UNINSTALL ${DISABLED_SCRIPT_MODULE_PROJECTS}) + if (EXISTS \"\${SCRIPT_TO_UNINSTALL}\") + message(STATUS \"Uninstalling: \${SCRIPT_TO_UNINSTALL}\") + file(REMOVE \"\${SCRIPT_TO_UNINSTALL}\") + endif() + endforeach() + ") endif() + +message("") diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index f25e91ee3e6..4bce2d168a9 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -121,10 +121,16 @@ public: if (!accountName || !password) return false; - AccountOpResult result = sAccountMgr->CreateAccount(std::string(accountName), std::string(password), email); - switch (result) + if (strchr(accountName, '@')) + { + handler->PSendSysMessage(LANG_ACCOUNT_USE_BNET_COMMANDS); + handler->SetSentErrorMessage(true); + return false; + } + + switch (sAccountMgr->CreateAccount(std::string(accountName), std::string(password), email)) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName); if (handler->GetSession()) { @@ -134,15 +140,15 @@ public: accountName, email.c_str()); } break; - case AOR_NAME_TOO_LONG: + case AccountOpResult::AOR_NAME_TOO_LONG: handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG); handler->SetSentErrorMessage(true); return false; - case AOR_NAME_ALREADY_EXIST: + case AccountOpResult::AOR_NAME_ALREADY_EXIST: handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); handler->SetSentErrorMessage(true); return false; - case AOR_DB_INTERNAL_ERROR: + case AccountOpResult::AOR_DB_INTERNAL_ERROR: handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName); handler->SetSentErrorMessage(true); return false; @@ -168,7 +174,7 @@ public: return false; std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -192,14 +198,14 @@ public: AccountOpResult result = AccountMgr::DeleteAccount(accountId); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->PSendSysMessage(LANG_ACCOUNT_DELETED, accountName.c_str()); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_DB_INTERNAL_ERROR: + case AccountOpResult::AOR_DB_INTERNAL_ERROR: handler->PSendSysMessage(LANG_ACCOUNT_NOT_DELETED_SQL_ERROR, accountName.c_str()); handler->SetSentErrorMessage(true); return false; @@ -415,7 +421,7 @@ public: AccountOpResult result = AccountMgr::ChangeEmail(handler->GetSession()->GetAccountId(), std::string(email)); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); sScriptMgr->OnEmailChange(handler->GetSession()->GetAccountId()); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Email from [%s] to [%s].", @@ -423,7 +429,7 @@ public: handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().GetCounter(), oldEmail, email); break; - case AOR_EMAIL_TOO_LONG: + case AccountOpResult::AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); @@ -505,14 +511,14 @@ public: AccountOpResult result = AccountMgr::ChangePassword(handler->GetSession()->GetAccountId(), std::string(newPassword)); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_PASSWORD); sScriptMgr->OnPasswordChange(handler->GetSession()->GetAccountId()); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Password.", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().GetCounter()); break; - case AOR_PASS_TOO_LONG: + case AccountOpResult::AOR_PASS_TOO_LONG: handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); @@ -592,7 +598,7 @@ public: { ///- Convert Account name to Upper Format accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -662,7 +668,7 @@ public: if (isAccountNameGiven) { targetAccountName = arg1; - if (!AccountMgr::normalizeString(targetAccountName) || !AccountMgr::GetId(targetAccountName)) + if (!Utf8ToUpperOnlyLatin(targetAccountName) || !AccountMgr::GetId(targetAccountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, targetAccountName.c_str()); handler->SetSentErrorMessage(true); @@ -750,7 +756,7 @@ public: return false; std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -781,14 +787,14 @@ public: switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_PASSWORD); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_PASS_TOO_LONG: + case AccountOpResult::AOR_PASS_TOO_LONG: handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -819,7 +825,7 @@ public: } std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -849,16 +855,16 @@ public: AccountOpResult result = AccountMgr::ChangeEmail(targetAccountId, email); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); TC_LOG_INFO("entities.player.character", "ChangeEmail: Account %s [Id: %u] had it's email changed to %s.", accountName.c_str(), targetAccountId, email); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_EMAIL_TOO_LONG: + case AccountOpResult::AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -895,7 +901,7 @@ public: } std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -925,16 +931,16 @@ public: AccountOpResult result = AccountMgr::ChangeRegEmail(targetAccountId, email); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); TC_LOG_INFO("entities.player.character", "ChangeRegEmail: Account %s [Id: %u] had it's Registration Email changed to %s.", accountName.c_str(), targetAccountId, email); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_EMAIL_TOO_LONG: + case AccountOpResult::AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); handler->SetSentErrorMessage(true); return false; diff --git a/src/server/scripts/Commands/cs_ahbot.cpp b/src/server/scripts/Commands/cs_ahbot.cpp index 65e90394261..47553d085b1 100644 --- a/src/server/scripts/Commands/cs_ahbot.cpp +++ b/src/server/scripts/Commands/cs_ahbot.cpp @@ -33,7 +33,7 @@ class ahbot_commandscript : public CommandScript public: ahbot_commandscript(): CommandScript("ahbot_commandscript") {} - std::vector<ChatCommand> GetCommands() const + std::vector<ChatCommand> GetCommands() const override { static std::vector<ChatCommand> ahbotItemsAmountCommandTable = { diff --git a/src/server/scripts/Commands/cs_ban.cpp b/src/server/scripts/Commands/cs_ban.cpp index 4a1bf71e1d8..ba512dbf8eb 100644 --- a/src/server/scripts/Commands/cs_ban.cpp +++ b/src/server/scripts/Commands/cs_ban.cpp @@ -171,7 +171,7 @@ public: switch (mode) { case BAN_ACCOUNT: - if (!AccountMgr::normalizeString(nameOrIP)) + if (!Utf8ToUpperOnlyLatin(nameOrIP)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, nameOrIP.c_str()); handler->SetSentErrorMessage(true); @@ -244,7 +244,7 @@ public: return false; std::string accountName = nameStr; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -712,7 +712,7 @@ public: switch (mode) { case BAN_ACCOUNT: - if (!AccountMgr::normalizeString(nameOrIP)) + if (!Utf8ToUpperOnlyLatin(nameOrIP)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, nameOrIP.c_str()); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index eb1aa98f4ff..9557d182df1 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -854,7 +854,7 @@ public: return false; std::string accountName = accountStr; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index b937fc4e0a4..1d8094885d4 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -124,6 +124,23 @@ public: return false; } + // Dump camera locations + if (CinematicSequencesEntry const* cineSeq = sCinematicSequencesStore.LookupEntry(id)) + { + std::unordered_map<uint32, FlyByCameraCollection>::const_iterator itr = sFlyByCameraStore.find(cineSeq->cinematicCamera); + if (itr != sFlyByCameraStore.end()) + { + handler->PSendSysMessage("Waypoints for sequence %u, camera %u", id, cineSeq->cinematicCamera); + uint32 count = 1 ; + for (FlyByCamera cam : itr->second) + { + handler->PSendSysMessage("%02u - %7ums [%f, %f, %f] Facing %f (%f degrees)", count, cam.timeStamp, cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w, cam.locations.w * (180 / M_PI)); + count++; + } + handler->PSendSysMessage("%u waypoints dumped", itr->second.size()); + } + } + handler->GetSession()->GetPlayer()->SendCinematicStart(id); return true; } @@ -1045,7 +1062,8 @@ public: return false; uint32 animId = atoi((char*)args); - handler->GetSession()->GetPlayer()->HandleEmoteCommand(animId); + if (Unit* unit = handler->getSelectedUnit()) + unit->HandleEmoteCommand(animId); return true; } @@ -1409,10 +1427,7 @@ public: map = player->GetMap(); handler->PSendSysMessage("Loading all cells (mapId: %u). Current next GameObject %u, Creature %u", map->GetId(), map->GetMaxLowGuid<HighGuid::GameObject>(), map->GetMaxLowGuid<HighGuid::Unit>()); - for (uint32 cellX = 0; cellX < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellX++) - for (uint32 cellY = 0; cellY < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellY++) - map->LoadGrid((cellX + 0.5f - CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL, (cellY + 0.5f - CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL); - + map->LoadAllCells(); handler->PSendSysMessage("Cells loaded (mapId: %u) After load - Next GameObject %u, Creature %u", map->GetId(), map->GetMaxLowGuid<HighGuid::GameObject>(), map->GetMaxLowGuid<HighGuid::Unit>()); return true; } @@ -1436,7 +1451,7 @@ public: duration = 3 * MINUTE; bool doFill = fill_str ? (stricmp(fill_str, "FILL") == 0) : false; - + int32 errMsg = target->AI()->VisualizeBoundary(duration, player, doFill); if (errMsg > 0) handler->PSendSysMessage(errMsg); diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp index e03942bc247..ffe8ea67816 100644 --- a/src/server/scripts/Commands/cs_gm.cpp +++ b/src/server/scripts/Commands/cs_gm.cpp @@ -164,7 +164,7 @@ public: ///- Get the accounts with GM Level >0 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_GM_ACCOUNTS); stmt->setUInt8(0, uint8(SEC_MODERATOR)); - stmt->setInt32(1, int32(realmID)); + stmt->setInt32(1, int32(realm.Id.Realm)); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 61e6acfb4d8..161ade1a30f 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -1343,7 +1343,7 @@ public: char* limitStr = strtok(NULL, " "); int32 limit = limitStr ? atoi(limitStr) : -1; - if (!AccountMgr::normalizeString + if (!Utf8ToUpperOnlyLatin (account)) return false; diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index c70246f7fb5..3e35a721162 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -36,6 +36,7 @@ #include "MMapFactory.h" #include "DisableMgr.h" #include "SpellHistory.h" +#include "Transport.h" class misc_commandscript : public CommandScript { @@ -237,6 +238,10 @@ public: areaId, (areaEntry ? areaEntry->area_name[handler->GetSessionDbcLocale()] : unknown), object->GetPhaseMask(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation()); + if (Transport* transport = object->GetTransport()) + handler->PSendSysMessage(LANG_TRANSPORT_POSITION, + transport->GetGOInfo()->moTransport.mapID, object->GetTransOffsetX(), object->GetTransOffsetY(), object->GetTransOffsetZ(), object->GetTransOffsetO(), + transport->GetEntry(), transport->GetName().c_str()); handler->PSendSysMessage(LANG_GRID_POSITION, cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(), zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMap); @@ -1588,7 +1593,7 @@ public: // Query the prepared statement for login data stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO); - stmt->setInt32(0, int32(realmID)); + stmt->setInt32(0, int32(realm.Id.Realm)); stmt->setUInt32(1, accId); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -1964,7 +1969,7 @@ public: return false; std::string accountName = nameStr; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 761b4c9e0e6..f1ddb448b35 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -473,15 +473,15 @@ public: return false; } - handler->PSendSysMessage(LANG_YOU_CHANGE_ASPEED, ASpeed, targetNameLink.c_str()); + handler->PSendSysMessage(LANG_YOU_CHANGE_ASPEED, targetNameLink.c_str(), ASpeed); if (handler->needReportToTarget(target)) ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_ASPEED_CHANGED, handler->GetNameLink().c_str(), ASpeed); - target->SetSpeed(MOVE_WALK, ASpeed, true); - target->SetSpeed(MOVE_RUN, ASpeed, true); - target->SetSpeed(MOVE_SWIM, ASpeed, true); - //target->SetSpeed(MOVE_TURN, ASpeed, true); - target->SetSpeed(MOVE_FLIGHT, ASpeed, true); + target->SetSpeedRate(MOVE_WALK, ASpeed); + target->SetSpeedRate(MOVE_RUN, ASpeed); + target->SetSpeedRate(MOVE_SWIM, ASpeed); + //target->SetSpeedRate(MOVE_TURN, ASpeed); + target->SetSpeedRate(MOVE_FLIGHT, ASpeed); return true; } @@ -521,11 +521,11 @@ public: return false; } - handler->PSendSysMessage(LANG_YOU_CHANGE_SPEED, Speed, targetNameLink.c_str()); + handler->PSendSysMessage(LANG_YOU_CHANGE_SPEED, targetNameLink.c_str(), Speed); if (handler->needReportToTarget(target)) ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_SPEED_CHANGED, handler->GetNameLink().c_str(), Speed); - target->SetSpeed(MOVE_RUN, Speed, true); + target->SetSpeedRate(MOVE_RUN, Speed); return true; } @@ -566,11 +566,11 @@ public: return false; } - handler->PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, Swim, targetNameLink.c_str()); + handler->PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, targetNameLink.c_str(), Swim); if (handler->needReportToTarget(target)) ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_SWIM_SPEED_CHANGED, handler->GetNameLink().c_str(), Swim); - target->SetSpeed(MOVE_SWIM, Swim, true); + target->SetSpeedRate(MOVE_SWIM, Swim); return true; } @@ -611,11 +611,11 @@ public: return false; } - handler->PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, BSpeed, targetNameLink.c_str()); + handler->PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, targetNameLink.c_str(), BSpeed); if (handler->needReportToTarget(target)) ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_BACK_SPEED_CHANGED, handler->GetNameLink().c_str(), BSpeed); - target->SetSpeed(MOVE_RUN_BACK, BSpeed, true); + target->SetSpeedRate(MOVE_RUN_BACK, BSpeed); return true; } @@ -647,11 +647,11 @@ public: if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) return false; - handler->PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, FSpeed, handler->GetNameLink(target).c_str()); + handler->PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, handler->GetNameLink(target).c_str(), FSpeed); if (handler->needReportToTarget(target)) ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_FLY_SPEED_CHANGED, handler->GetNameLink().c_str(), FSpeed); - target->SetSpeed(MOVE_FLIGHT, FSpeed, true); + target->SetSpeedRate(MOVE_FLIGHT, FSpeed); return true; } @@ -684,7 +684,7 @@ public: if (handler->HasLowerSecurity(player, ObjectGuid::Empty)) return false; - handler->PSendSysMessage(LANG_YOU_CHANGE_SIZE, Scale, handler->GetNameLink(player).c_str()); + handler->PSendSysMessage(LANG_YOU_CHANGE_SIZE, handler->GetNameLink(player).c_str(), Scale); if (handler->needReportToTarget(player)) ChatHandler(player->GetSession()).PSendSysMessage(LANG_YOURS_SIZE_CHANGED, handler->GetNameLink().c_str(), Scale); } @@ -1339,8 +1339,8 @@ public: } // Set gender - target->SetByteValue(UNIT_FIELD_BYTES_0, 2, gender); - target->SetByteValue(PLAYER_BYTES_3, 0, gender); + target->SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, gender); + target->SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER, gender); // Change display ID target->InitDisplayIds(); diff --git a/src/server/scripts/Commands/cs_rbac.cpp b/src/server/scripts/Commands/cs_rbac.cpp index f7c2d21c12d..64692c4d0ed 100644 --- a/src/server/scripts/Commands/cs_rbac.cpp +++ b/src/server/scripts/Commands/cs_rbac.cpp @@ -49,7 +49,7 @@ class rbac_commandscript : public CommandScript public: rbac_commandscript() : CommandScript("rbac_commandscript") { } - std::vector<ChatCommand> GetCommands() const + std::vector<ChatCommand> GetCommands() const override { static std::vector<ChatCommand> rbacAccountCommandTable = { @@ -139,7 +139,7 @@ public: { accountName = param1; - if (AccountMgr::normalizeString(accountName)) + if (Utf8ToUpperOnlyLatin(accountName)) accountId = AccountMgr::GetId(accountName); if (!accountId) @@ -157,7 +157,7 @@ public: if (!rdata) { - data->rbac = new rbac::RBACData(accountId, accountName, realmID, AccountMgr::GetSecurity(accountId, realmID)); + data->rbac = new rbac::RBACData(accountId, accountName, realm.Id.Realm, AccountMgr::GetSecurity(accountId, realm.Id.Realm)); data->rbac->LoadFromDB(); data->needDelete = true; } diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 56b0dbf43d0..eb28a8adae4 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -251,7 +251,7 @@ public: static bool HandleReloadAllScriptsCommand(ChatHandler* handler, const char* /*args*/) { - if (sScriptMgr->IsScriptScheduled()) + if (sMapMgr->IsScriptScheduled()) { handler->PSendSysMessage("DB scripts used currently, please attempt reload later."); handler->SetSentErrorMessage(true); @@ -393,7 +393,7 @@ public: static bool HandleReloadCommandCommand(ChatHandler* handler, const char* /*args*/) { - handler->SetLoadCommandTable(true); + ChatHandler::invalidateCommandTable(); handler->SendGlobalGMSysMessage("DB table `command` will be reloaded at next chat command use."); return true; } @@ -893,7 +893,7 @@ public: static bool HandleReloadEventScriptsCommand(ChatHandler* handler, const char* args) { - if (sScriptMgr->IsScriptScheduled()) + if (sMapMgr->IsScriptScheduled()) { handler->SendSysMessage("DB scripts used currently, please attempt reload later."); handler->SetSentErrorMessage(true); @@ -913,7 +913,7 @@ public: static bool HandleReloadWpScriptsCommand(ChatHandler* handler, const char* args) { - if (sScriptMgr->IsScriptScheduled()) + if (sMapMgr->IsScriptScheduled()) { handler->SendSysMessage("DB scripts used currently, please attempt reload later."); handler->SetSentErrorMessage(true); @@ -946,7 +946,7 @@ public: static bool HandleReloadSpellScriptsCommand(ChatHandler* handler, const char* args) { - if (sScriptMgr->IsScriptScheduled()) + if (sMapMgr->IsScriptScheduled()) { handler->SendSysMessage("DB scripts used currently, please attempt reload later."); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_reset.cpp b/src/server/scripts/Commands/cs_reset.cpp index 05941120423..ba1dab28350 100644 --- a/src/server/scripts/Commands/cs_reset.cpp +++ b/src/server/scripts/Commands/cs_reset.cpp @@ -102,7 +102,7 @@ public: player->setFactionForRace(player->getRace()); - player->SetUInt32Value(UNIT_FIELD_BYTES_0, ((player->getRace()) | (player->getClass() << 8) | (player->getGender() << 16) | (powerType << 24))); + player->SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE, powerType); // reset only if player not in some form; if (player->GetShapeshiftForm() == FORM_NONE) diff --git a/src/server/scripts/Commands/cs_ticket.cpp b/src/server/scripts/Commands/cs_ticket.cpp index c5c85f5f3cc..899c5615206 100644 --- a/src/server/scripts/Commands/cs_ticket.cpp +++ b/src/server/scripts/Commands/cs_ticket.cpp @@ -95,7 +95,7 @@ public: ObjectGuid targetGuid = sObjectMgr->GetPlayerGUIDByName(target); uint32 accountId = sObjectMgr->GetPlayerAccountIdByGUID(targetGuid); // Target must exist and have administrative rights - if (!AccountMgr::HasPermission(accountId, rbac::RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realmID)) + if (!AccountMgr::HasPermission(accountId, rbac::RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realm.Id.Realm)) { handler->SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); return true; @@ -119,7 +119,7 @@ public: // Assign ticket SQLTransaction trans = SQLTransaction(NULL); - ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(AccountMgr::GetSecurity(accountId, realmID))); + ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(AccountMgr::GetSecurity(accountId, realm.Id.Realm))); ticket->SaveToDB(trans); sTicketMgr->UpdateLastChange(); @@ -387,7 +387,7 @@ public: { ObjectGuid guid = ticket->GetAssignedToGUID(); uint32 accountId = sObjectMgr->GetPlayerAccountIdByGUID(guid); - security = AccountMgr::GetSecurity(accountId, realmID); + security = AccountMgr::GetSecurity(accountId, realm.Id.Realm); } // Check security diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index ef61c231104..424f94f7385 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -561,29 +561,24 @@ public: // -> variable lowguid is filled with the GUID of the NPC uint32 pathid = 0; uint32 point = 0; - uint32 wpGuid = 0; Creature* target = handler->getSelectedCreature(); PreparedStatement* stmt = NULL; + // User did select a visual waypoint? if (!target || target->GetEntry() != VISUAL_WAYPOINT) { handler->SendSysMessage("|cffff33ffERROR: You must select a waypoint.|r"); return false; } - // The visual waypoint - wpGuid = target->GetGUID().GetCounter(); - - // User did select a visual waypoint? - // Check the creature stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_BY_WPGUID); - stmt->setUInt32(0, wpGuid); + stmt->setUInt32(0, target->GetSpawnId()); PreparedQueryResult result = WorldDatabase.Query(stmt); if (!result) { - handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUID().GetCounter()); + handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetSpawnId()); // Select waypoint number from database // Since we compare float values, we have to deal with // some difficulties. @@ -599,11 +594,11 @@ public: stmt->setString(3, maxDiff); stmt->setFloat(4, target->GetPositionZ()); stmt->setString(5, maxDiff); - PreparedQueryResult queryResult = WorldDatabase.Query(stmt); + result = WorldDatabase.Query(stmt); - if (!queryResult) + if (!result) { - handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid); + handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetSpawnId()); return true; } } @@ -631,13 +626,8 @@ public: { handler->PSendSysMessage("|cff00ff00DEBUG: wp modify del, PathID: |r|cff00ffff%u|r", pathid); - if (wpGuid != 0) - if (Creature* wpCreature = handler->GetSession()->GetPlayer()->GetMap()->GetCreature(ObjectGuid(HighGuid::Unit, VISUAL_WAYPOINT, wpGuid))) - { - wpCreature->CombatStop(); - wpCreature->DeleteFromDB(); - wpCreature->AddObjectToRemoveList(); - } + target->DeleteFromDB(); + target->AddObjectToRemoveList(); stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_WAYPOINT_DATA); stmt->setUInt32(0, pathid); @@ -659,51 +649,40 @@ public: Player* chr = handler->GetSession()->GetPlayer(); Map* map = chr->GetMap(); + // What to do: + // Move the visual spawnpoint + // Respawn the owner of the waypoints + target->DeleteFromDB(); + target->AddObjectToRemoveList(); + + // re-create + Creature* wpCreature = new Creature(); + if (!wpCreature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation())) { - // What to do: - // Move the visual spawnpoint - // Respawn the owner of the waypoints - if (wpGuid != 0) - { - if (Creature* wpCreature = map->GetCreature(ObjectGuid(HighGuid::Unit, VISUAL_WAYPOINT, wpGuid))) - { - wpCreature->CombatStop(); - wpCreature->DeleteFromDB(); - wpCreature->AddObjectToRemoveList(); - } - // re-create - Creature* wpCreature2 = new Creature(); - if (!wpCreature2->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation())) - { - handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - delete wpCreature2; - wpCreature2 = NULL; - return false; - } + handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); + delete wpCreature; + return false; + } - wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - /// @todo Should we first use "Create" then use "LoadFromDB"? - if (!wpCreature2->LoadCreatureFromDB(wpCreature2->GetSpawnId(), map)) - { - handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - delete wpCreature2; - wpCreature2 = NULL; - return false; - } - //sMapMgr->GetMap(npcCreature->GetMapId())->Add(wpCreature2); - } + wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + /// @todo Should we first use "Create" then use "LoadFromDB"? + if (!wpCreature->LoadCreatureFromDB(wpCreature->GetSpawnId(), map)) + { + handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); + delete wpCreature; + return false; + } - stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_POSITION); - stmt->setFloat(0, chr->GetPositionX()); - stmt->setFloat(1, chr->GetPositionY()); - stmt->setFloat(2, chr->GetPositionZ()); - stmt->setUInt32(3, pathid); - stmt->setUInt32(4, point); - WorldDatabase.Execute(stmt); + stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_POSITION); + stmt->setFloat(0, chr->GetPositionX()); + stmt->setFloat(1, chr->GetPositionY()); + stmt->setFloat(2, chr->GetPositionZ()); + stmt->setUInt32(3, pathid); + stmt->setUInt32(4, point); + WorldDatabase.Execute(stmt); - handler->PSendSysMessage(LANG_WAYPOINT_CHANGED); - } + handler->PSendSysMessage(LANG_WAYPOINT_CHANGED); return true; } // move @@ -897,14 +876,15 @@ public: return false; } + wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + // Set "wpguid" column to the visual waypoint stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_WPGUID); - stmt->setInt32(0, int32(wpCreature->GetGUID().GetCounter())); + stmt->setInt32(0, int32(wpCreature->GetSpawnId())); stmt->setUInt32(1, pathid); stmt->setUInt32(2, point); WorldDatabase.Execute(stmt); - wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); if (!wpCreature->LoadCreatureFromDB(wpCreature->GetSpawnId(), map)) { diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp index 9cd724e5596..79709734e18 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp @@ -508,19 +508,11 @@ public: }; // npc_lokhtos_darkbargainer -enum LokhtosItems +enum Lokhtos { + QUEST_A_BINDING_CONTRACT = 7604, + ITEM_SULFURON_INGOT = 17203, ITEM_THRORIUM_BROTHERHOOD_CONTRACT = 18628, - ITEM_SULFURON_INGOT = 17203 -}; - -enum LokhtosQuests -{ - QUEST_A_BINDING_CONTRACT = 7604 -}; - -enum LokhtosSpells -{ SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND = 23059 }; @@ -570,67 +562,12 @@ public: } }; -// npc_dughal_stormwing -enum DughalQuests -{ - QUEST_JAIL_BREAK = 4322 -}; - -#define SAY_DUGHAL_FREE "Thank you, $N! I'm free!!!" -#define GOSSIP_DUGHAL "You're free, Dughal! Get out of here!" - -// npc_marshal_windsor -#define SAY_WINDSOR_AGGRO1 "You locked up the wrong Marshal. Prepare to be destroyed!" -#define SAY_WINDSOR_AGGRO2 "I bet you're sorry now, aren't you !?!!" -#define SAY_WINDSOR_AGGRO3 "You better hold me back $N or they are going to feel some prison house beatings." -#define SAY_WINDSOR_1 "Let's get a move on. My gear should be in the storage area up this way..." -#define SAY_WINDSOR_4_1 "Check that cell, $N. If someone is alive in there, we need to get them out." -#define SAY_WINDSOR_4_2 "Get him out of there!" -#define SAY_WINDSOR_4_3 "Good work! We're almost there, $N. This way." -#define SAY_WINDSOR_6 "This is it, $N. My stuff should be in that room. Cover me, I'm going in!" -#define SAY_WINDSOR_9 "Ah, there it is!" - -enum MarshalWindsor -{ - NPC_REGINALD_WINDSOR = 9682 -}; - -// npc_marshal_reginald_windsor -#define SAY_REGINALD_WINDSOR_0_1 "Can you feel the power, $N??? It's time to ROCK!" -#define SAY_REGINALD_WINDSOR_0_2 "Now we just have to free Tobias and we can get out of here. This way!" -#define SAY_REGINALD_WINDSOR_5_1 "Open it." -#define SAY_REGINALD_WINDSOR_5_2 "I never did like those two. Let's get moving." -#define SAY_REGINALD_WINDSOR_7_1 "Open it and be careful this time!" -#define SAY_REGINALD_WINDSOR_7_2 "That intolerant dirtbag finally got what was coming to him. Good riddance!" -#define SAY_REGINALD_WINDSOR_7_3 "Alright, let's go." -#define SAY_REGINALD_WINDSOR_13_1 "Open it. We need to hurry up. I can smell those Dark Irons coming a mile away and I can tell you one thing, they're COMING!" -#define SAY_REGINALD_WINDSOR_13_2 "Administering fists of fury on Crest Killer!" -#define SAY_REGINALD_WINDSOR_13_3 "He has to be in the last cell. Unless... they killed him." -#define SAY_REGINALD_WINDSOR_14_1 "Get him out of there!" -#define SAY_REGINALD_WINDSOR_14_2 "Excellent work, $N. Let's find the exit. I think I know the way. Follow me!" -#define SAY_REGINALD_WINDSOR_20_1 "We made it!" -#define SAY_REGINALD_WINDSOR_20_2 "Meet me at Maxwell's encampment. We'll go over the next stages of the plan there and figure out a way to decode my tablets without the decryption ring." - -enum MarshalReginaldWindor -{ - NPC_SHILL_DINGER = 9678, - NPC_CREST_KILLER = 9680 -}; - // npc_rocknot -enum RocknotSays -{ - SAY_GOT_BEER = 0 -}; - -enum RocknotSpells -{ - SPELL_DRUNKEN_RAGE = 14872 -}; - -enum RocknotQuests +enum Rocknot { - QUEST_ALE = 4295 + SAY_GOT_BEER = 0, + QUEST_ALE = 4295, + SPELL_DRUNKEN_RAGE = 14872 }; class npc_rocknot : public CreatureScript diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp index 51bb314968d..ffec32c0619 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp @@ -27,6 +27,8 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "molten_core.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" enum Emotes { @@ -36,9 +38,10 @@ enum Emotes enum Spells { SPELL_INFERNO = 19695, + SPELL_INFERNO_DMG = 19698, SPELL_IGNITE_MANA = 19659, SPELL_LIVING_BOMB = 20475, - SPELL_ARMAGEDDON = 20479, + SPELL_ARMAGEDDON = 20478, }; enum Events @@ -119,7 +122,36 @@ class boss_baron_geddon : public CreatureScript } }; +class spell_baron_geddon_inferno : public SpellScriptLoader +{ + public: + spell_baron_geddon_inferno() : SpellScriptLoader("spell_baron_geddon_inferno") { } + + class spell_baron_geddon_inferno_AuraScript : public AuraScript + { + PrepareAuraScript(spell_baron_geddon_inferno_AuraScript); + + void OnPeriodic(AuraEffect const* aurEff) + { + PreventDefaultAction(); + int32 damageForTick[8] = { 500, 500, 1000, 1000, 2000, 2000, 3000, 5000 }; + GetTarget()->CastCustomSpell(SPELL_INFERNO_DMG, SPELLVALUE_BASE_POINT0, damageForTick[aurEff->GetTickNumber() - 1], (Unit*)nullptr, TRIGGERED_FULL_MASK, nullptr, aurEff); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_baron_geddon_inferno_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_baron_geddon_inferno_AuraScript(); + } +}; + void AddSC_boss_baron_geddon() { new boss_baron_geddon(); + new spell_baron_geddon_inferno(); } diff --git a/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp b/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp index b827fdf7e8b..7599cf38f08 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp +++ b/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp @@ -59,6 +59,7 @@ class instance_deadmines : public InstanceMapScript State = CANNON_NOT_USED; CannonBlast_Timer = 0; PiratesDelay_Timer = 0; + SmiteAlarmDelay_Timer = 0; } ObjectGuid FactoryDoorGUID; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp index 9f4a31fdbbc..b694c074879 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp @@ -50,19 +50,9 @@ class boss_maiden_of_virtue : public CreatureScript public: boss_maiden_of_virtue() : CreatureScript("boss_maiden_of_virtue") { } - CreatureAI* GetAI(Creature* creature) const override - { - return new boss_maiden_of_virtueAI(creature); - } - struct boss_maiden_of_virtueAI : public BossAI { - boss_maiden_of_virtueAI(Creature* creature) : BossAI(creature, TYPE_MAIDEN) { } - - void Reset() override - { - _Reset(); - } + boss_maiden_of_virtueAI(Creature* creature) : BossAI(creature, DATA_MAIDEN_OF_VIRTUE) { } void KilledUnit(Unit* /*Victim*/) override { @@ -132,6 +122,11 @@ public: DoMeleeAttackIfReady(); } }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new boss_maiden_of_virtueAI(creature); + } }; void AddSC_boss_maiden_of_virtue() diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp index ced8dd8f37e..43ef7e006ef 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp @@ -26,6 +26,7 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellInfo.h" +#include "karazhan.h" enum Midnight { @@ -109,6 +110,9 @@ public: Talk(SAY_DEATH); if (Unit* midnight = ObjectAccessor::GetUnit(*me, Midnight)) midnight->KillSelf(); + + if (InstanceScript* instance = me->GetInstanceScript()) + instance->SetBossState(DATA_ATTUMEN, DONE); } void UpdateAI(uint32 diff) override; @@ -157,7 +161,11 @@ public: me->SetVisible(true); } - void EnterCombat(Unit* /*who*/) override { } + void EnterCombat(Unit* /*who*/) override + { + if (InstanceScript* instance = me->GetInstanceScript()) + instance->SetBossState(DATA_ATTUMEN, IN_PROGRESS); + } void KilledUnit(Unit* /*victim*/) override { diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp index 79e36442f4b..e667141fa29 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp @@ -143,12 +143,12 @@ public: if (me->IsAlive()) SpawnAdds(); - instance->SetData(TYPE_MOROES, NOT_STARTED); + instance->SetBossState(DATA_MOROES, NOT_STARTED); } void StartEvent() { - instance->SetData(TYPE_MOROES, IN_PROGRESS); + instance->SetBossState(DATA_MOROES, IN_PROGRESS); DoZoneInCombat(); } @@ -171,7 +171,7 @@ public: { Talk(SAY_DEATH); - instance->SetData(TYPE_MOROES, DONE); + instance->SetBossState(DATA_MOROES, DONE); DeSpawnAdds(); @@ -257,12 +257,6 @@ public: if (!UpdateVictim()) return; - if (!instance->GetData(TYPE_MOROES)) - { - EnterEvadeMode(); - return; - } - if (!Enrage && HealthBelowPct(30)) { DoCast(me, SPELL_FRENZY); @@ -347,7 +341,7 @@ struct boss_moroes_guestAI : public ScriptedAI void Reset() override { - instance->SetData(TYPE_MOROES, NOT_STARTED); + instance->SetBossState(DATA_MOROES, NOT_STARTED); } void AcquireGUID() @@ -373,7 +367,7 @@ struct boss_moroes_guestAI : public ScriptedAI void UpdateAI(uint32 /*diff*/) override { - if (!instance->GetData(TYPE_MOROES)) + if (instance->GetBossState(DATA_MOROES) != IN_PROGRESS) EnterEvadeMode(); DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp index 6f5f2b8f65f..6ff20e66f7f 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp @@ -138,15 +138,15 @@ public: { Initialize(); - me->SetSpeed(MOVE_RUN, 2.0f); + me->SetSpeedRate(MOVE_RUN, 2.0f); me->SetDisableGravity(true); me->SetWalk(false); me->setActive(true); - if (instance->GetData(TYPE_NIGHTBANE) == DONE || instance->GetData(TYPE_NIGHTBANE) == IN_PROGRESS) + if (instance->GetBossState(DATA_NIGHTBANE) == DONE || instance->GetBossState(DATA_NIGHTBANE) == IN_PROGRESS) me->DisappearAndDie(); else - instance->SetData(TYPE_NIGHTBANE, NOT_STARTED); + instance->SetBossState(DATA_NIGHTBANE, NOT_STARTED); HandleTerraceDoors(true); @@ -165,10 +165,10 @@ public: void EnterCombat(Unit* /*who*/) override { - instance->SetData(TYPE_NIGHTBANE, IN_PROGRESS); + instance->SetBossState(DATA_NIGHTBANE, IN_PROGRESS); HandleTerraceDoors(false); - Talk(YELL_AGGRO); + Talk(YELL_AGGRO); } void AttackStart(Unit* who) override @@ -179,7 +179,7 @@ public: void JustDied(Unit* /*killer*/) override { - instance->SetData(TYPE_NIGHTBANE, DONE); + instance->SetBossState(DATA_NIGHTBANE, DONE); HandleTerraceDoors(true); } diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp index 450678a0f86..17a23a0b2e7 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp @@ -154,7 +154,7 @@ public: Initialize(); // Not in progress - instance->SetData(TYPE_ARAN, NOT_STARTED); + instance->SetBossState(DATA_ARAN, NOT_STARTED); instance->HandleGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR), true); } @@ -167,7 +167,7 @@ public: { Talk(SAY_DEATH); - instance->SetData(TYPE_ARAN, DONE); + instance->SetBossState(DATA_ARAN, DONE); instance->HandleGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR), true); } @@ -175,7 +175,7 @@ public: { Talk(SAY_AGGRO); - instance->SetData(TYPE_ARAN, IN_PROGRESS); + instance->SetBossState(DATA_ARAN, IN_PROGRESS); instance->HandleGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR), false); } diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp index 7bc835dcced..2e33f0933e3 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp @@ -61,7 +61,6 @@ enum Creatures NPC_DEMONCHAINS = 17248, NPC_FIENDISHIMP = 17267, NPC_PORTAL = 17265, - NPC_KILREK = 17229 }; @@ -316,7 +315,7 @@ public: Initialize(); - instance->SetData(TYPE_TERESTIAN, NOT_STARTED); + instance->SetBossState(DATA_TERESTIAN, NOT_STARTED); me->RemoveAurasDueToSpell(SPELL_BROKEN_PACT); @@ -371,7 +370,7 @@ public: Talk(SAY_DEATH); - instance->SetData(TYPE_TERESTIAN, DONE); + instance->SetBossState(DATA_TERESTIAN, DONE); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp index d4d0e6fa70d..3f236c060d7 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp @@ -674,6 +674,12 @@ public: void Initialize() { + // Hello, developer from the future! It's me again! + // This time, you're fixing Karazhan scripts. Awesome. These are a mess of hacks. An amalgamation of hacks, so to speak. Maybe even a Patchwerk thereof. + // Anyway, I digress. + // @todo This line below is obviously a hack. Duh. I'm just coming in here to hackfix the encounter to actually be completable. + // It needs a rewrite. Badly. Please, take good care of it. + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); CycloneTimer = 30000; ChainLightningTimer = 10000; } @@ -701,20 +707,12 @@ public: void EnterCombat(Unit* /*who*/) override { Talk(SAY_CRONE_AGGRO); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); } void JustDied(Unit* /*killer*/) override { Talk(SAY_CRONE_DEATH); - - instance->SetData(TYPE_OPERA, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORRIGHT), true); - - if (GameObject* pSideEntrance = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_SIDE_ENTRANCE_DOOR))) - pSideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); } void UpdateAI(uint32 diff) override @@ -722,9 +720,6 @@ public: if (!UpdateVictim()) return; - if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - if (CycloneTimer <= diff) { if (Creature* Cyclone = DoSpawnCreature(CREATURE_CYCLONE, float(urand(0, 9)), float(urand(0, 9)), 0, 0, TEMPSUMMON_TIMED_DESPAWN, 15000)) @@ -908,13 +903,7 @@ public: void JustDied(Unit* /*killer*/) override { DoPlaySoundToSet(me, SOUND_WOLF_DEATH); - - instance->SetData(TYPE_OPERA, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORRIGHT), true); - - if (GameObject* pSideEntrance = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_SIDE_ENTRANCE_DOOR))) - pSideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); } void UpdateAI(uint32 diff) override @@ -1158,12 +1147,7 @@ public: void JustDied(Unit* /*killer*/) override { Talk(SAY_JULIANNE_DEATH02); - - instance->SetData(TYPE_OPERA, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORRIGHT), true); - if (GameObject* pSideEntrance = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_SIDE_ENTRANCE_DOOR))) - pSideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); } void KilledUnit(Unit* /*victim*/) override @@ -1316,13 +1300,7 @@ public: void JustDied(Unit* /*killer*/) override { Talk(SAY_ROMULO_DEATH); - - instance->SetData(TYPE_OPERA, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORRIGHT), true); - - if (GameObject* pSideEntrance = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_SIDE_ENTRANCE_DOOR))) - pSideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); } void KilledUnit(Unit* /*victim*/) override diff --git a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp index b725f421c8f..ad403e6aeed 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp @@ -27,8 +27,6 @@ EndScriptData */ #include "InstanceScript.h" #include "karazhan.h" -#define MAX_ENCOUNTER 12 - /* 0 - Attumen + Midnight (optional) 1 - Moroes @@ -47,8 +45,8 @@ EndScriptData */ const Position OptionalSpawn[] = { { -10960.981445f, -1940.138428f, 46.178097f, 4.12f }, // Hyakiss the Lurker - { -10899.903320f, -2085.573730f, 49.474449f, 1.38f }, // Rokad the Ravager - { -10945.769531f, -2040.153320f, 49.474438f, 0.077f } // Shadikith the Glider + { -10945.769531f, -2040.153320f, 49.474438f, 0.077f }, // Shadikith the Glider + { -10899.903320f, -2085.573730f, 49.474449f, 1.38f } // Rokad the Ravager }; class instance_karazhan : public InstanceMapScript @@ -66,53 +64,27 @@ public: instance_karazhan_InstanceMapScript(Map* map) : InstanceScript(map) { SetHeaders(DataHeader); - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + SetBossNumber(EncounterCount); // 1 - OZ, 2 - HOOD, 3 - RAJ, this never gets altered. - m_uiOperaEvent = urand(1, 3); - m_uiOzDeathCount = 0; + OperaEvent = urand(EVENT_OZ, EVENT_RAJ); + OzDeathCount = 0; OptionalBossCount = 0; } - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strSaveData; - - uint32 m_uiOperaEvent; - uint32 m_uiOzDeathCount; - uint32 OptionalBossCount; - - ObjectGuid m_uiCurtainGUID; - ObjectGuid m_uiStageDoorLeftGUID; - ObjectGuid m_uiStageDoorRightGUID; - ObjectGuid m_uiKilrekGUID; - ObjectGuid m_uiTerestianGUID; - ObjectGuid m_uiMoroesGUID; - ObjectGuid m_uiLibraryDoor; // Door at Shade of Aran - ObjectGuid m_uiMassiveDoor; // Door at Netherspite - ObjectGuid m_uiSideEntranceDoor; // Side Entrance - ObjectGuid m_uiGamesmansDoor; // Door before Chess - ObjectGuid m_uiGamesmansExitDoor; // Door after Chess - ObjectGuid m_uiNetherspaceDoor; // Door at Malchezaar - ObjectGuid MastersTerraceDoor[2]; - ObjectGuid ImageGUID; - ObjectGuid DustCoveredChest; - - bool IsEncounterInProgress() const override - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - - return false; - } - void OnCreatureCreate(Creature* creature) override { switch (creature->GetEntry()) { - case 17229: m_uiKilrekGUID = creature->GetGUID(); break; - case 15688: m_uiTerestianGUID = creature->GetGUID(); break; - case 15687: m_uiMoroesGUID = creature->GetGUID(); break; + case NPC_KILREK: + KilrekGUID = creature->GetGUID(); + break; + case NPC_TERESTIAN_ILLHOOF: + TerestianGUID = creature->GetGUID(); + break; + case NPC_MOROES: + MoroesGUID = creature->GetGUID(); + break; } } @@ -132,130 +104,129 @@ public: case NPC_PHASE_HOUND: case NPC_DREADBEAST: case NPC_SHADOWBEAST: - SetData(TYPE_OPTIONAL_BOSS, NOT_STARTED); - break; - default: - break; - } - } - - void SetData(uint32 type, uint32 uiData) override - { - switch (type) - { - case TYPE_ATTUMEN: m_auiEncounter[0] = uiData; break; - case TYPE_MOROES: - if (m_auiEncounter[1] == DONE) - break; - m_auiEncounter[1] = uiData; - break; - case TYPE_MAIDEN: m_auiEncounter[2] = uiData; break; - case TYPE_OPTIONAL_BOSS: - m_auiEncounter[3] = uiData; - if (uiData == NOT_STARTED) + if (GetBossState(DATA_OPTIONAL_BOSS) == TO_BE_DECIDED) { ++OptionalBossCount; - if (OptionalBossCount == 50) + if (OptionalBossCount == OPTIONAL_BOSS_REQUIRED_DEATH_COUNT) { - switch (urand(0, 2)) + switch (urand(NPC_HYAKISS_THE_LURKER, NPC_ROKAD_THE_RAVAGER)) { - case 0: + case NPC_HYAKISS_THE_LURKER: instance->SummonCreature(NPC_HYAKISS_THE_LURKER, OptionalSpawn[0]); break; - case 1: - instance->SummonCreature(NPC_ROKAD_THE_RAVAGER, OptionalSpawn[1]); + case NPC_SHADIKITH_THE_GLIDER: + instance->SummonCreature(NPC_SHADIKITH_THE_GLIDER, OptionalSpawn[1]); break; - case 2: - instance->SummonCreature(NPC_SHADIKITH_THE_GLIDER, OptionalSpawn[2]); + case NPC_ROKAD_THE_RAVAGER: + instance->SummonCreature(NPC_ROKAD_THE_RAVAGER, OptionalSpawn[2]); break; } } } break; - case TYPE_OPERA: - m_auiEncounter[4] = uiData; - if (uiData == DONE) - UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, 16812, NULL); - break; - case TYPE_CURATOR: m_auiEncounter[5] = uiData; break; - case TYPE_ARAN: m_auiEncounter[6] = uiData; break; - case TYPE_TERESTIAN: m_auiEncounter[7] = uiData; break; - case TYPE_NETHERSPITE: m_auiEncounter[8] = uiData; break; - case TYPE_CHESS: - if (uiData == DONE) - DoRespawnGameObject(DustCoveredChest, DAY); - m_auiEncounter[9] = uiData; - break; - case TYPE_MALCHEZZAR: m_auiEncounter[10] = uiData; break; - case TYPE_NIGHTBANE: - if (m_auiEncounter[11] != DONE) - m_auiEncounter[11] = uiData; - break; - case DATA_OPERA_OZ_DEATHCOUNT: - if (uiData == SPECIAL) - ++m_uiOzDeathCount; - else if (uiData == IN_PROGRESS) - m_uiOzDeathCount = 0; + default: break; } + } - if (uiData == DONE) + void SetData(uint32 type, uint32 data) override + { + switch (type) { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' - << m_auiEncounter[3] << ' ' << m_auiEncounter[4] << ' ' << m_auiEncounter[5] << ' ' << m_auiEncounter[6] << ' ' - << m_auiEncounter[7] << ' ' << m_auiEncounter[8] << ' ' << m_auiEncounter[9] << ' ' << m_auiEncounter[10] << ' ' << m_auiEncounter[11]; + case DATA_OPERA_OZ_DEATHCOUNT: + if (data == SPECIAL) + ++OzDeathCount; + else if (data == IN_PROGRESS) + OzDeathCount = 0; + break; + } + } - strSaveData = saveStream.str(); + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; + switch (type) + { + case DATA_OPERA_PERFORMANCE: + if (state == DONE) + { + HandleGameObject(StageDoorLeftGUID, true); + HandleGameObject(StageDoorRightGUID, true); + if (GameObject* sideEntrance = instance->GetGameObject(SideEntranceDoor)) + sideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, 16812, NULL); + } + break; + case DATA_CHESS: + if (state == DONE) + DoRespawnGameObject(DustCoveredChest, DAY); + break; + default: + break; } + + return true; } - void SetGuidData(uint32 identifier, ObjectGuid data) override + void SetGuidData(uint32 type, ObjectGuid data) override { - switch (identifier) - { - case DATA_IMAGE_OF_MEDIVH: ImageGUID = data; - } + if (type == DATA_IMAGE_OF_MEDIVH) + ImageGUID = data; } void OnGameObjectCreate(GameObject* go) override { switch (go->GetEntry()) { - case 183932: m_uiCurtainGUID = go->GetGUID(); break; - case 184278: - m_uiStageDoorLeftGUID = go->GetGUID(); - if (m_auiEncounter[4] == DONE) + case GO_STAGE_CURTAIN: + CurtainGUID = go->GetGUID(); + break; + case GO_STAGE_DOOR_LEFT: + StageDoorLeftGUID = go->GetGUID(); + if (GetBossState(DATA_OPERA_PERFORMANCE) == DONE) go->SetGoState(GO_STATE_ACTIVE); break; - case 184279: - m_uiStageDoorRightGUID = go->GetGUID(); - if (m_auiEncounter[4] == DONE) + case GO_STAGE_DOOR_RIGHT: + StageDoorRightGUID = go->GetGUID(); + if (GetBossState(DATA_OPERA_PERFORMANCE) == DONE) go->SetGoState(GO_STATE_ACTIVE); break; - case 184517: m_uiLibraryDoor = go->GetGUID(); break; - case 185521: m_uiMassiveDoor = go->GetGUID(); break; - case 184276: m_uiGamesmansDoor = go->GetGUID(); break; - case 184277: m_uiGamesmansExitDoor = go->GetGUID(); break; - case 185134: m_uiNetherspaceDoor = go->GetGUID(); break; - case 184274: MastersTerraceDoor[0] = go->GetGUID(); break; - case 184280: MastersTerraceDoor[1] = go->GetGUID(); break; - case 184275: - m_uiSideEntranceDoor = go->GetGUID(); - if (m_auiEncounter[4] == DONE) + case GO_PRIVATE_LIBRARY_DOOR: + LibraryDoor = go->GetGUID(); + break; + case GO_MASSIVE_DOOR: + MassiveDoor = go->GetGUID(); + break; + case GO_GAMESMAN_HALL_DOOR: + GamesmansDoor = go->GetGUID(); + break; + case GO_GAMESMAN_HALL_EXIT_DOOR: + GamesmansExitDoor = go->GetGUID(); + break; + case GO_NETHERSPACE_DOOR: + NetherspaceDoor = go->GetGUID(); + break; + case GO_MASTERS_TERRACE_DOOR: + MastersTerraceDoor[0] = go->GetGUID(); + break; + case GO_MASTERS_TERRACE_DOOR2: + MastersTerraceDoor[1] = go->GetGUID(); + break; + case GO_SIDE_ENTRANCE_DOOR: + SideEntranceDoor = go->GetGUID(); + if (GetBossState(DATA_OPERA_PERFORMANCE) == DONE) go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); else go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); break; - case 185119: DustCoveredChest = go->GetGUID(); break; + case GO_DUST_COVERED_CHEST: + DustCoveredChest = go->GetGUID(); + break; } - switch (m_uiOperaEvent) + switch (OperaEvent) { /// @todo Set Object visibilities for Opera based on performance case EVENT_OZ: @@ -269,77 +240,77 @@ public: } } - std::string GetSaveData() override - { - return strSaveData; - } - - uint32 GetData(uint32 uiData) const override + uint32 GetData(uint32 type) const override { - switch (uiData) + switch (type) { - case TYPE_ATTUMEN: return m_auiEncounter[0]; - case TYPE_MOROES: return m_auiEncounter[1]; - case TYPE_MAIDEN: return m_auiEncounter[2]; - case TYPE_OPTIONAL_BOSS: return m_auiEncounter[3]; - case TYPE_OPERA: return m_auiEncounter[4]; - case TYPE_CURATOR: return m_auiEncounter[5]; - case TYPE_ARAN: return m_auiEncounter[6]; - case TYPE_TERESTIAN: return m_auiEncounter[7]; - case TYPE_NETHERSPITE: return m_auiEncounter[8]; - case TYPE_CHESS: return m_auiEncounter[9]; - case TYPE_MALCHEZZAR: return m_auiEncounter[10]; - case TYPE_NIGHTBANE: return m_auiEncounter[11]; - case DATA_OPERA_PERFORMANCE: return m_uiOperaEvent; - case DATA_OPERA_OZ_DEATHCOUNT: return m_uiOzDeathCount; + case DATA_OPERA_PERFORMANCE: + return OperaEvent; + case DATA_OPERA_OZ_DEATHCOUNT: + return OzDeathCount; } return 0; } - ObjectGuid GetGuidData(uint32 uiData) const override + ObjectGuid GetGuidData(uint32 type) const override { - switch (uiData) + switch (type) { - case DATA_KILREK: return m_uiKilrekGUID; - case DATA_TERESTIAN: return m_uiTerestianGUID; - case DATA_MOROES: return m_uiMoroesGUID; - case DATA_GO_STAGEDOORLEFT: return m_uiStageDoorLeftGUID; - case DATA_GO_STAGEDOORRIGHT: return m_uiStageDoorRightGUID; - case DATA_GO_CURTAINS: return m_uiCurtainGUID; - case DATA_GO_LIBRARY_DOOR: return m_uiLibraryDoor; - case DATA_GO_MASSIVE_DOOR: return m_uiMassiveDoor; - case DATA_GO_SIDE_ENTRANCE_DOOR: return m_uiSideEntranceDoor; - case DATA_GO_GAME_DOOR: return m_uiGamesmansDoor; - case DATA_GO_GAME_EXIT_DOOR: return m_uiGamesmansExitDoor; - case DATA_GO_NETHER_DOOR: return m_uiNetherspaceDoor; - case DATA_MASTERS_TERRACE_DOOR_1: return MastersTerraceDoor[0]; - case DATA_MASTERS_TERRACE_DOOR_2: return MastersTerraceDoor[1]; - case DATA_IMAGE_OF_MEDIVH: return ImageGUID; + case DATA_KILREK: + return KilrekGUID; + case DATA_TERESTIAN: + return TerestianGUID; + case DATA_MOROES: + return MoroesGUID; + case DATA_GO_STAGEDOORLEFT: + return StageDoorLeftGUID; + case DATA_GO_STAGEDOORRIGHT: + return StageDoorRightGUID; + case DATA_GO_CURTAINS: + return CurtainGUID; + case DATA_GO_LIBRARY_DOOR: + return LibraryDoor; + case DATA_GO_MASSIVE_DOOR: + return MassiveDoor; + case DATA_GO_SIDE_ENTRANCE_DOOR: + return SideEntranceDoor; + case DATA_GO_GAME_DOOR: + return GamesmansDoor; + case DATA_GO_GAME_EXIT_DOOR: + return GamesmansExitDoor; + case DATA_GO_NETHER_DOOR: + return NetherspaceDoor; + case DATA_MASTERS_TERRACE_DOOR_1: + return MastersTerraceDoor[0]; + case DATA_MASTERS_TERRACE_DOOR_2: + return MastersTerraceDoor[1]; + case DATA_IMAGE_OF_MEDIVH: + return ImageGUID; } return ObjectGuid::Empty; } - void Load(char const* chrIn) override - { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(chrIn); - std::istringstream loadStream(chrIn); - - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] - >> m_auiEncounter[8] >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11]; - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. - m_auiEncounter[i] = NOT_STARTED; - OUT_LOAD_INST_DATA_COMPLETE; - } + private: + uint32 OperaEvent; + uint32 OzDeathCount; + uint32 OptionalBossCount; + ObjectGuid CurtainGUID; + ObjectGuid StageDoorLeftGUID; + ObjectGuid StageDoorRightGUID; + ObjectGuid KilrekGUID; + ObjectGuid TerestianGUID; + ObjectGuid MoroesGUID; + ObjectGuid LibraryDoor; // Door at Shade of Aran + ObjectGuid MassiveDoor; // Door at Netherspite + ObjectGuid SideEntranceDoor; // Side Entrance + ObjectGuid GamesmansDoor; // Door before Chess + ObjectGuid GamesmansExitDoor; // Door after Chess + ObjectGuid NetherspaceDoor; // Door at Malchezaar + ObjectGuid MastersTerraceDoor[2]; + ObjectGuid ImageGUID; + ObjectGuid DustCoveredChest; }; }; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp index aa2da8cc391..ace15cc2a7e 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp @@ -168,7 +168,7 @@ public: void StartEvent() { - instance->SetData(TYPE_OPERA, IN_PROGRESS); + instance->SetBossState(DATA_OPERA_PERFORMANCE, IN_PROGRESS); //resets count for this event, in case earlier failed if (m_uiEventId == EVENT_OZ) @@ -377,7 +377,7 @@ public: if (InstanceScript* instance = creature->GetInstanceScript()) { // Check for death of Moroes and if opera event is not done already - if (instance->GetData(TYPE_MOROES) == DONE && instance->GetData(TYPE_OPERA) != DONE) + if (instance->GetBossState(DATA_MOROES) == DONE && instance->GetBossState(DATA_OPERA_PERFORMANCE) != DONE) { player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, OZ_GOSSIP1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); @@ -562,7 +562,7 @@ public: arca->GetMotionMaster()->MovePoint(0, -11010.82f, -1761.18f, 156.47f); arca->setActive(true); arca->InterruptNonMeleeSpells(true); - arca->SetSpeed(MOVE_FLIGHT, 2.0f); + arca->SetSpeedRate(MOVE_FLIGHT, 2.0f); } return 10000; case 13: diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h index 4d86492257c..05de9e43a91 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h @@ -21,27 +21,26 @@ #define DataHeader "KZ" +uint32 const EncounterCount = 12; + enum DataTypes { - TYPE_ATTUMEN = 1, - TYPE_MOROES = 2, - TYPE_MAIDEN = 3, - TYPE_OPTIONAL_BOSS = 4, - TYPE_OPERA = 5, - TYPE_CURATOR = 6, - TYPE_ARAN = 7, - TYPE_TERESTIAN = 8, - TYPE_NETHERSPITE = 9, - TYPE_CHESS = 10, - TYPE_MALCHEZZAR = 11, - TYPE_NIGHTBANE = 12, + DATA_ATTUMEN = 0, + DATA_MOROES = 1, + DATA_MAIDEN_OF_VIRTUE = 2, + DATA_OPTIONAL_BOSS = 3, + DATA_OPERA_PERFORMANCE = 4, + DATA_CURATOR = 5, + DATA_ARAN = 6, + DATA_TERESTIAN = 7, + DATA_NETHERSPITE = 8, + DATA_CHESS = 9, + DATA_MALCHEZZAR = 10, + DATA_NIGHTBANE = 11, - DATA_OPERA_PERFORMANCE = 13, DATA_OPERA_OZ_DEATHCOUNT = 14, DATA_KILREK = 15, - DATA_TERESTIAN = 16, - DATA_MOROES = 17, DATA_GO_CURTAINS = 18, DATA_GO_STAGEDOORLEFT = 19, DATA_GO_STAGEDOORRIGHT = 20, @@ -69,6 +68,8 @@ enum MiscCreatures NPC_HYAKISS_THE_LURKER = 16179, NPC_ROKAD_THE_RAVAGER = 16181, NPC_SHADIKITH_THE_GLIDER = 16180, + NPC_TERESTIAN_ILLHOOF = 15688, + NPC_MOROES = 15687, // Trash NPC_COLDMIST_WIDOW = 16171, @@ -78,6 +79,29 @@ enum MiscCreatures NPC_GREATER_SHADOWBAT = 16174, NPC_PHASE_HOUND = 16178, NPC_DREADBEAST = 16177, - NPC_SHADOWBEAST = 16176 + NPC_SHADOWBEAST = 16176, + NPC_KILREK = 17229 +}; + +enum GameObjectIds +{ + GO_STAGE_CURTAIN = 183932, + GO_STAGE_DOOR_LEFT = 184278, + GO_STAGE_DOOR_RIGHT = 184279, + GO_PRIVATE_LIBRARY_DOOR = 184517, + GO_MASSIVE_DOOR = 185521, + GO_GAMESMAN_HALL_DOOR = 184276, + GO_GAMESMAN_HALL_EXIT_DOOR = 184277, + GO_NETHERSPACE_DOOR = 185134, + GO_MASTERS_TERRACE_DOOR = 184274, + GO_MASTERS_TERRACE_DOOR2 = 184280, + GO_SIDE_ENTRANCE_DOOR = 184275, + GO_DUST_COVERED_CHEST = 185119 }; + +enum Misc +{ + OPTIONAL_BOSS_REQUIRED_DEATH_COUNT = 50 +}; + #endif diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp index b809128e731..ebe406c8909 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp @@ -405,7 +405,7 @@ public: Creature* Orb = DoSpawnCreature(CREATURE_ARCANE_SPHERE, 5, 5, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); if (Orb && target) { - Orb->SetSpeed(MOVE_RUN, 0.5f); + Orb->SetSpeedRate(MOVE_RUN, 0.5f); Orb->AddThreat(target, 1000000.0f); Orb->AI()->AttackStart(target); } diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 81044a0dbb1..3cf78b79f67 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -396,7 +396,7 @@ class npc_eye_of_acherus : public CreatureScript if (Player* owner = me->GetCharmerOrOwner()->ToPlayer()) { for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) - me->SetSpeed(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i)), true); + me->SetSpeedRate(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i))); Talk(TALK_MOVE_START, owner); } me->GetMotionMaster()->MovePath(me->GetEntry() * 100, false); @@ -419,7 +419,7 @@ class npc_eye_of_acherus : public CreatureScript { owner->RemoveAura(SPELL_EYE_FLIGHT_BOOST); for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) - me->SetSpeed(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i)), true); + me->SetSpeedRate(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i))); Talk(TALK_CONTROL, owner); } @@ -703,7 +703,7 @@ class npc_dark_rider_of_acherus : public CreatureScript TargetGUID = who->GetGUID(); me->SetWalk(true); - me->SetSpeed(MOVE_RUN, 0.4f); + me->SetSpeedRate(MOVE_RUN, 0.4f); me->GetMotionMaster()->MoveChase(who); me->SetTarget(TargetGUID); Intro = true; @@ -1050,7 +1050,7 @@ class npc_scarlet_miner_cart : public CreatureScript // Not 100% correct, but movement is smooth. Sometimes miner walks faster // than normal, this speed is fast enough to keep up at those times. - me->SetSpeed(MOVE_RUN, 1.25f); + me->SetSpeedRate(MOVE_RUN, 1.25f); me->GetMotionMaster()->MoveFollow(miner, 1.0f, 0); } diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp index e336ff24382..d25a225717a 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp @@ -923,7 +923,7 @@ public: if (ObjectAccessor::GetCreature(*me, uiLichKingGUID)) DoCast(me, SPELL_MOGRAINE_CHARGE); // jumping charge // doesn't make it looks well, so workarounds, Darion charges, looks better - me->SetSpeed(MOVE_RUN, 3.0f); + me->SetSpeedRate(MOVE_RUN, 3.0f); me->SetWalk(false); SetHoldState(false); JumpToNextStep(0); @@ -935,7 +935,7 @@ public: temp->HandleEmoteCommand(EMOTE_ONESHOT_KICK); temp->AI()->Talk(SAY_LIGHT_OF_DAWN46); } - me->SetSpeed(MOVE_RUN, 6.0f); + me->SetSpeedRate(MOVE_RUN, 6.0f); me->SetStandState(UNIT_STAND_STATE_DEAD); SetHoldState(false); // Darion got kicked by lich king JumpToNextStep(0); @@ -997,7 +997,7 @@ public: Unit* temp = me->SummonCreature(NPC_DEFENDER_OF_THE_LIGHT, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 10), float(rand32() % 10), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_ATTACK_UNARMED); temp->SetWalk(false); - temp->SetSpeed(MOVE_RUN, 2.0f); + temp->SetSpeedRate(MOVE_RUN, 2.0f); temp->setFaction(me->getFaction()); temp->GetMotionMaster()->MovePoint(0, fLichPositionX, fLichPositionY, fLichPositionZ); uiDefenderGUID[0] = temp->GetGUID(); @@ -1005,7 +1005,7 @@ public: temp = me->SummonCreature(NPC_RIMBLAT_EARTHSHATTER, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 10), float(rand32() % 10), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_ATTACK_UNARMED); temp->SetWalk(false); - temp->SetSpeed(MOVE_RUN, 2.0f); + temp->SetSpeedRate(MOVE_RUN, 2.0f); temp->setFaction(me->getFaction()); temp->GetMotionMaster()->MovePoint(0, fLichPositionX, fLichPositionY, fLichPositionZ); uiEarthshatterGUID[0] = temp->GetGUID(); @@ -1014,7 +1014,7 @@ public: { temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_ATTACK_UNARMED); temp->SetWalk(false); - temp->SetSpeed(MOVE_RUN, 2.0f); + temp->SetSpeedRate(MOVE_RUN, 2.0f); temp->GetMotionMaster()->MovePoint(0, fLichPositionX, fLichPositionY, fLichPositionZ); temp->AI()->Talk(SAY_LIGHT_OF_DAWN50); } @@ -1022,7 +1022,7 @@ public: { temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_ATTACK_UNARMED); temp->SetWalk(false); - temp->SetSpeed(MOVE_RUN, 2.0f); + temp->SetSpeedRate(MOVE_RUN, 2.0f); temp->HandleEmoteCommand(EMOTE_STATE_ATTACK_UNARMED); temp->GetMotionMaster()->MovePoint(0, fLichPositionX, fLichPositionY, fLichPositionZ); } @@ -1030,7 +1030,7 @@ public: { temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_ATTACK_UNARMED); temp->SetWalk(false); - temp->SetSpeed(MOVE_RUN, 2.0f); + temp->SetSpeedRate(MOVE_RUN, 2.0f); temp->GetMotionMaster()->MovePoint(0, fLichPositionX, fLichPositionY, fLichPositionZ); } } @@ -1044,33 +1044,33 @@ public: if (Creature* temp = ObjectAccessor::GetCreature(*me, uiMaxwellGUID)) { temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - temp->SetSpeed(MOVE_RUN, 6.0f); + temp->SetSpeedRate(MOVE_RUN, 6.0f); temp->SetStandState(UNIT_STAND_STATE_DEAD); temp->GetMotionMaster()->MovePoint(0, LightofDawnLoc[14]); } if (Creature* temp = ObjectAccessor::GetCreature(*me, uiKorfaxGUID)) { temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - temp->SetSpeed(MOVE_RUN, 6.0f); + temp->SetSpeedRate(MOVE_RUN, 6.0f); temp->SetStandState(UNIT_STAND_STATE_DEAD); temp->GetMotionMaster()->MovePoint(0, LightofDawnLoc[11]); } if (Creature* temp = ObjectAccessor::GetCreature(*me, uiEligorGUID)) { temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - temp->SetSpeed(MOVE_RUN, 6.0f); + temp->SetSpeedRate(MOVE_RUN, 6.0f); temp->SetStandState(UNIT_STAND_STATE_DEAD); temp->GetMotionMaster()->MovePoint(0, LightofDawnLoc[17]); } if (Creature* temp = ObjectAccessor::GetCreature(*me, uiDefenderGUID[0])) { - temp->SetSpeed(MOVE_RUN, 6.0f); + temp->SetSpeedRate(MOVE_RUN, 6.0f); temp->SetStandState(UNIT_STAND_STATE_DEAD); temp->GetMotionMaster()->MovePoint(0, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 10), float(rand32() % 10), 0.0f, 0.0f })); } if (Creature* temp = ObjectAccessor::GetCreature(*me, uiEarthshatterGUID[0])) { - temp->SetSpeed(MOVE_RUN, 6.0f); + temp->SetSpeedRate(MOVE_RUN, 6.0f); temp->SetStandState(UNIT_STAND_STATE_DEAD); temp->GetMotionMaster()->MovePoint(0, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 10), float(rand32() % 10), 0.0f, 0.0f })); } @@ -1093,7 +1093,7 @@ public: break; case 46: // Darion stand up, "not today" - me->SetSpeed(MOVE_RUN, 1.0f); + me->SetSpeedRate(MOVE_RUN, 1.0f); me->SetWalk(true); me->SetStandState(UNIT_STAND_STATE_STAND); Talk(SAY_LIGHT_OF_DAWN53); @@ -1153,7 +1153,7 @@ public: temp->AI()->Talk(EMOTE_LIGHT_OF_DAWN16); temp->CastSpell(temp, SPELL_TIRION_CHARGE, false); // jumping charge temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H); - temp->SetSpeed(MOVE_RUN, 3.0f); // workarounds, make Tirion still running + temp->SetSpeedRate(MOVE_RUN, 3.0f); // workarounds, make Tirion still running temp->SetWalk(false); temp->GetMotionMaster()->MovePoint(0, LightofDawnLoc[2]); if (Creature* lktemp = ObjectAccessor::GetCreature(*me, uiLichKingGUID)) @@ -1171,7 +1171,7 @@ public: case 54: if (Creature* temp = ObjectAccessor::GetCreature(*me, uiLichKingGUID)) { - temp->SetSpeed(MOVE_RUN, 1.0f); + temp->SetSpeedRate(MOVE_RUN, 1.0f); me->SetWalk(true); temp->GetMotionMaster()->MovePoint(0, LightofDawnLoc[29]); // 26 } @@ -1208,7 +1208,7 @@ public: if (Creature* temp = ObjectAccessor::GetCreature(*me, uiTirionGUID)) // Tirion runs to Darion { temp->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - temp->SetSpeed(MOVE_RUN, 1.0f); + temp->SetSpeedRate(MOVE_RUN, 1.0f); temp->GetMotionMaster()->MovePoint(0, LightofDawnLoc[6]); } JumpToNextStep(2500); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp index 53b6d2be8dd..9abd0c049d8 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp @@ -109,7 +109,7 @@ public: FlyBackTimer = 4500; break; case 2: - if (!player->isResurrectRequested()) + if (!player->IsResurrectRequested()) { me->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_01); DoCast(player, SPELL_REVIVE, true); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index dff0a66cec0..f7a1c18c234 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -134,8 +134,6 @@ static char const* Text[]= "Now, know demise!" }; -#define EMOTE_LAUGHS "Headless Horseman laughs" // needs assigned to db. - class npc_wisp_invis : public CreatureScript { public: @@ -347,7 +345,6 @@ public: Creature* speaker = DoSpawnCreature(HELPER, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 1000); if (speaker) speaker->CastSpell(speaker, SPELL_HEAD_SPEAKS, false); - me->TextEmote(EMOTE_LAUGHS); } else laugh -= diff; } @@ -453,7 +450,7 @@ public: me->SetVisible(false); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); me->SetDisableGravity(true); - me->SetSpeed(MOVE_WALK, 5.0f, true); + me->SetSpeedRate(MOVE_WALK, 5.0f); wp_reached = false; count = 0; say_timer = 3000; @@ -724,7 +721,6 @@ public: if (laugh <= diff) { laugh = urand(11000, 22000); - me->TextEmote(EMOTE_LAUGHS); DoPlaySoundToSet(me, RandomLaugh[rand32() % 3]); } else laugh -= diff; diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp index 118d28e2142..6a6a0b0994b 100644 --- a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp +++ b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp @@ -35,15 +35,25 @@ enum Gameobject GO_ATALAI_STATUE4 = 148833, GO_ATALAI_STATUE5 = 148834, GO_ATALAI_STATUE6 = 148835, - GO_ATALAI_IDOL = 148836, GO_ATALAI_LIGHT1 = 148883, GO_ATALAI_LIGHT2 = 148937 - }; enum CreatureIds { - NPC_MALFURION_STORMRAGE = 15362 + NPC_ATALALARION = 8580 +}; + +static Position const atalalarianPos = { -466.5134f, 95.19822f, -189.6463f, 0.03490658f }; +static uint8 const nStatues = 6; +static Position const statuePositions[nStatues] +{ + { -515.553f, 95.25821f, -173.707f, 0.0f }, + { -419.8487f, 94.48368f, -173.707f, 0.0f }, + { -491.4003f, 135.9698f, -173.707f, 0.0f }, + { -491.4909f, 53.48179f, -173.707f, 0.0f }, + { -443.8549f, 136.1007f, -173.707f, 0.0f }, + { -443.4171f, 53.83124f, -173.707f, 0.0f } }; class instance_sunken_temple : public InstanceMapScript @@ -77,7 +87,6 @@ public: ObjectGuid GOAtalaiStatue4; ObjectGuid GOAtalaiStatue5; ObjectGuid GOAtalaiStatue6; - ObjectGuid GOAtalaiIdol; uint32 State; @@ -98,7 +107,6 @@ public: case GO_ATALAI_STATUE4: GOAtalaiStatue4 = go->GetGUID(); break; case GO_ATALAI_STATUE5: GOAtalaiStatue5 = go->GetGUID(); break; case GO_ATALAI_STATUE6: GOAtalaiStatue6 = go->GetGUID(); break; - case GO_ATALAI_IDOL: GOAtalaiIdol = go->GetGUID(); break; } } @@ -155,7 +163,10 @@ public: if (s1 && s2 && s3 && s4 && s5 && !s6) { if (GameObject* pAtalaiStatue6 = instance->GetGameObject(GOAtalaiStatue6)) + { UseStatue(pAtalaiStatue6); + UseLastStatue(pAtalaiStatue6); + } s6 = true; State = 0; } @@ -169,18 +180,13 @@ public: go->SetUInt32Value(GAMEOBJECT_FLAGS, 4); } - /* - void UseLastStatue(GameObject* go) - { - AtalaiStatue1->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue1->GetPositionX(), AtalaiStatue1->GetPositionY(), AtalaiStatue1->GetPositionZ(), 0, 0, 0, 0, 0, 100); - AtalaiStatue2->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue2->GetPositionX(), AtalaiStatue2->GetPositionY(), AtalaiStatue2->GetPositionZ(), 0, 0, 0, 0, 0, 100); - AtalaiStatue3->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue3->GetPositionX(), AtalaiStatue3->GetPositionY(), AtalaiStatue3->GetPositionZ(), 0, 0, 0, 0, 0, 100); - AtalaiStatue4->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue4->GetPositionX(), AtalaiStatue4->GetPositionY(), AtalaiStatue4->GetPositionZ(), 0, 0, 0, 0, 0, 100); - AtalaiStatue5->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue5->GetPositionX(), AtalaiStatue5->GetPositionY(), AtalaiStatue5->GetPositionZ(), 0, 0, 0, 0, 0, 100); - AtalaiStatue6->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue6->GetPositionX(), AtalaiStatue6->GetPositionY(), AtalaiStatue6->GetPositionZ(), 0, 0, 0, 0, 0, 100); - go->SummonGameObject(148838, -488.997, 96.61, -189.019, -1.52, 0, 0, 0, 0, 100); - } - */ + void UseLastStatue(GameObject* go) + { + for (uint8 i = 0; i < nStatues; ++i) + go->SummonGameObject(GO_ATALAI_LIGHT2, statuePositions[i].GetPositionX(), statuePositions[i].GetPositionY(), statuePositions[i].GetPositionZ(), statuePositions[i].GetOrientation(), 0, 0, 0, 0, 0); + + go->SummonCreature(NPC_ATALALARION, atalalarianPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 7200); + } void SetData(uint32 type, uint32 data) override { diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp index d9b481d7b6d..fded249f9ca 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp @@ -249,7 +249,7 @@ public: me->CastStop(SPELL_FOG_BREATH); me->RemoveAurasDueToSpell(SPELL_FOG_BREATH); me->StopMoving(); - me->SetSpeed(MOVE_RUN, 2.0f); + me->SetSpeedRate(MOVE_RUN, 2.0f); events.ScheduleEvent(EVENT_CLEAVE, urand(5000, 10000)); events.ScheduleEvent(EVENT_CORROSION, urand(10000, 20000)); @@ -530,7 +530,7 @@ public: npc_felmyst_vaporAI(Creature* creature) : ScriptedAI(creature) { me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetSpeed(MOVE_RUN, 0.8f); + me->SetSpeedRate(MOVE_RUN, 0.8f); } void Reset() override { } diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp index 791f68bae31..72e76ba52bf 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp @@ -425,7 +425,7 @@ class npc_akilzon_eagle : public CreatureScript if (Unit* target = ObjectAccessor::GetUnit(*me, TargetGUID)) DoCast(target, SPELL_EAGLE_SWOOP, true); TargetGUID.Clear(); - me->SetSpeed(MOVE_RUN, 1.2f); + me->SetSpeedRate(MOVE_RUN, 1.2f); EagleSwoop_Timer = urand(5000, 10000); } } @@ -454,7 +454,7 @@ class npc_akilzon_eagle : public CreatureScript { target->GetContactPoint(me, x, y, z); z += 2; - me->SetSpeed(MOVE_RUN, 5.0f); + me->SetSpeedRate(MOVE_RUN, 5.0f); TargetGUID = target->GetGUID(); } me->GetMotionMaster()->MovePoint(0, x, y, z); diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp index cc55f758a22..5ec57fc44b6 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp @@ -29,109 +29,104 @@ EndScriptData */ #include "SpellAuraEffects.h" #include "zulaman.h" -#define YELL_AGGRO "Da shadow gonna fall on you... " -#define SOUND_YELL_AGGRO 12041 -#define YELL_SPIRIT_BOLTS "Your soul gonna bleed!" -#define SOUND_YELL_SPIRIT_BOLTS 12047 -#define YELL_DRAIN_POWER "Darkness comin\' for you" -#define SOUND_YELL_DRAIN_POWER 12046 -#define YELL_KILL_ONE "Dis a nightmare ya don\' wake up from!" -#define SOUND_YELL_KILL_ONE 12043 -#define YELL_KILL_TWO "Azzaga choogo zinn!" -#define SOUND_YELL_KILL_TWO 12044 -#define YELL_DEATH "Dis not... da end of me..." -#define SOUND_YELL_DEATH 12051 - +enum Yells +{ + YELL_AGGRO = 0, + YELL_KILL_ONE = 1, + YELL_KILL_TWO = 2, + YELL_DRAIN_POWER = 3, + YELL_SPIRIT_BOLTS = 4, + YELL_DEATH = 5 +}; enum Creatures { - NPC_TEMP_TRIGGER = 23920 + NPC_TEMP_TRIGGER = 23920 }; enum Spells { - SPELL_SPIRIT_BOLTS = 43383, - SPELL_DRAIN_POWER = 44131, - SPELL_SIPHON_SOUL = 43501, + SPELL_SPIRIT_BOLTS = 43383, + SPELL_DRAIN_POWER = 44131, + SPELL_SIPHON_SOUL = 43501, // Druid - SPELL_DR_THORNS = 43420, - SPELL_DR_LIFEBLOOM = 43421, - SPELL_DR_MOONFIRE = 43545, + SPELL_DR_THORNS = 43420, + SPELL_DR_LIFEBLOOM = 43421, + SPELL_DR_MOONFIRE = 43545, // Hunter - SPELL_HU_EXPLOSIVE_TRAP = 43444, - SPELL_HU_FREEZING_TRAP = 43447, - SPELL_HU_SNAKE_TRAP = 43449, + SPELL_HU_EXPLOSIVE_TRAP = 43444, + SPELL_HU_FREEZING_TRAP = 43447, + SPELL_HU_SNAKE_TRAP = 43449, // Mage - SPELL_MG_FIREBALL = 41383, - SPELL_MG_FROST_NOVA = 43426, - SPELL_MG_ICE_LANCE = 43427, - SPELL_MG_FROSTBOLT = 43428, + SPELL_MG_FIREBALL = 41383, + SPELL_MG_FROST_NOVA = 43426, + SPELL_MG_ICE_LANCE = 43427, + SPELL_MG_FROSTBOLT = 43428, // Paladin - SPELL_PA_CONSECRATION = 43429, - SPELL_PA_AVENGING_WRATH = 43430, - SPELL_PA_HOLY_LIGHT = 43451, + SPELL_PA_CONSECRATION = 43429, + SPELL_PA_AVENGING_WRATH = 43430, + SPELL_PA_HOLY_LIGHT = 43451, // Priest - SPELL_PR_HEAL = 41372, - SPELL_PR_MIND_BLAST = 41374, - SPELL_PR_SW_DEATH = 41375, - SPELL_PR_PSYCHIC_SCREAM = 43432, - SPELL_PR_MIND_CONTROL = 43550, - SPELL_PR_PAIN_SUPP = 44416, + SPELL_PR_HEAL = 41372, + SPELL_PR_MIND_BLAST = 41374, + SPELL_PR_SW_DEATH = 41375, + SPELL_PR_PSYCHIC_SCREAM = 43432, + SPELL_PR_MIND_CONTROL = 43550, + SPELL_PR_PAIN_SUPP = 44416, // Rogue - SPELL_RO_BLIND = 43433, - SPELL_RO_SLICE_DICE = 43457, - SPELL_RO_WOUND_POISON = 43461, + SPELL_RO_BLIND = 43433, + SPELL_RO_SLICE_DICE = 43457, + SPELL_RO_WOUND_POISON = 43461, // Shaman - SPELL_SH_CHAIN_LIGHT = 43435, - SPELL_SH_FIRE_NOVA = 43436, - SPELL_SH_HEALING_WAVE = 43548, + SPELL_SH_CHAIN_LIGHT = 43435, + SPELL_SH_FIRE_NOVA = 43436, + SPELL_SH_HEALING_WAVE = 43548, // Warlock - SPELL_WL_CURSE_OF_DOOM = 43439, - SPELL_WL_RAIN_OF_FIRE = 43440, - SPELL_WL_UNSTABLE_AFFL = 43522, - SPELL_WL_UNSTABLE_AFFL_DISPEL = 43523, + SPELL_WL_CURSE_OF_DOOM = 43439, + SPELL_WL_RAIN_OF_FIRE = 43440, + SPELL_WL_UNSTABLE_AFFL = 43522, + SPELL_WL_UNSTABLE_AFFL_DISPEL = 43523, // Warrior - SPELL_WR_MORTAL_STRIKE = 43441, - SPELL_WR_WHIRLWIND = 43442, - SPELL_WR_SPELL_REFLECT = 43443, + SPELL_WR_MORTAL_STRIKE = 43441, + SPELL_WR_WHIRLWIND = 43442, + SPELL_WR_SPELL_REFLECT = 43443, // Thurg - SPELL_BLOODLUST = 43578, - SPELL_CLEAVE = 15496, + SPELL_BLOODLUST = 43578, + SPELL_CLEAVE = 15496, // Gazakroth - SPELL_FIREBOLT = 43584, + SPELL_FIREBOLT = 43584, // Alyson Antille - SPELL_FLASH_HEAL = 43575, - SPELL_DISPEL_MAGIC = 43577, + SPELL_FLASH_HEAL = 43575, + SPELL_DISPEL_MAGIC = 43577, // Lord Raadan - SPELL_FLAME_BREATH = 43582, - SPELL_THUNDERCLAP = 43583, + SPELL_FLAME_BREATH = 43582, + SPELL_THUNDERCLAP = 43583, // Darkheart - SPELL_PSYCHIC_WAIL = 43590, + SPELL_PSYCHIC_WAIL = 43590, // Slither - SPELL_VENOM_SPIT = 43579, + SPELL_VENOM_SPIT = 43579, // Fenstalker - SPELL_VOLATILE_INFECTION = 43586, + SPELL_VOLATILE_INFECTION = 43586, // Koragg - SPELL_COLD_STARE = 43593, - SPELL_MIGHTY_BLOW = 43592 - + SPELL_COLD_STARE = 43593, + SPELL_MIGHTY_BLOW = 43592 }; #define ORIENT 1.5696f @@ -306,8 +301,7 @@ class boss_hexlord_malacrass : public CreatureScript instance->SetData(DATA_HEXLORDEVENT, IN_PROGRESS); DoZoneInCombat(); - me->Yell(YELL_AGGRO, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_AGGRO); + Talk(YELL_AGGRO); for (uint8 i = 0; i < 4; ++i) { @@ -327,12 +321,10 @@ class boss_hexlord_malacrass : public CreatureScript switch (urand(0, 1)) { case 0: - me->Yell(YELL_KILL_ONE, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_KILL_ONE); + Talk(YELL_KILL_ONE); break; case 1: - me->Yell(YELL_KILL_TWO, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_KILL_TWO); + Talk(YELL_KILL_TWO); break; } } @@ -341,8 +333,7 @@ class boss_hexlord_malacrass : public CreatureScript { instance->SetData(DATA_HEXLORDEVENT, DONE); - me->Yell(YELL_DEATH, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_DEATH); + Talk(YELL_DEATH); for (uint8 i = 0; i < 4; ++i) { @@ -415,8 +406,7 @@ class boss_hexlord_malacrass : public CreatureScript if (DrainPower_Timer <= diff) { DoCast(me, SPELL_DRAIN_POWER, true); - me->Yell(YELL_DRAIN_POWER, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_DRAIN_POWER); + Talk(YELL_DRAIN_POWER); DrainPower_Timer = urand(40000, 55000); // must cast in 60 sec, or buff/debuff will disappear } else DrainPower_Timer -= diff; @@ -427,8 +417,7 @@ class boss_hexlord_malacrass : public CreatureScript else { DoCast(me, SPELL_SPIRIT_BOLTS, false); - me->Yell(YELL_SPIRIT_BOLTS, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_SPIRIT_BOLTS); + Talk(YELL_SPIRIT_BOLTS); SpiritBolts_Timer = 40000; SiphonSoul_Timer = 10000; // ready to drain PlayerAbility_Timer = 99999; diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp index 37505a8b74d..188f9d0cc03 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp @@ -30,21 +30,41 @@ EndScriptData */ #include "GridNotifiersImpl.h" #include "CellImpl.h" -enum Spells +enum Yells { - SPELL_BERSERK = 45078, + YELL_NALORAKK_WAVE1 = 0, + YELL_NALORAKK_WAVE2 = 1, + YELL_NALORAKK_WAVE3 = 2, + YELL_NALORAKK_WAVE4 = 3, + YELL_AGGRO = 4, + YELL_SURGE = 5, + YELL_SHIFTEDTOBEAR = 6, + YELL_SHIFTEDTOTROLL = 7, + YELL_BERSERK = 8, + YELL_KILL_ONE = 9, + YELL_KILL_TWO = 10, + YELL_DEATH = 11 + +// Not yet implemented +// YELL_NALORAKK_EVENT1 = 12, +// YELL_NALORAKK_EVENT2 = 13 +}; +enum Spells +{ // Troll form - SPELL_BRUTALSWIPE = 42384, - SPELL_MANGLE = 42389, - SPELL_MANGLEEFFECT = 44955, - SPELL_SURGE = 42402, - SPELL_BEARFORM = 42377, + SPELL_BRUTALSWIPE = 42384, + SPELL_MANGLE = 42389, + SPELL_MANGLEEFFECT = 44955, + SPELL_SURGE = 42402, + SPELL_BEARFORM = 42377, // Bear form - SPELL_LACERATINGSLASH = 42395, - SPELL_RENDFLESH = 42397, - SPELL_DEAFENINGROAR = 42398 + SPELL_LACERATINGSLASH = 42395, + SPELL_RENDFLESH = 42397, + SPELL_DEAFENINGROAR = 42398, + + SPELL_BERSERK = 45078 }; // Trash Waves @@ -57,45 +77,9 @@ float NalorakkWay[8][3] = {-79.929f, 1395.958f, 27.31f}, {-80.072f, 1374.555f, 40.87f}, // waypoint 3 {-80.072f, 1314.398f, 40.87f}, - {-80.072f, 1295.775f, 48.60f} // waypoint 4 + {-80.072f, 1295.775f, 48.60f} // waypoint 4 }; -#define YELL_NALORAKK_WAVE1 "Get da move on, guards! It be killin' time!" -#define SOUND_NALORAKK_WAVE1 12066 -#define YELL_NALORAKK_WAVE2 "Guards, go already! Who you more afraid of, dem... or me?" -#define SOUND_NALORAKK_WAVE2 12067 -#define YELL_NALORAKK_WAVE3 "Ride now! Ride out dere and bring me back some heads!" -#define SOUND_NALORAKK_WAVE3 12068 -#define YELL_NALORAKK_WAVE4 "I be losin' me patience! Go on: make dem wish dey was never born!" -#define SOUND_NALORAKK_WAVE4 12069 - -//Unimplemented SoundIDs -/* -#define SOUND_NALORAKK_EVENT1 12078 -#define SOUND_NALORAKK_EVENT2 12079 -*/ - -//General defines -#define YELL_AGGRO "You be dead soon enough!" -#define SOUND_YELL_AGGRO 12070 -#define YELL_KILL_ONE "Mua-ha-ha! Now whatchoo got to say?" -#define SOUND_YELL_KILL_ONE 12075 -#define YELL_KILL_TWO "Da Amani gonna rule again!" -#define SOUND_YELL_KILL_TWO 12076 -#define YELL_DEATH "I... be waitin' on da udda side...." -#define SOUND_YELL_DEATH 12077 -#define YELL_BERSERK "You had your chance, now it be too late!" //Never seen this being used, so just guessing from what I hear. -#define SOUND_YELL_BERSERK 12074 -#define YELL_SURGE "I bring da pain!" -#define SOUND_YELL_SURGE 12071 - -#define YELL_SHIFTEDTOTROLL "Make way for Nalorakk!" -#define SOUND_YELL_TOTROLL 12073 - - -#define YELL_SHIFTEDTOBEAR "You call on da beast, you gonna get more dan you bargain for!" -#define SOUND_YELL_TOBEAR 12072 - class boss_nalorakk : public CreatureScript { public: @@ -158,7 +142,7 @@ class boss_nalorakk : public CreatureScript me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); inMove = false; waitTimer = 0; - me->SetSpeed(MOVE_RUN, 2); + me->SetSpeedRate(MOVE_RUN, 2); me->SetWalk(false); }else { @@ -227,8 +211,7 @@ class boss_nalorakk : public CreatureScript case 0: if (me->IsWithinDistInMap(who, 50)) { - me->Yell(YELL_NALORAKK_WAVE1, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_NALORAKK_WAVE1); + Talk(YELL_NALORAKK_WAVE1); (*me).GetMotionMaster()->MovePoint(1, NalorakkWay[1][0], NalorakkWay[1][1], NalorakkWay[1][2]); MovePhase ++; @@ -240,8 +223,7 @@ class boss_nalorakk : public CreatureScript case 2: if (me->IsWithinDistInMap(who, 40)) { - me->Yell(YELL_NALORAKK_WAVE2, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_NALORAKK_WAVE2); + Talk(YELL_NALORAKK_WAVE2); (*me).GetMotionMaster()->MovePoint(3, NalorakkWay[3][0], NalorakkWay[3][1], NalorakkWay[3][2]); MovePhase ++; @@ -253,8 +235,7 @@ class boss_nalorakk : public CreatureScript case 5: if (me->IsWithinDistInMap(who, 40)) { - me->Yell(YELL_NALORAKK_WAVE3, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_NALORAKK_WAVE3); + Talk(YELL_NALORAKK_WAVE3); (*me).GetMotionMaster()->MovePoint(6, NalorakkWay[6][0], NalorakkWay[6][1], NalorakkWay[6][2]); MovePhase ++; @@ -268,8 +249,7 @@ class boss_nalorakk : public CreatureScript { SendAttacker(who); - me->Yell(YELL_NALORAKK_WAVE4, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_NALORAKK_WAVE4); + Talk(YELL_NALORAKK_WAVE4); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -287,8 +267,7 @@ class boss_nalorakk : public CreatureScript { instance->SetData(DATA_NALORAKKEVENT, IN_PROGRESS); - me->Yell(YELL_AGGRO, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_AGGRO); + Talk(YELL_AGGRO); DoZoneInCombat(); } @@ -296,8 +275,7 @@ class boss_nalorakk : public CreatureScript { instance->SetData(DATA_NALORAKKEVENT, DONE); - me->Yell(YELL_DEATH, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_DEATH); + Talk(YELL_DEATH); } void KilledUnit(Unit* /*victim*/) override @@ -305,12 +283,10 @@ class boss_nalorakk : public CreatureScript switch (urand(0, 1)) { case 0: - me->Yell(YELL_KILL_ONE, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_KILL_ONE); + Talk(YELL_KILL_ONE); break; case 1: - me->Yell(YELL_KILL_TWO, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_KILL_TWO); + Talk(YELL_KILL_TWO); break; } } @@ -373,8 +349,7 @@ class boss_nalorakk : public CreatureScript if (Berserk_Timer <= diff) { DoCast(me, SPELL_BERSERK, true); - me->Yell(YELL_BERSERK, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_BERSERK); + Talk(YELL_BERSERK); Berserk_Timer = 600000; } else Berserk_Timer -= diff; @@ -383,8 +358,7 @@ class boss_nalorakk : public CreatureScript if (inBearForm) { // me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 5122); - me->Yell(YELL_SHIFTEDTOTROLL, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_TOTROLL); + Talk(YELL_SHIFTEDTOTROLL); me->RemoveAurasDueToSpell(SPELL_BEARFORM); Surge_Timer = urand(15000, 20000); BrutalSwipe_Timer = urand(7000, 12000); @@ -395,8 +369,7 @@ class boss_nalorakk : public CreatureScript else { // me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 0); - me->Yell(YELL_SHIFTEDTOBEAR, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_TOBEAR); + Talk(YELL_SHIFTEDTOBEAR); DoCast(me, SPELL_BEARFORM, true); LaceratingSlash_Timer = 2000; // dur 18s RendFlesh_Timer = 3000; // dur 5s @@ -426,8 +399,7 @@ class boss_nalorakk : public CreatureScript if (Surge_Timer <= diff) { - me->Yell(YELL_SURGE, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_SURGE); + Talk(YELL_SURGE); Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 45, true); if (target) DoCast(target, SPELL_SURGE); diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_zuljin.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_zuljin.cpp index 96c0798ae05..a1c2369cf66 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_zuljin.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_zuljin.cpp @@ -347,7 +347,7 @@ class boss_zuljin : public CreatureScript Vortex->CastSpell(Vortex, SPELL_CYCLONE_PASSIVE, true); Vortex->CastSpell(Vortex, SPELL_CYCLONE_VISUAL, true); Vortex->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Vortex->SetSpeed(MOVE_RUN, 1.0f); + Vortex->SetSpeedRate(MOVE_RUN, 1.0f); Vortex->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM, 0)); DoZoneInCombat(Vortex); } @@ -438,7 +438,7 @@ class boss_zuljin : public CreatureScript { if (me->GetVictim()) TankGUID = me->EnsureVictim()->GetGUID(); - me->SetSpeed(MOVE_RUN, 5.0f); + me->SetSpeedRate(MOVE_RUN, 5.0f); AttackStart(target); // change victim Claw_Rage_Timer = 0; Claw_Loop_Timer = 500; @@ -462,7 +462,7 @@ class boss_zuljin : public CreatureScript if (Claw_Counter == 12) { Claw_Rage_Timer = urand(15000, 20000); - me->SetSpeed(MOVE_RUN, 1.2f); + me->SetSpeedRate(MOVE_RUN, 1.2f); AttackStart(ObjectAccessor::GetUnit(*me, TankGUID)); TankGUID.Clear(); return; @@ -487,7 +487,7 @@ class boss_zuljin : public CreatureScript if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { TankGUID = me->EnsureVictim()->GetGUID(); - me->SetSpeed(MOVE_RUN, 5.0f); + me->SetSpeedRate(MOVE_RUN, 5.0f); AttackStart(target); // change victim Lynx_Rush_Timer = 0; Claw_Counter = 0; @@ -510,7 +510,7 @@ class boss_zuljin : public CreatureScript if (Claw_Counter == 9) { Lynx_Rush_Timer = urand(15000, 20000); - me->SetSpeed(MOVE_RUN, 1.2f); + me->SetSpeedRate(MOVE_RUN, 1.2f); AttackStart(ObjectAccessor::GetUnit(*me, TankGUID)); TankGUID.Clear(); } diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp index 8c781bb9001..b794a653791 100644 --- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -89,7 +89,6 @@ void AddSC_boss_sulfuron(); void AddSC_boss_majordomo(); void AddSC_boss_ragnaros(); void AddSC_instance_molten_core(); -void AddSC_instance_ragefire_chasm(); //Ragefire Chasm void AddSC_the_scarlet_enclave(); //Scarlet Enclave void AddSC_the_scarlet_enclave_c1(); void AddSC_the_scarlet_enclave_c2(); @@ -268,7 +267,6 @@ void AddEasternKingdomsScripts() AddSC_boss_majordomo(); AddSC_boss_ragnaros(); AddSC_instance_molten_core(); - AddSC_instance_ragefire_chasm(); //Ragefire Chasm AddSC_the_scarlet_enclave(); //Scarlet Enclave AddSC_the_scarlet_enclave_c1(); AddSC_the_scarlet_enclave_c2(); diff --git a/src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp b/src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp index df61a010f84..73b397553a5 100644 --- a/src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp +++ b/src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp @@ -19,7 +19,7 @@ /* ScriptData SDName: Burning_Steppes SD%Complete: 100 -SDComment: Quest support: 4224, 4866 +SDComment: Quest support: 4866 SDCategory: Burning Steppes EndScriptData */ @@ -36,25 +36,11 @@ EndContentData */ ## npc_ragged_john ######*/ -#define GOSSIP_HELLO "Official buisness, John. I need some information about Marsha Windsor. Tell me about the last time you saw him." -#define GOSSIP_SELECT1 "So what did you do?" -#define GOSSIP_SELECT2 "Start making sense, dwarf. I don't want to have anything to do with your cracker, your pappy, or any sort of 'discreditin'." -#define GOSSIP_SELECT3 "Ironfoe?" -#define GOSSIP_SELECT4 "Interesting... continue John." -#define GOSSIP_SELECT5 "So that's how Windsor died..." -#define GOSSIP_SELECT6 "So how did he die?" -#define GOSSIP_SELECT7 "Ok so where the hell is he? Wait a minute! Are you drunk?" -#define GOSSIP_SELECT8 "WHY is he in Blackrock Depths?" -#define GOSSIP_SELECT9 "300? So the Dark Irons killed him and dragged him into the Depths?" -#define GOSSIP_SELECT10 "Ahh... Ironfoe" -#define GOSSIP_SELECT11 "Thanks, Ragged John. Your story was very uplifting and informative" - enum RaggedJohn { - QUEST_THE_TRUE_MASTERS = 4224, - QUEST_MOTHERS_MILK = 4866, - SPELL_MOTHERS_MILK = 16468, - SPELL_WICKED_MILKING = 16472 + QUEST_MOTHERS_MILK = 4866, + SPELL_MOTHERS_MILK = 16468, + SPELL_WICKED_MILKING = 16472 }; class npc_ragged_john : public CreatureScript @@ -86,72 +72,13 @@ public: void EnterCombat(Unit* /*who*/) override { } }; - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(2714, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(2715, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(2716, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(2717, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(2718, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(2719, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(2720, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT8, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->SEND_GOSSIP_MENU(2721, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+8: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT9, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->SEND_GOSSIP_MENU(2722, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+9: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT10, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->SEND_GOSSIP_MENU(2723, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+10: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT11, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(2725, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(QUEST_THE_TRUE_MASTERS); - break; - } - return true; - } - bool OnGossipHello(Player* player, Creature* creature) override { if (creature->IsQuestGiver()) + { player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(QUEST_THE_TRUE_MASTERS) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(2713, creature->GetGUID()); + player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); + } return true; } diff --git a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp index 2d6d4da5aef..4a585bcb267 100644 --- a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp +++ b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp @@ -19,14 +19,12 @@ /* ScriptData SDName: Stormwind_City SD%Complete: 100 -SDComment: Quest support: 1640, 1447, 4185, 11223, 434. +SDComment: Quest support: 1640, 1447, 434. SDCategory: Stormwind City EndScriptData */ /* ContentData -npc_archmage_malin npc_bartleby -npc_lady_katrana_prestor npc_tyrion npc_tyrion_spybot npc_marzon_silent_blade @@ -40,50 +38,13 @@ EndContentData */ #include "Player.h" /*###### -## npc_archmage_malin -######*/ - -#define GOSSIP_ITEM_MALIN "Can you send me to Theramore? I have an urgent message for Lady Jaina from Highlord Bolvar." - -class npc_archmage_malin : public CreatureScript -{ -public: - npc_archmage_malin() : CreatureScript("npc_archmage_malin") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_ACTION_INFO_DEF) - { - player->CLOSE_GOSSIP_MENU(); - creature->CastSpell(player, 42711, true); - } - - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(11223) == QUEST_STATUS_COMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MALIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - - return true; - } -}; - -/*###### ## npc_bartleby ######*/ enum Bartleby { - FACTION_ENEMY = 168, - QUEST_BEAT = 1640 + FACTION_ENEMY = 168, + QUEST_BEAT = 1640 }; class npc_bartleby : public CreatureScript @@ -148,71 +109,18 @@ public: }; /*###### -## npc_lady_katrana_prestor -######*/ - -#define GOSSIP_ITEM_KAT_1 "Pardon the intrusion, Lady Prestor, but Highlord Bolvar suggested that I seek your advice." -#define GOSSIP_ITEM_KAT_2 "My apologies, Lady Prestor." -#define GOSSIP_ITEM_KAT_3 "Begging your pardon, Lady Prestor. That was not my intent." -#define GOSSIP_ITEM_KAT_4 "Thank you for your time, Lady Prestor." - -class npc_lady_katrana_prestor : public CreatureScript -{ -public: - npc_lady_katrana_prestor() : CreatureScript("npc_lady_katrana_prestor") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(2694, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(2695, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(2696, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(4185); - break; - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(4185) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(2693, creature->GetGUID()); - - return true; - } -}; - -/*###### ## npc_lord_gregor_lescovar ######*/ enum LordGregorLescovar { - SAY_GUARD_2 = 0, - SAY_LESCOVAR_2 = 0, - SAY_LESCOVAR_3 = 1, - SAY_LESCOVAR_4 = 2, - SAY_MARZON_1 = 0, - SAY_MARZON_2 = 1, - SAY_TYRION_2 = 1, + SAY_GUARD_2 = 0, + SAY_LESCOVAR_2 = 0, + SAY_LESCOVAR_3 = 1, + SAY_LESCOVAR_4 = 2, + SAY_MARZON_1 = 0, + SAY_MARZON_2 = 1, + SAY_TYRION_2 = 1, NPC_STORMWIND_ROYAL = 1756, NPC_MARZON_BLADE = 1755, @@ -650,9 +558,7 @@ public: void AddSC_stormwind_city() { - new npc_archmage_malin(); new npc_bartleby(); - new npc_lady_katrana_prestor(); new npc_tyrion(); new npc_tyrion_spybot(); new npc_lord_gregor_lescovar(); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.h b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.h index 55b85801652..54d3c53039e 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.h @@ -121,15 +121,15 @@ struct hyjalAI : public npc_escortAI void Initialize(); - void Reset(); // Generically used to reset our variables. Do *not* call in EnterEvadeMode as this may make problems if the raid is still in combat + void Reset() override; // Generically used to reset our variables. Do *not* call in EnterEvadeMode as this may make problems if the raid is still in combat - void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER); // Send creature back to spawn location and evade. + void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override; // Send creature back to spawn location and evade. - void EnterCombat(Unit* /*who*/); // Used to reset cooldowns for our spells and to inform the raid that we're under attack + void EnterCombat(Unit* /*who*/) override; // Used to reset cooldowns for our spells and to inform the raid that we're under attack - void UpdateAI(uint32 diff); // Called to summon waves, check for boss deaths and to cast our spells. + void UpdateAI(uint32 diff) override; // Called to summon waves, check for boss deaths and to cast our spells. - void JustDied(Unit* /*killer*/); // Called on death, informs the raid that they have failed. + void JustDied(Unit* /*killer*/) override; // Called on death, informs the raid that they have failed. void SetFaction(uint32 _faction) // Set the faction to either Alliance or Horde in Hyjal { @@ -140,13 +140,13 @@ struct hyjalAI : public npc_escortAI void SpawnVeins(); void DeSpawnVeins(); - void JustSummoned(Creature* summoned); - void SummonedCreatureDespawn(Creature* summoned); + void JustSummoned(Creature* summoned) override; + void SummonedCreatureDespawn(Creature* summoned) override; void HideNearPos(float x, float y); void RespawnNearPos(float x, float y); - void WaypointReached(uint32 waypointId); + void WaypointReached(uint32 waypointId) override; void DoOverrun(uint32 faction, const uint32 diff); - void MoveInLineOfSight(Unit* who); + void MoveInLineOfSight(Unit* who) override; void SummonCreature(uint32 entry, float Base[4][3]); // Summons a creature for that wave in that base diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h index 5275c07f63a..f29851e7cea 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h @@ -25,11 +25,11 @@ struct hyjal_trashAI : public npc_escortAI { hyjal_trashAI(Creature* creature); - void UpdateAI(uint32 diff); + void UpdateAI(uint32 diff) override; - void JustDied(Unit* /*killer*/); + void JustDied(Unit* /*killer*/) override; - void DamageTaken(Unit* done_by, uint32 &damage); + void DamageTaken(Unit* done_by, uint32 &damage) override; public: InstanceScript* instance; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp index 44cbdec2cb5..0526dcfa630 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp @@ -479,12 +479,12 @@ public: void DoMount() { me->Mount(SKARLOC_MOUNT_MODEL); - me->SetSpeed(MOVE_RUN, SPEED_MOUNT); + me->SetSpeedRate(MOVE_RUN, SPEED_MOUNT); } void DoUnmount() { me->Dismount(); - me->SetSpeed(MOVE_RUN, SPEED_RUN); + me->SetSpeedRate(MOVE_RUN, SPEED_RUN); } void EnterCombat(Unit* /*who*/) override { diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp index 7da15b1fdce..71ebe870e3d 100644 --- a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp +++ b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp @@ -205,7 +205,7 @@ public: PointData = GetMoveData(); MovePoint = PointData->LocIdEnd; - me->SetSpeed(MOVE_FLIGHT, 1.5f); + me->SetSpeedRate(MOVE_FLIGHT, 1.5f); me->GetMotionMaster()->MovePoint(8, MiddleRoomLocation); } } @@ -220,7 +220,7 @@ public: PointData = GetMoveData(); if (PointData) { - me->SetSpeed(MOVE_FLIGHT, 1.0f); + me->SetSpeedRate(MOVE_FLIGHT, 1.0f); me->GetMotionMaster()->MovePoint(PointData->LocId, PointData->fX, PointData->fY, PointData->fZ); } break; @@ -250,7 +250,7 @@ public: if (Creature * trigger = me->SummonCreature(NPC_TRIGGER, MiddleRoomLocation, TEMPSUMMON_CORPSE_DESPAWN)) triggerGUID = trigger->GetGUID(); me->GetMotionMaster()->MoveTakeoff(11, Phase2Floating); - me->SetSpeed(MOVE_FLIGHT, 1.0f); + me->SetSpeedRate(MOVE_FLIGHT, 1.0f); Talk(SAY_PHASE_2_TRANS); instance->SetData(DATA_ONYXIA_PHASE, Phase); events.ScheduleEvent(EVENT_WHELP_SPAWN, 5000); diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp index f1969a063d6..87edf4781d4 100644 --- a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp +++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp @@ -47,6 +47,7 @@ void AddSC_boss_meathook(); void AddSC_culling_of_stratholme(); void AddSC_instance_culling_of_stratholme(); void AddSC_instance_dire_maul(); //Dire Maul +void AddSC_instance_ragefire_chasm(); //Ragefire Chasm void AddSC_boss_celebras_the_cursed(); //Maraudon void AddSC_boss_landslide(); void AddSC_boss_noxxion(); @@ -143,6 +144,7 @@ void AddKalimdorScripts() AddSC_culling_of_stratholme(); AddSC_instance_culling_of_stratholme(); AddSC_instance_dire_maul(); //Dire Maul + AddSC_instance_ragefire_chasm(); //Ragefire Chasm AddSC_boss_celebras_the_cursed(); //Maraudon AddSC_boss_landslide(); AddSC_boss_noxxion(); diff --git a/src/server/scripts/Kalimdor/zone_azshara.cpp b/src/server/scripts/Kalimdor/zone_azshara.cpp index 1ed95c16a0d..4847ac46542 100644 --- a/src/server/scripts/Kalimdor/zone_azshara.cpp +++ b/src/server/scripts/Kalimdor/zone_azshara.cpp @@ -404,7 +404,7 @@ public: DoCast(me, SPELL_PERIODIC_DEPTH_CHARGE); me->SetHover(true); me->SetSwim(true); - me->SetSpeed(MOVE_RUN, 0.85f, true); + me->SetSpeedRate(MOVE_RUN, 0.85f); me->GetMotionMaster()->MovementExpired(); me->GetMotionMaster()->MovePoint(CurrWP, WPs[CurrWP]); Escape = true; diff --git a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp index 273e81d83c0..6063b9fe5c6 100644 --- a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp +++ b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp @@ -240,11 +240,6 @@ class npc_sironas : public CreatureScript public: npc_sironas() : CreatureScript("npc_sironas") { } - CreatureAI* GetAI(Creature* creature) const - { - return new npc_sironasAI(creature); - } - struct npc_sironasAI : public ScriptedAI { npc_sironasAI(Creature* creature) : ScriptedAI(creature) { } @@ -343,6 +338,11 @@ public: GuidList _beamGuidList; EventMap _events; }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_sironasAI(creature); + } }; /*###### @@ -354,11 +354,6 @@ class npc_demolitionist_legoso : public CreatureScript public: npc_demolitionist_legoso() : CreatureScript("npc_demolitionist_legoso") { } - CreatureAI* GetAI(Creature* creature) const - { - return new npc_demolitionist_legosoAI(creature); - } - struct npc_demolitionist_legosoAI : public npc_escortAI { npc_demolitionist_legosoAI(Creature* creature) : npc_escortAI(creature) @@ -812,6 +807,11 @@ public: GuidList _explosivesGuids; EventMap _events; }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_demolitionist_legosoAI(creature); + } }; void AddSC_bloodmyst_isle() diff --git a/src/server/scripts/Kalimdor/zone_desolace.cpp b/src/server/scripts/Kalimdor/zone_desolace.cpp index 621e0b0a585..3f4a905147f 100644 --- a/src/server/scripts/Kalimdor/zone_desolace.cpp +++ b/src/server/scripts/Kalimdor/zone_desolace.cpp @@ -66,7 +66,6 @@ public: npc_aged_dying_ancient_kodoAI(Creature* creature) : ScriptedAI(creature) { } void MoveInLineOfSight(Unit* who) override - { if (who->GetEntry() == NPC_SMEED && me->IsWithinDistInMap(who, 10.0f) && !me->HasAura(SPELL_KODO_KOMBO_GOSSIP)) { @@ -90,7 +89,7 @@ public: me->UpdateEntry(NPC_TAMED_KODO); me->CombatStop(); me->DeleteThreatList(); - me->SetSpeed(MOVE_RUN, 0.6f, true); + me->SetSpeedRate(MOVE_RUN, 0.6f); me->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, me->GetFollowAngle()); me->setActive(true); } @@ -226,37 +225,9 @@ public: } }; -/*###### -## go_demon_portal -######*/ - -enum DemonPortal -{ - NPC_DEMON_GUARDIAN = 11937, - QUEST_PORTAL_OF_THE_LEGION = 5581 -}; - -class go_demon_portal : public GameObjectScript -{ - public: - go_demon_portal() : GameObjectScript("go_demon_portal") { } - - bool OnGossipHello(Player* player, GameObject* go) override - { - if (player->GetQuestStatus(QUEST_PORTAL_OF_THE_LEGION) == QUEST_STATUS_INCOMPLETE && !go->FindNearestCreature(NPC_DEMON_GUARDIAN, 5.0f, true)) - { - if (Creature* guardian = player->SummonCreature(NPC_DEMON_GUARDIAN, go->GetPositionX(), go->GetPositionY(), go->GetPositionZ(), 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0)) - guardian->AI()->AttackStart(player); - } - - return true; - } -}; - void AddSC_desolace() { new npc_aged_dying_ancient_kodo(); new go_iruxos(); new npc_dalinda(); - new go_demon_portal(); } diff --git a/src/server/scripts/Kalimdor/zone_durotar.cpp b/src/server/scripts/Kalimdor/zone_durotar.cpp index 05caf9cca3a..62a041e7798 100644 --- a/src/server/scripts/Kalimdor/zone_durotar.cpp +++ b/src/server/scripts/Kalimdor/zone_durotar.cpp @@ -483,8 +483,8 @@ class spell_mount_check : public SpellScriptLoader else if (!owner->IsMounted() && target->IsMounted()) target->Dismount(); - target->SetSpeed(MOVE_RUN, owner->GetSpeedRate(MOVE_RUN)); - target->SetSpeed(MOVE_WALK, owner->GetSpeedRate(MOVE_WALK)); + target->SetSpeedRate(MOVE_RUN, owner->GetSpeedRate(MOVE_RUN)); + target->SetSpeedRate(MOVE_WALK, owner->GetSpeedRate(MOVE_WALK)); } void Register() override diff --git a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp index 9df9f0b604a..be49778ee4a 100644 --- a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp +++ b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp @@ -24,7 +24,6 @@ SDCategory: Dustwallow Marsh EndScriptData */ /* ContentData -npc_lady_jaina_proudmoore npc_nat_pagle npc_private_hendel npc_cassa_crimsonwing - handled by npc_taxi @@ -39,49 +38,6 @@ EndContentData */ #include "WorldSession.h" /*###### -## npc_lady_jaina_proudmoore -######*/ - -enum LadyJaina -{ - QUEST_JAINAS_AUTOGRAPH = 558, - SPELL_JAINAS_AUTOGRAPH = 23122 -}; - -#define GOSSIP_ITEM_JAINA "I know this is rather silly but i have a young ward who is a bit shy and would like your autograph." - -class npc_lady_jaina_proudmoore : public CreatureScript -{ -public: - npc_lady_jaina_proudmoore() : CreatureScript("npc_lady_jaina_proudmoore") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_SENDER_INFO) - { - player->SEND_GOSSIP_MENU(7012, creature->GetGUID()); - player->CastSpell(player, SPELL_JAINAS_AUTOGRAPH, false); - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(QUEST_JAINAS_AUTOGRAPH) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_JAINA, GOSSIP_SENDER_MAIN, GOSSIP_SENDER_INFO); - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - - return true; - } - -}; - -/*###### ## npc_nat_pagle ######*/ @@ -417,7 +373,6 @@ class spell_energize_aoe : public SpellScriptLoader void AddSC_dustwallow_marsh() { - new npc_lady_jaina_proudmoore(); new npc_nat_pagle(); new npc_private_hendel(); new npc_zelfrax(); diff --git a/src/server/scripts/Kalimdor/zone_orgrimmar.cpp b/src/server/scripts/Kalimdor/zone_orgrimmar.cpp index ac26aa1f811..adb6439272a 100644 --- a/src/server/scripts/Kalimdor/zone_orgrimmar.cpp +++ b/src/server/scripts/Kalimdor/zone_orgrimmar.cpp @@ -143,20 +143,30 @@ public: enum ThrallWarchief { - QUEST_6566 = 6566, - - SPELL_CHAIN_LIGHTNING = 16033, - SPELL_SHOCK = 16034 + GOSSIP_MENU_OPTION_ID_ALL = 0, + + OPTION_PLEASE_SHARE_YOUR = 3664, + OPTION_WHAT_DISCOVERIES = 3665, + OPTION_USURPER = 3666, + OPTION_WITH_ALL_DUE_RESPECT = 3667, + OPTION_I_I_DID_NOT_THINK_OF = 3668, + OPTION_I_LIVE_ONLY_TO_SERVE = 3669, + OPTION_OF_COURSE_WARCHIEF = 3670, + + GOSSIP_MEMBERS_OF_THE_HORDE = 4477, + GOSSIP_THE_SHATTERED_HAND = 5733, + GOSSIP_IT_WOULD_APPEAR_AS = 5734, + GOSSIP_THE_BROOD_MOTHER = 5735, + GOSSIP_SO_MUCH_TO_LEARN = 5736, + GOSSIP_I_DO_NOT_FAULT_YOU = 5737, + GOSSIP_NOW_PAY_ATTENTION = 5738, + + QUEST_WHAT_THE_WIND_CARRIES = 6566, + + SPELL_CHAIN_LIGHTNING = 16033, + SPELL_SHOCK = 16034 }; -#define GOSSIP_HTW "Please share your wisdom with me, Warchief." -#define GOSSIP_STW1 "What discoveries?" -#define GOSSIP_STW2 "Usurper?" -#define GOSSIP_STW3 "With all due respect, Warchief - why not allow them to be destroyed? Does this not strengthen our position?" -#define GOSSIP_STW4 "I... I did not think of it that way, Warchief." -#define GOSSIP_STW5 "I live only to serve, Warchief! My life is empty and meaningless without your guidance." -#define GOSSIP_STW6 "Of course, Warchief!" - /// @todo verify abilities/timers class npc_thrall_warchief : public CreatureScript { @@ -169,32 +179,32 @@ public: switch (action) { case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_STW1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(5733, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(OPTION_WHAT_DISCOVERIES, GOSSIP_MENU_OPTION_ID_ALL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->SEND_GOSSIP_MENU(GOSSIP_THE_SHATTERED_HAND, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_STW2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->SEND_GOSSIP_MENU(5734, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(OPTION_USURPER, GOSSIP_MENU_OPTION_ID_ALL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->SEND_GOSSIP_MENU(GOSSIP_IT_WOULD_APPEAR_AS, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_STW3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(5735, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(OPTION_WITH_ALL_DUE_RESPECT, GOSSIP_MENU_OPTION_ID_ALL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->SEND_GOSSIP_MENU(GOSSIP_THE_BROOD_MOTHER, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_STW4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(5736, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(OPTION_I_I_DID_NOT_THINK_OF, GOSSIP_MENU_OPTION_ID_ALL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(GOSSIP_SO_MUCH_TO_LEARN, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_STW5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - player->SEND_GOSSIP_MENU(5737, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(OPTION_I_LIVE_ONLY_TO_SERVE, GOSSIP_MENU_OPTION_ID_ALL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + player->SEND_GOSSIP_MENU(GOSSIP_I_DO_NOT_FAULT_YOU, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+6: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_STW6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); - player->SEND_GOSSIP_MENU(5738, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(OPTION_OF_COURSE_WARCHIEF, GOSSIP_MENU_OPTION_ID_ALL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); + player->SEND_GOSSIP_MENU(GOSSIP_NOW_PAY_ATTENTION, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+7: player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(QUEST_6566); + player->AreaExploredOrEventHappens(QUEST_WHAT_THE_WIND_CARRIES); break; } return true; @@ -205,10 +215,10 @@ public: if (creature->IsQuestGiver()) player->PrepareQuestMenu(creature->GetGUID()); - if (player->GetQuestStatus(QUEST_6566) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HTW, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + if (player->GetQuestStatus(QUEST_WHAT_THE_WIND_CARRIES) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM_DB(OPTION_PLEASE_SHARE_YOUR, GOSSIP_MENU_OPTION_ID_ALL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); + player->SEND_GOSSIP_MENU(GOSSIP_MEMBERS_OF_THE_HORDE, creature->GetGUID()); return true; } diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp index 852cd62c277..b113615ca50 100644 --- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp +++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp @@ -552,7 +552,7 @@ public: { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { - if (me->getStandState() == UNIT_STAND_STATE_DEAD) + if (me->GetStandState() == UNIT_STAND_STATE_DEAD) me->SetStandState(UNIT_STAND_STATE_STAND); IsPostEvent = false; diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp index ab09dd45710..3c11fd5d9a6 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp @@ -454,11 +454,11 @@ public: float distance = me->GetDistance(JedogaPosition[1]); if (distance < 9.0f) - me->SetSpeed(MOVE_WALK, 0.5f, true); + me->SetSpeedRate(MOVE_WALK, 0.5f); else if (distance < 15.0f) - me->SetSpeed(MOVE_WALK, 0.75f, true); + me->SetSpeedRate(MOVE_WALK, 0.75f); else if (distance < 20.0f) - me->SetSpeed(MOVE_WALK, 1.0f, true); + me->SetSpeedRate(MOVE_WALK, 1.0f); me->GetMotionMaster()->Clear(false); me->GetMotionMaster()->MovePoint(1, JedogaPosition[1]); diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp index e25f64f61aa..04b62f77e9a 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp @@ -178,7 +178,7 @@ class boss_prince_taldaram : public CreatureScript if (Unit* embraceTarget = GetEmbraceTarget()) { me->GetMotionMaster()->Clear(); - me->SetSpeed(MOVE_WALK, 2.0f, true); + me->SetSpeedRate(MOVE_WALK, 2.0f); me->GetMotionMaster()->MoveChase(embraceTarget); } events.ScheduleEvent(EVENT_VANISHED, 1300); @@ -188,7 +188,7 @@ class boss_prince_taldaram : public CreatureScript DoCast(embraceTarget, SPELL_EMBRACE_OF_THE_VAMPYR); Talk(SAY_FEED); me->GetMotionMaster()->Clear(); - me->SetSpeed(MOVE_WALK, 1.0f, true); + me->SetSpeedRate(MOVE_WALK, 1.0f); me->GetMotionMaster()->MoveChase(me->GetVictim()); events.ScheduleEvent(EVENT_FEEDING, 20000); break; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp index a6cd8362db3..739c3602f44 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp @@ -23,7 +23,7 @@ #include "WorldPacket.h" #include "ruby_sanctum.h" -BossBoundaryData const boundaries = +BossBoundaryData const boundaries = { { DATA_GENERAL_ZARITHRIAN, new EllipseBoundary(Position(3013.409f, 529.492f), 45.0, 100.0) }, { DATA_HALION, new CircleBoundary(Position(3156.037f, 533.2656f), 48.5) } diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp index ae4a5e2a69a..9235b75d53e 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp @@ -18,6 +18,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" +#include "SpellScript.h" #include "ruby_sanctum.h" #include "Player.h" @@ -45,6 +46,11 @@ enum Events EVENT_XERESTRASZA_EVENT_7 = 7, }; +enum Spells +{ + SPELL_RALLY = 75416 +}; + Position const xerestraszaMovePos = {3151.236f, 379.8733f, 86.31996f, 0.0f}; class npc_xerestrasza : public CreatureScript @@ -165,8 +171,53 @@ class at_baltharus_plateau : public AreaTriggerScript } }; +// 75415 - Rallying Shout +class spell_ruby_sanctum_rallying_shout : public SpellScriptLoader +{ + public: + spell_ruby_sanctum_rallying_shout() : SpellScriptLoader("spell_ruby_sanctum_rallying_shout") { } + + class spell_ruby_sanctum_rallying_shout_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ruby_sanctum_rallying_shout_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_RALLY)) + return false; + return true; + } + + void CountTargets(std::list<WorldObject*>& targets) + { + _targetCount = targets.size(); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (_targetCount && !GetCaster()->HasAura(SPELL_RALLY)) + GetCaster()->CastCustomSpell(SPELL_RALLY, SPELLVALUE_AURA_STACK, _targetCount, GetCaster(), TRIGGERED_FULL_MASK); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ruby_sanctum_rallying_shout_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + OnEffectHit += SpellEffectFn(spell_ruby_sanctum_rallying_shout_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + + private: + uint32 _targetCount = 0; + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ruby_sanctum_rallying_shout_SpellScript(); + } +}; + void AddSC_ruby_sanctum() { new npc_xerestrasza(); new at_baltharus_plateau(); + new spell_ruby_sanctum_rallying_shout(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index c89510211b9..7440984d7c5 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -804,7 +804,7 @@ class npc_anubarak_spike : public CreatureScript void StartChase(Unit* who) { DoCast(who, SPELL_MARK); - me->SetSpeed(MOVE_RUN, 0.5f); + me->SetSpeedRate(MOVE_RUN, 0.5f); // make sure the Spine will really follow the one he should me->getThreatManager().clearReferences(); me->SetInCombatWithZone(); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index eb1e769c07e..278f6a7ab4f 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -132,7 +132,7 @@ class OrbsDespawner : public BasicEvent { } - bool Execute(uint64 /*currTime*/, uint32 /*diff*/) + bool Execute(uint64 /*currTime*/, uint32 /*diff*/) override { Trinity::CreatureWorker<OrbsDespawner> worker(_creature, *this); _creature->VisitNearbyGridObject(5000.0f, worker); diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index 4c2b92da0ea..3ac85809fa2 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -2580,7 +2580,7 @@ class npc_quel_delar_sword : public CreatureScript void Reset() override { _events.Reset(); - me->SetSpeed(MOVE_FLIGHT, 4.5f, true); + me->SetSpeedRate(MOVE_FLIGHT, 4.5f); DoCast(SPELL_WHIRLWIND_VISUAL); if (_intro) _events.ScheduleEvent(EVENT_QUEL_DELAR_INIT, 0); diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_krickandick.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_krickandick.cpp index 03f12e46bc3..b24a36da3fb 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_krickandick.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_krickandick.cpp @@ -418,7 +418,7 @@ class boss_krick : public CreatureScript case EVENT_OUTRO_6: if (Creature* tyrannus = ObjectAccessor::GetCreature(*me, _instanceScript->GetGuidData(DATA_TYRANNUS_EVENT))) { - tyrannus->SetSpeed(MOVE_FLIGHT, 3.5f, true); + tyrannus->SetSpeedRate(MOVE_FLIGHT, 3.5f); tyrannus->GetMotionMaster()->MovePoint(1, outroPos[4]); _tyrannusGUID = tyrannus->GetGUID(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index f59701b9c25..51711f9ded5 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -160,7 +160,7 @@ class StandUpEvent : public BasicEvent public: StandUpEvent(Creature& owner) : BasicEvent(), _owner(owner) { } - bool Execute(uint64 /*eventTime*/, uint32 /*diff*/) + bool Execute(uint64 /*eventTime*/, uint32 /*diff*/) override { _owner.HandleEmoteCommand(EMOTE_ONESHOT_ROAR); _owner.SetReactState(REACT_AGGRESSIVE); @@ -1069,7 +1069,7 @@ class npc_blood_queen_lana_thel : public CreatureScript if (Creature* summon = DoSummon(NPC_FLOATING_TRIGGER, triggerPos, 15000, TEMPSUMMON_TIMED_DESPAWN)) { summon->CastSpell(summon, SPELL_OOC_INVOCATION_VISUAL, true); - summon->SetSpeed(MOVE_FLIGHT, 0.15f, true); // todo: creature is swimming, check if this is blizzlike or not. + summon->SetSpeedRate(MOVE_FLIGHT, 0.15f); // todo: creature is swimming, check if this is blizzlike or not. summon->GetMotionMaster()->MovePoint(0, triggerEndPos); } } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp index bc8c7f877a9..3d21388ca11 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp @@ -809,7 +809,7 @@ class spell_blood_queen_pact_of_the_darkfallen_dmg : public SpellScriptLoader // this is an additional effect to be executed void PeriodicTick(AuraEffect const* aurEff) { - SpellInfo const* damageSpell = sSpellMgr->EnsureSpellInfo(SPELL_PACT_OF_THE_DARKFALLEN_DAMAGE); + SpellInfo const* damageSpell = sSpellMgr->AssertSpellInfo(SPELL_PACT_OF_THE_DARKFALLEN_DAMAGE); int32 damage = damageSpell->Effects[EFFECT_0].CalcValue(); float multiplier = 0.3375f + 0.1f * uint32(aurEff->GetTickNumber()/10); // do not convert to 0.01f - we need tick number/10 as INT (damage increases every 10 ticks) damage = int32(damage * multiplier); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp index 9b0693ec95e..d77842fff0a 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -1843,7 +1843,7 @@ class spell_igb_rocket_pack : public SpellScriptLoader void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - SpellInfo const* damageInfo = sSpellMgr->EnsureSpellInfo(SPELL_ROCKET_PACK_DAMAGE); + SpellInfo const* damageInfo = sSpellMgr->AssertSpellInfo(SPELL_ROCKET_PACK_DAMAGE); GetTarget()->CastCustomSpell(SPELL_ROCKET_PACK_DAMAGE, SPELLVALUE_BASE_POINT0, 2 * (damageInfo->Effects[EFFECT_0].CalcValue() + aurEff->GetTickNumber() * aurEff->GetAmplitude()), NULL, TRIGGERED_FULL_MASK); GetTarget()->CastSpell(NULL, SPELL_ROCKET_BURST, TRIGGERED_FULL_MASK); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index d3cf6495aa7..b3a11b8eb31 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -203,7 +203,7 @@ class DaranavanMoveEvent : public BasicEvent public: DaranavanMoveEvent(Creature& darnavan) : _darnavan(darnavan) { } - bool Execute(uint64 /*time*/, uint32 /*diff*/) + bool Execute(uint64 /*time*/, uint32 /*diff*/) override { _darnavan.GetMotionMaster()->MovePoint(POINT_DESPAWN, SummonPositions[6]); return true; @@ -421,7 +421,7 @@ class boss_lady_deathwhisper : public CreatureScript void UpdateAI(uint32 diff) override { - if ((!UpdateVictim() && !events.IsInPhase(PHASE_INTRO))) + if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) return; events.Update(diff); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 056231285e2..9f20799df82 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -142,7 +142,7 @@ class boss_lord_marrowgar : public CreatureScript void Reset() override { _Reset(); - me->SetSpeed(MOVE_RUN, _baseSpeed, true); + me->SetSpeedRate(MOVE_RUN, _baseSpeed); me->RemoveAurasDueToSpell(SPELL_BONE_STORM); me->RemoveAurasDueToSpell(SPELL_BERSERK); events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000); @@ -224,7 +224,7 @@ class boss_lord_marrowgar : public CreatureScript case EVENT_BONE_STORM_BEGIN: if (Aura* pStorm = me->GetAura(SPELL_BONE_STORM)) pStorm->SetDuration(int32(_boneStormDuration)); - me->SetSpeed(MOVE_RUN, _baseSpeed*3.0f, true); + me->SetSpeedRate(MOVE_RUN, _baseSpeed*3.0f); Talk(SAY_BONE_STORM); events.ScheduleEvent(EVENT_BONE_STORM_END, _boneStormDuration+1); // no break here @@ -242,7 +242,7 @@ class boss_lord_marrowgar : public CreatureScript if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) me->GetMotionMaster()->MovementExpired(); me->GetMotionMaster()->MoveChase(me->GetVictim()); - me->SetSpeed(MOVE_RUN, _baseSpeed, true); + me->SetSpeedRate(MOVE_RUN, _baseSpeed); events.CancelEvent(EVENT_BONE_STORM_MOVE); events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000); if (!IsHeroic()) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 2db9d206a00..fe6e4081326 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -369,21 +369,21 @@ class boss_professor_putricide : public CreatureScript { case POINT_FESTERGUT: instance->SetBossState(DATA_FESTERGUT, IN_PROGRESS); // needed here for delayed gate close - me->SetSpeed(MOVE_RUN, _baseSpeed, true); + me->SetSpeedRate(MOVE_RUN, _baseSpeed); DoAction(ACTION_FESTERGUT_GAS); if (Creature* festergut = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FESTERGUT))) festergut->CastSpell(festergut, SPELL_GASEOUS_BLIGHT_LARGE, false, NULL, NULL, festergut->GetGUID()); break; case POINT_ROTFACE: instance->SetBossState(DATA_ROTFACE, IN_PROGRESS); // needed here for delayed gate close - me->SetSpeed(MOVE_RUN, _baseSpeed, true); + me->SetSpeedRate(MOVE_RUN, _baseSpeed); DoAction(ACTION_ROTFACE_OOZE); events.ScheduleEvent(EVENT_ROTFACE_OOZE_FLOOD, 25000, 0, PHASE_ROTFACE); break; case POINT_TABLE: // stop attack me->GetMotionMaster()->MoveIdle(); - me->SetSpeed(MOVE_RUN, _baseSpeed, true); + me->SetSpeedRate(MOVE_RUN, _baseSpeed); if (GameObject* table = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_PUTRICIDE_TABLE))) me->SetFacingToObject(table); // operating on new phase already @@ -418,7 +418,7 @@ class boss_professor_putricide : public CreatureScript { case ACTION_FESTERGUT_COMBAT: SetPhase(PHASE_FESTERGUT); - me->SetSpeed(MOVE_RUN, _baseSpeed*2.0f, true); + me->SetSpeedRate(MOVE_RUN, _baseSpeed*2.0f); me->GetMotionMaster()->MovePoint(POINT_FESTERGUT, festergutWatchPos); me->SetReactState(REACT_PASSIVE); DoZoneInCombat(me); @@ -435,7 +435,7 @@ class boss_professor_putricide : public CreatureScript case ACTION_ROTFACE_COMBAT: { SetPhase(PHASE_ROTFACE); - me->SetSpeed(MOVE_RUN, _baseSpeed*2.0f, true); + me->SetSpeedRate(MOVE_RUN, _baseSpeed*2.0f); me->GetMotionMaster()->MovePoint(POINT_ROTFACE, rotfaceWatchPos); me->SetReactState(REACT_PASSIVE); _oozeFloodStage = 0; @@ -477,7 +477,7 @@ class boss_professor_putricide : public CreatureScript events.ScheduleEvent(EVENT_ROTFACE_DIES, 4500, 0, PHASE_ROTFACE); break; case ACTION_CHANGE_PHASE: - me->SetSpeed(MOVE_RUN, _baseSpeed*2.0f, true); + me->SetSpeedRate(MOVE_RUN, _baseSpeed*2.0f); events.DelayEvents(30000); me->AttackStop(); if (!IsHeroic()) @@ -562,7 +562,7 @@ class boss_professor_putricide : public CreatureScript void UpdateAI(uint32 diff) override { - if ((!(events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT)) && !UpdateVictim())) + if (!(events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT)) && !UpdateVictim()) return; events.Update(diff); @@ -776,7 +776,7 @@ class npc_volatile_ooze : public CreatureScript { } - void CastMainSpell() + void CastMainSpell() override { me->CastSpell(me, SPELL_VOLATILE_OOZE_ADHESIVE, false); } @@ -800,7 +800,7 @@ class npc_gas_cloud : public CreatureScript _newTargetSelectTimer = 0; } - void CastMainSpell() + void CastMainSpell() override { me->CastCustomSpell(SPELL_GASEOUS_BLOAT, SPELLVALUE_AURA_STACK, 10, me, false); } @@ -1257,7 +1257,7 @@ class spell_putricide_mutated_plague : public SpellScriptLoader return; uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - SpellInfo const* spell = sSpellMgr->EnsureSpellInfo(triggerSpell); + SpellInfo const* spell = sSpellMgr->AssertSpellInfo(triggerSpell); spell = sSpellMgr->GetSpellForDifficultyFromSpell(spell, caster); int32 damage = spell->Effects[EFFECT_0].CalcValue(caster); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp index 683dd976b7a..bf69a49055c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp @@ -856,14 +856,14 @@ class spell_rotface_vile_gas_trigger : public SpellScriptLoader GetCaster()->CastSpell(GetHitUnit(), SPELL_VILE_GAS_TRIGGER_SUMMON); } - void Register() + void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_vile_gas_trigger_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); OnEffectHitTarget += SpellEffectFn(spell_rotface_vile_gas_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_rotface_vile_gas_trigger_SpellScript(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index ac094588d35..caa37465165 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -134,6 +134,7 @@ enum FrostwingData DATA_WHELP_MARKER = 2, DATA_LINKED_GAMEOBJECT = 3, DATA_TRAPPED_PLAYER = 4, + DATA_IS_THIRD_PHASE = 5 }; enum MovementPoints @@ -168,7 +169,7 @@ class FrostwyrmLandEvent : public BasicEvent public: FrostwyrmLandEvent(Creature& owner, Position const& dest) : _owner(owner), _dest(dest) { } - bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) + bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override { _owner.GetMotionMaster()->MoveLand(POINT_FROSTWYRM_LAND, _dest); return true; @@ -184,7 +185,7 @@ class FrostBombExplosion : public BasicEvent public: FrostBombExplosion(Creature* owner, ObjectGuid sindragosaGUID) : _owner(owner), _sindragosaGUID(sindragosaGUID) { } - bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) + bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override { _owner->CastSpell((Unit*)NULL, SPELL_FROST_BOMB, false, NULL, NULL, _sindragosaGUID); _owner->RemoveAurasDueToSpell(SPELL_FROST_BOMB_VISUAL); @@ -196,20 +197,19 @@ class FrostBombExplosion : public BasicEvent ObjectGuid _sindragosaGUID; }; -class FrostBeaconSelector +class FrostBeaconSelector : NonTankTargetSelector { public: - FrostBeaconSelector(Unit* source) : _source(source) { } + FrostBeaconSelector(Unit* source) : NonTankTargetSelector(source, true) { } - bool operator()(Unit* target) const + bool operator()(WorldObject* target) const { - return target->GetTypeId() == TYPEID_PLAYER && - target != _source->GetVictim() && - !target->HasAura(SPELL_ICE_TOMB_UNTARGETABLE); - } + if (Unit* unitTarget = target->ToUnit()) + return !NonTankTargetSelector::operator()(unitTarget) || + unitTarget->HasAura(SPELL_ICE_TOMB_UNTARGETABLE); - private: - Unit* _source; + return false; + } }; class boss_sindragosa : public CreatureScript @@ -315,7 +315,7 @@ class boss_sindragosa : public CreatureScript me->SetCanFly(true); me->SetDisableGravity(true); me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); - me->SetSpeed(MOVE_FLIGHT, 4.0f); + me->SetSpeedRate(MOVE_FLIGHT, 4.0f); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); float moveTime = me->GetExactDist(&SindragosaFlyPos) / (me->GetSpeed(MOVE_FLIGHT) * 0.001f); me->m_Events.AddEvent(new FrostwyrmLandEvent(*me, SindragosaLandPos), me->m_Events.CalculateTime(uint64(moveTime) + 250)); @@ -326,9 +326,15 @@ class boss_sindragosa : public CreatureScript uint32 GetData(uint32 type) const override { - if (type == DATA_MYSTIC_BUFFET_STACK) - return _mysticBuffetStack; - return 0xFFFFFFFF; + switch (type) + { + case DATA_MYSTIC_BUFFET_STACK: + return _mysticBuffetStack; + case DATA_IS_THIRD_PHASE: + return _isThirdPhase; + default: + return 0xFFFFFFFF; + } } void MovementInform(uint32 type, uint32 point) override @@ -345,7 +351,7 @@ class boss_sindragosa : public CreatureScript me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); me->SetHomePosition(SindragosaLandPos); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetSpeed(MOVE_FLIGHT, 2.5f); + me->SetSpeedRate(MOVE_FLIGHT, 2.5f); // Sindragosa enters combat as soon as she lands DoZoneInCombat(); @@ -419,7 +425,6 @@ class boss_sindragosa : public CreatureScript if (spellId == spell->Id) if (Aura const* mysticBuffet = target->GetAura(spell->Id)) _mysticBuffetStack = std::max<uint8>(_mysticBuffetStack, mysticBuffet->GetStackAmount()); - } void UpdateAI(uint32 diff) override @@ -494,11 +499,7 @@ class boss_sindragosa : public CreatureScript me->GetMotionMaster()->MovePoint(POINT_AIR_PHASE_FAR, SindragosaAirPosFar); break; case EVENT_ICE_TOMB: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, FrostBeaconSelector(me))) - { - Talk(EMOTE_WARN_FROZEN_ORB, target); - me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, 1, nullptr, TRIGGERED_FULL_MASK); - } + me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, 1, nullptr, TRIGGERED_FULL_MASK); events.ScheduleEvent(EVENT_ICE_TOMB, urand(16000, 23000)); break; case EVENT_FROST_BOMB: @@ -696,7 +697,7 @@ class npc_spinestalker : public CreatureScript return; me->setActive(true); - me->SetSpeed(MOVE_FLIGHT, 2.0f); + me->SetSpeedRate(MOVE_FLIGHT, 2.0f); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); float moveTime = me->GetExactDist(&SpinestalkerFlyPos) / (me->GetSpeed(MOVE_FLIGHT) * 0.001f); me->m_Events.AddEvent(new FrostwyrmLandEvent(*me, SpinestalkerLandPos), me->m_Events.CalculateTime(uint64(moveTime) + 250)); @@ -833,7 +834,7 @@ class npc_rimefang : public CreatureScript return; me->setActive(true); - me->SetSpeed(MOVE_FLIGHT, 2.0f); + me->SetSpeedRate(MOVE_FLIGHT, 2.0f); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); float moveTime = me->GetExactDist(&RimefangFlyPos) / (me->GetSpeed(MOVE_FLIGHT) * 0.001f); me->m_Events.AddEvent(new FrostwyrmLandEvent(*me, RimefangLandPos), me->m_Events.CalculateTime(uint64(moveTime) + 250)); @@ -1576,6 +1577,41 @@ class spell_frostwarden_handler_focus_fire : public SpellScriptLoader } }; +class spell_sindragosa_ice_tomb_target : public SpellScriptLoader +{ +public: + spell_sindragosa_ice_tomb_target() : SpellScriptLoader("spell_sindragosa_ice_tomb_target") { } + + class spell_sindragosa_ice_tomb_target_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sindragosa_ice_tomb_target_SpellScript); + + void FilterTargets(std::list<WorldObject*>& unitList) + { + Unit* caster = GetCaster(); + unitList.remove_if(FrostBeaconSelector(caster)); + } + + void HandleSindragosaTalk(SpellEffIndex /*effIndex*/) + { + if (Creature* creatureCaster = GetCaster()->ToCreature()) + if (creatureCaster->GetAI()->GetData(DATA_IS_THIRD_PHASE)) + creatureCaster->AI()->Talk(EMOTE_WARN_FROZEN_ORB, GetHitUnit()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sindragosa_ice_tomb_target_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectLaunchTarget += SpellEffectFn(spell_sindragosa_ice_tomb_target_SpellScript::HandleSindragosaTalk, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_sindragosa_ice_tomb_target_SpellScript(); + } +}; + class at_sindragosa_lair : public AreaTriggerScript { public: @@ -1641,6 +1677,7 @@ void AddSC_boss_sindragosa() new spell_frostwarden_handler_focus_fire(); new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY, TRIGGERED_IGNORE_SET_FACING); new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb_dummy", SPELL_FROST_BEACON); + new spell_sindragosa_ice_tomb_target(); new at_sindragosa_lair(); new achievement_all_you_can_eat(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 9fa624aaad3..4a0a8217af8 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -437,7 +437,7 @@ class StartMovementEvent : public BasicEvent { } - bool Execute(uint64 /*time*/, uint32 /*diff*/) + bool Execute(uint64 /*time*/, uint32 /*diff*/) override { _owner->SetReactState(REACT_AGGRESSIVE); if (Creature* _summoner = ObjectAccessor::GetCreature(*_owner, _summonerGuid)) @@ -459,7 +459,7 @@ class VileSpiritActivateEvent : public BasicEvent { } - bool Execute(uint64 /*time*/, uint32 /*diff*/) + bool Execute(uint64 /*time*/, uint32 /*diff*/) override { _owner->SetReactState(REACT_AGGRESSIVE); _owner->CastSpell(_owner, SPELL_VILE_SPIRIT_MOVE_SEARCH, true); @@ -479,7 +479,7 @@ class TriggerWickedSpirit : public BasicEvent { } - bool Execute(uint64 /*time*/, uint32 /*diff*/) + bool Execute(uint64 /*time*/, uint32 /*diff*/) override { _owner->CastCustomSpell(SPELL_TRIGGER_VILE_SPIRIT_HEROIC, SPELLVALUE_MAX_TARGETS, 1, NULL, true); @@ -763,7 +763,7 @@ class boss_the_lich_king : public CreatureScript { summons.Summon(summon); summon->SetReactState(REACT_PASSIVE); - summon->SetSpeed(MOVE_FLIGHT, 0.5f); + summon->SetSpeedRate(MOVE_FLIGHT, 0.5f); summon->GetMotionMaster()->MoveRandom(10.0f); if (!events.IsInPhase(PHASE_FROSTMOURNE)) summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(15000)); @@ -1448,7 +1448,7 @@ class npc_valkyr_shadowguard : public CreatureScript _events.Reset(); me->SetReactState(REACT_PASSIVE); DoCast(me, SPELL_WINGS_OF_THE_DAMNED, false); - me->SetSpeed(MOVE_FLIGHT, 0.642857f, true); + me->SetSpeedRate(MOVE_FLIGHT, 0.642857f); } void IsSummonedBy(Unit* /*summoner*/) override diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index 4f35f848927..b07de3457bd 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -179,7 +179,7 @@ class DelayedCastEvent : public BasicEvent { } - bool Execute(uint64 /*time*/, uint32 /*diff*/) + bool Execute(uint64 /*time*/, uint32 /*diff*/) override { _trigger->CastSpell(_trigger, _spellId, false, NULL, NULL, _originalCaster); if (_despawnTime) @@ -201,7 +201,7 @@ class AuraRemoveEvent : public BasicEvent { } - bool Execute(uint64 /*time*/, uint32 /*diff*/) + bool Execute(uint64 /*time*/, uint32 /*diff*/) override { _trigger->RemoveAurasDueToSpell(_spellId); return true; @@ -219,7 +219,7 @@ class ValithriaDespawner : public BasicEvent { } - bool Execute(uint64 /*currTime*/, uint32 /*diff*/) + bool Execute(uint64 /*currTime*/, uint32 /*diff*/) override { Trinity::CreatureWorker<ValithriaDespawner> worker(_creature, *this); _creature->VisitNearbyGridObject(333.0f, worker); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 25ca99f6a20..abb9c025771 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -365,7 +365,7 @@ class CaptainSurviveTalk : public BasicEvent public: explicit CaptainSurviveTalk(Creature const& owner) : _owner(owner) { } - bool Execute(uint64 /*currTime*/, uint32 /*diff*/) + bool Execute(uint64 /*currTime*/, uint32 /*diff*/) override { _owner.AI()->Talk(SAY_CAPTAIN_SURVIVE_TALK); return true; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index e8c4216b00e..60c60640c04 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -162,13 +162,13 @@ public: summons.DoZoneInCombat(); events.SetPhase(PHASE_NORMAL); - events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL); - events.ScheduleEvent(EVENT_SCARABS, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS), 0, PHASE_NORMAL); - events.ScheduleEvent(EVENT_LOCUST, urand(80,120) * IN_MILLISECONDS, 0, PHASE_NORMAL); - events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_IMPALE, randtime(Seconds(10), Seconds(20)), 0, PHASE_NORMAL); + events.ScheduleEvent(EVENT_SCARABS, randtime(Seconds(20), Seconds(30)), 0, PHASE_NORMAL); + events.ScheduleEvent(EVENT_LOCUST, Minutes(1)+randtime(Seconds(40), Seconds(60)), 0, PHASE_NORMAL); + events.ScheduleEvent(EVENT_BERSERK, Minutes(10)); if (!Is25ManRaid()) - events.ScheduleEvent(EVENT_SPAWN_GUARD, urand(15, 20) * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SPAWN_GUARD, randtime(Seconds(15), Seconds(20))); } void UpdateAI(uint32 diff) override @@ -189,11 +189,9 @@ public: else EnterEvadeMode(); - events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL); + events.Repeat(randtime(Seconds(10), Seconds(20))); break; case EVENT_SCARABS: - events.ScheduleEvent(EVENT_SCARABS, urand(40 * IN_MILLISECONDS, 60 * IN_MILLISECONDS), 0, PHASE_NORMAL); - if (!guardCorpses.empty()) { if (ObjectGuid target = Trinity::Containers::SelectRandomContainerElement(guardCorpses)) @@ -204,27 +202,28 @@ public: creatureTarget->DespawnOrUnsummon(); } } + events.Repeat(randtime(Seconds(40), Seconds(60))); break; case EVENT_LOCUST: Talk(EMOTE_LOCUST); + events.SetPhase(PHASE_SWARM); DoCast(me, SPELL_LOCUST_SWARM); - events.ScheduleEvent(EVENT_SPAWN_GUARD, 3 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_LOCUST_ENDS, RAID_MODE(19, 23) * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_LOCUST, 90000); - events.SetPhase(PHASE_SWARM); + events.ScheduleEvent(EVENT_SPAWN_GUARD, Seconds(3)); + events.ScheduleEvent(EVENT_LOCUST_ENDS, RAID_MODE(Seconds(19), Seconds(23))); + events.Repeat(Minutes(1)+Seconds(30)); break; case EVENT_LOCUST_ENDS: - events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL); - events.ScheduleEvent(EVENT_SCARABS, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS), 0, PHASE_NORMAL); events.SetPhase(PHASE_NORMAL); + events.ScheduleEvent(EVENT_IMPALE, randtime(Seconds(10), Seconds(20)), 0, PHASE_NORMAL); + events.ScheduleEvent(EVENT_SCARABS, randtime(Seconds(20), Seconds(30)), 0, PHASE_NORMAL); break; case EVENT_SPAWN_GUARD: me->SummonCreatureGroup(GROUP_SINGLE_SPAWN); break; case EVENT_BERSERK: DoCast(me, SPELL_BERSERK, true); - events.ScheduleEvent(EVENT_BERSERK, 600000); + events.ScheduleEvent(EVENT_BERSERK, Minutes(10)); break; } } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index 39c41c935bf..8a7bdd293ba 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -100,9 +100,9 @@ class boss_faerlina : public CreatureScript _EnterCombat(); Talk(SAY_AGGRO); summons.DoZoneInCombat(); - events.ScheduleEvent(EVENT_POISON, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS)); - events.ScheduleEvent(EVENT_FIRE, urand(6 * IN_MILLISECONDS, 18 * IN_MILLISECONDS)); - events.ScheduleEvent(EVENT_FRENZY, urand(60 * IN_MILLISECONDS, 80 * IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_POISON, randtime(Seconds(10), Seconds(15))); + events.ScheduleEvent(EVENT_FIRE, randtime(Seconds(6), Seconds(18))); + events.ScheduleEvent(EVENT_FRENZY, Minutes(1)+randtime(Seconds(0), Seconds(20))); } void Reset() override @@ -111,9 +111,9 @@ class boss_faerlina : public CreatureScript _frenzyDispels = 0; } - void KilledUnit(Unit* /*victim*/) override + void KilledUnit(Unit* victim) override { - if (!urand(0, 2)) + if (victim->GetTypeId() == TYPEID_PLAYER) Talk(SAY_SLAY); } @@ -158,21 +158,21 @@ class boss_faerlina : public CreatureScript case EVENT_POISON: if (!me->HasAura(SPELL_WIDOWS_EMBRACE_HELPER)) DoCastAOE(SPELL_POISON_BOLT_VOLLEY); - events.ScheduleEvent(EVENT_POISON, urand(8000, 15000)); + events.Repeat(randtime(Seconds(8), Seconds(15))); break; case EVENT_FIRE: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_RAIN_OF_FIRE); - events.ScheduleEvent(EVENT_FIRE, urand(6000, 18000)); + events.Repeat(randtime(Seconds(6), Seconds(18))); break; case EVENT_FRENZY: if (Aura* widowsEmbrace = me->GetAura(SPELL_WIDOWS_EMBRACE_HELPER)) - events.ScheduleEvent(EVENT_FRENZY, widowsEmbrace->GetDuration()+1 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_FRENZY, Milliseconds(widowsEmbrace->GetDuration()+1)); else { DoCast(SPELL_FRENZY); Talk(EMOTE_FRENZY); - events.ScheduleEvent(EVENT_FRENZY, urand(60 * IN_MILLISECONDS, 80 * IN_MILLISECONDS)); + events.Repeat(Minutes(1) + randtime(Seconds(0), Seconds(20))); } break; } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp index a7a89f44d81..0de1c4785b8 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp @@ -285,7 +285,7 @@ struct boss_four_horsemen_baseAI : public BossAI void EnterCombat(Unit* /*who*/) override { - if (instance->GetBossState(BOSS_HORSEMEN) != NOT_STARTED) // another horseman already did it + if (instance->GetBossState(BOSS_HORSEMEN) == IN_PROGRESS || instance->GetBossState(BOSS_HORSEMEN) == DONE) // another horseman already did it return; Talk(SAY_AGGRO); BeginEncounter(); @@ -411,9 +411,9 @@ class boss_four_horsemen_baron : public CreatureScript else AttackStart(threat.getHostilTarget()); - events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_UNHOLYSHADOW, urandms(3,7)); + events.ScheduleEvent(EVENT_BERSERK, Minutes(10)); + events.ScheduleEvent(EVENT_MARK, Seconds(24)); + events.ScheduleEvent(EVENT_UNHOLYSHADOW, randtime(Seconds(3), Seconds(7))); } void _UpdateAI(uint32 diff) override @@ -431,11 +431,11 @@ class boss_four_horsemen_baron : public CreatureScript break; case EVENT_MARK: DoCastAOE(SPELL_BARON_MARK, true); - events.ScheduleEvent(EVENT_MARK, 12 * IN_MILLISECONDS); + events.Repeat(Seconds(12)); break; case EVENT_UNHOLYSHADOW: DoCastVictim(SPELL_UNHOLY_SHADOW); - events.ScheduleEvent(EVENT_UNHOLYSHADOW, urandms(10,30)); + events.Repeat(randtime(Seconds(10), Seconds(30))); break; } } @@ -484,9 +484,9 @@ class boss_four_horsemen_thane : public CreatureScript else AttackStart(threat.getHostilTarget()); - events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_METEOR, urandms(10,15)); + events.ScheduleEvent(EVENT_BERSERK, Minutes(10)); + events.ScheduleEvent(EVENT_MARK, Seconds(24)); + events.ScheduleEvent(EVENT_METEOR, randtime(Seconds(10), Seconds(25))); } void _UpdateAI(uint32 diff) override { @@ -503,7 +503,7 @@ class boss_four_horsemen_thane : public CreatureScript break; case EVENT_MARK: DoCastAOE(SPELL_THANE_MARK, true); - events.ScheduleEvent(EVENT_MARK, 12 * IN_MILLISECONDS); + events.Repeat(Seconds(12)); break; case EVENT_METEOR: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, true)) @@ -511,7 +511,7 @@ class boss_four_horsemen_thane : public CreatureScript DoCast(target, SPELL_METEOR); _shouldSay = true; } - events.ScheduleEvent(EVENT_METEOR, urandms(13,17)); + events.Repeat(randtime(Seconds(13), Seconds(17))); break; } } @@ -550,9 +550,9 @@ class boss_four_horsemen_lady : public CreatureScript boss_four_horsemen_ladyAI(Creature* creature) : boss_four_horsemen_baseAI(creature, LADY, ladyPath) { } void BeginFighting() override { - events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_VOIDZONE, urandms(5,10)); + events.ScheduleEvent(EVENT_BERSERK, Minutes(10)); + events.ScheduleEvent(EVENT_MARK, Seconds(24)); + events.ScheduleEvent(EVENT_VOIDZONE, randtime(Seconds(5), Seconds(10))); } void _UpdateAI(uint32 diff) override @@ -578,7 +578,7 @@ class boss_four_horsemen_lady : public CreatureScript break; case EVENT_MARK: DoCastAOE(SPELL_LADY_MARK, true); - events.ScheduleEvent(EVENT_MARK, 15 * IN_MILLISECONDS); + events.Repeat(Seconds(15)); break; case EVENT_VOIDZONE: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true)) @@ -586,7 +586,7 @@ class boss_four_horsemen_lady : public CreatureScript DoCast(target, SPELL_VOID_ZONE, true); Talk(SAY_SPECIAL); } - events.ScheduleEvent(EVENT_VOIDZONE, urandms(12, 18)); + events.Repeat(randtime(Seconds(12), Seconds(18))); break; } } @@ -620,9 +620,9 @@ class boss_four_horsemen_sir : public CreatureScript boss_four_horsemen_sirAI(Creature* creature) : boss_four_horsemen_baseAI(creature, SIR, sirPath), _shouldSay(true) { } void BeginFighting() override { - events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_HOLYWRATH, urandms(13,18)); + events.ScheduleEvent(EVENT_BERSERK, Minutes(10)); + events.ScheduleEvent(EVENT_MARK, Seconds(24)); + events.ScheduleEvent(EVENT_HOLYWRATH, randtime(Seconds(13), Seconds(18))); } void _UpdateAI(uint32 diff) override @@ -648,7 +648,7 @@ class boss_four_horsemen_sir : public CreatureScript break; case EVENT_MARK: DoCastAOE(SPELL_SIR_MARK, true); - events.ScheduleEvent(EVENT_MARK, 15 * IN_MILLISECONDS); + events.Repeat(Seconds(15)); break; case EVENT_HOLYWRATH: if (Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 45.0f, true)) @@ -656,7 +656,7 @@ class boss_four_horsemen_sir : public CreatureScript DoCast(target, SPELL_HOLY_WRATH, true); _shouldSay = true; } - events.ScheduleEvent(EVENT_HOLYWRATH, urandms(10,18)); + events.Repeat(randtime(Seconds(10), Seconds(18))); break; } } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp index be12894ebea..30c05c9dca9 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp @@ -65,7 +65,7 @@ enum Spells /* gothik phase two spells */ SPELL_HARVEST_SOUL = 28679, SPELL_SHADOW_BOLT = 29317, - + /* visual spells */ SPELL_ANCHOR_1_TRAINEE = 27892, SPELL_ANCHOR_1_DK = 27928, @@ -324,13 +324,13 @@ class boss_gothik : public CreatureScript { _EnterCombat(); events.SetPhase(PHASE_ONE); - events.ScheduleEvent(EVENT_SUMMON, 25 * IN_MILLISECONDS, 0, PHASE_ONE); - events.ScheduleEvent(EVENT_DOORS_UNLOCK, 205 * IN_MILLISECONDS, 0, PHASE_ONE); - events.ScheduleEvent(EVENT_PHASE_TWO, 270 * IN_MILLISECONDS, 0, PHASE_ONE); + events.ScheduleEvent(EVENT_SUMMON, Seconds(25), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_DOORS_UNLOCK, Minutes(3) + Seconds(25), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_PHASE_TWO, Minutes(4) + Seconds(30), 0, PHASE_ONE); Talk(SAY_INTRO_1); - events.ScheduleEvent(EVENT_INTRO_2, 4 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_INTRO_3, 9 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_INTRO_4, 14 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_INTRO_2, Seconds(4)); + events.ScheduleEvent(EVENT_INTRO_3, Seconds(9)); + events.ScheduleEvent(EVENT_INTRO_4, Seconds(14)); instance->SetData(DATA_GOTHIK_GATE, GO_STATE_READY); _gateIsOpen = false; } @@ -373,7 +373,7 @@ class boss_gothik : public CreatureScript instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE); Talk(EMOTE_GATE_OPENED); _gateIsOpen = true; - + for (ObjectGuid summonGuid : summons) { if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid)) @@ -444,7 +444,7 @@ class boss_gothik : public CreatureScript TC_LOG_INFO("scripts", "GothikAI: Wave count %d is out of range for difficulty %d.", _waveCount, GetDifficulty()); break; } - + std::list<Creature*> triggers; me->GetCreatureListWithEntryInGrid(triggers, NPC_TRIGGER, 150.0f); for (GothikWaveEntry entry : RAID_MODE(waves10, waves25)[_waveCount].first) @@ -470,7 +470,7 @@ class boss_gothik : public CreatureScript default: targetDBGuid = 0; } - + for (Creature* trigger : triggers) if (trigger && trigger->GetSpawnId() == targetDBGuid) { @@ -480,7 +480,7 @@ class boss_gothik : public CreatureScript } if (uint8 timeToNext = RAID_MODE(waves10, waves25)[_waveCount].second) - events.ScheduleEvent(EVENT_SUMMON, timeToNext * IN_MILLISECONDS, 0, PHASE_ONE); + events.Repeat(Seconds(timeToNext)); ++_waveCount; break; @@ -497,9 +497,9 @@ class boss_gothik : public CreatureScript break; case EVENT_PHASE_TWO: events.SetPhase(PHASE_TWO); - events.ScheduleEvent(EVENT_TELEPORT, 20 * IN_MILLISECONDS, 0, PHASE_TWO); - events.ScheduleEvent(EVENT_HARVEST, 15 * IN_MILLISECONDS, 0, PHASE_TWO); - events.ScheduleEvent(EVENT_RESUME_ATTACK, 2 * IN_MILLISECONDS, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_TELEPORT, Seconds(20), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_HARVEST, Seconds(15), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_RESUME_ATTACK, Seconds(2), 0, PHASE_TWO); Talk(SAY_PHASE_TWO); Talk(EMOTE_PHASE_TWO); me->SetReactState(REACT_PASSIVE); @@ -518,23 +518,23 @@ class boss_gothik : public CreatureScript _lastTeleportDead = !_lastTeleportDead; events.CancelEvent(EVENT_BOLT); - events.ScheduleEvent(EVENT_TELEPORT, 20 * IN_MILLISECONDS, 0, PHASE_TWO); events.ScheduleEvent(EVENT_RESUME_ATTACK, 2 * IN_MILLISECONDS, 0, PHASE_TWO); + events.Repeat(Seconds(20)); } break; case EVENT_HARVEST: DoCastAOE(SPELL_HARVEST_SOUL, true); // triggered allows this to go "through" shadow bolt - events.ScheduleEvent(EVENT_HARVEST, 15 * IN_MILLISECONDS, 0, PHASE_TWO); + events.Repeat(Seconds(15)); break; case EVENT_RESUME_ATTACK: me->SetReactState(REACT_AGGRESSIVE); - events.ScheduleEvent(EVENT_BOLT, 0, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_BOLT, Seconds(0), 0, PHASE_TWO); // return to the start of this method so victim side etc is re-evaluated return UpdateAI(0u); // tail recursion for efficiency case EVENT_BOLT: DoCastVictim(SPELL_SHADOW_BOLT); - events.ScheduleEvent(EVENT_BOLT, 1 * IN_MILLISECONDS, 0, PHASE_TWO); + events.Repeat(Seconds(2)); break; case EVENT_INTRO_2: Talk(SAY_INTRO_2); @@ -548,7 +548,7 @@ class boss_gothik : public CreatureScript } } } - + private: uint32 _waveCount; bool _gateCanOpen; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp index a1d8f6e5e02..cf38d659d40 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp @@ -57,10 +57,10 @@ class boss_grobbulus : public CreatureScript void EnterCombat(Unit* /*who*/) override { _EnterCombat(); - events.ScheduleEvent(EVENT_CLOUD, 15000); - events.ScheduleEvent(EVENT_INJECT, 20000); - events.ScheduleEvent(EVENT_SPRAY, urand(15000, 30000)); // not sure - events.ScheduleEvent(EVENT_BERSERK, 12 * 60000); + events.ScheduleEvent(EVENT_CLOUD, Seconds(15)); + events.ScheduleEvent(EVENT_INJECT, Seconds(20)); + events.ScheduleEvent(EVENT_SPRAY, randtime(Seconds(15), Seconds(30))); // not sure + events.ScheduleEvent(EVENT_BERSERK, Minutes(12)); } void SpellHitTarget(Unit* target, SpellInfo const* spell) override @@ -82,19 +82,19 @@ class boss_grobbulus : public CreatureScript { case EVENT_CLOUD: DoCastAOE(SPELL_POISON_CLOUD); - events.ScheduleEvent(EVENT_CLOUD, 15000); + events.Repeat(Seconds(15)); return; case EVENT_BERSERK: DoCastAOE(SPELL_BERSERK, true); return; case EVENT_SPRAY: DoCastAOE(SPELL_SLIME_SPRAY); - events.ScheduleEvent(EVENT_SPRAY, urand(15000, 30000)); + events.Repeat(randtime(Seconds(15), Seconds(30))); return; case EVENT_INJECT: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_MUTATING_INJECTION)) DoCast(target, SPELL_MUTATING_INJECTION); - events.ScheduleEvent(EVENT_INJECT, 8000 + uint32(120 * me->GetHealthPct())); + events.Repeat(Seconds(8) + Milliseconds(uint32(std::round(120 * me->GetHealthPct())))); return; default: break; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp index 9b9619fe5b9..41d718d188d 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp @@ -27,6 +27,7 @@ enum Spells SPELL_SPELL_DISRUPTION = 29310, SPELL_PLAGUE_CLOUD = 29350, SPELL_TELEPORT_SELF = 30211, + SPELL_ERUPTION = 29371 }; enum Yells @@ -60,6 +61,15 @@ enum Misc DATA_SAFETY_DANCE = 19962139 }; +static const uint32 firstEruptionDBGUID = 84980; +static const uint8 numSections = 4; +static const uint8 numEruptions[numSections] = { // count of sequential GO DBGUIDs in the respective section of the room + 15, + 25, + 23, + 13 +}; + class boss_heigan : public CreatureScript { public: @@ -72,7 +82,7 @@ public: struct boss_heiganAI : public BossAI { - boss_heiganAI(Creature* creature) : BossAI(creature, BOSS_HEIGAN), eruptSection(0), eruptDirection(false), safetyDance(false) { } + boss_heiganAI(Creature* creature) : BossAI(creature, BOSS_HEIGAN), _safeSection(0), _danceDirection(false), _safetyDance(false) { } void Reset() override { @@ -82,15 +92,16 @@ public: void KilledUnit(Unit* who) override { - Talk(SAY_SLAY); - if (who->GetTypeId() == TYPEID_PLAYER) - safetyDance = false; + { + Talk(SAY_SLAY); + _safetyDance = false; + } } uint32 GetData(uint32 type) const override { - return (type == DATA_SAFETY_DANCE && safetyDance) ? 1u : 0u; + return (type == DATA_SAFETY_DANCE && _safetyDance) ? 1u : 0u; } void JustDied(Unit* /*killer*/) override @@ -104,13 +115,27 @@ public: _EnterCombat(); Talk(SAY_AGGRO); - eruptSection = 3; - events.ScheduleEvent(EVENT_DISRUPT, urand(15 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_FIGHT); - events.ScheduleEvent(EVENT_FEVER, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_FIGHT); - events.ScheduleEvent(EVENT_DANCE, 90 * IN_MILLISECONDS, 0, PHASE_FIGHT); - events.ScheduleEvent(EVENT_ERUPT, 15 * IN_MILLISECONDS, 0, PHASE_FIGHT); + _safeSection = 0; + events.ScheduleEvent(EVENT_DISRUPT, randtime(Seconds(15), Seconds(20)), 0, PHASE_FIGHT); + events.ScheduleEvent(EVENT_FEVER, randtime(Seconds(10), Seconds(20)), 0, PHASE_FIGHT); + events.ScheduleEvent(EVENT_DANCE, Minutes(1) + Seconds(30), 0, PHASE_FIGHT); + events.ScheduleEvent(EVENT_ERUPT, Seconds(15), 0, PHASE_FIGHT); + + _safetyDance = true; - safetyDance = true; + // figure out the current GUIDs of our eruption tiles and which segment they belong in + std::unordered_multimap<uint32, GameObject*> const& mapGOs = me->GetMap()->GetGameObjectBySpawnIdStore(); + uint32 spawnId = firstEruptionDBGUID; + for (uint8 section = 0; section < numSections; ++section) + { + _eruptTiles[section].clear(); + for (uint8 i = 0; i < numEruptions[section]; ++i) + { + std::pair<std::unordered_multimap<uint32, GameObject*>::const_iterator, std::unordered_multimap<uint32, GameObject*>::const_iterator> tileIt = mapGOs.equal_range(spawnId++); + for (std::unordered_multimap<uint32, GameObject*>::const_iterator it = tileIt.first; it != tileIt.second; ++it) + _eruptTiles[section].push_back(it->second->GetGUID()); + } + } } void UpdateAI(uint32 diff) override @@ -126,52 +151,56 @@ public: { case EVENT_DISRUPT: DoCastAOE(SPELL_SPELL_DISRUPTION); - events.ScheduleEvent(EVENT_DISRUPT, 11 * IN_MILLISECONDS); + events.Repeat(Seconds(11)); break; case EVENT_FEVER: DoCastAOE(SPELL_DECREPIT_FEVER); - events.ScheduleEvent(EVENT_FEVER, urand(20 * IN_MILLISECONDS, 25 * IN_MILLISECONDS)); + events.Repeat(randtime(Seconds(20), Seconds(25))); break; case EVENT_DANCE: events.SetPhase(PHASE_DANCE); Talk(SAY_TAUNT); Talk(EMOTE_DANCE); - eruptSection = 3; + _safeSection = 0; me->SetReactState(REACT_PASSIVE); me->AttackStop(); me->StopMoving(); DoCast(SPELL_TELEPORT_SELF); DoCastAOE(SPELL_PLAGUE_CLOUD); - events.ScheduleEvent(EVENT_DANCE_END, 45 * IN_MILLISECONDS, 0, PHASE_DANCE); - events.ScheduleEvent(EVENT_ERUPT, 10 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_DANCE_END, Seconds(45), 0, PHASE_DANCE); + events.ScheduleEvent(EVENT_ERUPT, Seconds(10)); break; case EVENT_DANCE_END: events.SetPhase(PHASE_FIGHT); Talk(EMOTE_DANCE_END); - eruptSection = 3; - events.ScheduleEvent(EVENT_DISRUPT, urand(10, 25) * IN_MILLISECONDS, 0, PHASE_FIGHT); - events.ScheduleEvent(EVENT_FEVER, urand(15, 20) * IN_MILLISECONDS, 0, PHASE_FIGHT); - events.ScheduleEvent(EVENT_DANCE, 90 * IN_MILLISECONDS, 0, PHASE_FIGHT); - events.ScheduleEvent(EVENT_ERUPT, 15 * IN_MILLISECONDS, 0, PHASE_FIGHT); + _safeSection = 0; + events.ScheduleEvent(EVENT_DISRUPT, randtime(Seconds(10), Seconds(25)), 0, PHASE_FIGHT); + events.ScheduleEvent(EVENT_FEVER, randtime(Seconds(15), Seconds(20)), 0, PHASE_FIGHT); + events.ScheduleEvent(EVENT_DANCE, Minutes(1) + Seconds(30), 0, PHASE_FIGHT); + events.ScheduleEvent(EVENT_ERUPT, Seconds(15), 0, PHASE_FIGHT); me->CastStop(); me->SetReactState(REACT_AGGRESSIVE); DoZoneInCombat(); break; case EVENT_ERUPT: - instance->SetData(DATA_HEIGAN_ERUPT, eruptSection); TeleportCheaters(); - - if (eruptSection == 0) - eruptDirection = true; - else if (eruptSection == 3) - eruptDirection = false; - - eruptDirection ? ++eruptSection : --eruptSection; - - if (events.IsInPhase(PHASE_DANCE)) - events.ScheduleEvent(EVENT_ERUPT, 3 * IN_MILLISECONDS, 0, PHASE_DANCE); - else - events.ScheduleEvent(EVENT_ERUPT, 10 * IN_MILLISECONDS, 0, PHASE_FIGHT); + for (uint8 section = 0; section < numSections; ++section) + if (section != _safeSection) + for (ObjectGuid tileGUID : _eruptTiles[section]) + if (GameObject* tile = ObjectAccessor::GetGameObject(*me, tileGUID)) + { + tile->SendCustomAnim(0); + tile->CastSpell(nullptr, SPELL_ERUPTION); + } + + if (_safeSection == 0) + _danceDirection = true; + else if (_safeSection == numSections-1) + _danceDirection = false; + + _danceDirection ? ++_safeSection : --_safeSection; + + events.Repeat(events.IsInPhase(PHASE_DANCE) ? Seconds(3) : Seconds(10)); break; } } @@ -180,10 +209,11 @@ public: } private: - uint32 eruptSection; - bool eruptDirection; + std::vector<ObjectGuid> _eruptTiles[numSections]; // populated on encounter start - bool safetyDance; // is achievement still possible? (= no player deaths yet) + uint32 _safeSection; // 0 is next to the entrance + bool _danceDirection; // true is counter-clockwise, false is clock-wise + bool _safetyDance; // is achievement still possible? (= no player deaths yet) }; }; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp index 086d21120e8..c6c9c76bed4 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp @@ -24,7 +24,6 @@ enum Spells { SPELL_NECROTIC_AURA = 55593, - SPELL_WARN_NECROTIC_AURA = 59481, SPELL_SUMMON_SPORE = 29234, SPELL_DEATHBLOOM = 29865, SPELL_INEVITABLE_DOOM = 29204, @@ -42,11 +41,12 @@ enum Texts enum Events { - EVENT_NECROTIC_AURA = 1, - EVENT_DEATHBLOOM = 2, - EVENT_INEVITABLE_DOOM = 3, - EVENT_SPORE = 4, - EVENT_NECROTIC_AURA_FADING = 5, + EVENT_NECROTIC_AURA = 1, + EVENT_DEATHBLOOM, + EVENT_INEVITABLE_DOOM, + EVENT_SPORE, + EVENT_NECROTIC_AURA_FADING, + EVENT_NECROTIC_AURA_FADED }; enum Achievement @@ -82,10 +82,10 @@ class boss_loatheb : public CreatureScript void EnterCombat(Unit* /*who*/) override { _EnterCombat(); - events.ScheduleEvent(EVENT_NECROTIC_AURA, 17 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_DEATHBLOOM, 5 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_SPORE, RAID_MODE(36,18) * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 2 * MINUTE * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_NECROTIC_AURA, Seconds(17)); + events.ScheduleEvent(EVENT_DEATHBLOOM, Seconds(5)); + events.ScheduleEvent(EVENT_SPORE, Seconds(18)); + events.ScheduleEvent(EVENT_INEVITABLE_DOOM, Minutes(2)); } void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override @@ -94,13 +94,6 @@ class boss_loatheb : public CreatureScript summon->CastSpell(summon,SPELL_FUNGAL_CREEP,true); } - void SummonedCreatureDespawn(Creature* summon) override - { - summons.Despawn(summon); - if (summon->IsAlive()) - summon->CastSpell(summon,SPELL_FUNGAL_CREEP,true); - } - uint32 GetData(uint32 id) const override { return (_sporeLoserData && id == DATA_ACHIEVEMENT_SPORE_LOSER) ? 1u : 0u; @@ -119,34 +112,33 @@ class boss_loatheb : public CreatureScript { case EVENT_NECROTIC_AURA: DoCastAOE(SPELL_NECROTIC_AURA); - DoCast(me, SPELL_WARN_NECROTIC_AURA); - events.ScheduleEvent(EVENT_NECROTIC_AURA, 20 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, 14 * IN_MILLISECONDS); + Talk(SAY_NECROTIC_AURA_APPLIED); + events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, Seconds(14)); + events.ScheduleEvent(EVENT_NECROTIC_AURA_FADED, Seconds(17)); + events.Repeat(Seconds(20)); break; case EVENT_DEATHBLOOM: DoCastAOE(SPELL_DEATHBLOOM); - events.ScheduleEvent(EVENT_DEATHBLOOM, 30 * IN_MILLISECONDS); + events.Repeat(Seconds(30)); break; case EVENT_INEVITABLE_DOOM: _doomCounter++; DoCastAOE(SPELL_INEVITABLE_DOOM); if (_doomCounter > 6) - { - if (_doomCounter & 1) // odd - events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 14 * IN_MILLISECONDS); - else - events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 17 * IN_MILLISECONDS); - } + events.Repeat((_doomCounter & 1) ? Seconds(14) : Seconds(17)); else - events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 30 * IN_MILLISECONDS); + events.Repeat(30); break; case EVENT_SPORE: DoCast(me, SPELL_SUMMON_SPORE, false); - events.ScheduleEvent(EVENT_SPORE, RAID_MODE(36,18) * IN_MILLISECONDS); + events.Repeat(RAID_MODE(Seconds(36), Seconds(15))); break; case EVENT_NECROTIC_AURA_FADING: Talk(SAY_NECROTIC_AURA_FADING); break; + case EVENT_NECROTIC_AURA_FADED: + Talk(SAY_NECROTIC_AURA_REMOVED); + break; default: break; } @@ -177,49 +169,6 @@ class achievement_spore_loser : public AchievementCriteriaScript } }; -typedef boss_loatheb::boss_loathebAI LoathebAI; - -class spell_loatheb_necrotic_aura_warning : public SpellScriptLoader -{ - public: - spell_loatheb_necrotic_aura_warning() : SpellScriptLoader("spell_loatheb_necrotic_aura_warning") { } - - class spell_loatheb_necrotic_aura_warning_AuraScript : public AuraScript - { - PrepareAuraScript(spell_loatheb_necrotic_aura_warning_AuraScript); - - bool Validate(SpellInfo const* /*spell*/) override - { - if (!sSpellStore.LookupEntry(SPELL_WARN_NECROTIC_AURA)) - return false; - return true; - } - - void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (GetTarget()->IsAIEnabled) - ENSURE_AI(LoathebAI, GetTarget()->GetAI())->Talk(SAY_NECROTIC_AURA_APPLIED); - } - - void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (GetTarget()->IsAIEnabled) - ENSURE_AI(LoathebAI, GetTarget()->GetAI())->Talk(SAY_NECROTIC_AURA_REMOVED); - } - - void Register() override - { - AfterEffectApply += AuraEffectApplyFn(spell_loatheb_necrotic_aura_warning_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_loatheb_necrotic_aura_warning_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_loatheb_necrotic_aura_warning_AuraScript(); - } -}; - class spell_loatheb_deathbloom : public SpellScriptLoader { public: @@ -260,6 +209,5 @@ void AddSC_boss_loatheb() { new boss_loatheb(); new achievement_spore_loser(); - new spell_loatheb_necrotic_aura_warning(); new spell_loatheb_deathbloom(); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp index 9d8f1365afb..9502193884a 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp @@ -73,6 +73,8 @@ struct WebTargetSelector : public std::unary_function<Unit*, bool> WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {} bool operator()(Unit const* target) const { + if (target->GetTypeId() != TYPEID_PLAYER) // never web nonplayers (pets, guardians, etc.) + return false; if (_maexxna->GetVictim() == target) // never target tank return false; if (target->HasAura(SPELL_WEB_WRAP)) // never target targets that are already webbed @@ -101,11 +103,11 @@ public: void EnterCombat(Unit* /*who*/) override { _EnterCombat(); - events.ScheduleEvent(EVENT_WRAP, 20 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_SPRAY, 40 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_SHOCK, urandms(5, 10)); - events.ScheduleEvent(EVENT_POISON, urandms(10, 15)); - events.ScheduleEvent(EVENT_SUMMON, 30 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_WRAP, Seconds(20)); + events.ScheduleEvent(EVENT_SPRAY, Seconds(40)); + events.ScheduleEvent(EVENT_SHOCK, randtime(Seconds(5), Seconds(10))); + events.ScheduleEvent(EVENT_POISON, randtime(Seconds(10), Seconds(15))); + events.ScheduleEvent(EVENT_SUMMON, Seconds(30)); } void Reset() override @@ -153,28 +155,28 @@ public: } } } - events.ScheduleEvent(EVENT_WRAP, 40000); + events.Repeat(Seconds(40)); break; } case EVENT_SPRAY: Talk(EMOTE_WEB_SPRAY); DoCastAOE(SPELL_WEB_SPRAY); - events.ScheduleEvent(EVENT_SPRAY, 40000); + events.Repeat(Seconds(40)); break; case EVENT_SHOCK: DoCastAOE(SPELL_POISON_SHOCK); - events.ScheduleEvent(EVENT_SHOCK, urandms(10, 20)); + events.Repeat(randtime(Seconds(10), Seconds(20))); break; case EVENT_POISON: DoCastVictim(SPELL_NECROTIC_POISON); - events.ScheduleEvent(EVENT_POISON, urandms(10, 20)); + events.Repeat(randtime(Seconds(10), Seconds(20))); break; case EVENT_SUMMON: Talk(EMOTE_SPIDERS); uint8 amount = urand(8, 10); for (uint8 i = 0; i < amount; ++i) DoSummon(NPC_SPIDERLING, me, 4.0f, 5 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN); - events.ScheduleEvent(EVENT_SUMMON, 40000); + events.Repeat(Seconds(40)); break; } } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp index 8ee3936dee3..2108b4ce102 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp @@ -131,25 +131,25 @@ public: Reset(); else { - uint8 secondsGround; + uint8 timeGround; switch (balconyCount) { case 0: - secondsGround = 90; + timeGround = 90; break; case 1: - secondsGround = 110; + timeGround = 110; break; case 2: default: - secondsGround = 180; + timeGround = 180; } - events.ScheduleEvent(EVENT_GROUND_ATTACKABLE, 2 * IN_MILLISECONDS, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_BALCONY, secondsGround * IN_MILLISECONDS, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_CURSE, urand(10,25) * IN_MILLISECONDS, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_WARRIOR, urand(20,30) * IN_MILLISECONDS, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_GROUND_ATTACKABLE, Seconds(2), 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_BALCONY, Seconds(timeGround), 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_CURSE, randtime(Seconds(10), Seconds(25)), 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_WARRIOR, randtime(Seconds(20), Seconds(30)), 0, PHASE_GROUND); if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) - events.ScheduleEvent(EVENT_BLINK, urand(20,30) * IN_MILLISECONDS, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_BLINK, randtime(Seconds(20), Seconds(30)), 0, PHASE_GROUND); } } @@ -220,7 +220,7 @@ public: case EVENT_CURSE: { DoCastAOE(SPELL_CURSE); - events.ScheduleEvent(EVENT_CURSE, urand(50, 70) * IN_MILLISECONDS, 0, PHASE_GROUND); + events.Repeat(randtime(Seconds(50), Seconds(70))); break; } case EVENT_WARRIOR: @@ -229,7 +229,7 @@ public: CastSummon(RAID_MODE(2, 3), 0, 0); - events.ScheduleEvent(EVENT_WARRIOR, 40 * IN_MILLISECONDS, 0, PHASE_GROUND); + events.Repeat(Seconds(40)); break; case EVENT_BLINK: DoCastAOE(SPELL_CRIPPLE, true); @@ -237,7 +237,7 @@ public: DoResetThreat(); justBlinked = true; - events.ScheduleEvent(EVENT_BLINK, 40000, 0, PHASE_GROUND); + events.Repeat(Seconds(40)); break; case EVENT_BALCONY: events.SetPhase(PHASE_BALCONY); @@ -247,24 +247,24 @@ public: me->StopMoving(); me->RemoveAllAuras(); - events.ScheduleEvent(EVENT_BALCONY_TELEPORT, 3 * IN_MILLISECONDS, 0, PHASE_BALCONY); - events.ScheduleEvent(EVENT_WAVE, urand(5 * IN_MILLISECONDS, 8 * IN_MILLISECONDS), 0, PHASE_BALCONY); + events.ScheduleEvent(EVENT_BALCONY_TELEPORT, Seconds(3), 0, PHASE_BALCONY); + events.ScheduleEvent(EVENT_WAVE, randtime(Seconds(5), Seconds(8)), 0, PHASE_BALCONY); - uint8 secondsBalcony; + uint8 timeBalcony; switch (balconyCount) { case 0: - secondsBalcony = 70; + timeBalcony = 70; break; case 1: - secondsBalcony = 97; + timeBalcony = 97; break; case 2: default: - secondsBalcony = 120; + timeBalcony = 120; break; } - events.ScheduleEvent(EVENT_GROUND, secondsBalcony * IN_MILLISECONDS, 0, PHASE_BALCONY); + events.ScheduleEvent(EVENT_GROUND, Seconds(timeBalcony), 0, PHASE_BALCONY); break; case EVENT_BALCONY_TELEPORT: Talk(EMOTE_TELEPORT_1); @@ -287,7 +287,7 @@ public: CastSummon(0, RAID_MODE(5, 10), RAID_MODE(5, 10)); break; } - events.ScheduleEvent(EVENT_WAVE, urand(30, 45) * IN_MILLISECONDS, 0, PHASE_BALCONY); + events.Repeat(randtime(Seconds(30), Seconds(45))); break; case EVENT_GROUND: ++balconyCount; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp index b8ce402a939..cfa6e2e9f30 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp @@ -97,8 +97,8 @@ public: _EnterCombat(); Enraged = false; Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_HATEFUL, 1 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_BERSERK, 6 * MINUTE * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_HATEFUL, Seconds(1)); + events.ScheduleEvent(EVENT_BERSERK, Minutes(6)); instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT); } @@ -167,17 +167,17 @@ public: if (thirdThreatTarget) me->getThreatManager().addThreat(thirdThreatTarget, HATEFUL_THREAT_AMT); // this will only ever be used in 25m - events.ScheduleEvent(EVENT_HATEFUL, 1 * IN_MILLISECONDS); + events.Repeat(Seconds(1)); break; } case EVENT_BERSERK: DoCast(me, SPELL_BERSERK, true); Talk(EMOTE_BERSERK); - events.ScheduleEvent(EVENT_SLIME, 2 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SLIME, Seconds(2)); break; case EVENT_SLIME: - DoCastVictim(SPELL_SLIME_BOLT, true); - events.ScheduleEvent(EVENT_SLIME, 2 * IN_MILLISECONDS); + DoCastAOE(SPELL_SLIME_BOLT, true); + events.Repeat(Seconds(2)); break; } } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp index 1d12f64a949..548f8086eb8 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp @@ -104,6 +104,9 @@ public: void JustDied(Unit* /*killer*/) override { + for (ObjectGuid summonGuid : summons) + if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid)) + summon->RemoveCharmAuras(); Talk(SAY_DEATH); DoCastAOE(SPELL_HOPELESS, true); @@ -117,10 +120,10 @@ public: me->StopMoving(); summons.DoZoneInCombat(); Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_ATTACK, 7 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_STRIKE, 21 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_KNIFE, 10 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_ATTACK, Seconds(7)); + events.ScheduleEvent(EVENT_STRIKE, Seconds(21)); + events.ScheduleEvent(EVENT_SHOUT, Seconds(16)); + events.ScheduleEvent(EVENT_KNIFE, Seconds(10)); } void UpdateAI(uint32 diff) override @@ -141,16 +144,16 @@ public: break; case EVENT_STRIKE: DoCastVictim(SPELL_UNBALANCING_STRIKE); - events.ScheduleEvent(EVENT_STRIKE, 6 * IN_MILLISECONDS); + events.Repeat(Seconds(6)); return; case EVENT_SHOUT: DoCastAOE(SPELL_DISRUPTING_SHOUT); - events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS); + events.Repeat(Seconds(16)); return; case EVENT_KNIFE: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f)) DoCast(target, SPELL_JAGGED_KNIFE); - events.ScheduleEvent(EVENT_KNIFE, urandms(10,15)); + events.Repeat(randtime(Seconds(10), Seconds(15))); return; } } @@ -174,7 +177,10 @@ class npc_dk_understudy : public CreatureScript struct npc_dk_understudyAI : public ScriptedAI { - npc_dk_understudyAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), bloodStrikeTimer(0) { } + npc_dk_understudyAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), bloodStrikeTimer(0) + { + creature->LoadEquipment(1); + } void EnterCombat(Unit* /*who*/) override { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp index 68b9e252150..4596b17bc23 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp @@ -16,7 +16,9 @@ */ #include "ScriptMgr.h" +#include "GameObjectAI.h" #include "ScriptedCreature.h" +#include "SpellScript.h" #include "Player.h" #include "SpellInfo.h" #include "naxxramas.h" @@ -31,25 +33,24 @@ enum Yells enum Spells { - SPELL_FROST_AURA = 28531, - SPELL_CLEAVE = 19983, - SPELL_TAIL_SWEEP = 55697, - SPELL_SUMMON_BLIZZARD = 28560, - SPELL_LIFE_DRAIN = 28542, - SPELL_ICEBOLT = 28522, - SPELL_FROST_BREATH = 29318, - SPELL_FROST_EXPLOSION = 28524, - SPELL_FROST_MISSILE = 30101, - SPELL_BERSERK = 26662, - SPELL_DIES = 29357, - SPELL_CHILL = 28547, - SPELL_CHECK_RESISTS = 60539, + SPELL_FROST_AURA = 28531, + SPELL_CLEAVE = 19983, + SPELL_TAIL_SWEEP = 55697, + SPELL_SUMMON_BLIZZARD = 28560, + SPELL_LIFE_DRAIN = 28542, + SPELL_ICEBOLT = 28522, + SPELL_FROST_BREATH_ANTICHEAT = 29318, // damage effect ignoring LoS on the entrance platform to prevent cheese + SPELL_FROST_BREATH = 28524, // damage effect below sapphiron + SPELL_FROST_MISSILE = 30101, // visual only + SPELL_BERSERK = 26662, + SPELL_DIES = 29357, + SPELL_CHECK_RESISTS = 60539, + SPELL_SAPPHIRON_WING_BUFFET = 29328 }; enum Phases { - PHASE_NULL = 0, - PHASE_BIRTH, + PHASE_BIRTH = 1, PHASE_GROUND, PHASE_FLIGHT }; @@ -72,9 +73,15 @@ enum Events EVENT_CHECK_RESISTS }; +enum Actions +{ + ACTION_BIRTH = 1 +}; + enum Misc { NPC_BLIZZARD = 16474, + NPC_WING_BUFFET = 17025, GO_ICEBLOCK = 181247, // The Hundred Club @@ -92,77 +99,74 @@ class boss_sapphiron : public CreatureScript struct boss_sapphironAI : public BossAI { boss_sapphironAI(Creature* creature) : - BossAI(creature, BOSS_SAPPHIRON), _iceboltCount(0), _map(me->GetMap()) + BossAI(creature, BOSS_SAPPHIRON) { Initialize(); } void Initialize() { - _phase = PHASE_NULL; - + _delayedDrain = false; _canTheHundredClub = true; } void InitializeAI() override { + if (instance->GetBossState(BOSS_SAPPHIRON) == DONE) + return; + _canTheHundredClub = true; - float x, y, z; - me->GetPosition(x, y, z); - me->SummonGameObject(GO_BIRTH, x, y, z, 0, 0, 0, 0, 0, 0); - me->SetVisible(false); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_PASSIVE); + if (!instance->GetData(DATA_HAD_SAPPHIRON_BIRTH)) + { + me->SetVisible(false); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_PASSIVE); + } BossAI::InitializeAI(); } void Reset() override { - _Reset(); - - if (_phase == PHASE_FLIGHT) + if (events.IsInPhase(PHASE_FLIGHT)) { - ClearIceBlock(); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_ICEBOLT); me->SetReactState(REACT_AGGRESSIVE); if (me->IsHovering()) { me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); me->SetHover(false); } - me->SetDisableGravity(false); } + _Reset(); Initialize(); } + void DamageTaken(Unit* /*who*/, uint32& damage) override + { + if (damage < me->GetHealth() || !events.IsInPhase(PHASE_FLIGHT)) + return; + damage = me->GetHealth()-1; // don't die during air phase + } + void EnterCombat(Unit* /*who*/) override { _EnterCombat(); me->CastSpell(me, SPELL_FROST_AURA, true); - DoCast(me, SPELL_CHECK_RESISTS); - events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_BERSERK, 15 * MINUTE * IN_MILLISECONDS); - EnterPhaseGround(); + events.SetPhase(PHASE_GROUND); + events.ScheduleEvent(EVENT_CHECK_RESISTS, Seconds(0)); + events.ScheduleEvent(EVENT_BERSERK, Minutes(15)); + EnterPhaseGround(true); } void SpellHitTarget(Unit* target, SpellInfo const* spell) override { switch(spell->Id) { - case SPELL_ICEBOLT: - { - IceBlockMap::iterator itr = _iceblocks.find(target->GetGUID()); - if (itr != _iceblocks.end() && !itr->second) - { - if (GameObject* iceblock = me->SummonGameObject(GO_ICEBLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, 0, 0, 0, 0, 25)) - itr->second = iceblock->GetGUID(); - } - break; - } case SPELL_CHECK_RESISTS: if (target && target->GetResistance(SPELL_SCHOOL_FROST) > MAX_FROST_RESISTANCE) _canTheHundredClub = false; @@ -179,41 +183,37 @@ class boss_sapphiron : public CreatureScript void MovementInform(uint32 /*type*/, uint32 id) override { if (id == 1) - events.ScheduleEvent(EVENT_LIFTOFF, 0); + events.ScheduleEvent(EVENT_LIFTOFF, Seconds(0), 0, PHASE_FLIGHT); } void DoAction(int32 param) override { - if (param == DATA_SAPPHIRON_BIRTH) + if (param == ACTION_BIRTH) { - _phase = PHASE_BIRTH; - events.ScheduleEvent(EVENT_BIRTH, 23 * IN_MILLISECONDS); + events.SetPhase(PHASE_BIRTH); + events.ScheduleEvent(EVENT_BIRTH, Seconds(23)); } } - void EnterPhaseGround() + void EnterPhaseGround(bool initial) { - _phase = PHASE_GROUND; me->SetReactState(REACT_AGGRESSIVE); - events.SetPhase(PHASE_GROUND); - events.ScheduleEvent(EVENT_CLEAVE, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_TAIL, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_DRAIN, 24 * IN_MILLISECONDS, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_BLIZZARD, urand(5, 10) * IN_MILLISECONDS, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_FLIGHT, 45 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(5), Seconds(15)), 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_TAIL, randtime(Seconds(7), Seconds(10)), 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_BLIZZARD, randtime(Seconds(5), Seconds(10)), 0, PHASE_GROUND); + if (initial) + { + events.ScheduleEvent(EVENT_DRAIN, randtime(Seconds(22), Seconds(28))); + events.ScheduleEvent(EVENT_FLIGHT, Seconds(48) + Milliseconds(500), 0, PHASE_GROUND); + } + else + events.ScheduleEvent(EVENT_FLIGHT, Minutes(1), 0, PHASE_GROUND); } - void ClearIceBlock() + inline void CastDrain() { - for (IceBlockMap::const_iterator itr = _iceblocks.begin(); itr != _iceblocks.end(); ++itr) - { - if (Player* player = ObjectAccessor::GetPlayer(*me, itr->first)) - player->RemoveAura(SPELL_ICEBOLT); - - if (GameObject* go = ObjectAccessor::GetGameObject(*me, itr->second)) - go->Delete(); - } - _iceblocks.clear(); + DoCastAOE(SPELL_LIFE_DRAIN); + events.ScheduleEvent(EVENT_DRAIN, randtime(Seconds(22), Seconds(28))); } uint32 GetData(uint32 data) const override @@ -226,15 +226,12 @@ class boss_sapphiron : public CreatureScript void UpdateAI(uint32 diff) override { - if (!_phase) - return; - events.Update(diff); - if (_phase != PHASE_BIRTH && !UpdateVictim()) + if (!events.IsInPhase(PHASE_BIRTH) && !UpdateVictim()) return; - if (_phase == PHASE_GROUND) + if (events.IsInPhase(PHASE_GROUND)) { while (uint32 eventId = events.ExecuteEvent()) { @@ -242,7 +239,10 @@ class boss_sapphiron : public CreatureScript { case EVENT_CHECK_RESISTS: DoCast(me, SPELL_CHECK_RESISTS); - events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS); + events.Repeat(Seconds(30)); + return; + case EVENT_GROUND: + EnterPhaseGround(false); return; case EVENT_BERSERK: Talk(EMOTE_ENRAGE); @@ -250,27 +250,26 @@ class boss_sapphiron : public CreatureScript return; case EVENT_CLEAVE: DoCastVictim(SPELL_CLEAVE); - events.ScheduleEvent(EVENT_CLEAVE, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(5), Seconds(15)), 0, PHASE_GROUND); return; case EVENT_TAIL: DoCastAOE(SPELL_TAIL_SWEEP); - events.ScheduleEvent(EVENT_TAIL, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_TAIL, randtime(Seconds(7), Seconds(10)), 0, PHASE_GROUND); return; case EVENT_DRAIN: - DoCastAOE(SPELL_LIFE_DRAIN); - events.ScheduleEvent(EVENT_DRAIN, 24 * IN_MILLISECONDS, 0, PHASE_GROUND); + if (events.IsInPhase(PHASE_FLIGHT)) + _delayedDrain = true; + else + CastDrain(); return; case EVENT_BLIZZARD: - { - if (Creature* summon = DoSummon(NPC_BLIZZARD, me, 0.0f, urand(25, 30) * IN_MILLISECONDS, TEMPSUMMON_TIMED_DESPAWN)) - summon->GetMotionMaster()->MoveRandom(40); - events.ScheduleEvent(EVENT_BLIZZARD, RAID_MODE(20, 7) * IN_MILLISECONDS, 0, PHASE_GROUND); + DoCastAOE(SPELL_SUMMON_BLIZZARD); + events.ScheduleEvent(EVENT_BLIZZARD, RAID_MODE(Seconds(20), Seconds(7)), 0, PHASE_GROUND); break; - } case EVENT_FLIGHT: if (HealthAbovePct(10)) { - _phase = PHASE_FLIGHT; + _delayedDrain = false; events.SetPhase(PHASE_FLIGHT); me->SetReactState(REACT_PASSIVE); me->AttackStop(); @@ -293,61 +292,69 @@ class boss_sapphiron : public CreatureScript { case EVENT_CHECK_RESISTS: DoCast(me, SPELL_CHECK_RESISTS); - events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS); + events.Repeat(Seconds(30)); return; case EVENT_LIFTOFF: + { Talk(EMOTE_AIR_PHASE); - me->SetDisableGravity(true); + if (Creature* buffet = DoSummon(NPC_WING_BUFFET, me, 0.0f, 0, TEMPSUMMON_MANUAL_DESPAWN)) + _buffet = buffet->GetGUID(); + me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); me->SetHover(true); - events.ScheduleEvent(EVENT_ICEBOLT, 1500); - _iceboltCount = RAID_MODE(2, 3); + events.ScheduleEvent(EVENT_ICEBOLT, Seconds(7), 0, PHASE_FLIGHT); + + _iceboltTargets.clear(); + std::list<Unit*> targets; + SelectTargetList(targets, RAID_MODE(2, 3), SELECT_TARGET_RANDOM, 200.0f, true); + for (Unit* target : targets) + if (target) + _iceboltTargets.push_back(target->GetGUID()); return; + } case EVENT_ICEBOLT: { - std::vector<Unit*> targets; - std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin(); - for (; i != me->getThreatManager().getThreatList().end(); ++i) - if ((*i)->getTarget()->GetTypeId() == TYPEID_PLAYER && !(*i)->getTarget()->HasAura(SPELL_ICEBOLT)) - targets.push_back((*i)->getTarget()); - - if (targets.empty()) - _iceboltCount = 0; - else + if (_iceboltTargets.empty()) { - std::vector<Unit*>::const_iterator itr = targets.begin(); - advance(itr, rand32() % targets.size()); - _iceblocks.insert(std::make_pair((*itr)->GetGUID(), ObjectGuid::Empty)); - DoCast(*itr, SPELL_ICEBOLT); - --_iceboltCount; + events.ScheduleEvent(EVENT_BREATH, Seconds(2), 0, PHASE_FLIGHT); + return; } - - if (_iceboltCount) - events.ScheduleEvent(EVENT_ICEBOLT, 1 * IN_MILLISECONDS); + ObjectGuid target = _iceboltTargets.back(); + if (Player* pTarget = ObjectAccessor::GetPlayer(*me, target)) + if (pTarget->IsAlive()) + DoCast(pTarget, SPELL_ICEBOLT); + _iceboltTargets.pop_back(); + + if (_iceboltTargets.empty()) + events.ScheduleEvent(EVENT_BREATH, Seconds(2), 0, PHASE_FLIGHT); else - events.ScheduleEvent(EVENT_BREATH, 1 * IN_MILLISECONDS); + events.Repeat(Seconds(3)); return; } case EVENT_BREATH: { Talk(EMOTE_BREATH); DoCastAOE(SPELL_FROST_MISSILE); - events.ScheduleEvent(EVENT_EXPLOSION, 8 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_EXPLOSION, Seconds(8), 0, PHASE_FLIGHT); return; } case EVENT_EXPLOSION: - CastExplosion(); - ClearIceBlock(); - events.ScheduleEvent(EVENT_LAND, 3 * IN_MILLISECONDS); + DoCastAOE(SPELL_FROST_BREATH); + DoCastAOE(SPELL_FROST_BREATH_ANTICHEAT); + events.ScheduleEvent(EVENT_LAND, Seconds(3) + Milliseconds(500), 0, PHASE_FLIGHT); return; case EVENT_LAND: + if (_delayedDrain) + CastDrain(); + if (Creature* cBuffet = ObjectAccessor::GetCreature(*me, _buffet)) + { + cBuffet->DespawnOrUnsummon(1 * IN_MILLISECONDS); + _buffet.Clear(); + } me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); Talk(EMOTE_GROUND_PHASE); me->SetHover(false); - me->SetDisableGravity(false); - events.ScheduleEvent(EVENT_GROUND, 1500); - return; - case EVENT_GROUND: - EnterPhaseGround(); + events.SetPhase(PHASE_GROUND); + events.ScheduleEvent(EVENT_GROUND, Seconds(3) + Milliseconds(500), 0, PHASE_GROUND); return; case EVENT_BIRTH: me->SetVisible(true); @@ -359,56 +366,261 @@ class boss_sapphiron : public CreatureScript } } - void CastExplosion() + private: + std::vector<ObjectGuid> _iceboltTargets; + ObjectGuid _buffet; + bool _delayedDrain; + bool _canTheHundredClub; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new boss_sapphironAI(creature); + } +}; + +class go_sapphiron_birth : public GameObjectScript +{ + public: + go_sapphiron_birth() : GameObjectScript("go_sapphiron_birth") { } + + struct go_sapphiron_birthAI : public GameObjectAI + { + go_sapphiron_birthAI(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { } + + void OnStateChanged(uint32 state, Unit* who) override + { + if (state == GO_ACTIVATED) + { + if (who) + { + if (Creature* sapphiron = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_SAPPHIRON))) + sapphiron->AI()->DoAction(ACTION_BIRTH); + instance->SetData(DATA_HAD_SAPPHIRON_BIRTH, 1u); + } + } + else if (state == GO_JUST_DEACTIVATED) + { // prevent ourselves from going back to _READY and resetting the client anim + go->SetRespawnTime(0); + go->Delete(); + } + } + + InstanceScript* instance; + }; + + GameObjectAI* GetAI(GameObject* go) const override + { + return GetInstanceAI<go_sapphiron_birthAI>(go); + } +}; + + +class spell_sapphiron_change_blizzard_target : public SpellScriptLoader +{ + public: + spell_sapphiron_change_blizzard_target() : SpellScriptLoader("spell_sapphiron_change_blizzard_target") { } + + class spell_sapphiron_change_blizzard_target_AuraScript : public AuraScript + { + PrepareAuraScript(spell_sapphiron_change_blizzard_target_AuraScript); + + void HandlePeriodic(AuraEffect const* /*eff*/) + { + TempSummon* me = GetTarget()->ToTempSummon(); + if (Creature* owner = me ? me->GetSummonerCreatureBase() : nullptr) + { + Unit* newTarget = owner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true); + if (!newTarget) + newTarget = owner->getAttackerForHelper(); + if (newTarget) + me->GetMotionMaster()->MoveFollow(newTarget, 0.1f, 0.0f); + else + { + me->StopMoving(); + me->GetMotionMaster()->Clear(); + } + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_sapphiron_change_blizzard_target_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_sapphiron_change_blizzard_target_AuraScript(); + } +}; + +class spell_sapphiron_icebolt : public SpellScriptLoader +{ + public: + spell_sapphiron_icebolt() : SpellScriptLoader("spell_sapphiron_icebolt") { } + + class spell_sapphiron_icebolt_AuraScript : public AuraScript + { + PrepareAuraScript(spell_sapphiron_icebolt_AuraScript); + + void HandleApply(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->ApplySpellImmune(SPELL_ICEBOLT, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FROST, true); + } + + void HandleRemove(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/) + { + if (_block) + if (GameObject* oBlock = ObjectAccessor::GetGameObject(*GetTarget(), _block)) + oBlock->Delete(); + GetTarget()->ApplySpellImmune(SPELL_ICEBOLT, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FROST, false); + } + + void HandlePeriodic(AuraEffect const* /*eff*/) + { + if (_block) + return; + if (GetTarget()->isMoving()) + return; + float x, y, z; + GetTarget()->GetPosition(x, y, z); + if (GameObject* block = GetTarget()->SummonGameObject(GO_ICEBLOCK, x, y, z, 0, 0, 0, 0, 0, 25)) + _block = block->GetGUID(); + } + + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_sapphiron_icebolt_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_sapphiron_icebolt_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_sapphiron_icebolt_AuraScript::HandlePeriodic, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + + ObjectGuid _block; + }; + + AuraScript* GetAuraScript() const override + { + return new spell_sapphiron_icebolt_AuraScript(); + } +}; + +// @hack Hello, developer from the future! How has your day been? +// Anyway, this is, as you can undoubtedly see, a hack to emulate line of sight checks on a spell that abides line of sight anyway. +// In the current core, line of sight is not properly checked for people standing behind an ice block. This is not a good thing and kills people. +// Thus, we have this hack to check for ice block LoS in a "safe" way. Kind of. It's inaccurate, but in a good way (tends to save people when it shouldn't in edge cases). +// If LoS handling is better in whatever the current revision is when you read this, please get rid of the hack. Thanks! +class spell_sapphiron_frost_breath : public SpellScriptLoader +{ + public: + spell_sapphiron_frost_breath() : SpellScriptLoader("spell_sapphiron_frost_breath") { } + + class spell_sapphiron_frost_breath_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sapphiron_frost_breath_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + return !!sSpellMgr->GetSpellInfo(SPELL_FROST_BREATH); + } + + void HandleTargets(std::list<WorldObject*>& targetList) { - DoZoneInCombat(); // make sure everyone is in threatlist - std::vector<Unit*> targets; - std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin(); - for (; i != me->getThreatManager().getThreatList().end(); ++i) + std::list<GameObject*> blocks; + if (GetCaster()) + GetCaster()->GetGameObjectListWithEntryInGrid(blocks, GO_ICEBLOCK, 200.0f); + + std::vector<Unit*> toRemove; + toRemove.reserve(3); + std::list<WorldObject*>::iterator it = targetList.begin(); + while (it != targetList.end()) { - Unit* target = (*i)->getTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) + Unit* target = (*it)->ToUnit(); + if (!target) + { + it = targetList.erase(it); continue; + } if (target->HasAura(SPELL_ICEBOLT)) { - target->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true); - targets.push_back(target); + it = targetList.erase(it); + toRemove.push_back(target); + continue; + } + + bool found = false; + for (GameObject* block : blocks) + if (block->IsInBetween(GetCaster(), target, 2.0f) && GetCaster()->GetExactDist2d(block) + 5 >= GetCaster()->GetExactDist2d(target)) + { + found = true; + break; + } + if (found) + { + it = targetList.erase(it); continue; } + ++it; + } + + for (Unit* block : toRemove) + block->RemoveAura(SPELL_ICEBOLT); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_breath_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); + } + }; - for (IceBlockMap::const_iterator itr = _iceblocks.begin(); itr != _iceblocks.end(); ++itr) + SpellScript* GetSpellScript() const override + { + return new spell_sapphiron_frost_breath_SpellScript(); + } +}; + +class spell_sapphiron_summon_blizzard : public SpellScriptLoader +{ + public: + spell_sapphiron_summon_blizzard() : SpellScriptLoader("spell_sapphiron_summon_blizzard") { } + + class spell_sapphiron_summon_blizzard_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sapphiron_summon_blizzard_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + return !!sSpellMgr->GetSpellInfo(SPELL_SUMMON_BLIZZARD); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + if (Creature* blizzard = GetCaster()->SummonCreature(NPC_BLIZZARD, *target, TEMPSUMMON_TIMED_DESPAWN, urandms(25, 30))) { - if (GameObject* go = ObjectAccessor::GetGameObject(*me, itr->second)) + blizzard->CastSpell(nullptr, blizzard->m_spells[0], TRIGGERED_NONE); + if (Creature* creatureCaster = GetCaster()->ToCreature()) { - if (go->IsInBetween(me, target, 2.0f) - && me->GetExactDist2d(target->GetPositionX(), target->GetPositionY()) - me->GetExactDist2d(go->GetPositionX(), go->GetPositionY()) < 5.0f) + if (Unit* newTarget = creatureCaster->AI()->SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true)) { - target->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true); - targets.push_back(target); - break; + blizzard->GetMotionMaster()->MoveFollow(newTarget, 0.1f, 0.0f); + return; } } + blizzard->GetMotionMaster()->MoveFollow(target, 0.1f, 0.0f); } - } - - me->CastSpell(me, SPELL_FROST_EXPLOSION, true); - - for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) - (*itr)->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, false); } - private: - Phases _phase; - uint32 _iceboltCount; - IceBlockMap _iceblocks; - bool _canTheHundredClub; - Map* _map; + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_sapphiron_summon_blizzard_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } }; - CreatureAI* GetAI(Creature* creature) const override + SpellScript* GetSpellScript() const override { - return new boss_sapphironAI(creature); + return new spell_sapphiron_summon_blizzard_SpellScript(); } }; @@ -426,5 +638,10 @@ class achievement_the_hundred_club : public AchievementCriteriaScript void AddSC_boss_sapphiron() { new boss_sapphiron(); + new go_sapphiron_birth(); + new spell_sapphiron_change_blizzard_target(); + new spell_sapphiron_icebolt(); + new spell_sapphiron_frost_breath(); + new spell_sapphiron_summon_blizzard(); new achievement_the_hundred_club(); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp index 7330f90e585..2cf3a4664dd 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp @@ -109,6 +109,10 @@ enum PetSpells SPELL_MAGNETIC_PULL = 54517, SPELL_MAGNETIC_PULL_EFFECT = 28337, + // @hack feugen/stalagg use this in P1 after gripping tanks to prevent mmaps from pathing them off the platform once they approach the ramp + // developer from the future, if you read this and mmaps in the room has been fixed, then get rid of the hackfix, please + SPELL_ROOT_SELF = 75215, + SPELL_TESLA_SHOCK = 28099 }; @@ -166,10 +170,12 @@ public: struct boss_thaddiusAI : public BossAI { public: - boss_thaddiusAI(Creature* creature) : BossAI(creature, BOSS_THADDIUS), stalaggAlive(true), feugenAlive(true), ballLightningEnabled(false), shockingEligibility(true) + boss_thaddiusAI(Creature* creature) : BossAI(creature, BOSS_THADDIUS), stalaggAlive(true), feugenAlive(true), ballLightningUnlocked(false), ballLightningEnabled(false), shockingEligibility(true) {} + + void InitializeAI() override { if (instance->GetBossState(BOSS_THADDIUS) != DONE) - { + { events.SetPhase(PHASE_NOT_ENGAGED); SetCombatMovement(false); @@ -184,12 +190,33 @@ public: Talk(SAY_SLAY); } - void Reset() override + void Reset() override { } + + void EnterEvadeMode(EvadeReason why) override { + if (!ballLightningEnabled && why == EVADE_REASON_NO_HOSTILES) + { + ballLightningEnabled = true; + return; // try again + } if (events.IsInPhase(PHASE_TRANSITION) || (events.IsInPhase(PHASE_THADDIUS) && me->IsAlive())) BeginResetEncounter(); } + bool CanAIAttack(Unit const* who) const override + { + if (ballLightningEnabled || me->IsWithinMeleeRange(who)) + return BossAI::CanAIAttack(who); + else + return false; + } + + void JustRespawned() override + { + if (events.IsInPhase(PHASE_RESETTING)) + ResetEncounter(); + } + void JustDied(Unit* /*killer*/) override { _JustDied(); @@ -217,18 +244,25 @@ public: case ACTION_FEUGEN_AGGRO: case ACTION_STALAGG_AGGRO: if (events.IsInPhase(PHASE_RESETTING)) - return BeginResetEncounter(); + { + BeginResetEncounter(); + return; + } if (!events.IsInPhase(PHASE_NOT_ENGAGED)) return; events.SetPhase(PHASE_PETS); shockingEligibility = true; - + if (!instance->CheckRequiredBosses(BOSS_THADDIUS)) - return BeginResetEncounter(); + { + BeginResetEncounter(); + return; + } instance->SetBossState(BOSS_THADDIUS, IN_PROGRESS); me->setActive(true); + DoZoneInCombat(); if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) stalagg->setActive(true); if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) @@ -239,7 +273,7 @@ public: feugen->AI()->DoAction(ACTION_FEUGEN_REVIVING_FX); feugenAlive = false; if (stalaggAlive) - events.ScheduleEvent(EVENT_REVIVE_FEUGEN, 5 * IN_MILLISECONDS, 0, PHASE_PETS); + events.ScheduleEvent(EVENT_REVIVE_FEUGEN, Seconds(5), 0, PHASE_PETS); else Transition(); @@ -249,7 +283,7 @@ public: stalagg->AI()->DoAction(ACTION_STALAGG_REVIVING_FX); stalaggAlive = false; if (feugenAlive) - events.ScheduleEvent(EVENT_REVIVE_STALAGG, 5 * IN_MILLISECONDS, 0, PHASE_PETS); + events.ScheduleEvent(EVENT_REVIVE_STALAGG, Seconds(5), 0, PHASE_PETS); else Transition(); @@ -274,9 +308,9 @@ public: me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - events.ScheduleEvent(EVENT_TRANSITION_1, 10 * IN_MILLISECONDS, 0, PHASE_TRANSITION); - events.ScheduleEvent(EVENT_TRANSITION_2, 12 * IN_MILLISECONDS, 0, PHASE_TRANSITION); - events.ScheduleEvent(EVENT_TRANSITION_3, 14 * IN_MILLISECONDS, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_TRANSITION_1, Seconds(10), 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_TRANSITION_2, Seconds(12), 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_TRANSITION_3, Seconds(14), 0, PHASE_TRANSITION); } void BeginResetEncounter(bool initial = false) @@ -286,16 +320,12 @@ public: if (events.IsInPhase(PHASE_RESETTING)) return; - if (initial) // signal shorter spawn timer to instance script - instance->SetBossState(BOSS_THADDIUS, SPECIAL); - instance->ProcessEvent(me, EVENT_THADDIUS_BEGIN_RESET); - instance->SetBossState(BOSS_THADDIUS, NOT_STARTED); - // remove polarity shift debuffs on reset instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_APPLY); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_APPLY); me->DespawnOrUnsummon(); + me->SetRespawnTime(initial ? 5 : 30); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED); events.SetPhase(PHASE_RESETTING); @@ -312,11 +342,9 @@ public: feugenAlive = true; stalaggAlive = true; - me->Respawn(true); _Reset(); events.SetPhase(PHASE_NOT_ENGAGED); - - me->CastSpell(me, SPELL_THADDIUS_INACTIVE_VISUAL, true); + me->SetReactState(REACT_PASSIVE); if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) feugen->AI()->DoAction(ACTION_RESET_ENCOUNTER); @@ -361,16 +389,20 @@ public: break; case EVENT_TRANSITION_3: // thaddius becomes active me->CastSpell(me, SPELL_THADDIUS_SPARK_VISUAL, true); - ballLightningEnabled = false; + ballLightningUnlocked = false; me->RemoveAura(SPELL_THADDIUS_INACTIVE_VISUAL); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); - + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); if (Unit* closest = SelectTarget(SELECT_TARGET_NEAREST, 0, 500.0f)) AttackStart(closest); else // if there is no nearest target, then there is no target, meaning we should reset - return BeginResetEncounter(); + { + BeginResetEncounter(); + return; + } if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) feugen->AI()->DoAction(ACTION_TRANSITION_3); @@ -381,20 +413,20 @@ public: Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, 5 * IN_MILLISECONDS, 0, PHASE_THADDIUS); - events.ScheduleEvent(EVENT_SHIFT, 10 * IN_MILLISECONDS, 0, PHASE_THADDIUS); - events.ScheduleEvent(EVENT_CHAIN, urand(10, 20) * IN_MILLISECONDS, 0, PHASE_THADDIUS); - events.ScheduleEvent(EVENT_BERSERK, 6 * MINUTE * IN_MILLISECONDS, 0, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, Seconds(5), 0, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_SHIFT, Seconds(10), 0, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_CHAIN, randtime(Seconds(10), Seconds(20)), 0, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_BERSERK, Minutes(6), 0, PHASE_THADDIUS); break; case EVENT_ENABLE_BALL_LIGHTNING: - ballLightningEnabled = true; + ballLightningUnlocked = true; break; case EVENT_SHIFT: me->CastStop(); // shift overrides all other spells DoCastAOE(SPELL_POLARITY_SHIFT); - events.ScheduleEvent(EVENT_SHIFT_TALK, 3 * IN_MILLISECONDS, PHASE_THADDIUS); - events.ScheduleEvent(EVENT_SHIFT, 30 * IN_MILLISECONDS, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_SHIFT_TALK, Seconds(3), PHASE_THADDIUS); + events.ScheduleEvent(EVENT_SHIFT, Seconds(30), PHASE_THADDIUS); break; case EVENT_SHIFT_TALK: Talk(SAY_ELECT); @@ -402,12 +434,12 @@ public: break; case EVENT_CHAIN: if (me->FindCurrentSpellBySpellId(SPELL_POLARITY_SHIFT)) // delay until shift is over - events.ScheduleEvent(EVENT_CHAIN, 3 * IN_MILLISECONDS, 0, PHASE_THADDIUS); + events.Repeat(Seconds(3)); else { me->CastStop(); DoCastVictim(SPELL_CHAIN_LIGHTNING); - events.ScheduleEvent(EVENT_CHAIN, urand(10, 20) * IN_MILLISECONDS, PHASE_THADDIUS); + events.Repeat(randtime(Seconds(10), Seconds(20))); } break; case EVENT_BERSERK: @@ -418,22 +450,24 @@ public: break; } } - - if (events.IsInPhase(PHASE_THADDIUS)) + if (events.IsInPhase(PHASE_THADDIUS) && !me->HasUnitState(UNIT_STATE_CASTING) && me->isAttackReady()) { if (me->IsWithinMeleeRange(me->GetVictim())) + { + ballLightningEnabled = false; DoMeleeAttackIfReady(); - else - if (ballLightningEnabled) - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_BALL_LIGHTNING); + } + else if (ballLightningUnlocked) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_BALL_LIGHTNING); } } private: bool stalaggAlive; bool feugenAlive; - bool ballLightningEnabled; + bool ballLightningUnlocked; // whether the initial ball lightning grace period has expired and we should proceed to exterminate with extreme prejudice + bool ballLightningEnabled; // switch that is flipped to true if we try to evade due to no eligible targets in melee range bool shockingEligibility; }; @@ -521,7 +555,7 @@ public: me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); Talk(EMOTE_FEIGN_REVIVE); isFeignDeath = false; - + refreshBeam = true; // force beam refresh if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) @@ -586,7 +620,7 @@ public: damage = 0; return; } - + isFeignDeath = true; isOverloading = false; @@ -652,7 +686,7 @@ public: else { DoCast(me, SPELL_STALAGG_POWERSURGE); - powerSurgeTimer = urand(25, 30) * IN_MILLISECONDS; + powerSurgeTimer = urandms(25, 30); } } else @@ -790,7 +824,7 @@ public: me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); Talk(EMOTE_FEIGN_REVIVE); isFeignDeath = false; - + refreshBeam = true; // force beam refresh if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) @@ -836,7 +870,7 @@ public: Talk(SAY_FEUGEN_AGGRO); if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) - thaddius->AI()->DoAction(ACTION_STALAGG_AGGRO); + thaddius->AI()->DoAction(ACTION_FEUGEN_AGGRO); if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) if (!stalagg->IsInCombat()) @@ -922,7 +956,7 @@ public: magneticPullTimer = 20 * IN_MILLISECONDS; } else magneticPullTimer -= uiDiff; - + if (staticFieldTimer <= uiDiff) { DoCast(me, SPELL_FEUGEN_STATICFIELD); @@ -971,7 +1005,7 @@ public: ObjectGuid _myCoil; ObjectGuid _myCoilGO; - + bool isOverloading; bool refreshBeam; bool isFeignDeath; @@ -1094,7 +1128,7 @@ class spell_thaddius_polarity_charge : public SpellScriptLoader SpellScript* GetSpellScript() const override { - return new spell_thaddius_polarity_charge_SpellScript; + return new spell_thaddius_polarity_charge_SpellScript(); } }; @@ -1169,7 +1203,7 @@ class spell_thaddius_magnetic_pull : public SpellScriptLoader Unit* feugen = GetCaster(); if (!feugen || feugen->GetEntry() != NPC_FEUGEN) return; - + Unit* stalagg = ObjectAccessor::GetCreature(*feugen, feugen->GetInstanceScript()->GetGuidData(DATA_STALAGG)); if (!stalagg) return; @@ -1212,6 +1246,10 @@ class spell_thaddius_magnetic_pull : public SpellScriptLoader feugenTank->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true); stalaggTank->CastSpell(feugenTank, SPELL_MAGNETIC_PULL_EFFECT, true); + // @hack prevent mmaps clusterfucks from breaking tesla while tanks are midair + feugen->AddAura(SPELL_ROOT_SELF, feugen); + stalagg->AddAura(SPELL_ROOT_SELF, stalagg); + // and make both attack their respective new tanks if (feugen->GetAI()) feugen->GetAI()->AttackStart(stalaggTank); diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index c8a4eb7fbc8..02b82d255cd 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -20,7 +20,7 @@ #include "InstanceScript.h" #include "naxxramas.h" -BossBoundaryData const boundaries = +BossBoundaryData const boundaries = { /* Arachnid Quarter */ { BOSS_ANUBREKHAN, new CircleBoundary(Position(3273.376709f, -3475.876709f), Position(3195.668213f, -3475.930176f)) }, @@ -100,36 +100,6 @@ ObjectData const objectData[] = { 0, 0, } }; -// from P2 teleport spell stored target -float const HeiganPos[2] = { 2793.86f, -3707.38f }; -float const HeiganEruptionSlope[3] = -{ - (-3703.303223f - HeiganPos[1]) / (2777.494141f - HeiganPos[0]), // between right center and far right - (-3696.948242f - HeiganPos[1]) / (2785.624268f - HeiganPos[0]), // between left and right halves - (-3691.880615f - HeiganPos[1]) / (2790.280029f - HeiganPos[0]) // between far left and left center -}; - -// 0 H x -// 1 ^ -// 2 | -// 3 y<--o -inline uint32 GetEruptionSection(float x, float y) -{ - y -= HeiganPos[1]; - if (y < 1.0f) - return 0; - - x -= HeiganPos[0]; - if (x > -1.0f) - return 3; - - float slope = y/x; - for (uint32 i = 0; i < 3; ++i) - if (slope > HeiganEruptionSlope[i]) - return i; - return 3; -} - class instance_naxxramas : public InstanceMapScript { public: @@ -149,6 +119,7 @@ class instance_naxxramas : public InstanceMapScript hadAnubRekhanGreet = false; hadFaerlinaGreet = false; hadThaddiusGreet = false; + hadSapphironBirth = false; CurrentWingTaunt = SAY_KELTHUZAD_FIRST_WING_TAUNT; playerDied = 0; @@ -208,28 +179,8 @@ class instance_naxxramas : public InstanceMapScript } } - void ProcessEvent(WorldObject* /*source*/, uint32 eventId) override - { - switch (eventId) - { - case EVENT_THADDIUS_BEGIN_RESET: - if (GetBossState(BOSS_THADDIUS) == SPECIAL) // this is the initial spawn, we want a shorter spawn time - events.ScheduleEvent(EVENT_THADDIUS_RESET, 5 * IN_MILLISECONDS); - else - events.ScheduleEvent(EVENT_THADDIUS_RESET, 30 * IN_MILLISECONDS); - break; - } - } - void OnGameObjectCreate(GameObject* go) override { - if (go->GetGOInfo()->displayId == 6785 || go->GetGOInfo()->displayId == 1287) - { - uint32 section = GetEruptionSection(go->GetPositionX(), go->GetPositionY()); - HeiganEruptionGUID[section].insert(go->GetGUID()); - return; - } - switch (go->GetEntry()) { case GO_GOTHIK_GATE: @@ -273,37 +224,18 @@ class instance_naxxramas : public InstanceMapScript if (GetBossState(BOSS_HORSEMEN) == DONE) go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); break; - default: - break; - } - - InstanceScript::OnGameObjectCreate(go); - } - - void OnGameObjectRemove(GameObject* go) override - { - if (go->GetGOInfo()->displayId == 6785 || go->GetGOInfo()->displayId == 1287) - { - uint32 section = GetEruptionSection(go->GetPositionX(), go->GetPositionY()); - HeiganEruptionGUID[section].erase(go->GetGUID()); - return; - } - - switch (go->GetEntry()) - { case GO_BIRTH: - if (SapphironGUID) + if (hadSapphironBirth || GetBossState(BOSS_SAPPHIRON) == DONE) { - if (Creature* sapphiron = instance->GetCreature(SapphironGUID)) - sapphiron->AI()->DoAction(DATA_SAPPHIRON_BIRTH); - return; + hadSapphironBirth = true; + go->Delete(); } break; default: break; } - InstanceScript::OnGameObjectRemove(go); + InstanceScript::OnGameObjectCreate(go); } void OnUnitDeath(Unit* unit) override @@ -328,9 +260,6 @@ class instance_naxxramas : public InstanceMapScript { switch (id) { - case DATA_HEIGAN_ERUPT: - HeiganErupt(value); - break; case DATA_GOTHIK_GATE: if (GameObject* gate = instance->GetGameObject(GothikGateGUID)) gate->SetGoState(GOState(value)); @@ -347,6 +276,9 @@ class instance_naxxramas : public InstanceMapScript case DATA_HAD_THADDIUS_GREET: hadThaddiusGreet = (value == 1u); break; + case DATA_HAD_SAPPHIRON_BIRTH: + hadSapphironBirth = (value == 1u); + break; default: break; } @@ -364,6 +296,8 @@ class instance_naxxramas : public InstanceMapScript return hadFaerlinaGreet ? 1u : 0u; case DATA_HAD_THADDIUS_GREET: return hadThaddiusGreet ? 1u : 0u; + case DATA_HAD_SAPPHIRON_BIRTH: + return hadSapphironBirth ? 1u : 0u; default: break; } @@ -399,6 +333,8 @@ class instance_naxxramas : public InstanceMapScript return StalaggGUID; case DATA_THADDIUS: return ThaddiusGUID; + case DATA_SAPPHIRON: + return SapphironGUID; case DATA_KELTHUZAD: return KelthuzadGUID; case DATA_KELTHUZAD_PORTAL01: @@ -431,7 +367,7 @@ class instance_naxxramas : public InstanceMapScript if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_ARACHNID)) teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6)); } break; case BOSS_LOATHEB: @@ -440,7 +376,7 @@ class instance_naxxramas : public InstanceMapScript if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_PLAGUE)) teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6)); } break; case BOSS_THADDIUS: @@ -449,12 +385,12 @@ class instance_naxxramas : public InstanceMapScript if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_CONSTRUCT)) teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6)); } break; case BOSS_GOTHIK: if (state == DONE) - events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ, 10000); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ, Seconds(10)); break; case BOSS_HORSEMEN: if (state == DONE) @@ -468,12 +404,12 @@ class instance_naxxramas : public InstanceMapScript if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_MILITARY)) teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6)); } break; case BOSS_SAPPHIRON: if (state == DONE) - events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, 6000); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, Seconds(6)); break; default: break; @@ -493,37 +429,37 @@ class instance_naxxramas : public InstanceMapScript case EVENT_DIALOGUE_GOTHIK_KORTHAZZ: if (Creature* korthazz = instance->GetCreature(ThaneGUID)) korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN); - events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK, 5000); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK, Seconds(5)); break; case EVENT_DIALOGUE_GOTHIK_ZELIEK: if (Creature* zeliek = instance->GetCreature(SirGUID)) zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN); - events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX, 6000); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX, Seconds(6)); break; case EVENT_DIALOGUE_GOTHIK_BLAUMEUX: if (Creature* blaumeux = instance->GetCreature(LadyGUID)) blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN); - events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE, 6000); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE, Seconds(6)); break; case EVENT_DIALOGUE_GOTHIK_RIVENDARE: if (Creature* rivendare = instance->GetCreature(BaronGUID)) rivendare->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN); - events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX2, 6000); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX2, Seconds(6)); break; case EVENT_DIALOGUE_GOTHIK_BLAUMEUX2: if (Creature* blaumeux = instance->GetCreature(LadyGUID)) blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2); - events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK2, 6000); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK2, Seconds(6)); break; case EVENT_DIALOGUE_GOTHIK_ZELIEK2: if (Creature* zeliek = instance->GetCreature(SirGUID)) zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2); - events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, 6000); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, Seconds(6)); break; case EVENT_DIALOGUE_GOTHIK_KORTHAZZ2: if (Creature* korthazz = instance->GetCreature(ThaneGUID)) korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2); - events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE2, 6000); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE2, Seconds(6)); break; case EVENT_DIALOGUE_GOTHIK_RIVENDARE2: if (Creature* rivendare = instance->GetCreature(BaronGUID)) @@ -540,62 +476,39 @@ class instance_naxxramas : public InstanceMapScript if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD); HandleGameObject(KelthuzadDoorGUID, false); - events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING, 6000); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING, Seconds(6)); break; case EVENT_DIALOGUE_SAPPHIRON_LICHKING: if (Creature* lichKing = instance->GetCreature(LichKingGUID)) lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING); - events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2, 16000); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2, Seconds(16)); break; case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2: if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD2); - events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING2, 9000); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING2, Seconds(9)); break; case EVENT_DIALOGUE_SAPPHIRON_LICHKING2: if (Creature* lichKing = instance->GetCreature(LichKingGUID)) lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING2); - events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3, 12000); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3, Seconds(12)); break; case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3: if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD3); - events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4, 6000); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4, Seconds(6)); break; case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4: if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD4); HandleGameObject(KelthuzadDoorGUID, true); break; - case EVENT_THADDIUS_RESET: - if (GetBossState(BOSS_THADDIUS) != DONE) - if (Creature* thaddius = instance->GetCreature(ThaddiusGUID)) - thaddius->AI()->DoAction(-1); - break; default: break; } } } - void HeiganErupt(uint32 section) - { - for (uint32 i = 0; i < 4; ++i) - { - if (i == section) - continue; - - for (ObjectGuid guid : HeiganEruptionGUID[i]) - { - if (GameObject* heiganEruption = instance->GetGameObject(guid)) - { - heiganEruption->SendCustomAnim(heiganEruption->GetGoAnimProgress()); - heiganEruption->CastSpell(NULL, SPELL_ERUPTION); - } - } - } - } - // This Function is called in CheckAchievementCriteriaMeet and CheckAchievementCriteriaMeet is called before SetBossState(bossId, DONE), // so to check if all bosses are done the checker must exclude 1 boss, the last done, if there is at most 1 encouter in progress when is // called this function then all bosses are done. The one boss that check is the boss that calls this function, so it is dead. @@ -653,7 +566,6 @@ class instance_naxxramas : public InstanceMapScript /* The Plague Quarter */ // Heigan the Unclean - GuidSet HeiganEruptionGUID[4]; ObjectGuid HeiganGUID; /* The Military Quarter */ @@ -688,6 +600,7 @@ class instance_naxxramas : public InstanceMapScript bool hadAnubRekhanGreet; bool hadFaerlinaGreet; bool hadThaddiusGreet; + bool hadSapphironBirth; uint8 CurrentWingTaunt; /* The Immortal / The Undying */ diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index c0caa86e93f..bece5a60bee 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -43,12 +43,11 @@ enum Encounter enum Data { - DATA_HEIGAN_ERUPT, DATA_GOTHIK_GATE, - DATA_SAPPHIRON_BIRTH, DATA_HAD_ANUBREKHAN_GREET, DATA_HAD_FAERLINA_GREET, DATA_HAD_THADDIUS_GREET, + DATA_HAD_SAPPHIRON_BIRTH, DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT, DATA_ABOMINATION_KILLED, @@ -73,6 +72,7 @@ enum Data64 DATA_HEIGAN, DATA_FEUGEN, DATA_STALAGG, + DATA_SAPPHIRON, DATA_KELTHUZAD, DATA_KELTHUZAD_PORTAL01, DATA_KELTHUZAD_PORTAL02, @@ -158,12 +158,6 @@ enum GameObjectsIds GO_NAXX_PORTAL_MILITARY = 181578 }; -enum SpellIds -{ - SPELL_ERUPTION = 29371, - SPELL_SLIME = 28801 -}; - enum InstanceEvents { // Dialogue that happens after Gothik's death. @@ -176,10 +170,6 @@ enum InstanceEvents EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, EVENT_DIALOGUE_GOTHIK_RIVENDARE2, - // Thaddius AI requesting timed encounter (re-)spawn - EVENT_THADDIUS_BEGIN_RESET, - EVENT_THADDIUS_RESET, - // Dialogue that happens after each wing. EVENT_KELTHUZAD_WING_TAUNT, diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 277ca793a8f..f000d7a3ef7 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -377,7 +377,7 @@ public: me->SetDisableGravity(true); me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); // TO DO: find what in core is making boss slower than in retail (when correct speed data) or find missing movement flag update or forced spline change - me->SetSpeed(MOVE_FLIGHT, _flySpeed * 0.25f); + me->SetSpeedRate(MOVE_FLIGHT, _flySpeed * 0.25f); if (_despawned) DoAction(ACTION_HANDLE_RESPAWN); @@ -603,7 +603,7 @@ public: me->SetRespawnDelay(respawnDelay); // Set speed to normal value - me->SetSpeed(MOVE_FLIGHT, _flySpeed); + me->SetSpeedRate(MOVE_FLIGHT, _flySpeed); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->RemoveAllAuras(); @@ -1165,7 +1165,7 @@ public: _instance = creature->GetInstanceScript(); me->SetReactState(REACT_PASSIVE); // TO DO: These were a bit faster than what they should be. Not sure what is the reason. - me->SetSpeed(MOVE_FLIGHT, 1.25f); + me->SetSpeedRate(MOVE_FLIGHT, 1.25f); } void Initialize() @@ -1274,7 +1274,7 @@ public: me->SetReactState(REACT_PASSIVE); // TO DO: Something is wrong with calculations for flying creatures that are on WP/Cyclic path. // They should get the same difference as to when at ground from run creature switch to walk. - me->SetSpeed(MOVE_FLIGHT, 0.45f); + me->SetSpeedRate(MOVE_FLIGHT, 0.45f); } void Reset() override @@ -1566,7 +1566,7 @@ public: { me->DespawnOrUnsummon(2050); me->SetOrientation(2.5f); - me->SetSpeed(MOVE_FLIGHT, 1.0f, true); + me->SetSpeedRate(MOVE_FLIGHT, 1.0f); Position pos = me->GetPosition(); pos.m_positionX += 10.0f; pos.m_positionY += 10.0f; diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp index e1a4a6ed7b8..3d9ea97b136 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp @@ -375,7 +375,7 @@ class npc_ruby_emerald_amber_drake : public CreatureScript { me->DespawnOrUnsummon(2050); me->SetOrientation(2.5f); - me->SetSpeed(MOVE_FLIGHT, 1.0f, true); + me->SetSpeedRate(MOVE_FLIGHT, 1.0f); Talk(SAY_DRAKES_TAKEOFF); Position pos = me->GetPosition(); Position offset = { 10.0f, 10.0f, 12.0f, 0.0f }; diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index a98da2c6e3d..8f7687d0fca 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -174,7 +174,7 @@ public: { if (pSpark->IsAlive()) { - pSpark->SetSpeed(MOVE_RUN, 2.0f); + pSpark->SetSpeedRate(MOVE_RUN, 2.0f); pSpark->GetMotionMaster()->Clear(); pSpark->GetMotionMaster()->MovePoint(DATA_POINT_CALLBACK, pos); } @@ -355,7 +355,7 @@ public: { Position pos = ionar->GetPosition(); - me->SetSpeed(MOVE_RUN, 2.0f); + me->SetSpeedRate(MOVE_RUN, 2.0f); me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePoint(DATA_POINT_CALLBACK, pos); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 89868fc7bf2..b2a1bb70077 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -1164,6 +1164,7 @@ class spell_algalon_trigger_3_adds : public SpellScriptLoader void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_trigger_3_adds_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_algalon_trigger_3_adds_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 6dfc3bf01e7..98827fb3e00 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -334,7 +334,8 @@ class boss_flame_leviathan : public CreatureScript void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override { if (spell->Id == SPELL_START_THE_ENGINE) - ASSERT_NOTNULL(me->GetVehicleKit())->InstallAllAccessories(false); + if (Vehicle* vehicleKit = me->GetVehicleKit()) + vehicleKit->InstallAllAccessories(false); if (spell->Id == SPELL_ELECTROSHOCK) me->InterruptSpell(CURRENT_CHANNELED_SPELL); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index e694433c614..8aa443cba3f 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -359,9 +359,9 @@ static bool IsEncounterFinished(Unit* who) if (!mkii || !vx001 || !aerial) return false; - if (mkii->getStandState() == UNIT_STAND_STATE_DEAD && - vx001->getStandState() == UNIT_STAND_STATE_DEAD && - aerial->getStandState() == UNIT_STAND_STATE_DEAD) + if (mkii->GetStandState() == UNIT_STAND_STATE_DEAD && + vx001->GetStandState() == UNIT_STAND_STATE_DEAD && + aerial->GetStandState() == UNIT_STAND_STATE_DEAD) { who->Kill(mkii); who->Kill(vx001); @@ -703,7 +703,7 @@ class boss_leviathan_mk_ii : public CreatureScript if (Unit* turret = me->GetVehicleKit()->GetPassenger(3)) turret->KillSelf(); - me->SetSpeed(MOVE_RUN, 1.5f, true); + me->SetSpeedRate(MOVE_RUN, 1.5f); me->GetMotionMaster()->MovePoint(WP_MKII_P1_IDLE, VehicleRelocation[WP_MKII_P1_IDLE]); } else if (events.IsInPhase(PHASE_VOL7RON)) @@ -2759,7 +2759,7 @@ class achievement_setup_boom : public AchievementCriteriaScript public: achievement_setup_boom() : AchievementCriteriaScript("achievement_setup_boom") { } - bool OnCheck(Player* /*source*/, Unit* target) + bool OnCheck(Player* /*source*/, Unit* target) override { return target && target->GetAI()->GetData(DATA_SETUP_BOMB); } @@ -2770,7 +2770,7 @@ class achievement_setup_mine : public AchievementCriteriaScript public: achievement_setup_mine() : AchievementCriteriaScript("achievement_setup_mine") { } - bool OnCheck(Player* /*source*/, Unit* target) + bool OnCheck(Player* /*source*/, Unit* target) override { return target && target->GetAI()->GetData(DATA_SETUP_MINE); } @@ -2781,7 +2781,7 @@ class achievement_setup_rocket : public AchievementCriteriaScript public: achievement_setup_rocket() : AchievementCriteriaScript("achievement_setup_rocket") { } - bool OnCheck(Player* /*source*/, Unit* target) + bool OnCheck(Player* /*source*/, Unit* target) override { return target && target->GetAI()->GetData(DATA_SETUP_ROCKET); } @@ -2792,7 +2792,7 @@ class achievement_firefighter : public AchievementCriteriaScript public: achievement_firefighter() : AchievementCriteriaScript("achievement_firefighter") { } - bool OnCheck(Player* /*source*/, Unit* target) + bool OnCheck(Player* /*source*/, Unit* target) override { return target && target->GetAI()->GetData(DATA_FIREFIGHTER); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index f5337b2dca5..363f5907048 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -366,7 +366,7 @@ class boss_razorscale : public CreatureScript _EnterCombat(); if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAZORSCALE_CONTROL))) controller->AI()->DoAction(ACTION_HARPOON_BUILD); - me->SetSpeed(MOVE_FLIGHT, 3.0f, true); + me->SetSpeedRate(MOVE_FLIGHT, 3.0f); me->SetReactState(REACT_PASSIVE); phase = PHASE_GROUND; events.SetPhase(PHASE_GROUND); @@ -550,7 +550,7 @@ class boss_razorscale : public CreatureScript me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); me->SetReactState(REACT_AGGRESSIVE); me->RemoveAurasDueToSpell(SPELL_HARPOON_TRIGGER); - me->SetSpeed(MOVE_FLIGHT, 1.0f, true); + me->SetSpeedRate(MOVE_FLIGHT, 1.0f); PermaGround = true; DoCastAOE(SPELL_FLAMEBREATH); events.ScheduleEvent(EVENT_FLAME, 15000, 0, PHASE_PERMAGROUND); @@ -677,7 +677,7 @@ class npc_expedition_commander : public CreatureScript if (Creature* summonedEngineer = me->SummonCreature(NPC_ENGINEER, PosEngSpawn, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000)) { summonedEngineer->SetWalk(false); - summonedEngineer->SetSpeed(MOVE_RUN, 0.5f); + summonedEngineer->SetSpeedRate(MOVE_RUN, 0.5f); summonedEngineer->SetHomePosition(PosEngRepair[n]); summonedEngineer->GetMotionMaster()->MoveTargetedHome(); Engineer[n] = summonedEngineer->GetGUID(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index 8cb20eadc9f..f3aeec85af2 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -637,7 +637,7 @@ class BoomEvent : public BasicEvent { } - bool Execute(uint64 /*time*/, uint32 /*diff*/) + bool Execute(uint64 /*time*/, uint32 /*diff*/) override { // This hack is here because we suspect our implementation of spell effect execution on targets // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets, diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp index 7da67171b5c..675268b4e93 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp @@ -230,6 +230,9 @@ enum Spells // Descend Into Madness SPELL_TELEPORT_PORTAL_VISUAL = 64416, + SPELL_TELEPORT_TO_STORMWIND_ILLUSION = 63989, + SPELL_TELEPORT_TO_CHAMBER_ILLUSION = 63997, + SPELL_TELEPORT_TO_ICECROWN_ILLUSION = 63998, // Illusions SPELL_GRIM_REPRISAL = 63305, @@ -395,6 +398,14 @@ enum MiscData { ACHIEV_TIMED_START_EVENT = 21001, SOUND_LUNATIC_GAZE = 15757, + MAX_ILLUSION_ROOMS = 3 +}; + +uint32 const IllusionSpells[MAX_ILLUSION_ROOMS] +{ + SPELL_TELEPORT_TO_CHAMBER_ILLUSION, + SPELL_TELEPORT_TO_ICECROWN_ILLUSION, + SPELL_TELEPORT_TO_STORMWIND_ILLUSION }; class StartAttackEvent : public BasicEvent @@ -405,7 +416,7 @@ class StartAttackEvent : public BasicEvent { } - bool Execute(uint64 /*time*/, uint32 /*diff*/) + bool Execute(uint64 /*time*/, uint32 /*diff*/) override { _owner->SetReactState(REACT_AGGRESSIVE); if (Creature* _summoner = ObjectAccessor::GetCreature(*_owner, _summonerGuid)) @@ -1419,7 +1430,11 @@ class npc_descend_into_madness : public CreatureScript { if (!result) return; + clicker->RemoveAurasDueToSpell(SPELL_BRAIN_LINK); + uint32 illusion = _instance->GetData(DATA_ILLUSION); + if (illusion < MAX_ILLUSION_ROOMS) + DoCast(clicker, IllusionSpells[illusion], true); me->DespawnOrUnsummon(); } diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp index 1af45f3031a..ee71c696d7c 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp @@ -746,7 +746,7 @@ public: //! HACK: Creature's can't have MOVEMENTFLAG_FLYING me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); me->RemoveAurasDueToSpell(SPELL_ORB_VISUAL); - me->SetSpeed(MOVE_FLIGHT, 0.5f); + me->SetSpeedRate(MOVE_FLIGHT, 0.5f); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index d7b65093898..7615217a794 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -209,7 +209,7 @@ public: Initialize(); Summons.DespawnAll(); - me->SetSpeed(MOVE_FLIGHT, 3.0f); + me->SetSpeedRate(MOVE_FLIGHT, 3.0f); if ((ObjectAccessor::GetCreature(*me, m_uiGraufGUID) == NULL) && !me->IsMounted()) me->SummonCreature(NPC_GRAUF, Location[0].GetPositionX(), Location[0].GetPositionY(), Location[0].GetPositionZ(), 3.0f); instance->SetBossState(DATA_SKADI_THE_RUTHLESS, NOT_STARTED); diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp index 8f2d5a61770..547dc681ac6 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp @@ -19,7 +19,7 @@ #include "InstanceScript.h" #include "utgarde_pinnacle.h" -BossBoundaryData const boundaries = +BossBoundaryData const boundaries = { { DATA_KING_YMIRON, new RectangleBoundary(340.0f, 450.0f, -412.0f, -275.0f) } }; diff --git a/src/server/scripts/Northrend/isle_of_conquest.cpp b/src/server/scripts/Northrend/isle_of_conquest.cpp index 68121e940c9..11cc645f0cb 100644 --- a/src/server/scripts/Northrend/isle_of_conquest.cpp +++ b/src/server/scripts/Northrend/isle_of_conquest.cpp @@ -210,7 +210,7 @@ class StartLaunchEvent : public BasicEvent { } - bool Execute(uint64 /*time*/, uint32 /*diff*/) + bool Execute(uint64 /*time*/, uint32 /*diff*/) override { Player* player = sObjectMgr->GetPlayerByLowGUID(_lowGuid); if (!player || !player->GetVehicle()) diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp index 2ec2af80624..d7ff1e5cb4d 100644 --- a/src/server/scripts/Northrend/zone_dragonblight.cpp +++ b/src/server/scripts/Northrend/zone_dragonblight.cpp @@ -360,7 +360,7 @@ class npc_commander_eligor_dawnbringer : public CreatureScript uint8 talkWing; }; - CreatureAI* GetAI(Creature* creature) const + CreatureAI* GetAI(Creature* creature) const override { return new npc_commander_eligor_dawnbringerAI(creature); } @@ -695,7 +695,7 @@ class npc_torturer_lecraft : public CreatureScript ObjectGuid _playerGUID; }; - CreatureAI* GetAI(Creature* creature) const + CreatureAI* GetAI(Creature* creature) const override { return new npc_torturer_lecraftAI(creature); } diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.h b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.h index 71dbd139ea0..4fd608ccd1c 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.h @@ -96,9 +96,9 @@ class OPvPCapturePointHP : public OPvPCapturePoint public: OPvPCapturePointHP(OutdoorPvP* pvp, OutdoorPvPHPTowerType type); - void ChangeState(); + void ChangeState() override; - void FillInitialWorldStates(WorldPacket & data); + void FillInitialWorldStates(WorldPacket & data) override; private: OutdoorPvPHPTowerType m_TowerType; @@ -109,18 +109,18 @@ class OutdoorPvPHP : public OutdoorPvP public: OutdoorPvPHP(); - bool SetupOutdoorPvP(); + bool SetupOutdoorPvP() override; - void HandlePlayerEnterZone(Player* player, uint32 zone); - void HandlePlayerLeaveZone(Player* player, uint32 zone); + void HandlePlayerEnterZone(Player* player, uint32 zone) override; + void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff); + bool Update(uint32 diff) override; - void FillInitialWorldStates(WorldPacket &data); + void FillInitialWorldStates(WorldPacket &data) override; - void SendRemoveWorldStates(Player* player); + void SendRemoveWorldStates(Player* player) override; - void HandleKillImpl(Player* player, Unit* killed); + void HandleKillImpl(Player* player, Unit* killed) override; uint32 GetAllianceTowersControlled() const; void SetAllianceTowersControlled(uint32 count); diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h index 4ed47c42206..80878828d44 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h @@ -311,18 +311,18 @@ class OutdoorPvPNA : public OutdoorPvP public: OutdoorPvPNA(); - bool SetupOutdoorPvP(); + bool SetupOutdoorPvP() override; - void HandlePlayerEnterZone(Player* player, uint32 zone); - void HandlePlayerLeaveZone(Player* player, uint32 zone); + void HandlePlayerEnterZone(Player* player, uint32 zone) override; + void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff); + bool Update(uint32 diff) override; - void FillInitialWorldStates(WorldPacket &data); + void FillInitialWorldStates(WorldPacket &data) override; - void SendRemoveWorldStates(Player* player); + void SendRemoveWorldStates(Player* player) override; - void HandleKillImpl(Player* player, Unit* killed); + void HandleKillImpl(Player* player, Unit* killed) override; private: OPvPCapturePointNA * m_obj; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.h b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.h index f28fea926fc..fae2ea9738e 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.h @@ -56,22 +56,22 @@ class OutdoorPvPSI : public OutdoorPvP public: OutdoorPvPSI(); - bool SetupOutdoorPvP(); + bool SetupOutdoorPvP() override; - void HandlePlayerEnterZone(Player* player, uint32 zone); - void HandlePlayerLeaveZone(Player* player, uint32 zone); + void HandlePlayerEnterZone(Player* player, uint32 zone) override; + void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff); + bool Update(uint32 diff) override; - void FillInitialWorldStates(WorldPacket &data); + void FillInitialWorldStates(WorldPacket &data) override; - void SendRemoveWorldStates(Player* player); + void SendRemoveWorldStates(Player* player) override; - bool HandleAreaTrigger(Player* player, uint32 trigger); + bool HandleAreaTrigger(Player* player, uint32 trigger) override; - bool HandleDropFlag(Player* player, uint32 spellId); + bool HandleDropFlag(Player* player, uint32 spellId) override; - bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go); + bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go) override; void UpdateWorldState(); diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h index 237fee3283b..ebbccfd63cb 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h @@ -132,11 +132,11 @@ class OPvPCapturePointTF : public OPvPCapturePoint public: OPvPCapturePointTF(OutdoorPvP* pvp, OutdoorPvPTF_TowerType type); - bool Update(uint32 diff); + bool Update(uint32 diff) override; - void ChangeState(); + void ChangeState() override; - void FillInitialWorldStates(WorldPacket & data); + void FillInitialWorldStates(WorldPacket & data) override; void UpdateTowerState(); @@ -151,16 +151,16 @@ class OutdoorPvPTF : public OutdoorPvP public: OutdoorPvPTF(); - bool SetupOutdoorPvP(); + bool SetupOutdoorPvP() override; - void HandlePlayerEnterZone(Player* player, uint32 zone); - void HandlePlayerLeaveZone(Player* player, uint32 zone); + void HandlePlayerEnterZone(Player* player, uint32 zone) override; + void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff); + bool Update(uint32 diff) override; - void FillInitialWorldStates(WorldPacket &data); + void FillInitialWorldStates(WorldPacket &data) override; - void SendRemoveWorldStates(Player* player); + void SendRemoveWorldStates(Player* player) override; uint32 GetAllianceTowersControlled() const; void SetAllianceTowersControlled(uint32 count); diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h index e71fbf79280..352e6f108ea 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h @@ -161,9 +161,9 @@ class OPvPCapturePointZM_Beacon : public OPvPCapturePoint public: OPvPCapturePointZM_Beacon(OutdoorPvP* pvp, ZM_BeaconType type); - void ChangeState(); + void ChangeState() override; - void FillInitialWorldStates(WorldPacket & data); + void FillInitialWorldStates(WorldPacket & data) override; void UpdateTowerState(); @@ -218,18 +218,18 @@ class OutdoorPvPZM : public OutdoorPvP public: OutdoorPvPZM(); - bool SetupOutdoorPvP(); + bool SetupOutdoorPvP() override; - void HandlePlayerEnterZone(Player* player, uint32 zone); - void HandlePlayerLeaveZone(Player* player, uint32 zone); + void HandlePlayerEnterZone(Player* player, uint32 zone) override; + void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff); + bool Update(uint32 diff) override; - void FillInitialWorldStates(WorldPacket &data); + void FillInitialWorldStates(WorldPacket &data) override; - void SendRemoveWorldStates(Player* player); + void SendRemoveWorldStates(Player* player) override; - void HandleKillImpl(Player* player, Unit* killed); + void HandleKillImpl(Player* player, Unit* killed) override; uint32 GetAllianceTowersControlled() const; void SetAllianceTowersControlled(uint32 count); diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index 7902c585509..3c651e10a1e 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -745,7 +745,7 @@ public: if (!Trigger) return; - Trigger->SetSpeed(MOVE_WALK, 3); + Trigger->SetSpeedRate(MOVE_WALK, 3); Trigger->SetWalk(true); Trigger->GetMotionMaster()->MovePoint(0, final.x, final.y, final.z); @@ -1524,7 +1524,7 @@ public: void BeginWalk() { me->SetWalk(false); - me->SetSpeed(MOVE_RUN, 1.0f); + me->SetSpeedRate(MOVE_RUN, 1.0f); me->GetMotionMaster()->MovePoint(0, AkamaWP[WalkCount].x, AkamaWP[WalkCount].y, AkamaWP[WalkCount].z); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp index 7e1215488e1..1a9074c2464 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp @@ -238,8 +238,8 @@ public: if (me->GetAuraCount(SPELL_SHADE_SOUL_CHANNEL_2) <= 3) { moveSpeed = (2.0f - (0.6f * me->GetAuraCount(SPELL_SHADE_SOUL_CHANNEL_2))); - me->SetSpeed(MOVE_WALK, moveSpeed / 2.5f); - me->SetSpeed(MOVE_RUN, (moveSpeed * 2) / 7); + me->SetSpeedRate(MOVE_WALK, moveSpeed / 2.5f); + me->SetSpeedRate(MOVE_RUN, (moveSpeed * 2) / 7); me->ClearUnitState(UNIT_STATE_ROOT); } else diff --git a/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp b/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp index ae4d17bdad4..0999f1fcd6b 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp @@ -117,7 +117,7 @@ public: DummyEntryCheckPredicate pred; summons.DoAction(EVENT_VOLCANO, pred); events.ScheduleEvent(EVENT_HATEFUL_STRIKE, 5000, GCD_CAST, PHASE_STRIKE); - me->SetSpeed(MOVE_RUN, 1.2f); + me->SetSpeedRate(MOVE_RUN, 1.2f); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); } @@ -126,7 +126,7 @@ public: phase = PHASE_CHASE; events.ScheduleEvent(EVENT_VOLCANO, 5000, GCD_CAST, PHASE_CHASE); events.ScheduleEvent(EVENT_SWITCH_TARGET, 10000, 0, PHASE_CHASE); - me->SetSpeed(MOVE_RUN, 0.9f); + me->SetSpeedRate(MOVE_RUN, 0.9f); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp index e24499c3aee..3ddf0fec416 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp @@ -585,8 +585,8 @@ public: void Reset() override { - me->SetSpeed(MOVE_WALK, 0.6f); // walk - me->SetSpeed(MOVE_RUN, 0.6f); // run + me->SetSpeedRate(MOVE_WALK, 0.6f); // walk + me->SetSpeedRate(MOVE_RUN, 0.6f); // run Initialize(); //search for nearest waypoint (up on stairs) diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp index 8d117f7c3ef..f72b9a8d2ca 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp @@ -244,7 +244,7 @@ public: CheckChannelers(); Initialize(); me->SetCanDualWield(true); - me->SetSpeed(MOVE_RUN, 2.0f, true); + me->SetSpeedRate(MOVE_RUN, 2.0f); me->SetDisplayId(MODEL_NIGHTELF); me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID , 0); me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID+1, 0); diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp new file mode 100644 index 00000000000..9b53b62cdee --- /dev/null +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp @@ -0,0 +1,1051 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "CreatureTextMgr.h" +#include "LFGMgr.h" +#include "ScriptedGossip.h" +#include "ScriptedCreature.h" +#include "ScriptMgr.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "the_slave_pens.h" + +enum Spells +{ + // Ahune + SPELL_SYNCH_HEALTH = 46430, + SPELL_AHUNES_SHIELD = 45954, + SPELL_STAY_SUBMERGED = 46981, + SPELL_AHUNE_SELF_STUN = 46416, + SPELL_AHUNE_ACHIEVEMENT = 62043, + SPELL_AHUNE_SPANKY_HANDS = 46146, + SPELL_COLD_SLAP = 46145, + SPELL_RESURFACE = 46402, + SPELL_SUBMERGED = 37751, + SPELL_STAND = 37752, + + //Earther Ring Flamecaller + SPELL_FIND_OPENING_VISUAL = 45964, + SPELL_FIND_OPENING_BEAM_END = 46333, + SPELL_FIND_OPENING_TRIGGER = 46341, + SPELL_FIND_OPENING_CHANNEL = 46345, + SPELL_BONFIRE_VISUAL = 46339, + SPELL_FOUND_OPENING = 46421, + + //Ahune Bunny + SPELL_SUMMON_COLDWEAVE = 46143, + SPELL_SUMMON_FROSTWIND = 46382, + SPELL_SUMMON_HAILSTONE = 46176, + SPELL_SUMMONING_VISUAL_1 = 45937, + SPELL_SUMMONING_RHYME_AURA = 45926, + SPELL_SUMMONING_RHYME_BONFIRE = 45930, + SPELL_FORCE_WHISP_FLIGHT = 46603, + SPELL_SHAMANS_LOOK_FOR_OPENING = 46422, + SPELL_CLOSE_OPENING_VISUAL = 46236, + SPELL_ICE_BOMBARD = 46397, + SPELL_ICE_BOMBARDMENT_DEST_PICKER = 46398, + SPELL_ICE_BOMBARDMENT = 46396, + + // Ice Spear + SPELL_SUMMON_ICE_SPEAR_BUNNY = 46359, + SPELL_ICE_SPEAR_KNOCKBACK = 46360, + SPELL_SUMMON_ICE_SPEAR_GO = 46369, + SPELL_ICE_SPEAR_AURA = 46371, + SPELL_ICE_SPEAR_TARGET_PICKER = 46372, + SPELL_ICE_SPEAR_DELAY = 46878, + SPELL_ICE_SPEAR_VISUAL = 75498, + + // Slippery Floor + SPELL_SLIPPERY_FLOOR_AMBIENT = 46314, + SPELL_SLIPPERY_FLOOR_PERIODIC = 46320, + SPELL_SLIPPERY_FLOOR_SLIP = 45947, + + // Frozen Core + SPELL_SUICIDE = 45254, + SPELL_SUMMON_LOOT_MISSILE = 45941, + SPELL_FROZEN_CORE_GETS_HIT = 46810, + SPELL_MINION_DESPAWNER = 46843, + SPELL_GHOST_DISGUISE = 46786 +}; + +enum Emotes +{ + EMOTE_EARTHEN_ASSAULT = 0, + EMOTE_RETREAT = 0, + EMOTE_RESURFACE = 1 +}; + +enum Says +{ + SAY_PLAYER_TEXT_1 = 0, + SAY_PLAYER_TEXT_2 = 1, + SAY_PLAYER_TEXT_3 = 2 +}; + +enum Events +{ + EVENT_EMERGE = 1, + EVENT_INITIAL_EMERGE = 2, + EVENT_SYNCH_HEALTH = 3, + EVENT_FOUND_OPENING = 4, + EVENT_LOOKFOROPENING_0 = 5, + EVENT_LOOKFOROPENING_1 = 6, + EVENT_LOOKFOROPENING_2 = 7, + EVENT_SUMMON_HAILSTONE = 8, + EVENT_SUMMON_COLDWEAVE = 9, + EVENT_SUMMON_FROSTWIND = 10, + EVENT_SUMMON_AHUNE = 11, + EVENT_CLOSE_OPENING = 12, + EVENT_AHUNE_PHASE_ONE = 13, + EVENT_AHUNE_PHASE_TWO = 14, + EVENT_START_LOOKING_FOR_OPENING = 15, + EVENT_STOP_LOOKING_FOR_OPENING = 16 +}; + +enum Actions +{ + ACTION_START_EVENT = -2574500, + ACTION_AHUNE_RETREAT = -2586500, + ACTION_AHUNE_RESURFACE = -2586501, + ACTION_EMOTE_RESURFACE = -2575400 +}; + +enum Phases +{ + PHASE_ONE = 0, + PHASE_TWO = 1 +}; + +enum Points +{ + POINT_FLAMECALLER_000, + POINT_FLAMECALLER_001, + POINT_FLAMECALLER_002 +}; + +enum Misc +{ + MAX_FLAMECALLERS = 3 +}; + +Position const SummonPositions[] = +{ + { -99.1021f, -233.7526f, -1.22307f, 1.588250f }, // Ahune + { -98.0151f, -230.4555f, -1.21089f, 1.797689f }, // Frozen Core + { -143.172f, -147.6801f, -3.16113f, 4.852015f }, // Bonfire Bunny 000 + { -134.304f, -145.7803f, -1.70332f, 4.677482f }, // Bonfire Bunny 001 + { -125.036f, -144.2065f, -1.91660f, 4.991642f }, // Bonfire Bunny 002 + { -69.8121f, -162.4954f, -2.30451f, 1.710423f }, // Wisp Source Bunny + { -98.1029f, -230.7864f, -10.8085f, 1.448623f } // Wisp Dest Bunny +}; + +Position const FlameCallerSpots[] = +{ + { -145.2233f, -137.5543f, -1.59056f, 5.427049f }, + { -137.4383f, -136.4050f, -1.72384f, 5.336747f }, + { -129.0413f, -132.1494f, -2.09285f, 5.460842f } +}; + +class boss_ahune : public CreatureScript +{ +public: + boss_ahune() : CreatureScript("boss_ahune") { } + + struct boss_ahuneAI : public BossAI + { + boss_ahuneAI(Creature* creature) : BossAI(creature, DATA_AHUNE) + { + Initialize(); + } + + void Initialize() + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); + } + + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + events.ScheduleEvent(EVENT_INITIAL_EMERGE, 4); + events.ScheduleEvent(EVENT_SYNCH_HEALTH, 3000); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + if (Creature* ahuneBunny = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AHUNE_BUNNY))) + ahuneBunny->AI()->EnterEvadeMode(); + summons.DespawnAll(); + me->DespawnOrUnsummon(); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->DoCastSpellOnPlayers(SPELL_AHUNE_ACHIEVEMENT); + + if (Creature* ahuneBunny = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AHUNE_BUNNY))) + me->Kill(ahuneBunny); + if (Creature* frozenCore = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FROZEN_CORE))) + me->Kill(frozenCore); + + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + if (!players.isEmpty()) + { + if (Group* group = players.begin()->GetSource()->GetGroup()) + if (group->isLFGGroup()) + sLFGMgr->FinishDungeon(group->GetGUID(), 286); + } + } + + void JustSummoned(Creature* summon) override + { + BossAI::JustSummoned(summon); + } + + void DoAction(int32 action) override + { + if (action == ACTION_AHUNE_RETREAT) + { + Submerge(); + events.ScheduleEvent(EVENT_EMERGE, 35000); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INITIAL_EMERGE: + DoCast(me, SPELL_STAND); + DoCast(me, SPELL_AHUNE_SPANKY_HANDS); + DoCast(me, SPELL_AHUNES_SHIELD); + break; + case EVENT_EMERGE: + Emerge(); + break; + case EVENT_SYNCH_HEALTH: + if (Creature* frozenCore = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FROZEN_CORE))) + DoCast(frozenCore, SPELL_SYNCH_HEALTH); + else + DoCast(me, SPELL_SUICIDE); + events.ScheduleEvent(EVENT_SYNCH_HEALTH, 3000); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + + void Emerge() + { + if (Creature* frozenCore = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FROZEN_CORE))) + frozenCore->AI()->DoAction(ACTION_AHUNE_RESURFACE); + + DoCast(me, SPELL_AHUNES_SHIELD); + me->RemoveAurasDueToSpell(SPELL_AHUNE_SELF_STUN); + me->RemoveAurasDueToSpell(SPELL_STAY_SUBMERGED); + DoCast(me, SPELL_STAND); + DoCast(me, SPELL_RESURFACE, true); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + events.ScheduleEvent(EVENT_SYNCH_HEALTH, 3000); + } + + void Submerge() + { + if (Creature* frozenCore = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FROZEN_CORE))) + frozenCore->AI()->DoAction(ACTION_AHUNE_RETREAT); + me->RemoveAurasDueToSpell(SPELL_AHUNES_SHIELD); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_SUBMERGED, true); + DoCast(me, SPELL_AHUNE_SELF_STUN, true); + DoCast(me, SPELL_STAY_SUBMERGED, true); + me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); + events.Reset(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_ahuneAI>(creature); + } +}; + +class npc_frozen_core : public CreatureScript +{ +public: + npc_frozen_core() : CreatureScript("npc_frozen_core") { } + + struct npc_frozen_coreAI : public ScriptedAI + { + npc_frozen_coreAI(Creature* creature) : ScriptedAI(creature) + { + _instance = me->GetInstanceScript(); + Initialize(); + } + + void Initialize() + { + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); + DoCast(me, SPELL_FROZEN_CORE_GETS_HIT); + DoCast(me, SPELL_ICE_SPEAR_AURA); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + DoCast(SPELL_MINION_DESPAWNER); + if (Creature* ahune = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AHUNE))) + ahune->AI()->EnterEvadeMode(); + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* ahune = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AHUNE))) + me->Kill(ahune); + + DoCast(SPELL_SUMMON_LOOT_MISSILE); + DoCast(SPELL_MINION_DESPAWNER); + } + + void DoAction(int32 action) override + { + if (action == ACTION_AHUNE_RETREAT) + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_PC); + me->RemoveAurasDueToSpell(SPELL_ICE_SPEAR_AURA); + _events.ScheduleEvent(EVENT_SYNCH_HEALTH, 3000, 0, PHASE_TWO); + } + else if (action == ACTION_AHUNE_RESURFACE) + { + _events.Reset(); + DoCast(me, SPELL_ICE_SPEAR_AURA); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_DISABLE_MOVE); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SYNCH_HEALTH: + if (Creature* ahune = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AHUNE))) + DoCast(ahune, SPELL_SYNCH_HEALTH); + else + DoCast(me, SPELL_SUICIDE); + _events.ScheduleEvent(EVENT_SYNCH_HEALTH, 3000); + break; + default: + break; + } + } + } + + private: + InstanceScript* _instance; + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_frozen_coreAI>(creature); + } +}; + +class npc_ahune_bunny : public CreatureScript +{ +public: + npc_ahune_bunny() : CreatureScript("npc_ahune_bunny") { } + + struct npc_ahune_bunnyAI : public ScriptedAI + { + npc_ahune_bunnyAI(Creature* creature) : ScriptedAI(creature), _summons(me) + { + _instance = me->GetInstanceScript(); + _submerged = false; + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_AHUNE) + return; + + summon->SetInCombatWithZone(); + _summons.Summon(summon); + } + + void JustDied(Unit* /*killer*/) override + { + _summons.DespawnAll(); + ResetFlameCallers(); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + _summons.DespawnAll(); + ResetFlameCallers(); + + me->SummonGameObject(GO_ICE_STONE, -69.90455f, -162.2449f, -2.366563f, 2.426008f, 0.0f, 0.0f, 0.9366722f, 0.3502074f, 0); + } + + void DoAction(int32 action) override + { + if (action == ACTION_START_EVENT) + { + DoCast(me, SPELL_SUMMONING_VISUAL_1); + me->SummonCreature(NPC_WHISP_SOURCE_BUNNY, SummonPositions[5], TEMPSUMMON_MANUAL_DESPAWN); + me->SummonCreature(NPC_WHISP_DEST_BUNNY, SummonPositions[6], TEMPSUMMON_MANUAL_DESPAWN); + me->SummonCreature(NPC_SHAMAN_BONFIRE_BUNNY_000, SummonPositions[2], TEMPSUMMON_MANUAL_DESPAWN); + me->SummonCreature(NPC_SHAMAN_BONFIRE_BUNNY_001, SummonPositions[3], TEMPSUMMON_MANUAL_DESPAWN); + me->SummonCreature(NPC_SHAMAN_BONFIRE_BUNNY_002, SummonPositions[4], TEMPSUMMON_MANUAL_DESPAWN); + + for (uint8 counter = 0; counter < MAX_FLAMECALLERS; ++counter) + if (Creature* flameCaller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FLAMECALLER_000 + counter))) + flameCaller->GetMotionMaster()->MovePoint(counter, FlameCallerSpots[counter].GetPosition()); + + _submerged = false; + _events.Reset(); + _events.SetPhase(PHASE_ONE); + _events.ScheduleEvent(EVENT_SUMMON_AHUNE, 10000); + _events.ScheduleEvent(EVENT_START_LOOKING_FOR_OPENING, 14000, 0, PHASE_ONE); + _events.ScheduleEvent(EVENT_SUMMON_COLDWEAVE, 22000, 0, PHASE_ONE); + _events.ScheduleEvent(EVENT_SUMMON_HAILSTONE, 14000, 0, PHASE_ONE); + _events.ScheduleEvent(EVENT_AHUNE_PHASE_TWO, 108000, 0, PHASE_ONE); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_START_LOOKING_FOR_OPENING: + Talk(EMOTE_EARTHEN_ASSAULT); + for (uint8 counter = 0; counter < MAX_FLAMECALLERS; ++counter) + if (Creature* flamecaller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FLAMECALLER_000 + counter))) + DoCast(flamecaller, SPELL_SHAMANS_LOOK_FOR_OPENING, true); + break; + case EVENT_SUMMON_HAILSTONE: + DoCast(SPELL_SUMMON_HAILSTONE); + break; + case EVENT_SUMMON_COLDWEAVE: + DoCast(SPELL_SUMMON_COLDWEAVE); + DoCast(SPELL_SUMMON_COLDWEAVE); + _events.ScheduleEvent(EVENT_SUMMON_COLDWEAVE, 8000, 0, PHASE_ONE); + if (_submerged) + _events.ScheduleEvent(EVENT_SUMMON_FROSTWIND, 4000, 0, PHASE_ONE); + break; + case EVENT_SUMMON_FROSTWIND: + DoCast(SPELL_SUMMON_FROSTWIND); + break; + case EVENT_SUMMON_AHUNE: + if (TempSummon* ahune = me->SummonCreature(NPC_AHUNE, SummonPositions[0], TEMPSUMMON_DEAD_DESPAWN)) + { + ahune->SummonCreature(NPC_FROZEN_CORE, SummonPositions[1], TEMPSUMMON_CORPSE_DESPAWN); + ahune->SetInCombatWithZone(); + DoCast(ahune, SPELL_RESURFACE); + } + break; + case EVENT_CLOSE_OPENING: + if (Creature* flamecaller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FLAMECALLER_000))) + flamecaller->AI()->DoAction(ACTION_EMOTE_RESURFACE); + DoCast(SPELL_CLOSE_OPENING_VISUAL); + DoCast(me, SPELL_ICE_BOMBARD); + break; + case EVENT_AHUNE_PHASE_TWO: + if (Creature* flamecaller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FLAMECALLER_000))) + DoCast(flamecaller, SPELL_FOUND_OPENING); + if (Creature* ahune = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AHUNE))) + ahune->AI()->DoAction(ACTION_AHUNE_RETREAT); + _events.Reset(); + _events.SetPhase(PHASE_TWO); + _events.ScheduleEvent(EVENT_CLOSE_OPENING, 25000, 0, PHASE_TWO); + _events.ScheduleEvent(EVENT_AHUNE_PHASE_ONE, 35000, 0, PHASE_TWO); + break; + case EVENT_AHUNE_PHASE_ONE: + _submerged = true; + _events.Reset(); + _events.SetPhase(PHASE_ONE); + _events.ScheduleEvent(EVENT_SUMMON_COLDWEAVE, 8000, 0, PHASE_ONE); + _events.ScheduleEvent(EVENT_SUMMON_HAILSTONE, 5000, 0, PHASE_ONE); + _events.ScheduleEvent(EVENT_START_LOOKING_FOR_OPENING, 5000, 0, PHASE_ONE); + _events.ScheduleEvent(EVENT_AHUNE_PHASE_TWO, 100000, 0, PHASE_ONE); + break; + default: + break; + } + } + } + + void ResetFlameCallers() + { + for (uint8 counter = 0; counter < MAX_FLAMECALLERS; ++counter) + if (Creature* flamecaller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FLAMECALLER_000 + counter))) + flamecaller->AI()->EnterEvadeMode(); + } + + private: + InstanceScript* _instance; + EventMap _events; + SummonList _summons; + bool _submerged; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_ahune_bunnyAI>(creature); + } +}; + +class npc_earthen_ring_flamecaller : public CreatureScript +{ +public: + npc_earthen_ring_flamecaller() : CreatureScript("npc_earthen_ring_flamecaller") { } + + struct npc_earthen_ring_flamecallerAI : public ScriptedAI + { + npc_earthen_ring_flamecallerAI(Creature* creature) : ScriptedAI(creature) + { + _instance = me->GetInstanceScript(); + } + + void Reset() override + { + _events.Reset(); + } + + void MovementInform(uint32 motionType, uint32 pointId) override + { + if (motionType != POINT_MOTION_TYPE) + return; + + switch (pointId) + { + case POINT_FLAMECALLER_000: + _mySpot = POINT_FLAMECALLER_000; + me->SetOrientation(FlameCallerSpots[_mySpot].GetOrientation()); + break; + case POINT_FLAMECALLER_001: + _mySpot = POINT_FLAMECALLER_001; + me->SetOrientation(FlameCallerSpots[_mySpot].GetOrientation()); + break; + case POINT_FLAMECALLER_002: + _mySpot = POINT_FLAMECALLER_002; + me->SetOrientation(FlameCallerSpots[_mySpot].GetOrientation()); + break; + default: + break; + } + + DoCast(me, SPELL_FIND_OPENING_CHANNEL); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + switch (spellInfo->Id) + { + case SPELL_SHAMANS_LOOK_FOR_OPENING: + _events.ScheduleEvent(EVENT_LOOKFOROPENING_0, 17000); + break; + case SPELL_FOUND_OPENING: + _events.ScheduleEvent(EVENT_FOUND_OPENING, 0); + break; + default: + break; + } + } + + void DoAction(int action) override + { + if (action == ACTION_EMOTE_RESURFACE) + Talk(EMOTE_RESURFACE); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_LOOKFOROPENING_0: + LookOpening(true, 0); + _events.ScheduleEvent(EVENT_LOOKFOROPENING_1, 26000); + break; + case EVENT_LOOKFOROPENING_1: + LookOpening(true, 1); + _events.ScheduleEvent(EVENT_LOOKFOROPENING_2, 25000); + break; + case EVENT_LOOKFOROPENING_2: + LookOpening(true, 2); + _events.ScheduleEvent(EVENT_STOP_LOOKING_FOR_OPENING, 27000); + break; + case EVENT_STOP_LOOKING_FOR_OPENING: + LookOpening(false, _mySpot); + break; + case EVENT_FOUND_OPENING: + Talk(EMOTE_RETREAT); + default: + break; + } + } + } + + void LookOpening(bool activate, uint8 spot) + { + if (_mySpot != spot) + return; + + if (Creature* bonfireBunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BONFIRE_BUNNY_000 + spot))) + if (Creature* beamBunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BEAM_BUNNY_000 + spot))) + { + if (activate) + { + DoCast(bonfireBunny, SPELL_FIND_OPENING_TRIGGER); + bonfireBunny->CastSpell(beamBunny, SPELL_FIND_OPENING_VISUAL, true); + } + else + { + DoCast(me, SPELL_FIND_OPENING_CHANNEL); + bonfireBunny->CastStop(); + beamBunny->RemoveAurasDueToSpell(SPELL_FIND_OPENING_BEAM_END); + } + } + } + + private: + EventMap _events; + InstanceScript* _instance; + uint8 _mySpot; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_earthen_ring_flamecallerAI>(creature); + } +}; + +class go_ahune_ice_stone : public GameObjectScript +{ +public: + go_ahune_ice_stone() : GameObjectScript("go_ahune_ice_stone") { } + + bool OnGossipSelect(Player* player, GameObject* go, uint32 /*sender*/, uint32 /*action*/) + { + InstanceScript* instance = go->GetInstanceScript(); + if (!instance) + return false; + + player->PlayerTalkClass->ClearMenus(); + + if (Creature* ahuneBunny = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_AHUNE_BUNNY))) + { + ahuneBunny->AI()->DoAction(ACTION_START_EVENT); + ahuneBunny->SetInCombatWithZone(); + } + if (Creature* luma = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_LUMA_SKYMOTHER))) + luma->CastSpell(player, SPELL_SUMMONING_RHYME_AURA, true); + player->CLOSE_GOSSIP_MENU(); + go->Delete(); + + return true; + } +}; + +// 46430 - Synch Health +class spell_ahune_synch_health : public SpellScriptLoader +{ +public: + spell_ahune_synch_health() : SpellScriptLoader("spell_ahune_synch_health") { } + + class spell_ahune_synch_health_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ahune_synch_health_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SYNCH_HEALTH)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + if (Unit* caster = GetCaster()) + target->SetHealth(caster->GetHealth()); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_ahune_synch_health_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ahune_synch_health_SpellScript(); + } +}; + +// 45926 - Summoning Rhyme Aura +class spell_summoning_rhyme_aura : public SpellScriptLoader +{ +public: + spell_summoning_rhyme_aura() : SpellScriptLoader("spell_summoning_rhyme_aura") { } + + class spell_summoning_rhyme_aura_AuraScript : public AuraScript + { + PrepareAuraScript(spell_summoning_rhyme_aura_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_FORCE_WHISP_FLIGHT) || !sSpellMgr->GetSpellInfo(SPELL_SUMMONING_RHYME_BONFIRE)) + return false; + return true; + } + + void PeriodicTick(AuraEffect const* aurEff) + { + Creature* caster = GetCaster()->ToCreature(); + Player* player = GetTarget()->ToPlayer(); + + if (!caster || !player) + return; + + player->CastSpell(player, SPELL_FORCE_WHISP_FLIGHT); + + switch (aurEff->GetTickNumber()) + { + case 1: + sCreatureTextMgr->SendChat(caster, SAY_PLAYER_TEXT_1, NULL, CHAT_MSG_SAY, LANG_UNIVERSAL, TEXT_RANGE_NORMAL, 0, TEAM_OTHER, false, player); + player->CastSpell(player, SPELL_SUMMONING_RHYME_BONFIRE, true); + break; + case 2: + sCreatureTextMgr->SendChat(caster, SAY_PLAYER_TEXT_2, NULL, CHAT_MSG_SAY, LANG_UNIVERSAL, TEXT_RANGE_NORMAL, 0, TEAM_OTHER, false, player); + break; + case 3: + sCreatureTextMgr->SendChat(caster, SAY_PLAYER_TEXT_3, NULL, CHAT_MSG_SAY, LANG_UNIVERSAL, TEXT_RANGE_NORMAL, 0, TEAM_OTHER, false, player); + Remove(); + break; + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_summoning_rhyme_aura_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_summoning_rhyme_aura_AuraScript(); + } +}; + +// 46878 - Summon Ice Spear Delayer +class spell_summon_ice_spear_delayer : public SpellScriptLoader +{ +public: + spell_summon_ice_spear_delayer() : SpellScriptLoader("spell_summon_ice_spear_delayer") { } + + class spell_summon_ice_spear_delayer_AuraScript : public AuraScript + { + PrepareAuraScript(spell_summon_ice_spear_delayer_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ICE_SPEAR_GO) || !sSpellMgr->GetSpellInfo(SPELL_ICE_SPEAR_KNOCKBACK)) + return false; + return true; + } + + void PeriodicTick(AuraEffect const* aurEff) + { + if (Creature* caster = GetCaster()->ToCreature()) + switch (aurEff->GetTickNumber()) + { + case 1: + caster->CastSpell(caster, SPELL_SUMMON_ICE_SPEAR_GO); + break; + case 3: + if (GameObject* spike = caster->FindNearestGameObject(GO_ICE_SPEAR, 3.0f)) + spike->UseDoorOrButton(); + caster->AI()->DoCastAOE(SPELL_ICE_SPEAR_KNOCKBACK, true); + break; + case 5: + if (GameObject* spike = caster->FindNearestGameObject(GO_ICE_SPEAR, 3.0f)) + spike->Delete(); + caster->DespawnOrUnsummon(); + break; + default: + break; + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_summon_ice_spear_delayer_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_summon_ice_spear_delayer_AuraScript(); + } +}; + +// 46371 - Ice Spear Control Aura +class spell_ice_spear_control_aura : public SpellScriptLoader +{ +public: + spell_ice_spear_control_aura() : SpellScriptLoader("spell_ice_spear_control_aura") { } + + class spell_ice_spear_control_aura_AuraScript : public AuraScript + { + PrepareAuraScript(spell_ice_spear_control_aura_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_ICE_SPEAR_TARGET_PICKER)) + return false; + return true; + } + + void PeriodicTick(AuraEffect const* /*aurEff*/) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(caster, SPELL_ICE_SPEAR_TARGET_PICKER); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_ice_spear_control_aura_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_ice_spear_control_aura_AuraScript(); + } +}; + +// 46372 - Ice Spear Target Picker +class spell_ice_spear_target_picker : public SpellScriptLoader +{ +public: + spell_ice_spear_target_picker() : SpellScriptLoader("spell_ice_spear_target_picker") { } + + class spell_ice_spear_target_picker_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ice_spear_target_picker_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ICE_SPEAR_BUNNY)) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_SUMMON_ICE_SPEAR_BUNNY, true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_ice_spear_target_picker_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ice_spear_target_picker_SpellScript(); + } +}; + +// 46320 - Spell Slippery Floor Periodic +class spell_slippery_floor_periodic : public SpellScriptLoader +{ +public: + spell_slippery_floor_periodic() : SpellScriptLoader("spell_slippery_floor_periodic") { } + + class spell_slippery_floor_periodic_SpellScript : public SpellScript + { + PrepareSpellScript(spell_slippery_floor_periodic_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SLIPPERY_FLOOR_SLIP)) + return false; + return true; + } + + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + if (target->isMoving()) + target->CastSpell(target, SPELL_SLIPPERY_FLOOR_SLIP, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_slippery_floor_periodic_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_slippery_floor_periodic_SpellScript(); + } +}; + +// 46146 - Ahune Spanky Hands +class spell_ahune_spanky_hands : public SpellScriptLoader +{ +public: + spell_ahune_spanky_hands() : SpellScriptLoader("spell_ahune_spanky_hands") { } + + class spell_ahune_spanky_hands_AuraScript : public AuraScript + { + PrepareAuraScript(spell_ahune_spanky_hands_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_COLD_SLAP)) + return false; + return true; + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_COLD_SLAP, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_ahune_spanky_hands_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_ahune_spanky_hands_AuraScript(); + } +}; + +class spell_ahune_minion_despawner : public SpellScriptLoader +{ +public: + spell_ahune_minion_despawner() : SpellScriptLoader("spell_ahune_minion_despawner") { } + + class spell_ahune_minion_despawner_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ahune_minion_despawner_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (GetHitCreature()) + GetHitCreature()->DespawnOrUnsummon(); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_ahune_minion_despawner_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ahune_minion_despawner_SpellScript(); + } +}; + +// 46398 - Spell Ice Bombardment Dest Picker +class spell_ice_bombardment_dest_picker : public SpellScriptLoader +{ +public: + spell_ice_bombardment_dest_picker() : SpellScriptLoader("spell_ice_bombardment_dest_picker") { } + + class spell_ice_bombardment_dest_picker_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ice_bombardment_dest_picker_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_ICE_BOMBARDMENT)) + return false; + return true; + } + + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitDest()->GetPositionX(), GetHitDest()->GetPositionY(), GetHitDest()->GetPositionZ(), SPELL_ICE_BOMBARDMENT, true); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_ice_bombardment_dest_picker_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ice_bombardment_dest_picker_SpellScript(); + } +}; + +void AddSC_boss_ahune() +{ + new boss_ahune(); + new npc_frozen_core(); + new npc_earthen_ring_flamecaller(); + new npc_ahune_bunny(); + new go_ahune_ice_stone(); + new spell_ahune_synch_health(); + new spell_summoning_rhyme_aura(); + new spell_summon_ice_spear_delayer(); + new spell_ice_spear_control_aura(); + new spell_slippery_floor_periodic(); + new spell_ahune_spanky_hands(); + new spell_ahune_minion_despawner(); + new spell_ice_spear_target_picker(); + new spell_ice_bombardment_dest_picker(); +} diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp index 87a07cd1e5e..0d85a8f0d86 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp @@ -31,15 +31,125 @@ class instance_the_slave_pens : public InstanceMapScript public: instance_the_slave_pens() : InstanceMapScript(SPScriptName, 547) { } + struct instance_the_slave_pens_InstanceMapScript : public InstanceScript + { + instance_the_slave_pens_InstanceMapScript(Map* map) : InstanceScript(map) + { + counter = DATA_FLAMECALLER_000; + } + + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) + { + case NPC_AHUNE: + AhuneGUID = creature->GetGUID(); + break; + case NPC_FROZEN_CORE: + FrozenCoreGUID = creature->GetGUID(); + break; + case NPC_AHUNE_LOC_BUNNY: + AhuneBunnyGUID = creature->GetGUID(); + break; + case NPC_SHAMAN_BONFIRE_BUNNY_000: + BonfireBunnyGUIDs[0] = creature->GetGUID(); + break; + case NPC_SHAMAN_BONFIRE_BUNNY_001: + BonfireBunnyGUIDs[1] = creature->GetGUID(); + break; + case NPC_SHAMAN_BONFIRE_BUNNY_002: + BonfireBunnyGUIDs[2] = creature->GetGUID(); + break; + case NPC_SHAMAN_BEAM_BUNNY_000: + BeamBunnyGUIDs[0] = creature->GetGUID(); + break; + case NPC_SHAMAN_BEAM_BUNNY_001: + BeamBunnyGUIDs[1] = creature->GetGUID(); + break; + case NPC_SHAMAN_BEAM_BUNNY_002: + BeamBunnyGUIDs[2] = creature->GetGUID(); + break; + case NPC_LUMA_SKYMOTHER: + LumaGUID = creature->GetGUID(); + break; + case NPC_EARTHEN_RING_FLAMECALLER: + SetGuidData(counter, creature->GetGUID()); + ++counter; + break; + default: + break; + } + } + + void SetGuidData(uint32 data, ObjectGuid guid) + { + switch (data) + { + case DATA_FLAMECALLER_000: + FlameCallerGUIDs[0] = guid; + break; + case DATA_FLAMECALLER_001: + FlameCallerGUIDs[1] = guid; + break; + case DATA_FLAMECALLER_002: + FlameCallerGUIDs[2] = guid; + break; + default: + break; + } + } + + ObjectGuid GetGuidData(uint32 type) const override + { + switch (type) + { + case DATA_AHUNE: + return AhuneGUID; + case DATA_AHUNE_BUNNY: + return AhuneBunnyGUID; + case DATA_FROZEN_CORE: + return FrozenCoreGUID; + case DATA_FLAMECALLER_000: + return FlameCallerGUIDs[0]; + case DATA_FLAMECALLER_001: + return FlameCallerGUIDs[1]; + case DATA_FLAMECALLER_002: + return FlameCallerGUIDs[2]; + case DATA_BONFIRE_BUNNY_000: + return BonfireBunnyGUIDs[0]; + case DATA_BONFIRE_BUNNY_001: + return BonfireBunnyGUIDs[1]; + case DATA_BONFIRE_BUNNY_002: + return BonfireBunnyGUIDs[2]; + case DATA_BEAM_BUNNY_000: + return BeamBunnyGUIDs[0]; + case DATA_BEAM_BUNNY_001: + return BeamBunnyGUIDs[1]; + case DATA_BEAM_BUNNY_002: + return BeamBunnyGUIDs[2]; + case DATA_LUMA_SKYMOTHER: + return LumaGUID; + default: + break; + } + return ObjectGuid::Empty; + } + + protected: + ObjectGuid AhuneGUID; + ObjectGuid AhuneBunnyGUID; + ObjectGuid FrozenCoreGUID; + ObjectGuid LumaGUID; + ObjectGuid FlameCallerGUIDs[3]; + ObjectGuid BonfireBunnyGUIDs[3]; + ObjectGuid BeamBunnyGUIDs[3]; + uint8 counter; + }; + InstanceScript* GetInstanceScript(InstanceMap* map) const override { return new instance_the_slave_pens_InstanceMapScript(map); } - - struct instance_the_slave_pens_InstanceMapScript : public InstanceScript - { - instance_the_slave_pens_InstanceMapScript(Map* map) : InstanceScript(map) { } - }; }; void AddSC_instance_the_slave_pens() diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h index 95e6e44121e..544e98fd206 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h @@ -27,7 +27,43 @@ enum DataTypes { DATA_MENNU_THE_BETRAYER = 1, DATA_ROKMAR_THE_CRACKLER = 2, - DATA_QUAGMIRRAN = 3 + DATA_QUAGMIRRAN = 3, + DATA_AHUNE = 4, + DATA_AHUNE_BUNNY = 5, + DATA_FROZEN_CORE = 6, + DATA_FLAMECALLER_000 = 7, + DATA_FLAMECALLER_001 = 8, + DATA_FLAMECALLER_002 = 9, + DATA_BONFIRE_BUNNY_000 = 10, + DATA_BONFIRE_BUNNY_001 = 11, + DATA_BONFIRE_BUNNY_002 = 12, + DATA_BEAM_BUNNY_000 = 13, + DATA_BEAM_BUNNY_001 = 14, + DATA_BEAM_BUNNY_002 = 15, + DATA_LUMA_SKYMOTHER = 16 +}; + +enum CreaturesIds +{ + NPC_AHUNE = 25740, + NPC_FROZEN_CORE = 25865, + NPC_LUMA_SKYMOTHER = 25697, + NPC_AHUNE_LOC_BUNNY = 25745, + NPC_EARTHEN_RING_FLAMECALLER = 25754, + NPC_SHAMAN_BONFIRE_BUNNY_000 = 25971, + NPC_SHAMAN_BONFIRE_BUNNY_001 = 25972, + NPC_SHAMAN_BONFIRE_BUNNY_002 = 25973, + NPC_SHAMAN_BEAM_BUNNY_000 = 25964, + NPC_SHAMAN_BEAM_BUNNY_001 = 25965, + NPC_SHAMAN_BEAM_BUNNY_002 = 25966, + NPC_WHISP_DEST_BUNNY = 26120, + NPC_WHISP_SOURCE_BUNNY = 26121 +}; + +enum GameObjectIds +{ + GO_ICE_SPEAR = 188077, + GO_ICE_STONE = 187882 }; #endif // SLAVE_PENS_H diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp index 4e20e6b0953..9b8220596c9 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp @@ -372,7 +372,7 @@ class boss_vazruden_the_herald : public CreatureScript if (summon->GetEntry() == NPC_NAZAN) { summon->SetDisableGravity(true); - summon->SetSpeed(MOVE_FLIGHT, 2.5f); + summon->SetSpeedRate(MOVE_FLIGHT, 2.5f); if (victim) AttackStartNoMove(victim); } diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp index 4faab709e16..c29d560529d 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp @@ -109,7 +109,7 @@ class boss_warchief_kargath_bladefist : public CreatureScript { removeAdds(); _Reset(); - me->SetSpeed(MOVE_RUN, 2); + me->SetSpeedRate(MOVE_RUN, 2); me->SetWalk(false); Initialize(); @@ -231,7 +231,7 @@ class boss_warchief_kargath_bladefist : public CreatureScript { // stop bladedance InBlade = false; - me->SetSpeed(MOVE_RUN, 2); + me->SetSpeedRate(MOVE_RUN, 2); me->GetMotionMaster()->MoveChase(me->GetVictim()); Blade_Dance_Timer = 30000; Wait_Timer = 0; @@ -264,7 +264,7 @@ class boss_warchief_kargath_bladefist : public CreatureScript Wait_Timer = 1; InBlade = true; Blade_Dance_Timer = 0; - me->SetSpeed(MOVE_RUN, 4); + me->SetSpeedRate(MOVE_RUN, 4); return; } else diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp index 102d567e810..20d96ecd29c 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp @@ -130,7 +130,7 @@ class boss_alar : public CreatureScript _Reset(); me->SetDisplayId(me->GetNativeDisplayId()); - me->SetSpeed(MOVE_RUN, DefaultMoveSpeedRate); + me->SetSpeedRate(MOVE_RUN, DefaultMoveSpeedRate); //me->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 10); //me->SetFloatValue(UNIT_FIELD_COMBATREACH, 10); me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true); @@ -178,7 +178,7 @@ class boss_alar : public CreatureScript me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); me->AttackStop(); me->SetTarget(ObjectGuid::Empty); - me->SetSpeed(MOVE_RUN, 5.0f); + me->SetSpeedRate(MOVE_RUN, 5.0f); me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePoint(0, waypoint[5][0], waypoint[5][1], waypoint[5][2]); } @@ -261,7 +261,7 @@ class boss_alar : public CreatureScript case WE_REVIVE: me->SetUInt32Value(UNIT_FIELD_BYTES_1, UNIT_STAND_STATE_STAND); me->SetFullHealth(); - me->SetSpeed(MOVE_RUN, DefaultMoveSpeedRate); + me->SetSpeedRate(MOVE_RUN, DefaultMoveSpeedRate); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); DoZoneInCombat(); DoCast(me, SPELL_REBIRTH, true); @@ -289,6 +289,7 @@ class boss_alar : public CreatureScript me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f); me->StopMoving(); WaitEvent = WE_LAND; + return; } else { diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp index 46388c3a185..edfa2aedf92 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,13 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Void_Reaver -SD%Complete: 90 -SDComment: Should reset if raid are out of room. -SDCategory: Tempest Keep, The Eye -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "the_eye.h" @@ -43,10 +35,17 @@ enum Spells SPELL_BERSERK = 27680 }; +enum Events +{ + EVENT_POUNDING = 1, + EVENT_ARCANE_ORB, + EVENT_KNOCK_AWAY, + EVENT_BERSERK +}; + class boss_void_reaver : public CreatureScript { public: - boss_void_reaver() : CreatureScript("boss_void_reaver") { } struct boss_void_reaverAI : public BossAI @@ -58,21 +57,9 @@ class boss_void_reaver : public CreatureScript void Initialize() { - Pounding_Timer = 15000; - ArcaneOrb_Timer = 3000; - KnockAway_Timer = 30000; - Berserk_Timer = 600000; - Enraged = false; } - uint32 Pounding_Timer; - uint32 ArcaneOrb_Timer; - uint32 KnockAway_Timer; - uint32 Berserk_Timer; - - bool Enraged; - void Reset() override { Initialize(); @@ -95,71 +82,84 @@ class boss_void_reaver : public CreatureScript { Talk(SAY_AGGRO); _EnterCombat(); + + events.ScheduleEvent(EVENT_POUNDING, 15000); + events.ScheduleEvent(EVENT_ARCANE_ORB, 3000); + events.ScheduleEvent(EVENT_KNOCK_AWAY, 30000); + events.ScheduleEvent(EVENT_BERSERK, 600000); } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; - // Pounding - if (Pounding_Timer <= diff) - { - DoCastVictim(SPELL_POUNDING); - Talk(SAY_POUNDING); - Pounding_Timer = 15000; //cast time(3000) + cooldown time(12000) - } - else - Pounding_Timer -= diff; - // Arcane Orb - if (ArcaneOrb_Timer <= diff) - { - Unit* target = NULL; - std::list<HostileReference*> t_list = me->getThreatManager().getThreatList(); - std::vector<Unit*> target_list; - for (std::list<HostileReference*>::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); - if (!target) - continue; - // exclude pets & totems, 18 yard radius minimum - if (target->GetTypeId() == TYPEID_PLAYER && target->IsAlive() && !target->IsWithinDist(me, 18, false)) - target_list.push_back(target); - target = NULL; - } - if (!target_list.empty()) - target = *(target_list.begin() + rand32() % target_list.size()); - else - target = me->GetVictim(); + events.Update(diff); - if (target) - me->CastSpell(target, SPELL_ARCANE_ORB, false, NULL, NULL); - ArcaneOrb_Timer = 3000; - } - else - ArcaneOrb_Timer -= diff; - // Single Target knock back, reduces aggro - if (KnockAway_Timer <= diff) - { - DoCastVictim(SPELL_KNOCK_AWAY); - //Drop 25% aggro - if (DoGetThreat(me->GetVictim())) - DoModifyThreatPercent(me->GetVictim(), -25); - KnockAway_Timer = 30000; - } - else - KnockAway_Timer -= diff; - //Berserk - if (Berserk_Timer < diff && !Enraged) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - DoCast(me, SPELL_BERSERK); - Enraged = true; + switch (eventId) + { + case EVENT_POUNDING: + DoCastVictim(SPELL_POUNDING); + Talk(SAY_POUNDING); + events.ScheduleEvent(EVENT_POUNDING, 15000); + break; + case EVENT_ARCANE_ORB: + { + Unit* target = NULL; + std::list<HostileReference*> t_list = me->getThreatManager().getThreatList(); + std::vector<Unit*> target_list; + for (std::list<HostileReference*>::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr) + { + target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); + if (!target) + continue; + // exclude pets & totems, 18 yard radius minimum + if (target->GetTypeId() == TYPEID_PLAYER && target->IsAlive() && !target->IsWithinDist(me, 18, false)) + target_list.push_back(target); + target = NULL; + } + + if (!target_list.empty()) + target = *(target_list.begin() + rand32() % target_list.size()); + else + target = me->GetVictim(); + + if (target) + me->CastSpell(target, SPELL_ARCANE_ORB, false, NULL, NULL); + + events.ScheduleEvent(EVENT_ARCANE_ORB, 3000); + break; + } + case EVENT_KNOCK_AWAY: + DoCastVictim(SPELL_KNOCK_AWAY); + // Drop 25% aggro + if (DoGetThreat(me->GetVictim())) + DoModifyThreatPercent(me->GetVictim(), -25); + + events.ScheduleEvent(EVENT_KNOCK_AWAY, 30000); + break; + case EVENT_BERSERK: + if (!Enraged) + { + DoCast(me, SPELL_BERSERK); + Enraged = true; + } + break; + default: + break; + } } - else - Berserk_Timer -= diff; DoMeleeAttackIfReady(); } + + private: + bool Enraged; }; CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp index 3aa2674aec6..d45e17bd28d 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp @@ -176,7 +176,7 @@ class npc_ragin_flames : public CreatureScript Initialize(); me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); - me->SetSpeed(MOVE_RUN, DUNGEON_MODE(0.5f, 0.7f)); + me->SetSpeedRate(MOVE_RUN, DUNGEON_MODE(0.5f, 0.7f)); } void EnterCombat(Unit* /*who*/) override diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp index 856649c6c5e..e64c0fe9f5e 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp @@ -167,7 +167,7 @@ class boss_warp_splinter : public CreatureScript { Initialize(); - me->SetSpeed(MOVE_RUN, 0.7f, true); + me->SetSpeedRate(MOVE_RUN, 0.7f); } void EnterCombat(Unit* /*who*/) override diff --git a/src/server/scripts/Outland/outland_script_loader.cpp b/src/server/scripts/Outland/outland_script_loader.cpp index 91ba4e5689f..ed2c21da6c3 100644 --- a/src/server/scripts/Outland/outland_script_loader.cpp +++ b/src/server/scripts/Outland/outland_script_loader.cpp @@ -72,6 +72,7 @@ void AddSC_instance_the_slave_pens(); void AddSC_boss_mennu_the_betrayer(); void AddSC_boss_rokmar_the_crackler(); void AddSC_boss_quagmirran(); +void AddSC_boss_ahune(); // Coilfang Reservoir - The Underbog void AddSC_instance_the_underbog(); @@ -193,6 +194,7 @@ void AddOutlandScripts() AddSC_boss_mennu_the_betrayer(); AddSC_boss_rokmar_the_crackler(); AddSC_boss_quagmirran(); + AddSC_boss_ahune(); // Coilfang Reservoir - The Underbog AddSC_instance_the_underbog(); diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index 404cdc7ceb2..668c484dd63 100644 --- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp +++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp @@ -159,7 +159,7 @@ public: else TC_LOG_ERROR("scripts", "TRINITY: npc_ancestral_wolf can not obtain owner or owner is not a player."); - creature->SetSpeed(MOVE_WALK, 1.5f); + creature->SetSpeedRate(MOVE_WALK, 1.5f); Reset(); } @@ -192,7 +192,7 @@ public: if (ryga->IsAlive() && !ryga->IsInCombat()) { ryga->SetWalk(true); - ryga->SetSpeed(MOVE_WALK, 1.5f); + ryga->SetSpeedRate(MOVE_WALK, 1.5f); ryga->GetMotionMaster()->MovePoint(0, 517.340698f, 3885.03975f, 190.455978f, true); Reset(); } @@ -778,7 +778,7 @@ public: me->AddAura(SPELL_JULES_THREATENS_AURA, me); me->SetCanFly(true); - me->SetSpeed(MOVE_RUN, 0.2f); + me->SetSpeedRate(MOVE_RUN, 0.2f); me->SetFacingTo(3.207566f); me->GetMotionMaster()->MoveJump(exorcismPos[2], 2.0f, 2.0f); @@ -798,7 +798,7 @@ public: break; case ACTION_JULES_MOVE_HOME: wpreached = false; - me->SetSpeed(MOVE_RUN, 1.0f); + me->SetSpeedRate(MOVE_RUN, 1.0f); me->GetMotionMaster()->MovePoint(11, exorcismPos[2]); events.CancelEvent(EVENT_SUMMON_SKULL); diff --git a/src/server/scripts/Pet/pet_dk.cpp b/src/server/scripts/Pet/pet_dk.cpp index 80b3a00774b..113b14a0d54 100644 --- a/src/server/scripts/Pet/pet_dk.cpp +++ b/src/server/scripts/Pet/pet_dk.cpp @@ -103,8 +103,8 @@ class npc_pet_dk_ebon_gargoyle : public CreatureScript //! HACK: Creature's can't have MOVEMENTFLAG_FLYING // Fly Away me->SetCanFly(true); - me->SetSpeed(MOVE_FLIGHT, 0.75f, true); - me->SetSpeed(MOVE_RUN, 0.75f, true); + me->SetSpeedRate(MOVE_FLIGHT, 0.75f); + me->SetSpeedRate(MOVE_RUN, 0.75f); float x = me->GetPositionX() + 20 * std::cos(me->GetOrientation()); float y = me->GetPositionY() + 20 * std::sin(me->GetOrientation()); float z = me->GetPositionZ() + 40; diff --git a/src/server/scripts/Pet/pet_generic.cpp b/src/server/scripts/Pet/pet_generic.cpp index 0ec6f08ae58..ff57bc0415c 100644 --- a/src/server/scripts/Pet/pet_generic.cpp +++ b/src/server/scripts/Pet/pet_generic.cpp @@ -21,9 +21,10 @@ */ /* ContentData - npc_pet_gen_egbert 100% Egbert run's around - npc_pet_gen_pandaren_monk 100% Pandaren Monk drinks and bows with you - npc_pet_gen_mojo 100% Mojo follows you when you kiss it + npc_pet_gen_baby_blizzard_bear 100% Baby Blizzard Bear sits down occasionally + npc_pet_gen_egbert 100% Egbert run's around + npc_pet_gen_pandaren_monk 100% Pandaren Monk drinks and bows with you + npc_pet_gen_mojo 100% Mojo follows you when you kiss it EndContentData */ #include "ScriptMgr.h" @@ -31,6 +32,63 @@ #include "PassiveAI.h" #include "Player.h" +enum BabyBlizzardBearMisc +{ + SPELL_BBB_PET_SIT = 61853, + EVENT_BBB_PET_SIT = 1, + EVENT_BBB_PET_SIT_INTER = 2 +}; + +class npc_pet_gen_baby_blizzard_bear : public CreatureScript +{ +public: + npc_pet_gen_baby_blizzard_bear() : CreatureScript("npc_pet_gen_baby_blizzard_bear") {} + + struct npc_pet_gen_baby_blizzard_bearAI : public NullCreatureAI + { + npc_pet_gen_baby_blizzard_bearAI(Creature* creature) : NullCreatureAI(creature) + { + if (Unit* owner = me->GetCharmerOrOwner()) + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle()); + _events.ScheduleEvent(EVENT_BBB_PET_SIT, urandms(10, 30)); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + if (Unit* owner = me->GetCharmerOrOwner()) + if (!me->IsWithinDist(owner, 25.f)) + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BBB_PET_SIT: + me->CastSpell(me, SPELL_BBB_PET_SIT, false); + _events.ScheduleEvent(EVENT_BBB_PET_SIT_INTER, urandms(15, 30)); + break; + case EVENT_BBB_PET_SIT_INTER: + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + _events.ScheduleEvent(EVENT_BBB_PET_SIT, urandms(10, 30)); + break; + default: + break; + } + } + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_pet_gen_baby_blizzard_bearAI(creature); + } +}; + enum EgbertMisc { SPELL_EGBERT = 40669, @@ -260,6 +318,7 @@ class npc_pet_gen_mojo : public CreatureScript void AddSC_generic_pet_scripts() { + new npc_pet_gen_baby_blizzard_bear(); new npc_pet_gen_egbert(); new npc_pet_gen_pandaren_monk(); new npc_pet_gen_mojo(); diff --git a/src/server/scripts/ScriptLoader.cpp.in.cmake b/src/server/scripts/ScriptLoader.cpp.in.cmake new file mode 100644 index 00000000000..33c336a9a93 --- /dev/null +++ b/src/server/scripts/ScriptLoader.cpp.in.cmake @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// This file was created automatically from your script configuration! +// Use CMake to reconfigure this file, never change it on your own! + +#cmakedefine TRINITY_IS_DYNAMIC_SCRIPTLOADER + +#include "Define.h" +#include <vector> +#include <string> + +@TRINITY_SCRIPTS_FORWARD_DECL@ +#ifdef TRINITY_IS_DYNAMIC_SCRIPTLOADER +# include "revision_data.h" +# define TC_SCRIPT_API TC_API_EXPORT +extern "C" { + +/// Exposed in script modules to return the script module revision hash. +TC_SCRIPT_API char const* GetScriptModuleRevisionHash() +{ + return _HASH; +} + +/// Exposed in script module to return the name of the script module +/// contained in this shared library. +TC_SCRIPT_API char const* GetScriptModule() +{ + return "@TRINITY_CURRENT_SCRIPT_PROJECT@"; +} + +#else +# include "ScriptLoader.h" +# define TC_SCRIPT_API +#endif + +/// Exposed in script modules to register all scripts to the ScriptMgr. +TC_SCRIPT_API void AddScripts() +{ +@TRINITY_SCRIPTS_INVOKE@} + +/// Exposed in script modules to get the build directive of the module. +TC_SCRIPT_API char const* GetBuildDirective() +{ + return _BUILD_DIRECTIVE; +} + +#ifdef TRINITY_IS_DYNAMIC_SCRIPTLOADER +} // extern "C" +#endif diff --git a/src/server/game/Scripting/ScriptLoader.h b/src/server/scripts/ScriptLoader.h index 57b62df22d1..57b62df22d1 100644 --- a/src/server/game/Scripting/ScriptLoader.h +++ b/src/server/scripts/ScriptLoader.h diff --git a/src/server/scripts/PrecompiledHeaders/ScriptPCH.cpp b/src/server/scripts/ScriptPCH.cpp index 41fecf3c60d..41fecf3c60d 100644 --- a/src/server/scripts/PrecompiledHeaders/ScriptPCH.cpp +++ b/src/server/scripts/ScriptPCH.cpp diff --git a/src/server/scripts/PrecompiledHeaders/ScriptPCH.h b/src/server/scripts/ScriptPCH.h index 1cd25309055..1cd25309055 100644 --- a/src/server/scripts/PrecompiledHeaders/ScriptPCH.h +++ b/src/server/scripts/ScriptPCH.h diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 7c2bb0bfaa5..724019a1b19 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -65,8 +65,6 @@ enum DeathKnightSpells SPELL_DK_UNHOLY_PRESENCE_TRIGGERED = 49772, SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189, SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284, - SPELL_DK_RAISE_ALLY_INITIAL = 61999, - SPELL_DK_RAISE_ALLY = 46619, SPELL_DK_GHOUL_THRASH = 47480 }; @@ -228,7 +226,7 @@ class spell_dk_anti_magic_zone : public SpellScriptLoader void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/) { - SpellInfo const* talentSpell = sSpellMgr->EnsureSpellInfo(SPELL_DK_ANTI_MAGIC_SHELL_TALENT); + SpellInfo const* talentSpell = sSpellMgr->AssertSpellInfo(SPELL_DK_ANTI_MAGIC_SHELL_TALENT); amount = talentSpell->Effects[EFFECT_0].CalcValue(GetCaster()); if (Player* player = GetCaster()->ToPlayer()) amount += int32(2 * player->GetTotalAttackPowerValue(BASE_ATTACK)); @@ -1636,7 +1634,7 @@ class spell_dk_will_of_the_necropolis : public SpellScriptLoader { // min pct of hp is stored in effect 0 of talent spell uint8 rank = GetSpellInfo()->GetRank(); - SpellInfo const* talentProto = sSpellMgr->EnsureSpellInfo(sSpellMgr->GetSpellWithRank(SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1, rank)); + SpellInfo const* talentProto = sSpellMgr->AssertSpellInfo(sSpellMgr->GetSpellWithRank(SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1, rank)); int32 remainingHp = int32(GetTarget()->GetHealth() - dmgInfo.GetDamage()); int32 minHp = int32(GetTarget()->CountPctFromMaxHealth(talentProto->Effects[EFFECT_0].CalcValue(GetCaster()))); @@ -1733,36 +1731,39 @@ public: { PrepareSpellScript(spell_dk_raise_ally_initial_SpellScript); - bool Validate(SpellInfo const* /*spellInfo*/) override + bool Validate(SpellInfo const* spellInfo) override { - if (!sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_ALLY_INITIAL)) + if (!sSpellMgr->GetSpellInfo(uint32(spellInfo->Effects[EFFECT_0].CalcValue()))) return false; return true; } + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + SpellCastResult CheckCast() { - // Raise Ally cannot be casted on alive players Unit* target = GetExplTargetUnit(); if (!target) return SPELL_FAILED_NO_VALID_TARGETS; if (target->IsAlive()) return SPELL_FAILED_TARGET_NOT_DEAD; - if (Player* playerCaster = GetCaster()->ToPlayer()) - if (playerCaster->InArena()) - return SPELL_FAILED_NOT_IN_ARENA; if (target->IsGhouled()) return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; - return SPELL_CAST_OK; } void HandleDummy(SpellEffIndex /*effIndex*/) { - Player* caster = GetCaster()->ToPlayer(); - Player* target = GetHitPlayer(); - if (caster && target) - caster->SendGhoulResurrectRequest(target); + if (Player* target = GetHitPlayer()) + { + if (target->IsResurrectRequested()) // already have one active request + return; + target->SetResurrectRequestData(GetCaster(), 0, 0, uint32(GetEffectValue())); + GetSpell()->SendResurrectRequest(target); + } } void Register() override @@ -1785,12 +1786,8 @@ class player_ghoulAI : public PlayerAI void UpdateAI(uint32 /*diff*/) override { - if (Creature* ghoul = ObjectAccessor::GetCreature(*me, _ghoulGUID)) - { - if (!ghoul->IsAlive()) - me->RemoveAura(SPELL_DK_RAISE_ALLY); - } - else + Creature* ghoul = ObjectAccessor::GetCreature(*me, _ghoulGUID); + if (!ghoul || !ghoul->IsAlive()) me->RemoveAura(SPELL_DK_RAISE_ALLY); } @@ -1799,28 +1796,25 @@ class player_ghoulAI : public PlayerAI }; // 46619 - Raise Ally +#define DkRaiseAllyScriptName "spell_dk_raise_ally" class spell_dk_raise_ally : public SpellScriptLoader { public: - spell_dk_raise_ally() : SpellScriptLoader("spell_dk_raise_ally") { } + spell_dk_raise_ally() : SpellScriptLoader(DkRaiseAllyScriptName) { } class spell_dk_raise_ally_SpellScript : public SpellScript { PrepareSpellScript(spell_dk_raise_ally_SpellScript); - bool Validate(SpellInfo const* /*spellInfo*/) override + bool Load() override { - if (!sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_ALLY)) - return false; - return true; + return GetCaster()->GetTypeId() == TYPEID_PLAYER; } void SendText() { - Player* caster = GetCaster()->ToPlayer(); - Unit* original = GetOriginalCaster(); - if (caster && original) - original->Whisper(TEXT_RISE_ALLY, caster, true); + if (Unit* original = GetOriginalCaster()) + original->Whisper(TEXT_RISE_ALLY, GetCaster()->ToPlayer(), true); } void HandleSummon(SpellEffIndex effIndex) @@ -1839,9 +1833,8 @@ public: SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(829); uint32 duration = uint32(GetSpellInfo()->GetDuration()); - Position pos = caster->GetPosition(); - TempSummon* summon = originalCaster->GetMap()->SummonCreature(entry, pos, properties, duration, originalCaster, GetSpellInfo()->Id); + TempSummon* summon = originalCaster->GetMap()->SummonCreature(entry, *GetHitDest(), properties, duration, originalCaster, GetSpellInfo()->Id); if (!summon) return; @@ -1868,15 +1861,25 @@ public: // SMSG_POWER_UPDATE is sent summon->SetMaxPower(POWER_ENERGY, 100); - if (Player* player = GetCaster()->ToPlayer()) - player->SetGhoulResurrectGhoulGUID(summon->GetGUID()); + _ghoulGuid = summon->GetGUID(); + } + + void SetGhoul(SpellEffIndex /*effIndex*/) + { + if (Aura* aura = GetHitAura()) + if (spell_dk_raise_ally_AuraScript* script = dynamic_cast<spell_dk_raise_ally_AuraScript*>(aura->GetScriptByName(DkRaiseAllyScriptName))) + script->SetGhoulGuid(_ghoulGuid); } void Register() override { AfterHit += SpellHitFn(spell_dk_raise_ally_SpellScript::SendText); OnEffectHit += SpellEffectFn(spell_dk_raise_ally_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON); + OnEffectHitTarget += SpellEffectFn(spell_dk_raise_ally_SpellScript::SetGhoul, EFFECT_1, SPELL_EFFECT_APPLY_AURA); } + + private: + ObjectGuid _ghoulGuid; }; SpellScript* GetSpellScript() const override @@ -1895,31 +1898,32 @@ public: oldAIState = false; } + void SetGhoulGuid(ObjectGuid guid) + { + ghoulGuid = guid; + } + private: - bool Validate(SpellInfo const* /*spellInfo*/) override + bool Load() override { - if (!sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_ALLY)) - return false; - return true; + return GetUnitOwner()->GetTypeId() == TYPEID_PLAYER; } void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Player* player = GetTarget()->ToPlayer(); - if (!player || player->GetGhoulResurrectGhoulGUID().IsEmpty()) + if (ghoulGuid.IsEmpty()) return; oldAI = player->AI(); oldAIState = player->IsAIEnabled; - player->SetAI(new player_ghoulAI(player, player->GetGhoulResurrectGhoulGUID())); + player->SetAI(new player_ghoulAI(player, ghoulGuid)); player->IsAIEnabled = true; } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Player* player = GetTarget()->ToPlayer(); - if (!player) - return; player->IsAIEnabled = oldAIState; PlayerAI* thisAI = player->AI(); @@ -1927,13 +1931,12 @@ public: delete thisAI; // Dismiss ghoul if necessary - if (Creature* ghoul = ObjectAccessor::GetCreature(*player, player->GetGhoulResurrectGhoulGUID())) + if (Creature* ghoul = ObjectAccessor::GetCreature(*player, ghoulGuid)) { - ghoul->RemoveCharmedBy(nullptr); + ghoul->RemoveCharmedBy(player); ghoul->DespawnOrUnsummon(1000); } - player->SetGhoulResurrectGhoulGUID(ObjectGuid::Empty); player->RemoveAura(SPELL_GHOUL_FRENZY); } @@ -1943,6 +1946,7 @@ public: AfterEffectRemove += AuraEffectRemoveFn(spell_dk_raise_ally_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } + ObjectGuid ghoulGuid; PlayerAI* oldAI; bool oldAIState; }; @@ -1965,7 +1969,7 @@ public: bool Validate(SpellInfo const* /*spellInfo*/) override { - if (!sSpellMgr->GetSpellInfo(SPELL_DK_GHOUL_THRASH)) + if (!sSpellMgr->GetSpellInfo(SPELL_GHOUL_FRENZY)) return false; return true; } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index abde43ef952..8b8c5300a9e 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1245,7 +1245,7 @@ class spell_gen_defend : public SpellScriptLoader void Register() override { - SpellInfo const* spell = sSpellMgr->EnsureSpellInfo(m_scriptSpellId); + SpellInfo const* spell = sSpellMgr->AssertSpellInfo(m_scriptSpellId); // Defend spells cast by NPCs (add visuals) if (spell->Effects[EFFECT_0].ApplyAuraName == SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN) @@ -2148,7 +2148,7 @@ class spell_gen_mounted_charge: public SpellScriptLoader void Register() override { - SpellInfo const* spell = sSpellMgr->EnsureSpellInfo(m_scriptSpellId); + SpellInfo const* spell = sSpellMgr->AssertSpellInfo(m_scriptSpellId); if (spell->HasEffect(SPELL_EFFECT_SCRIPT_EFFECT)) OnEffectHitTarget += SpellEffectFn(spell_gen_mounted_charge_SpellScript::HandleScriptEffect, EFFECT_FIRST_FOUND, SPELL_EFFECT_SCRIPT_EFFECT); @@ -4155,6 +4155,40 @@ public: } }; +// 34098 - ClearAllDebuffs +class spell_gen_clear_debuffs : public SpellScriptLoader +{ + public: + spell_gen_clear_debuffs() : SpellScriptLoader("spell_gen_clear_debuffs") { } + + class spell_gen_clear_debuffs_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_clear_debuffs_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + target->RemoveOwnedAuras([](Aura const* aura) + { + SpellInfo const* spellInfo = aura->GetSpellInfo(); + return !spellInfo->IsPositive() && !spellInfo->IsPassive(); + }); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gen_clear_debuffs_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gen_clear_debuffs_SpellScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -4241,4 +4275,5 @@ void AddSC_generic_spell_scripts() new spell_gen_stand(); new spell_gen_mixology_bonus(); new spell_gen_landmine_knockback_achievement(); + new spell_gen_clear_debuffs(); } diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp index a3359fdf6f9..6442eb8acca 100644 --- a/src/server/scripts/Spells/spell_holiday.cpp +++ b/src/server/scripts/Spells/spell_holiday.cpp @@ -65,7 +65,7 @@ class spell_love_is_in_the_air_romantic_picnic : public SpellScriptLoader Unit* caster = GetCaster(); // If our player is no longer sit, remove all auras - if (target->getStandState() != UNIT_STAND_STATE_SIT) + if (target->GetStandState() != UNIT_STAND_STATE_SIT) { target->RemoveAura(SPELL_ROMANTIC_PICNIC_ACHIEV); target->RemoveAura(GetAura()); @@ -84,7 +84,7 @@ class spell_love_is_in_the_air_romantic_picnic : public SpellScriptLoader target->VisitNearbyWorldObject(INTERACTION_DISTANCE*2, searcher); for (std::list<Player*>::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr) { - if ((*itr) != target && (*itr)->HasAura(GetId())) // && (*itr)->getStandState() == UNIT_STAND_STATE_SIT) + if ((*itr) != target && (*itr)->HasAura(GetId())) // && (*itr)->GetStandState() == UNIT_STAND_STATE_SIT) { if (caster) { diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index c927750e968..82d9d134445 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -193,8 +193,8 @@ class spell_hun_chimera_shot : public SpellScriptLoader { uint32 spellId = 0; int32 basePoint = 0; - Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator i = Auras.begin(); i != Auras.end(); ++i) + Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator i = auras.begin(); i != auras.end(); ++i) { Aura* aura = i->second->GetBase(); if (aura->GetCasterGUID() != caster->GetGUID()) @@ -318,12 +318,15 @@ class spell_hun_glyph_of_arcane_shot : public SpellScriptLoader { if (Unit* procTarget = eventInfo.GetProcTarget()) { - Unit::AuraApplicationMap& auras = procTarget->GetAppliedAuras(); + Unit::AuraApplicationMap const& auras = procTarget->GetAppliedAuras(); for (Unit::AuraApplicationMap::const_iterator i = auras.begin(); i != auras.end(); ++i) { - SpellInfo const* spellInfo = i->second->GetBase()->GetSpellInfo(); + Aura const* aura = i->second->GetBase(); + if (aura->GetCasterGUID() != GetTarget()->GetGUID()) + continue; // Search only Serpent Sting, Viper Sting, Scorpid Sting, Wyvern Sting - if (spellInfo->SpellFamilyFlags.HasFlag(0xC000, 0x1080) && spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER) + if (aura->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_HUNTER + && aura->GetSpellInfo()->SpellFamilyFlags.HasFlag(0xC000, 0x1080)) return true; } } @@ -760,7 +763,7 @@ class spell_hun_readiness : public SpellScriptLoader // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); ///! If spellId in cooldown map isn't valid, the above will return a null pointer. if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index d08968fbf55..2f4e4fa6f44 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -180,7 +180,7 @@ class spell_mage_cold_snap : public SpellScriptLoader { GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); return spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && spellInfo->Id != SPELL_MAGE_COLD_SNAP && spellInfo->GetRecoveryTime() > 0; }, true); @@ -405,7 +405,7 @@ class spell_mage_ignite : public SpellScriptLoader { PreventDefaultAction(); - SpellInfo const* igniteDot = sSpellMgr->EnsureSpellInfo(SPELL_MAGE_IGNITE); + SpellInfo const* igniteDot = sSpellMgr->AssertSpellInfo(SPELL_MAGE_IGNITE); int32 pct = 8 * GetSpellInfo()->GetRank(); int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), pct) / igniteDot->GetMaxTicks()); diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index 8bd4b3eb070..d9fd36f5fd4 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -1195,7 +1195,7 @@ class spell_pal_light_s_beacon : public SpellScriptLoader if (!procSpell) return; - uint32 healSpellId = procSpell->IsRankOf(sSpellMgr->EnsureSpellInfo(SPELL_PALADIN_HOLY_LIGHT)) ? SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_1 : SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_3; + uint32 healSpellId = procSpell->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PALADIN_HOLY_LIGHT)) ? SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_1 : SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_3; uint32 heal = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), aurEff->GetAmount()); Unit* beaconTarget = GetCaster(); diff --git a/src/server/scripts/Spells/spell_pet.cpp b/src/server/scripts/Spells/spell_pet.cpp index 7393a7d3bcb..cde291cd82b 100644 --- a/src/server/scripts/Spells/spell_pet.cpp +++ b/src/server/scripts/Spells/spell_pet.cpp @@ -916,7 +916,7 @@ public: if (itr != pet->ToPet()->m_spells.end()) // If pet has Wild Hunt { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value AddPct(mod, spellInfo->Effects[EFFECT_0].CalcValue()); } @@ -959,7 +959,7 @@ public: if (itr != pet->ToPet()->m_spells.end()) // If pet has Wild Hunt { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value mod += CalculatePct(1.0f, spellInfo->Effects[EFFECT_1].CalcValue()); } @@ -989,7 +989,7 @@ public: if (itr != pet->ToPet()->m_spells.end()) // If pet has Wild Hunt { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value mod += CalculatePct(1.0f, spellInfo->Effects[EFFECT_1].CalcValue()); } diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index ecf5b7b5acf..51f03346df1 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -236,7 +236,7 @@ class spell_pri_glyph_of_prayer_of_healing : public SpellScriptLoader { PreventDefaultAction(); - SpellInfo const* triggeredSpellInfo = sSpellMgr->EnsureSpellInfo(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL); + SpellInfo const* triggeredSpellInfo = sSpellMgr->AssertSpellInfo(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL); int32 heal = int32(CalculatePct(int32(eventInfo.GetHealInfo()->GetHeal()), aurEff->GetAmount()) / triggeredSpellInfo->GetMaxTicks()); GetTarget()->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL, SPELLVALUE_BASE_POINT0, heal, eventInfo.GetProcTarget(), true, NULL, aurEff); } diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index 9b577d4e140..affc4d1c26c 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -450,7 +450,7 @@ class spell_rog_preparation : public SpellScriptLoader Unit* caster = GetCaster(); caster->GetSpellHistory()->ResetCooldowns([caster](SpellHistory::CooldownStorageType::iterator itr) -> bool { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); if (spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE) return false; diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 7cc6fe888e9..a0a6189cbe2 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -271,7 +271,7 @@ class spell_warl_demonic_circle_summon : public SpellScriptLoader // WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST; allowing him to cast the WARLOCK_DEMONIC_CIRCLE_TELEPORT. // If not in range remove the WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST. - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(SPELL_WARLOCK_DEMONIC_CIRCLE_TELEPORT); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_WARLOCK_DEMONIC_CIRCLE_TELEPORT); if (GetTarget()->IsWithinDist(circle, spellInfo->GetMaxRange(true))) { @@ -362,7 +362,7 @@ class spell_warl_demonic_empowerment : public SpellScriptLoader break; case CREATURE_FAMILY_VOIDWALKER: { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER); int32 hp = int32(targetCreature->CountPctFromMaxHealth(GetCaster()->CalculateSpellDamage(targetCreature, spellInfo, 0))); targetCreature->CastCustomSpell(targetCreature, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER, &hp, NULL, NULL, true); //unitTarget->CastSpell(unitTarget, 54441, true); diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index d224c234cb4..ea9ccc956e5 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -271,7 +271,7 @@ class spell_warr_deep_wounds : public SpellScriptLoader { ApplyPct(damage, 16 * GetSpellInfo()->GetRank()); - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC); uint32 ticks = uint32(spellInfo->GetDuration()) / spellInfo->Effects[EFFECT_0].Amplitude; // Add remaining ticks to damage done diff --git a/src/server/scripts/World/boss_emerald_dragons.cpp b/src/server/scripts/World/boss_emerald_dragons.cpp index 1f89720803d..65dec74414b 100644 --- a/src/server/scripts/World/boss_emerald_dragons.cpp +++ b/src/server/scripts/World/boss_emerald_dragons.cpp @@ -205,7 +205,7 @@ class npc_dream_fog : public CreatureScript } // Seeping fog movement is slow enough for a player to be able to walk backwards and still outpace it me->SetWalk(true); - me->SetSpeed(MOVE_WALK, 0.75f); + me->SetSpeedRate(MOVE_WALK, 0.75f); } else _roamTimer -= diff; diff --git a/src/server/scripts/World/duel_reset.cpp b/src/server/scripts/World/duel_reset.cpp index 3c46255a1bf..b04f3ec0aa7 100644 --- a/src/server/scripts/World/duel_reset.cpp +++ b/src/server/scripts/World/duel_reset.cpp @@ -98,16 +98,16 @@ class DuelResetScript : public PlayerScript static void ResetSpellCooldowns(Player* player, bool onStartDuel) { - if (onStartDuel) + if (onStartDuel) { // remove cooldowns on spells that have < 10 min CD > 30 sec and has no onHold player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { SpellHistory::Clock::time_point now = SpellHistory::Clock::now(); uint32 cooldownDuration = itr->second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(itr->second.CooldownEnd - now).count() : 0; - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); - return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS - && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); + return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS + && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS && !itr->second.OnHold && cooldownDuration > 0 && ( spellInfo->RecoveryTime - cooldownDuration ) > (MINUTE / 2) * IN_MILLISECONDS @@ -119,11 +119,11 @@ class DuelResetScript : public PlayerScript // remove cooldowns on spells that have < 10 min CD and has no onHold player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); - return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS - && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); + return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS + && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS && !itr->second.OnHold; - }, true); + }, true); } // pet cooldowns diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index b90839f50c5..3094ecd660a 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -1211,7 +1211,7 @@ class go_toy_train_set : public GameObjectScript struct go_toy_train_setAI : public GameObjectAI { go_toy_train_setAI(GameObject* go) : GameObjectAI(go), _pulseTimer(3 * IN_MILLISECONDS) { } - + void UpdateAI(uint32 diff) override { if (diff < _pulseTimer) diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt index b6e5c8b1c6f..e99a81a084b 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -8,62 +8,60 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -if( USE_COREPCH ) - include_directories(${CMAKE_CURRENT_BINARY_DIR}) -endif() - -file(GLOB_RECURSE sources_DataStores DataStores/*.cpp DataStores/*.h) -file(GLOB_RECURSE sources_Dynamic Dynamic/*.cpp Dynamic/*.h) -file(GLOB_RECURSE sources_Networking Networking/*.cpp Networking/*.h) -file(GLOB_RECURSE sources_Packets Packets/*.cpp Packets/*.h) -if( WIN32 ) - file(GLOB_RECURSE sources_Service Service/*.cpp Service/*.h) -endif( WIN32 ) -file(GLOB sources_localdir *.cpp *.h) - -# -# Build shared sourcelist -# +CollectSourceFiles( + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE_SOURCES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) if (USE_COREPCH) - set(shared_STAT_PCH_HDR PrecompiledHeaders/sharedPCH.h) - set(shared_STAT_PCH_SRC PrecompiledHeaders/sharedPCH.cpp) + set(PRIVATE_PCH_HEADER PrecompiledHeaders/sharedPCH.h) + set(PRIVATE_PCH_SOURCE PrecompiledHeaders/sharedPCH.cpp) endif() -set(shared_STAT_SRCS - ${shared_STAT_SRCS} - ${sources_DataStores} - ${sources_Dynamic} - ${sources_Networking} - ${sources_Packets} - ${sources_Utilities} - ${sources_Service} - ${sources_localdir} -) +GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/Dynamic - ${CMAKE_CURRENT_SOURCE_DIR}/Networking - ${CMAKE_SOURCE_DIR}/dep/cppformat - ${CMAKE_SOURCE_DIR}/src/common/ - ${CMAKE_SOURCE_DIR}/src/common/Debugging - ${CMAKE_SOURCE_DIR}/src/common/Logging - ${CMAKE_SOURCE_DIR}/src/common/Utilities - ${MYSQL_INCLUDE_DIR} - ${OPENSSL_INCLUDE_DIR} - ${VALGRIND_INCLUDE_DIR} +add_definitions(-DTRINITY_API_EXPORT_SHARED) + +add_library(shared + ${PRIVATE_PCH_SOURCE} + ${PRIVATE_SOURCES} ) -GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) +CollectIncludeDirectories( + ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC_INCLUDES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) -add_library(shared STATIC - ${shared_STAT_SRCS} - ${shared_STAT_PCH_SRC} -) +target_include_directories(shared + PUBLIC + ${PUBLIC_INCLUDES} + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) -add_dependencies(shared revision_data.h) +target_link_libraries(shared + PUBLIC + database) + +set_target_properties(shared + PROPERTIES + FOLDER + "server") + +if( BUILD_SHARED_LIBS ) + if( UNIX ) + install(TARGETS shared + LIBRARY + DESTINATION lib) + elseif( WIN32 ) + install(TARGETS shared + RUNTIME + DESTINATION "${CMAKE_INSTALL_PREFIX}") + endif() +endif() # Generate precompiled header if (USE_COREPCH) - add_cxx_pch(shared ${shared_STAT_PCH_HDR} ${shared_STAT_PCH_SRC}) + add_cxx_pch(shared ${PRIVATE_PCH_HEADER} ${PRIVATE_PCH_SOURCE}) endif () diff --git a/src/server/shared/DataStores/DBCFileLoader.h b/src/server/shared/DataStores/DBCFileLoader.h index 00b1ee54a4a..abe18d1425e 100644 --- a/src/server/shared/DataStores/DBCFileLoader.h +++ b/src/server/shared/DataStores/DBCFileLoader.h @@ -37,7 +37,7 @@ enum DbcFieldFormat FT_SQL_ABSENT='a' //Used in sql format to mark column absent in sql dbc }; -class DBCFileLoader +class TC_SHARED_API DBCFileLoader { public: DBCFileLoader(); diff --git a/src/server/shared/DataStores/DBCStore.h b/src/server/shared/DataStores/DBCStore.h index b93bbdaea12..7c2cab1e36a 100644 --- a/src/server/shared/DataStores/DBCStore.h +++ b/src/server/shared/DataStores/DBCStore.h @@ -25,6 +25,121 @@ #include "DatabaseWorkerPool.h" #include "Implementation/WorldDatabase.h" #include "DatabaseEnv.h" +#include <G3D/Vector3.h> +#include <G3D/AABox.h> + + // Structures for M4 file. Source: https://wowdev.wiki +template<typename T> +struct M2SplineKey +{ + T p0; + T p1; + T p2; +}; + +struct M2Header +{ + char Magic[4]; // "MD20" + uint32 Version; // The version of the format. + uint32 lName; // Length of the model's name including the trailing \0 + uint32 ofsName; // Offset to the name, it seems like models can get reloaded by this name.should be unique, i guess. + uint32 GlobalModelFlags; // 0x0001: tilt x, 0x0002: tilt y, 0x0008: add 2 fields in header, 0x0020: load .phys data (MoP+), 0x0080: has _lod .skin files (MoP?+), 0x0100: is camera related. + uint32 nGlobalSequences; + uint32 ofsGlobalSequences; // A list of timestamps. + uint32 nAnimations; + uint32 ofsAnimations; // Information about the animations in the model. + uint32 nAnimationLookup; + uint32 ofsAnimationLookup; // Mapping of global IDs to the entries in the Animation sequences block. + uint32 nBones; // MAX_BONES = 0x100 + uint32 ofsBones; // Information about the bones in this model. + uint32 nKeyBoneLookup; + uint32 ofsKeyBoneLookup; // Lookup table for key skeletal bones. + uint32 nVertices; + uint32 ofsVertices; // Vertices of the model. + uint32 nViews; // Views (LOD) are now in .skins. + uint32 nSubmeshAnimations; + uint32 ofsSubmeshAnimations; // Submesh color and alpha animations definitions. + uint32 nTextures; + uint32 ofsTextures; // Textures of this model. + uint32 nTransparency; + uint32 ofsTransparency; // Transparency of textures. + uint32 nUVAnimation; + uint32 ofsUVAnimation; + uint32 nTexReplace; + uint32 ofsTexReplace; // Replaceable Textures. + uint32 nRenderFlags; + uint32 ofsRenderFlags; // Blending modes / render flags. + uint32 nBoneLookupTable; + uint32 ofsBoneLookupTable; // A bone lookup table. + uint32 nTexLookup; + uint32 ofsTexLookup; // The same for textures. + uint32 nTexUnits; // possibly removed with cata?! + uint32 ofsTexUnits; // And texture units. Somewhere they have to be too. + uint32 nTransLookup; + uint32 ofsTransLookup; // Everything needs its lookup. Here are the transparencies. + uint32 nUVAnimLookup; + uint32 ofsUVAnimLookup; + G3D::AABox BoundingBox; // min/max( [1].z, 2.0277779f ) - 0.16f seems to be the maximum camera height + float BoundingSphereRadius; + G3D::AABox CollisionBox; + float CollisionSphereRadius; + uint32 nBoundingTriangles; + uint32 ofsBoundingTriangles; // Our bounding volumes. Similar structure like in the old ofsViews. + uint32 nBoundingVertices; + uint32 ofsBoundingVertices; + uint32 nBoundingNormals; + uint32 ofsBoundingNormals; + uint32 nAttachments; + uint32 ofsAttachments; // Attachments are for weapons etc. + uint32 nAttachLookup; + uint32 ofsAttachLookup; // Of course with a lookup. + uint32 nEvents; + uint32 ofsEvents; // Used for playing sounds when dying and a lot else. + uint32 nLights; + uint32 ofsLights; // Lights are mainly used in loginscreens but in wands and some doodads too. + uint32 nCameras; // Format of Cameras changed with version 271! + uint32 ofsCameras; // The cameras are present in most models for having a model in the Character-Tab. + uint32 nCameraLookup; + uint32 ofsCameraLookup; // And lookup-time again. + uint32 nRibbonEmitters; + uint32 ofsRibbonEmitters; // Things swirling around. See the CoT-entrance for light-trails. + uint32 nParticleEmitters; + uint32 ofsParticleEmitters; // Spells and weapons, doodads and loginscreens use them. Blood dripping of a blade? Particles. + uint32 nBlendMaps; // This has to deal with blending. Exists IFF (flags & 0x8) != 0. When set, textures blending is overriden by the associated array. See M2/WotLK#Blend_mode_overrides + uint32 ofsBlendMaps; // Same as above. Points to an array of uint16 of nBlendMaps entries -- From WoD information.}; +}; + +struct M2Array +{ + uint32_t number; + uint32 offset_elements; +}; +struct M2Track +{ + uint16_t interpolation_type; + uint16_t global_sequence; + M2Array timestamps; + M2Array values; +}; + +struct M2Camera +{ + uint32_t type; // 0: portrait, 1: characterinfo; -1: else (flyby etc.); referenced backwards in the lookup table. + float fov; // No radians, no degrees. Multiply by 35 to get degrees. + float far_clip; + float near_clip; + M2Track positions; // How the camera's position moves. Should be 3*3 floats. + G3D::Vector3 position_base; + M2Track target_positions; // How the target moves. Should be 3*3 floats. + G3D::Vector3 target_position_base; + M2Track rolldata; // The camera can have some roll-effect. Its 0 to 2*Pi. +}; + +struct FlyByCamera +{ + uint32 timeStamp; + G3D::Vector4 locations; +}; struct SqlDbc { diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h index 0f3fd9a145b..f68da230553 100644 --- a/src/server/shared/Networking/AsyncAcceptor.h +++ b/src/server/shared/Networking/AsyncAcceptor.h @@ -21,6 +21,7 @@ #include "Log.h" #include <boost/asio.hpp> #include <functional> +#include <atomic> using boost::asio::ip::tcp; diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h index d1ba7f49aa4..0674ede57d8 100644 --- a/src/server/shared/Networking/Socket.h +++ b/src/server/shared/Networking/Socket.h @@ -55,11 +55,11 @@ public: virtual bool Update() { - if (!IsOpen()) + if (_closed) return false; #ifndef TC_SOCKET_USE_IOCP - if (_isWritingAsync || _writeQueue.empty()) + if (_isWritingAsync || (_writeQueue.empty() && !_closing)) return true; for (; HandleQueue();) @@ -90,6 +90,17 @@ public: std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } + void AsyncReadWithCallback(void (T::*callback)(boost::system::error_code, std::size_t)) + { + if (!IsOpen()) + return; + + _readBuffer.Normalize(); + _readBuffer.EnsureFreeSpace(); + _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), _readBuffer.GetRemainingSpace()), + std::bind(callback, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); + } + void QueuePacket(MessageBuffer&& buffer) { _writeQueue.push(std::move(buffer)); @@ -144,6 +155,15 @@ protected: return false; } + void SetNoDelay(bool enable) + { + boost::system::error_code err; + _socket.set_option(tcp::no_delay(enable), err); + if (err) + TC_LOG_DEBUG("network", "Socket::SetNoDelay: failed to set_option(boost::asio::ip::tcp::no_delay) for %s - %d (%s)", + GetRemoteIpAddress().to_string().c_str(), err.value(), err.message().c_str()); + } + private: void ReadHandlerInternal(boost::system::error_code error, size_t transferredBytes) { @@ -187,9 +207,6 @@ private: bool HandleQueue() { - if (!IsOpen()) - return false; - if (_writeQueue.empty()) return false; @@ -206,11 +223,15 @@ private: return AsyncProcessQueue(); _writeQueue.pop(); + if (_closing && _writeQueue.empty()) + CloseSocket(); return false; } else if (bytesSent == 0) { _writeQueue.pop(); + if (_closing && _writeQueue.empty()) + CloseSocket(); return false; } else if (bytesSent < bytesToSend) // now n > 0 @@ -220,6 +241,8 @@ private: } _writeQueue.pop(); + if (_closing && _writeQueue.empty()) + CloseSocket(); return !_writeQueue.empty(); } diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h index b14aac4ca47..e479cd2450d 100644 --- a/src/server/shared/Networking/SocketMgr.h +++ b/src/server/shared/Networking/SocketMgr.h @@ -19,7 +19,6 @@ #define SocketMgr_h__ #include "AsyncAcceptor.h" -#include "Config.h" #include "Errors.h" #include "NetworkThread.h" #include <boost/asio/ip/tcp.hpp> @@ -36,15 +35,9 @@ public: ASSERT(!_threads && !_acceptor && !_threadCount, "StopNetwork must be called prior to SocketMgr destruction"); } - virtual bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) + virtual bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port, int threadCount) { - _threadCount = sConfigMgr->GetIntDefault("Network.Threads", 1); - - if (_threadCount <= 0) - { - TC_LOG_ERROR("misc", "Network.Threads is wrong in your config file"); - return false; - } + ASSERT(threadCount > 0); try { @@ -56,6 +49,7 @@ public: return false; } + _threadCount = threadCount; _threads = CreateThreads(); ASSERT(_threads); diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 5ebe5258a44..d24a91ed458 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -23,22 +23,12 @@ #include "Errors.h" #include "ByteConverter.h" #include "Util.h" - -#include <exception> -#include <list> -#include <map> -#include <string> -#include <vector> #include <cstring> -#include <time.h> -#include <cmath> -#include <type_traits> -#include <boost/asio/buffer.hpp> class MessageBuffer; // Root of ByteBuffer exception hierarchy -class ByteBufferException : public std::exception +class TC_SHARED_API ByteBufferException : public std::exception { public: ~ByteBufferException() throw() { } @@ -52,7 +42,7 @@ private: std::string msg_; }; -class ByteBufferPositionException : public ByteBufferException +class TC_SHARED_API ByteBufferPositionException : public ByteBufferException { public: ByteBufferPositionException(bool add, size_t pos, size_t size, size_t valueSize); @@ -60,7 +50,7 @@ public: ~ByteBufferPositionException() throw() { } }; -class ByteBufferSourceException : public ByteBufferException +class TC_SHARED_API ByteBufferSourceException : public ByteBufferException { public: ByteBufferSourceException(size_t pos, size_t size, size_t valueSize); @@ -68,7 +58,7 @@ public: ~ByteBufferSourceException() throw() { } }; -class ByteBuffer +class TC_SHARED_API ByteBuffer { public: const static size_t DEFAULT_SIZE = 0x1000; @@ -628,15 +618,4 @@ inline void ByteBuffer::read_skip<std::string>() read_skip<char*>(); } -namespace boost -{ - namespace asio - { - inline const_buffers_1 buffer(ByteBuffer const& packet) - { - return buffer(packet.contents(), packet.size()); - } - } -} - #endif diff --git a/src/server/shared/Realm/Realm.cpp b/src/server/shared/Realm/Realm.cpp new file mode 100644 index 00000000000..11c52f281a9 --- /dev/null +++ b/src/server/shared/Realm/Realm.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Realm.h" + +ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const +{ + ip::address realmIp; + + // Attempt to send best address for client + if (clientAddr.is_loopback()) + { + // Try guessing if realm is also connected locally + if (LocalAddress.is_loopback() || ExternalAddress.is_loopback()) + realmIp = clientAddr; + else + { + // Assume that user connecting from the machine that bnetserver is located on + // has all realms available in his local network + realmIp = LocalAddress; + } + } + else + { + if (clientAddr.is_v4() && + (clientAddr.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong()) == + (LocalAddress.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong())) + { + realmIp = LocalAddress; + } + else + realmIp = ExternalAddress; + } + + ip::tcp::endpoint endpoint(realmIp, Port); + + // Return external IP + return endpoint; +} diff --git a/src/server/shared/Realm/Realm.h b/src/server/shared/Realm/Realm.h new file mode 100644 index 00000000000..241ccd2bca8 --- /dev/null +++ b/src/server/shared/Realm/Realm.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef Realm_h__ +#define Realm_h__ + +#include "Common.h" +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/tcp.hpp> + +using namespace boost::asio; + +enum RealmFlags +{ + REALM_FLAG_NONE = 0x00, + REALM_FLAG_VERSION_MISMATCH = 0x01, + REALM_FLAG_OFFLINE = 0x02, + REALM_FLAG_SPECIFYBUILD = 0x04, + REALM_FLAG_UNK1 = 0x08, + REALM_FLAG_UNK2 = 0x10, + REALM_FLAG_RECOMMENDED = 0x20, + REALM_FLAG_NEW = 0x40, + REALM_FLAG_FULL = 0x80 +}; + +struct TC_SHARED_API RealmHandle +{ + RealmHandle() : Realm(0) { } + RealmHandle(uint32 index) : Realm(index) { } + + uint32 Realm; // primary key in `realmlist` table + + bool operator<(RealmHandle const& r) const + { + return Realm < r.Realm; + } +}; + +/// Type of server, this is values from second column of Cfg_Configs.dbc +enum RealmType +{ + REALM_TYPE_NORMAL = 0, + REALM_TYPE_PVP = 1, + REALM_TYPE_NORMAL2 = 4, + REALM_TYPE_RP = 6, + REALM_TYPE_RPPVP = 8, + + MAX_CLIENT_REALM_TYPE = 14, + + REALM_TYPE_FFA_PVP = 16 // custom, free for all pvp mode like arena PvP in all zones except rest activated places and sanctuaries + // replaced by REALM_PVP in realm list +}; + +// Storage object for a realm +struct TC_SHARED_API Realm +{ + RealmHandle Id; + uint32 Build; + ip::address ExternalAddress; + ip::address LocalAddress; + ip::address LocalSubnetMask; + uint16 Port; + std::string Name; + uint8 Type; + RealmFlags Flags; + uint8 Timezone; + AccountTypes AllowedSecurityLevel; + float PopulationLevel; + + ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; +}; + +#endif // Realm_h__ diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/shared/Realm/RealmList.cpp index 53aeff6133b..e941800cd76 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/shared/Realm/RealmList.cpp @@ -16,74 +16,78 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <boost/asio/ip/tcp.hpp> -#include "Common.h" #include "RealmList.h" #include "Database/DatabaseEnv.h" +#include "Util.h" -namespace boost { namespace asio { namespace ip { class address; } } } +RealmList::RealmList() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr) +{ +} -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)), _resolver(nullptr) { } RealmList::~RealmList() { - delete _resolver; + delete _updateTimer; +} + +RealmList* RealmList::Instance() +{ + static RealmList instance; + return &instance; } // Load the realm list from the database void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInterval) { + _updateInterval = updateInterval; + _updateTimer = new boost::asio::deadline_timer(ioService); _resolver = new boost::asio::ip::tcp::resolver(ioService); - m_UpdateInterval = updateInterval; // Get the content of the realmlist table in the database - UpdateRealms(true); + UpdateRealms(boost::system::error_code()); } -void RealmList::UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, - ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build) +void RealmList::Close() { - // Create new if not exist or update existed - Realm& realm = m_realms[name]; - - realm.m_ID = id; - realm.name = name; - realm.icon = icon; - realm.flag = flag; - realm.timezone = timezone; - realm.allowedSecurityLevel = allowedSecurityLevel; - realm.populationLevel = population; - - // Append port to IP address. + _updateTimer->cancel(); +} +void RealmList::UpdateRealm(RealmHandle const& id, uint32 build, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, + float population) +{ + // Create new if not exist or update existed + Realm& realm = _realms[id]; + + realm.Id = id; + realm.Build = build; + realm.Name = name; + realm.Type = icon; + realm.Flags = flag; + realm.Timezone = timezone; + realm.AllowedSecurityLevel = allowedSecurityLevel; + realm.PopulationLevel = population; realm.ExternalAddress = address; realm.LocalAddress = localAddr; realm.LocalSubnetMask = localSubmask; - realm.port = port; - realm.gamebuild = build; + realm.Port = port; } -void RealmList::UpdateIfNeed() +void RealmList::UpdateRealms(boost::system::error_code const& error) { - // maybe disabled or updated recently - if (!m_UpdateInterval || m_NextUpdateTime > time(NULL)) + if (error) return; - m_NextUpdateTime = time(NULL) + m_UpdateInterval; - - // Clears Realm list - m_realms.clear(); - - // Get the content of the realmlist table in the database - UpdateRealms(); -} - -void RealmList::UpdateRealms(bool init) -{ - TC_LOG_INFO("server.authserver", "Updating Realm List..."); + TC_LOG_DEBUG("server.authserver", "Updating Realm List..."); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST); PreparedQueryResult result = LoginDatabase.Query(stmt); + std::map<RealmHandle, std::string> existingRealms; + for (auto const& p : _realms) + existingRealms[p.first] = p.second.Name; + + _realms.clear(); + // Circle through results and add them to the realm map if (result) { @@ -102,8 +106,8 @@ void RealmList::UpdateRealms(bool init) boost::asio::ip::tcp::resolver::iterator endPoint = _resolver->resolve(externalAddressQuery, ec); if (endPoint == end || ec) { - TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[2].GetString().c_str()); - return; + TC_LOG_ERROR("server.authserver", "Could not resolve address %s for realm \"%s\" id %u", fields[2].GetString().c_str(), name.c_str(), realmId); + continue; } ip::address externalAddress = (*endPoint).endpoint().address(); @@ -112,8 +116,8 @@ void RealmList::UpdateRealms(bool init) endPoint = _resolver->resolve(localAddressQuery, ec); if (endPoint == end || ec) { - TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[3].GetString().c_str()); - return; + TC_LOG_ERROR("server.authserver", "Could not resolve localAddress %s for realm \"%s\" id %u", fields[3].GetString().c_str(), name.c_str(), realmId); + continue; } ip::address localAddress = (*endPoint).endpoint().address(); @@ -122,25 +126,35 @@ void RealmList::UpdateRealms(bool init) endPoint = _resolver->resolve(localSubmaskQuery, ec); if (endPoint == end || ec) { - TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[4].GetString().c_str()); - return; + TC_LOG_ERROR("server.authserver", "Could not resolve localSubnetMask %s for realm \"%s\" id %u", fields[4].GetString().c_str(), name.c_str(), realmId); + continue; } ip::address localSubmask = (*endPoint).endpoint().address(); uint16 port = fields[5].GetUInt16(); uint8 icon = fields[6].GetUInt8(); + if (icon == REALM_TYPE_FFA_PVP) + icon = REALM_TYPE_PVP; + if (icon >= MAX_CLIENT_REALM_TYPE) + icon = REALM_TYPE_NORMAL; RealmFlags flag = RealmFlags(fields[7].GetUInt8()); uint8 timezone = fields[8].GetUInt8(); uint8 allowedSecurityLevel = fields[9].GetUInt8(); float pop = fields[10].GetFloat(); uint32 build = fields[11].GetUInt32(); - UpdateRealm(realmId, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, - (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); + RealmHandle id{ realmId }; - if (init) - TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); + UpdateRealm(id, build, name, externalAddress, localAddress, localSubmask, port, icon, flag, + timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); + + if (!existingRealms.count(id)) + TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), externalAddress.to_string().c_str(), port); + else + TC_LOG_DEBUG("server.authserver", "Updating realm \"%s\" at %s:%u.", name.c_str(), externalAddress.to_string().c_str(), port); + + existingRealms.erase(id); } catch (std::exception& ex) { @@ -150,4 +164,22 @@ void RealmList::UpdateRealms(bool init) } while (result->NextRow()); } + + for (auto itr = existingRealms.begin(); itr != existingRealms.end(); ++itr) + TC_LOG_INFO("server.authserver", "Removed realm \"%s\".", itr->second.c_str()); + + if (_updateInterval) + { + _updateTimer->expires_from_now(boost::posix_time::seconds(_updateInterval)); + _updateTimer->async_wait(std::bind(&RealmList::UpdateRealms, this, std::placeholders::_1)); + } +} + +Realm const* RealmList::GetRealm(RealmHandle const& id) const +{ + auto itr = _realms.find(id); + if (itr != _realms.end()) + return &itr->second; + + return NULL; } diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h new file mode 100644 index 00000000000..3b81337e762 --- /dev/null +++ b/src/server/shared/Realm/RealmList.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _REALMLIST_H +#define _REALMLIST_H + +#include "Common.h" +#include "Realm/Realm.h" +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/asio/deadline_timer.hpp> + +using namespace boost::asio; + +/// Storage object for the list of realms on the server +class TC_SHARED_API RealmList +{ +public: + typedef std::map<RealmHandle, Realm> RealmMap; + + static RealmList* Instance(); + + ~RealmList(); + + void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); + void Close(); + + RealmMap const& GetRealms() const { return _realms; } + Realm const* GetRealm(RealmHandle const& id) const; + +private: + RealmList(); + + void UpdateRealms(boost::system::error_code const& error); + void UpdateRealm(RealmHandle const& id, uint32 build, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population); + + RealmMap _realms; + uint32 _updateInterval; + boost::asio::deadline_timer* _updateTimer; + boost::asio::ip::tcp::resolver* _resolver; +}; + +#define sRealmList RealmList::Instance() +#endif diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 99495986842..0de8d6054f3 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -8,113 +8,29 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -file(GLOB_RECURSE sources_CommandLine CommandLine/*.cpp CommandLine/*.h) -file(GLOB_RECURSE sources_RemoteAccess RemoteAccess/*.cpp RemoteAccess/*.h) -file(GLOB_RECURSE sources_TCSoap TCSoap/*.cpp TCSoap/*.h) -file(GLOB sources_localdir *.cpp *.h) - -if (USE_COREPCH) - set(worldserver_PCH_HDR PrecompiledHeaders/worldPCH.h) - set(worldserver_PCH_SRC PrecompiledHeaders/worldPCH.cpp) -endif() - -set(worldserver_SRCS - ${worldserver_SRCS} - ${sources_CommandLine} - ${sources_RemoteAccess} - ${sources_TCSoap} - ${sources_localdir} -) +CollectSourceFiles( + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE_SOURCES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) if( WIN32 ) - set(worldserver_SRCS - ${worldserver_SRCS} - ${sources_windows_Debugging} - ) + list(APPEND PRIVATE_SOURCES ${sources_windows}) if ( MSVC ) - set(worldserver_SRCS - ${worldserver_SRCS} - worldserver.rc - ) + list(APPEND PRIVATE_SOURCES worldserver.rc) endif() endif() -include_directories( - ${CMAKE_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/CommandLine - ${CMAKE_CURRENT_SOURCE_DIR}/RemoteAccess - ${CMAKE_CURRENT_SOURCE_DIR}/TCSoap - ${CMAKE_SOURCE_DIR}/dep/cppformat - ${CMAKE_SOURCE_DIR}/dep/g3dlite/include - ${CMAKE_SOURCE_DIR}/dep/gsoap - ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include - ${CMAKE_SOURCE_DIR}/src/common/ - ${CMAKE_SOURCE_DIR}/src/common/Collision - ${CMAKE_SOURCE_DIR}/src/common/Collision/Models - ${CMAKE_SOURCE_DIR}/src/common/Configuration - ${CMAKE_SOURCE_DIR}/src/common/Cryptography - ${CMAKE_SOURCE_DIR}/src/common/Cryptography/Authentication - ${CMAKE_SOURCE_DIR}/src/common/Debugging - ${CMAKE_SOURCE_DIR}/src/common/Logging - ${CMAKE_SOURCE_DIR}/src/common/Threading - ${CMAKE_SOURCE_DIR}/src/common/Utilities - ${CMAKE_SOURCE_DIR}/src/server/authserver/Realms - ${CMAKE_SOURCE_DIR}/src/server/database/ - ${CMAKE_SOURCE_DIR}/src/server/database/Database - ${CMAKE_SOURCE_DIR}/src/server/database/Logging - ${CMAKE_SOURCE_DIR}/src/server/game - ${CMAKE_SOURCE_DIR}/src/server/game/Accounts - ${CMAKE_SOURCE_DIR}/src/server/game/Addons - ${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds - ${CMAKE_SOURCE_DIR}/src/server/game/Chat - ${CMAKE_SOURCE_DIR}/src/server/game/Combat - ${CMAKE_SOURCE_DIR}/src/server/game/Conditions - ${CMAKE_SOURCE_DIR}/src/server/game/DataStores - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Corpse - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Creature - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/DynamicObject - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/GameObject - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item/Container - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object/Updates - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Unit - ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Vehicle - ${CMAKE_SOURCE_DIR}/src/server/game/Globals - ${CMAKE_SOURCE_DIR}/src/server/game/Grids - ${CMAKE_SOURCE_DIR}/src/server/game/Grids/Cells - ${CMAKE_SOURCE_DIR}/src/server/game/Handlers - ${CMAKE_SOURCE_DIR}/src/server/game/Instances - ${CMAKE_SOURCE_DIR}/src/server/game/Loot - ${CMAKE_SOURCE_DIR}/src/server/game/Mails - ${CMAKE_SOURCE_DIR}/src/server/game/Maps - ${CMAKE_SOURCE_DIR}/src/server/game/Miscellaneous - ${CMAKE_SOURCE_DIR}/src/server/game/Movement - ${CMAKE_SOURCE_DIR}/src/server/game/Movement/Waypoints - ${CMAKE_SOURCE_DIR}/src/server/game/Quests - ${CMAKE_SOURCE_DIR}/src/server/game/Scripting - ${CMAKE_SOURCE_DIR}/src/server/game/Server - ${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol - ${CMAKE_SOURCE_DIR}/src/server/game/Spells/Auras - ${CMAKE_SOURCE_DIR}/src/server/game/Weather - ${CMAKE_SOURCE_DIR}/src/server/game/World - ${CMAKE_SOURCE_DIR}/src/server/shared - ${CMAKE_SOURCE_DIR}/src/server/shared/DataStores - ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic - ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference - ${CMAKE_SOURCE_DIR}/src/server/shared/Networking - ${CMAKE_SOURCE_DIR}/src/server/shared/Packets - ${CMAKE_SOURCE_DIR}/src/server/shared/Service - ${MYSQL_INCLUDE_DIR} - ${OPENSSL_INCLUDE_DIR} - ${VALGRIND_INCLUDE_DIR} -) +if (USE_COREPCH) + set(PRIVATE_PCH_HEADER PrecompiledHeaders/worldPCH.h) + set(PRIVATE_PCH_SOURCE PrecompiledHeaders/worldPCH.cpp) +endif() GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) add_executable(worldserver - ${worldserver_SRCS} - ${worldserver_PCH_SRC} + ${PRIVATE_PCH_SOURCE} + ${PRIVATE_SOURCES} ) if( NOT WIN32 ) @@ -130,24 +46,33 @@ endif() set_target_properties(worldserver PROPERTIES LINK_FLAGS "${worldserver_LINK_FLAGS}") target_link_libraries(worldserver - game - scripts - shared - database - common - g3dlib - gsoap - Detour - format - ${JEMALLOC_LIBRARY} - ${READLINE_LIBRARY} - ${TERMCAP_LIBRARY} - ${MYSQL_LIBRARY} - ${OPENSSL_LIBRARIES} - ${ZLIB_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_LIBRARIES} -) + PUBLIC + scripts + game + gsoap + readline) + +CollectIncludeDirectories( + ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC_INCLUDES + # Exclude + ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) + +target_include_directories(worldserver + PUBLIC + ${PUBLIC_INCLUDES} + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) + +set_target_properties(worldserver + PROPERTIES + FOLDER + "server") + +# Add all dynamic projects as dependency to the worldserver +if (WORLDSERVER_DYNAMIC_SCRIPT_MODULES_DEPENDENCIES) + add_dependencies(worldserver ${WORLDSERVER_DYNAMIC_SCRIPT_MODULES_DEPENDENCIES}) +endif() if( WIN32 ) if ( MSVC ) @@ -173,5 +98,5 @@ endif() # Generate precompiled header if( USE_COREPCH ) - add_cxx_pch(worldserver ${worldserver_PCH_HDR} ${worldserver_PCH_SRC}) + add_cxx_pch(worldserver ${PRIVATE_PCH_HEADER} ${PRIVATE_PCH_SOURCE}) endif() diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 53c5f250851..2b5553b4bb0 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -34,12 +34,13 @@ #include "OpenSSLCrypto.h" #include "ProcessPriority.h" #include "BigNumber.h" -#include "RealmList.h" #include "World.h" #include "MapManager.h" #include "InstanceSaveMgr.h" #include "ObjectAccessor.h" #include "ScriptMgr.h" +#include "ScriptReloadMgr.h" +#include "ScriptLoader.h" #include "OutdoorPvP/OutdoorPvPMgr.h" #include "BattlegroundMgr.h" #include "TCSoap.h" @@ -47,6 +48,7 @@ #include "GitRevision.h" #include "WorldSocket.h" #include "WorldSocketMgr.h" +#include "Realm/Realm.h" #include "DatabaseLoader.h" #include "AppenderDB.h" @@ -78,11 +80,6 @@ uint32 _worldLoopCounter(0); uint32 _lastChangeMsTime(0); uint32 _maxCoreStuckTimeInMs(0); -WorldDatabaseWorkerPool WorldDatabase; ///< Accessor to the world database -CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the character database -LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database -uint32 realmID; ///< Id of the realm - void SignalHandler(const boost::system::error_code& error, int signalNumber); void FreezeDetectorHandler(const boost::system::error_code& error); AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService); @@ -92,11 +89,14 @@ void WorldUpdateLoop(); void ClearOnlineAccounts(); void ShutdownCLIThread(std::thread* cliThread); void ShutdownThreadPool(std::vector<std::thread>& threadPool); +bool LoadRealmInfo(); variables_map GetConsoleArguments(int argc, char** argv, std::string& cfg_file, std::string& cfg_service); /// Launch the Trinity server extern int main(int argc, char** argv) { + signal(SIGABRT, &Trinity::AbortHandler); + std::string configFile = _TRINITY_CORE_CONFIG; std::string configService; @@ -188,9 +188,12 @@ extern int main(int argc, char** argv) } // Set server offline (not connectable) - LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); + LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realm.Id.Realm); + + LoadRealmInfo(); // Initialize the World + sScriptMgr->SetScriptLoader(AddScripts); sWorld->SetInitialWorldSettings(); // Launch CliRunnable thread @@ -220,10 +223,20 @@ extern int main(int argc, char** argv) uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD)); std::string worldListener = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); - sWorldSocketMgr.StartNetwork(_ioService, worldListener, worldPort); + int networkThreads = sConfigMgr->GetIntDefault("Network.Threads", 1); + + if (networkThreads <= 0) + { + TC_LOG_ERROR("server.worldserver", "Network.Threads must be greater than 0"); + return false; + } + + sWorldSocketMgr.StartNetwork(_ioService, worldListener, worldPort, networkThreads); // Set server online (allow connecting now) - LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); + LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_OFFLINE, realm.Id.Realm); + realm.PopulationLevel = 0.0f; + realm.Flags = RealmFlags(realm.Flags & ~uint32(REALM_FLAG_OFFLINE)); // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec) if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) @@ -243,6 +256,8 @@ extern int main(int argc, char** argv) // Shutdown starts here ShutdownThreadPool(threadPool); + sLog->SetSynchronous(); + sScriptMgr->OnShutdown(); sWorld->KickAll(); // save and kick all players @@ -257,9 +272,10 @@ extern int main(int argc, char** argv) sOutdoorPvPMgr->Die(); sMapMgr->UnloadAll(); // unload all grids (including locked in memory) sScriptMgr->Unload(); + sScriptReloadMgr->Unload(); // set server offline - LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); + LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realm.Id.Realm); // Clean up threads if any if (soapThread != nullptr) @@ -441,6 +457,59 @@ AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService) return acceptor; } +bool LoadRealmInfo() +{ + boost::asio::ip::tcp::resolver resolver(_ioService); + boost::asio::ip::tcp::resolver::iterator end; + + QueryResult result = LoginDatabase.PQuery("SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE id = %u", realm.Id.Realm); + if (!result) + return false; + + Field* fields = result->Fetch(); + realm.Name = fields[1].GetString(); + boost::asio::ip::tcp::resolver::query externalAddressQuery(ip::tcp::v4(), fields[2].GetString(), ""); + + boost::system::error_code ec; + boost::asio::ip::tcp::resolver::iterator endPoint = resolver.resolve(externalAddressQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.worldserver", "Could not resolve address %s", fields[2].GetString().c_str()); + return false; + } + + realm.ExternalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localAddressQuery(ip::tcp::v4(), fields[3].GetString(), ""); + endPoint = resolver.resolve(localAddressQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.worldserver", "Could not resolve address %s", fields[3].GetString().c_str()); + return false; + } + + realm.LocalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localSubmaskQuery(ip::tcp::v4(), fields[4].GetString(), ""); + endPoint = resolver.resolve(localSubmaskQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.worldserver", "Could not resolve address %s", fields[4].GetString().c_str()); + return false; + } + + realm.LocalSubnetMask = (*endPoint).endpoint().address(); + + realm.Port = fields[5].GetUInt16(); + realm.Type = fields[6].GetUInt8(); + realm.Flags = RealmFlags(fields[7].GetUInt8()); + realm.Timezone = fields[8].GetUInt8(); + realm.AllowedSecurityLevel = AccountTypes(fields[9].GetUInt8()); + realm.PopulationLevel = fields[10].GetFloat(); + realm.Build = fields[11].GetUInt32(); + return true; +} + /// Initialize connection to the databases bool StartDB() { @@ -449,21 +518,22 @@ bool StartDB() // Load databases DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE); loader - .AddDatabase(WorldDatabase, "World") + .AddDatabase(LoginDatabase, "Login") .AddDatabase(CharacterDatabase, "Character") - .AddDatabase(LoginDatabase, "Login"); + .AddDatabase(WorldDatabase, "World"); if (!loader.Load()) return false; ///- Get the realm Id from the configuration file - realmID = sConfigMgr->GetIntDefault("RealmID", 0); - if (!realmID) + realm.Id.Realm = sConfigMgr->GetIntDefault("RealmID", 0); + if (!realm.Id.Realm) { TC_LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file"); return false; } - TC_LOG_INFO("server.worldserver", "Realm running as realm ID %d", realmID); + + TC_LOG_INFO("server.worldserver", "Realm running as realm ID %d", realm.Id.Realm); ///- Clean the database before starting ClearOnlineAccounts(); @@ -490,7 +560,7 @@ void StopDB() void ClearOnlineAccounts() { // Reset online status for all accounts with characters on the current realm - LoginDatabase.DirectPExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = %d)", realmID); + LoginDatabase.DirectPExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = %d)", realm.Id.Realm); // Reset online status for all characters CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0"); diff --git a/src/server/worldserver/RemoteAccess/RASession.cpp b/src/server/worldserver/RemoteAccess/RASession.cpp index 59e7b138c48..1ad1ac1dc6c 100644 --- a/src/server/worldserver/RemoteAccess/RASession.cpp +++ b/src/server/worldserver/RemoteAccess/RASession.cpp @@ -121,7 +121,7 @@ bool RASession::CheckAccessLevel(const std::string& user) { std::string safeUser = user; - AccountMgr::normalizeString(safeUser); + Utf8ToUpperOnlyLatin(safeUser); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); stmt->setString(0, safeUser); @@ -153,10 +153,10 @@ bool RASession::CheckPassword(const std::string& user, const std::string& pass) { std::string safe_user = user; std::transform(safe_user.begin(), safe_user.end(), safe_user.begin(), ::toupper); - AccountMgr::normalizeString(safe_user); + Utf8ToUpperOnlyLatin(safe_user); std::string safe_pass = pass; - AccountMgr::normalizeString(safe_pass); + Utf8ToUpperOnlyLatin(safe_pass); std::transform(safe_pass.begin(), safe_pass.end(), safe_pass.begin(), ::toupper); std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 05d303cfd9b..c2694c640c5 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -12,6 +12,7 @@ # SERVER LOGGING # SERVER SETTINGS # UPDATE SETTINGS +# HOTSWAP SETTINGS # WARDEN SETTINGS # PLAYER INTERACTION # CREATURE SETTINGS @@ -270,6 +271,25 @@ MaxOverspeedPings = 2 GridUnload = 1 # +# BaseMapLoadAllGrids +# Description: Load all grids for base maps upon load. Requires GridUnload to be 0. +# This will take around 5GB of ram upon server load, and will take some time +# to initially load the server. +# Default: 0 - (Don't pre-load all base maps, dynamically load as used) +# 1 - (Preload all grids in all base maps upon load) + +BaseMapLoadAllGrids = 0 + +# +# InstanceMapLoadAllGrids +# Description: Load all grids for instance maps upon load. Requires GridUnload to be 0. +# Upon loading an instance map, all creatures/objects in the map will be pre-loaded +# Default: 0 - (Don't pre-load all base maps, dynamically load as used) +# 1 - (Preload all grids in the instance upon load) + +InstanceMapLoadAllGrids = 0 + +# # SocketTimeOutTime # Description: Time (in milliseconds) after which a connection being idle on the character # selection screen is disconnected. @@ -330,6 +350,13 @@ PlayerSave.Stats.MinLevel = 0 PlayerSave.Stats.SaveOnlyOnLogout = 1 # +# DisconnectToleranceInterval +# Description: Tolerance (in seconds) for disconnected players before reentering the queue. +# Default: 0 (disabled) + +DisconnectToleranceInterval = 0 + +# # mmap.enablePathFinding # Description: Enable/Disable pathfinding using mmaps - recommended. # Default: 0 - (Disabled) @@ -1100,9 +1127,8 @@ BeepAtStart = 1 # # Motd -# Description: Message of the Day, displayed at login. -# Use '@' for a newline and be sure to escape special characters. -# Example: "Welcome to John\'s Server@This server runs on Trinity Core." +# Description: Message of the Day, displayed at login. Use '@' for a newline. +# Example: "Welcome to John's Server!@This server is proud to be powered by Trinity Core." # Default: "Welcome to a Trinity Core server." Motd = "Welcome to a Trinity Core server." @@ -1255,6 +1281,78 @@ Updates.CleanDeadRefMaxCount = 3 ################################################################################################### ################################################################################################### +# HOTSWAP SETTINGS +# +# HotSwap.Enabled (Requires compilation with DYNAMIC_LINKING=1) +# Description: Enables dynamic script hotswapping. +# Reloads scripts on changes. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +HotSwap.Enabled = 1 + +# +# HotSwap.ScriptDir +# Description: Directory containing the script shared libraries (.dll/.so). +# Example: "/usr/local/scripts" +# Default: "scripts" + +HotSwap.ScriptDir = "scripts" + +# HotSwap.EnableReCompiler +# Description: Enables the dynamic script recompiler. +# Watches your script source directories and recompiles the +# script modules on changes. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +HotSwap.EnableReCompiler = 1 + +# HotSwap.EnableEarlyTermination +# Description: Terminate the build of a module when an associated +# source file was changed meanwhile. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +HotSwap.EnableEarlyTermination = 1 + +# HotSwap.EnableBuildFileRecreation +# Description: Recreate build files when sources to a module +# were added or removed. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +HotSwap.EnableBuildFileRecreation = 1 + +# +# HotSwap.EnableInstall +# Description: Enables cmake install after automatic builds have finished +# Default: 1 - (Enabled) +# 0 - (Disabled) + +HotSwap.EnableInstall = 1 + +# +# HotSwap.EnablePrefixCorrection +# Description: Allows the core to automatic set the CMAKE_INSTALL_PREFIX +# to it's current location in the filesystem. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +HotSwap.EnablePrefixCorrection = 1 + +# HotSwap.ReCompilerBuildType +# Description: Defines the build type of the builds invoked by the recompiler. +# Default: "" - Built-in build type of the module is used. +# "Release" - Release builds only +# "Debug" - Debug builds only + +HotSwap.ReCompilerBuildType = "" + +# +################################################################################################### + +################################################################################################### # WARDEN SETTINGS # # Warden.Enabled @@ -2279,16 +2377,16 @@ Battleground.InvitationType = 0 # Default: 300000 - (Enabled, 5 minutes) # 0 - (Disabled, Not recommended) -BattleGround.PrematureFinishTimer = 300000 +Battleground.PrematureFinishTimer = 300000 # -# BattleGround.PremadeGroupWaitForMatch +# Battleground.PremadeGroupWaitForMatch # Description: Time (in milliseconds) a pre-made group has to wait for matching group of the # other faction. # Default: 1800000 - (Enabled, 30 minutes) # 0 - (Disabled, Not recommended) -BattleGround.PremadeGroupWaitForMatch = 1800000 +Battleground.PremadeGroupWaitForMatch = 1800000 # # Battleground.GiveXPForKills @@ -2971,6 +3069,27 @@ AuctionHouseBot.MinTime = 1 AuctionHouseBot.MaxTime = 72 # +# AuctionHouseBot.Class.CLASS.Allow.Zero = 0 +# Description: Include items without a sell or buy price. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +AuctionHouseBot.Class.Consumable.Allow.Zero = 0 +AuctionHouseBot.Class.Container.Allow.Zero = 0 +AuctionHouseBot.Class.Weapon.Allow.Zero = 0 +AuctionHouseBot.Class.Gem.Allow.Zero = 0 +AuctionHouseBot.Class.Armor.Allow.Zero = 0 +AuctionHouseBot.Class.Reagent.Allow.Zero = 0 +AuctionHouseBot.Class.Projectile.Allow.Zero = 0 +AuctionHouseBot.Class.TradeGood.Allow.Zero = 0 +AuctionHouseBot.Class.Recipe.Allow.Zero = 0 +AuctionHouseBot.Class.Quiver.Allow.Zero = 0 +AuctionHouseBot.Class.Quest.Allow.Zero = 0 +AuctionHouseBot.Class.Key.Allow.Zero = 0 +AuctionHouseBot.Class.Misc.Allow.Zero = 0 +AuctionHouseBot.Class.Glyph.Allow.Zero = 0 + +# # AuctionHouseBot.Items.Vendor # Description: Include items that can be bought from vendors. # Default: 0 - (Disabled) @@ -3078,6 +3197,27 @@ AuctionHouseBot.Items.Orange.Price.Ratio = 100 AuctionHouseBot.Items.Yellow.Price.Ratio = 100 # +# AuctionHouseBot.Class.CLASS.Price.Ratio +# Description: Percentage by which the price of items sold of each class is incremented / decreased (for all houses) +# Default: 100 - (No change) + +AuctionHouseBot.Class.Consumable.Price.Ratio = 100 +AuctionHouseBot.Class.Container.Price.Ratio = 100 +AuctionHouseBot.Class.Weapon.Price.Ratio = 100 +AuctionHouseBot.Class.Gem.Price.Ratio = 100 +AuctionHouseBot.Class.Armor.Price.Ratio = 100 +AuctionHouseBot.Class.Reagent.Price.Ratio = 100 +AuctionHouseBot.Class.Projectile.Price.Ratio = 100 +AuctionHouseBot.Class.TradeGood.Price.Ratio = 100 +AuctionHouseBot.Class.Generic.Price.Ratio = 100 +AuctionHouseBot.Class.Recipe.Price.Ratio = 100 +AuctionHouseBot.Class.Quiver.Price.Ratio = 100 +AuctionHouseBot.Class.Quest.Price.Ratio = 100 +AuctionHouseBot.Class.Key.Price.Ratio = 100 +AuctionHouseBot.Class.Misc.Price.Ratio = 100 +AuctionHouseBot.Class.Glyph.Price.Ratio = 100 + +# # AuctionHouseBot.Items.ItemLevel.* # Description: Prevent seller from listing items below/above this item level # Default: 0 - (Disabled) @@ -3443,6 +3583,7 @@ Logger.server=3,Console Server Logger.commands.gm=3,Console GM Logger.sql.sql=5,Console DBErrors Logger.sql.updates=3,Console Server +Logger.mmaps=3,Server #Logger.achievement=3,Console Server #Logger.addon=3,Console Server @@ -3482,6 +3623,7 @@ Logger.sql.updates=3,Console Server #Logger.rbac=3,Console Server #Logger.scripts=3,Console Server #Logger.scripts.ai=3,Console Server +#Logger.scripts.hotswap=3,Console Server #Logger.server.authserver=3,Console Server #Logger.spells=3,Console Server #Logger.spells.periodic=3,Console Server diff --git a/src/tools/map_extractor/CMakeLists.txt b/src/tools/map_extractor/CMakeLists.txt index d0f3e42cef8..c0bd102f8e6 100644 --- a/src/tools/map_extractor/CMakeLists.txt +++ b/src/tools/map_extractor/CMakeLists.txt @@ -9,41 +9,38 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -file(GLOB_RECURSE mapextractor_SRCS *.cpp *.h) - -set(include_Dirs - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/dep/cppformat - ${CMAKE_SOURCE_DIR}/dep/g3dlite/include - ${CMAKE_SOURCE_DIR}/dep/libmpq - ${CMAKE_SOURCE_DIR}/src/common - ${CMAKE_SOURCE_DIR}/src/common/Utilities - ${CMAKE_SOURCE_DIR}/src/server/shared - ${CMAKE_CURRENT_SOURCE_DIR}/loadlib -) - -if( WIN32 ) - set(include_Dirs - ${include_Dirs} - ${CMAKE_SOURCE_DIR}/dep/libmpq/win - ) -endif() - -include_directories(${include_Dirs}) +CollectSourceFiles( + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE_SOURCES) add_executable(mapextractor - ${mapextractor_SRCS} + ${PRIVATE_SOURCES} ) +target_include_directories(mapextractor + PUBLIC + ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/loadlib) + target_link_libraries(mapextractor - common - format - g3dlib - mpq - ${BZIP2_LIBRARIES} - ${ZLIB_LIBRARIES} - ${Boost_LIBRARIES} -) + PUBLIC + common + mpq) + +CollectIncludeDirectories( + ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC_INCLUDES) + +target_include_directories(mapextractor + PUBLIC + ${PUBLIC_INCLUDES} + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) + +set_target_properties(mapextractor + PROPERTIES + FOLDER + "tools") if( UNIX ) install(TARGETS mapextractor DESTINATION bin) diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index f3a761fd437..1d84fc75d27 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -53,12 +53,13 @@ char input_path[MAX_PATH_LENGTH] = "."; // ************************************************** enum Extract { - EXTRACT_MAP = 1, - EXTRACT_DBC = 2 + EXTRACT_MAP = 1, + EXTRACT_DBC = 2, + EXTRACT_CAMERA = 4 }; // Select data for extract -int CONF_extract = EXTRACT_MAP | EXTRACT_DBC; +int CONF_extract = EXTRACT_MAP | EXTRACT_DBC | EXTRACT_CAMERA; // This option allow limit minimum height to some value (Allow save some memory) bool CONF_allow_height_limit = true; float CONF_use_minHeight = -500.0f; @@ -103,7 +104,7 @@ void Usage(char* prg) "%s -[var] [value]\n"\ "-i set input path (max %d characters)\n"\ "-o set output path (max %d characters)\n"\ - "-e extract only MAP(1)/DBC(2) - standard: both(3)\n"\ + "-e extract only MAP(1)/DBC(2)/Camera(4) - standard: all(7)\n"\ "-f height stored as int (less map size but lost some accuracy) 1 by default\n"\ "Example: %s -f 0 -i \"c:\\games\\game\"", prg, MAX_PATH_LENGTH - 1, MAX_PATH_LENGTH - 1, prg); exit(1); @@ -151,7 +152,7 @@ void HandleArgs(int argc, char * arg[]) if(c + 1 < argc) // all ok { CONF_extract=atoi(arg[(c++) + 1]); - if(!(CONF_extract > 0 && CONF_extract < 4)) + if(!(CONF_extract > 0 && CONF_extract < 8)) Usage(arg[0]); } else @@ -1025,6 +1026,56 @@ void ExtractDBCFiles(int locale, bool basicLocale) printf("Extracted %u DBC files\n\n", count); } +void ExtractCameraFiles(int locale, bool basicLocale) +{ + printf("Extracting camera files...\n"); + DBCFile camdbc("DBFilesClient\\CinematicCamera.dbc"); + + if (!camdbc.open()) + { + printf("Unable to open CinematicCamera.dbc. Camera extract aborted.\n"); + return; + } + + // get camera file list from DBC + std::vector<std::string> camerafiles; + size_t cam_count = camdbc.getRecordCount(); + + for (uint32 i = 0; i < cam_count; ++i) + { + std::string camFile(camdbc.getRecord(i).getString(1)); + size_t loc = camFile.find(".mdx"); + if (loc != std::string::npos) + camFile.replace(loc, 4, ".m2"); + camerafiles.push_back(std::string(camFile)); + } + + std::string path = output_path; + path += "/Cameras/"; + CreateDir(path); + if (!basicLocale) + { + path += langs[locale]; + path += "/"; + CreateDir(path); + } + + // extract M2s + uint32 count = 0; + for (std::string thisFile : camerafiles) + { + std::string filename = path; + filename += (thisFile.c_str() + strlen("Cameras\\")); + + if (boost::filesystem::exists(filename)) + continue; + + if (ExtractFile(thisFile.c_str(), filename)) + ++count; + } + printf("Extracted %u camera files\n", count); +} + void LoadLocaleMPQFiles(int const locale) { std::string fileName = Trinity::StringFormat("%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]); @@ -1111,6 +1162,19 @@ int main(int argc, char * arg[]) return 0; } + if (CONF_extract & EXTRACT_CAMERA) + { + printf("Using locale: %s\n", langs[FirstLocale]); + + // Open MPQs + LoadLocaleMPQFiles(FirstLocale); + LoadCommonMPQFiles(); + + ExtractCameraFiles(FirstLocale, true); + // Close MPQs + CloseMPQFiles(); + } + if (CONF_extract & EXTRACT_MAP) { printf("Using locale: %s\n", langs[FirstLocale]); diff --git a/src/tools/mmaps_generator/CMakeLists.txt b/src/tools/mmaps_generator/CMakeLists.txt index 4eb416a106b..64c82101f61 100644 --- a/src/tools/mmaps_generator/CMakeLists.txt +++ b/src/tools/mmaps_generator/CMakeLists.txt @@ -8,51 +8,33 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -file(GLOB_RECURSE mmap_gen_sources *.cpp *.h) +CollectSourceFiles( + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE_SOURCES) -set(mmap_gen_Includes - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/dep/libmpq - ${CMAKE_SOURCE_DIR}/dep/zlib - ${CMAKE_SOURCE_DIR}/dep/bzip2 - ${CMAKE_SOURCE_DIR}/dep/g3dlite/include - ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast - ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include - ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour - ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include - ${CMAKE_SOURCE_DIR}/src/server/shared - ${CMAKE_SOURCE_DIR}/src/server/game/Conditions - ${CMAKE_SOURCE_DIR}/src/common - ${CMAKE_SOURCE_DIR}/src/common/Collision - ${CMAKE_SOURCE_DIR}/src/common/Collision/Management - ${CMAKE_SOURCE_DIR}/src/common/Collision/Maps - ${CMAKE_SOURCE_DIR}/src/common/Collision/Models - ${CMAKE_SOURCE_DIR}/src/common/Debugging - ${CMAKE_SOURCE_DIR}/src/common/Threading - ${CMAKE_SOURCE_DIR}/src/common/Utilities -) +add_executable(mmaps_generator ${PRIVATE_SOURCES}) -if( WIN32 ) - set(mmap_gen_Includes - ${mmap_gen_Includes} - ${CMAKE_SOURCE_DIR}/dep/libmpq/win - ) -endif() +target_link_libraries(mmaps_generator + PUBLIC + common + Recast + Detour + mpq) -include_directories(${mmap_gen_Includes}) +CollectIncludeDirectories( + ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC_INCLUDES) -add_executable(mmaps_generator ${mmap_gen_sources}) +target_include_directories(mmaps_generator + PUBLIC + ${PUBLIC_INCLUDES} + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(mmaps_generator - common - g3dlib - Recast - Detour - ${BZIP2_LIBRARIES} - ${ZLIB_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_LIBRARIES} -) +set_target_properties(mmaps_generator + PROPERTIES + FOLDER + "tools") if( UNIX ) install(TARGETS mmaps_generator DESTINATION bin) diff --git a/src/tools/vmap4_assembler/CMakeLists.txt b/src/tools/vmap4_assembler/CMakeLists.txt index c33b2996685..58cb066f75b 100644 --- a/src/tools/vmap4_assembler/CMakeLists.txt +++ b/src/tools/vmap4_assembler/CMakeLists.txt @@ -9,17 +9,6 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -include_directories( - ${CMAKE_SOURCE_DIR}/dep/g3dlite/include - ${CMAKE_SOURCE_DIR}/src/server/shared - ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging - ${CMAKE_SOURCE_DIR}/src/common - ${CMAKE_SOURCE_DIR}/src/common/Collision - ${CMAKE_SOURCE_DIR}/src/common/Collision/Maps - ${CMAKE_SOURCE_DIR}/src/common/Collision/Models - ${ZLIB_INCLUDE_DIR} -) - add_executable(vmap4assembler VMapAssembler.cpp) if(CMAKE_SYSTEM_NAME MATCHES "Darwin") @@ -28,9 +17,12 @@ endif() target_link_libraries(vmap4assembler common - g3dlib - ${ZLIB_LIBRARIES} -) + zlib) + +set_target_properties(vmap4assembler + PROPERTIES + FOLDER + "tools") if( UNIX ) install(TARGETS vmap4assembler DESTINATION bin) diff --git a/src/tools/vmap4_extractor/CMakeLists.txt b/src/tools/vmap4_extractor/CMakeLists.txt index 55e66b32ea8..f13aaec15b2 100644 --- a/src/tools/vmap4_extractor/CMakeLists.txt +++ b/src/tools/vmap4_extractor/CMakeLists.txt @@ -9,28 +9,30 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -file(GLOB_RECURSE sources *.cpp *.h) +CollectSourceFiles( + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE_SOURCES) -set(include_Dirs - ${CMAKE_SOURCE_DIR}/dep/libmpq -) +add_executable(vmap4extractor ${PRIVATE_SOURCES}) -if( WIN32 ) - set(include_Dirs - ${include_Dirs} - ${CMAKE_SOURCE_DIR}/dep/libmpq/win - ) -endif() +target_link_libraries(vmap4extractor + PUBLIC + mpq) -include_directories(${include_Dirs}) +CollectIncludeDirectories( + ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC_INCLUDES) -add_executable(vmap4extractor ${sources}) +target_include_directories(vmap4extractor + PUBLIC + ${PUBLIC_INCLUDES} + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(vmap4extractor - mpq - ${BZIP2_LIBRARIES} - ${ZLIB_LIBRARIES} -) +set_target_properties(vmap4extractor + PROPERTIES + FOLDER + "tools") if( UNIX ) install(TARGETS vmap4extractor DESTINATION bin) |